"""
pyweblib.sslenv.py - retrieve SSL data from os.env
(C) by Michael Stroeder

This module is distributed under the terms of the
GPL (GNU GENERAL PUBLIC LICENSE) Version 2
(see http://www.gnu.org/copyleft/gpl.html)

$Id: sslenv.py,v 1.5 2002/01/27 00:36:35 michael Exp $
"""

__version__ = '0.6.0'

import sys,os,re,string

def t612html4(s):
  """
  Convert T.61 character representation to HTML-4 character representation
  """
  new = ''
  slashpos = string.find(s,'\\x')
  while slashpos!=-1:
    if (s[slashpos]==0) or (s[slashpos]>0 and s[slashpos-1]!='\\'):
      new = new+s[0:slashpos]+'&#%d;' % string.atoi(s[slashpos+2:slashpos+4],16)
      s = s[slashpos+4:]
    else:
      new = new+s[0:slashpos-1]
      s = s[slashpos+1:]
    slashpos = string.find(s,'\\x')
  return new+s

def asn12html4(s):
  """
  Convert BMPString to HTML-4 character representation
  """
  return t612html4(string.replace(s,'\\x00',''))


def GetAllSSLEnviron(env=os.environ):
  """
  Get all SSL-related environment vars and return mod_ssl
  compatible dictionary.
  
  mod_ssl compatible names are preferred. ApacheSSL names
  are used as fallback.
  """
  if env.get('HTTPS','off')!='on':
    return {}
  SSLEnv = {}
  SSLEnv['SSL_CIPHER_ALGKEYSIZE'] = \
    env.get('SSL_CIPHER_ALGKEYSIZE',
    env.get('HTTPS_KEYSIZE',
    env.get('SSL_KEYSIZE',
    env.get('SSL_SERVER_KEY_SIZE',
    None))))
  SSLEnv['SSL_CIPHER_EXPORT'] = \
    env.get('SSL_CIPHER_EXPORT',
    env.get('HTTPS_EXPORT',
    env.get('SSL_EXPORT',
    None)))
  SSLEnv['SSL_CIPHER'] = \
    env.get('SSL_CIPHER',
    env.get('HTTPS_CIPHER',
    None))
  SSLEnv['SSL_CIPHER_USEKEYSIZE'] = \
    env.get('SSL_CIPHER_USEKEYSIZE',
    env.get('HTTPS_SECRETKEYSIZE',
    env.get('SSL_SECKEYSIZE',
    None)))
  SSLEnv['SSL_CLIENT_A_SIG'] = \
    env.get('SSL_CLIENT_A_SIG',
    env.get('SSL_CLIENT_SIGNATURE_ALGORITHM',
    None))
  SSLEnv['SSL_CLIENT_CERT'] = \
    env.get('SSL_CLIENT_CERT',
    env.get('SSL_CLIENT_CERTIFICATE',
    None))
  SSLEnv['SSL_CLIENT_I_DN'] = \
    env.get('SSL_CLIENT_I_DN',
    env.get('SSL_CLIENT_IDN',
    None))
  SSLEnv['SSL_CLIENT_I_DN_CN'] = \
    env.get('SSL_CLIENT_I_DN_CN',
    env.get('SSL_CLIENT_ICN',
    None))
  SSLEnv['SSL_CLIENT_I_DN_C'] = \
    env.get('SSL_CLIENT_I_DN_C',
    env.get('SSL_CLIENT_IC',
    None))
  SSLEnv['SSL_CLIENT_I_DN_Email'] = \
    env.get('SSL_CLIENT_I_DN_Email',
    env.get('SSL_CLIENT_IEMAIL',
    None))
  SSLEnv['SSL_CLIENT_I_DN_L'] = \
    env.get('SSL_CLIENT_I_DN_L',
    env.get('SSL_CLIENT_IL',
    None))
  SSLEnv['SSL_CLIENT_I_DN_O'] = \
    env.get('SSL_CLIENT_I_DN_O',
    env.get('SSL_CLIENT_IO',
    None))
  SSLEnv['SSL_CLIENT_I_DN_OU'] = \
    env.get('SSL_CLIENT_I_DN_OU',
    env.get('SSL_CLIENT_IOU',
    None))
  SSLEnv['SSL_CLIENT_I_DN_SP'] = \
    env.get('SSL_CLIENT_I_DN_SP',
    env.get('SSL_CLIENT_ISP',
    None))
  SSLEnv['SSL_CLIENT_M_SERIAL'] = \
    env.get('SSL_CLIENT_M_SERIAL',
    env.get('SSL_CLIENT_CERT_SERIAL',
    None))
  SSLEnv['SSL_CLIENT_S_DN'] = \
    env.get('SSL_CLIENT_S_DN',
    env.get('SSL_CLIENT_DN',
    None))
  SSLEnv['SSL_CLIENT_S_DN_CN'] = \
    env.get('SSL_CLIENT_S_DN_CN',
    env.get('SSL_CLIENT_CN',
    None))
  SSLEnv['SSL_CLIENT_S_DN_C'] = \
    env.get('SSL_CLIENT_S_DN_C',
    env.get('SSL_CLIENT_C',
    None))
  SSLEnv['SSL_CLIENT_S_DN_Email'] = \
    env.get('SSL_CLIENT_S_DN_Email',
    env.get('SSL_CLIENT_EMAIL',
    None))
  SSLEnv['SSL_CLIENT_S_DN_L'] = \
    env.get('SSL_CLIENT_S_DN_L',
    env.get('SSL_CLIENT_L',
    None))
  SSLEnv['SSL_CLIENT_S_DN_O'] = \
    env.get('SSL_CLIENT_S_DN_O',
    env.get('SSL_CLIENT_O',
    None))
  SSLEnv['SSL_CLIENT_S_DN_OU'] = \
    env.get('SSL_CLIENT_S_DN_OU',
    env.get('SSL_CLIENT_OU',
    None))
  SSLEnv['SSL_CLIENT_S_DN_SP'] = \
    env.get('SSL_CLIENT_S_DN_SP',
    env.get('SSL_CLIENT_SP',
    None))
  SSLEnv['SSL_CLIENT_V_END'] = \
    env.get('SSL_CLIENT_V_END',
    env.get('SSL_CLIENT_CERT_END',
    None))
  SSLEnv['SSL_CLIENT_V_START'] = \
    env.get('SSL_CLIENT_V_START',
    env.get('SSL_CLIENT_CERT_START',
    None))
  SSLEnv['SSL_PROTOCOL'] = \
    env.get('SSL_PROTOCOL',
    env.get('SSL_PROTOCOL_VERSION',
    None))
  SSLEnv['SSL_SERVER_A_SIG'] = \
    env.get('SSL_SERVER_A_SIG',
    env.get('SSL_SERVER_SIGNATURE_ALGORITHM',
    None))
  SSLEnv['SSL_SERVER_CERT'] = \
    env.get('SSL_SERVER_CERT',
    env.get('SSL_SERVER_CERTIFICATE',
    None))
  SSLEnv['SSL_SERVER_I_DN_CN'] = \
    env.get('SSL_SERVER_I_DN_CN',
    env.get('SSL_SERVER_ICN',
    None))
  SSLEnv['SSL_SERVER_I_DN_C'] = \
    env.get('SSL_SERVER_I_DN_C',
    env.get('SSL_SERVER_IC',
    None))
  SSLEnv['SSL_SERVER_I_DN_Email'] = \
    env.get('SSL_SERVER_I_DN_Email',
    env.get('SSL_SERVER_IEMAIL',
    None))
  SSLEnv['SSL_SERVER_I_DN_L'] = \
    env.get('SSL_SERVER_I_DN_L',
    env.get('SSL_SERVER_IL',
    None))
  SSLEnv['SSL_SERVER_I_DN_O'] = \
    env.get('SSL_SERVER_I_DN_O',
    env.get('SSL_SERVER_IO',
    None))
  SSLEnv['SSL_SERVER_I_DN'] = \
    env.get('SSL_SERVER_I_DN',
    env.get('SSL_SERVER_IDN',
    None))
  SSLEnv['SSL_SERVER_I_DN_OU'] = \
    env.get('SSL_SERVER_I_DN_OU',
    env.get('SSL_SERVER_IOU',
    None))
  SSLEnv['SSL_SERVER_I_DN_SP'] = \
    env.get('SSL_SERVER_I_DN_SP',
    env.get('SSL_SERVER_ISP',
    None))
  SSLEnv['SSL_SERVER_M_SERIAL'] = \
    env.get('SSL_SERVER_M_SERIAL',
    env.get('SSL_SERVER_CERT_SERIAL',
    None))
  SSLEnv['SSL_SERVER_S_DN'] = \
    env.get('SSL_SERVER_S_DN',
    env.get('SSL_SERVER_DN',
    None))
  SSLEnv['SSL_SERVER_S_DN_CN'] = \
    env.get('SSL_SERVER_S_DN_CN',
    env.get('SSL_SERVER_CN',
    None))
  SSLEnv['SSL_SERVER_S_DN_C'] = \
    env.get('SSL_SERVER_S_DN_C',
    env.get('SSL_SERVER_C',
    None))
  SSLEnv['SSL_SERVER_S_DN_Email'] = \
    env.get('SSL_SERVER_S_DN_Email',
    env.get('SSL_SERVER_EMAIL',
    None))
  SSLEnv['SSL_SERVER_S_DN_L'] = \
    env.get('SSL_SERVER_S_DN_L',
    env.get('SSL_SERVER_L',
    None))
  SSLEnv['SSL_SERVER_S_DN_O'] = \
    env.get('SSL_SERVER_S_DN_O',
    env.get('SSL_SERVER_O',
    None))
  SSLEnv['SSL_SERVER_S_DN_OU'] = \
    env.get('SSL_SERVER_S_DN_OU',
    env.get('SSL_SERVER_OU',
    None))
  SSLEnv['SSL_SERVER_S_DN_SP'] = \
    env.get('SSL_SERVER_S_DN_SP',
    env.get('SSL_SERVER_SP',
    None))
  SSLEnv['SSL_SERVER_V_END'] = \
    env.get('SSL_SERVER_V_END',
    env.get('SSL_SERVER_CERT_END',
    None))
  SSLEnv['SSL_SERVER_V_START'] = \
    env.get('SSL_SERVER_V_START',
    env.get('SSL_SERVER_CERT_START',
    None))
  SSLEnv['SSL_VERSION_LIBRARY'] = \
    env.get('SSL_VERSION_LIBRARY',
    env.get('SSL_SSLEAY_VERSION',
    None))
  return SSLEnv


def SecLevel(env,acceptedciphers,valid_dn_regex='',valid_idn_regex=''):
  """
  Determine Security Level of SSL session.
  
  Returns:
  0	no SSL at all
  1	SSL-connection and cipher used is in acceptedciphers
  2	like 1 but client also has sent client certificate
  	matching valid_dn_regex and valid_idn_regex.
  """
  https_env = GetAllSSLEnviron(env)
  if https_env and https_env.get('SSL_CIPHER','') in acceptedciphers:
    ssl_client_s_dn = https_env.get('SSL_CLIENT_S_DN','')
    if ssl_client_s_dn:
      ssl_client_i_dn = https_env.get('SSL_CLIENT_I_DN','')
      dn_rm = re.compile(valid_dn_regex).match(ssl_client_s_dn)
      idn_rm = re.compile(valid_idn_regex).match(ssl_client_i_dn)
      if (dn_rm) and (idn_rm):
	return 2
      else:  
	return 1
    else:
      return 1
  else:
    return 0


def PrintSecInfo(env,acceptedciphers,valid_dn_regex='',valid_idn_regex='',f=sys.stdout):
  """
  Print the SSL data in HTML format
  """
  seclevel = SecLevel(env,acceptedciphers,valid_dn_regex,valid_idn_regex)
  https_env = GetAllSSLEnviron(env)
  f.write("""<h3>Security level</h3><p>Current security level is: <strong>%d</strong></p>
           <table cellspacing=5%%>
	   <tr>
	     <td align=center width=10%%>0</td>
	     <td>no encryption at all</td>
	   </tr>
	   <tr>
	     <td align=center>1</td>
	     <td>Session is encrypted with SSL and cipher is accepted</td>
	   </tr>
	   <tr>
	     <td align=center>2</td>
	     <td>Client presented valid certificate,<br>
	     the DN of the certified object matches "<CODE>%s</CODE>"<br>
	     and the DN of the certifier matches "<CODE>%s</CODE>"</td>
	   </tr>
	   </table>
	   """ % (seclevel,valid_dn_regex,valid_idn_regex))

  if seclevel>=1:
    SSL_CIPHER_ALGKEYSIZE = https_env.get('SSL_CIPHER_ALGKEYSIZE')
    SSL_CIPHER = https_env.get('SSL_CIPHER')
    SSL_CIPHER_USEKEYSIZE = https_env.get('SSL_CIPHER_USEKEYSIZE')
    SSL_SERVER_S_DN = https_env.get('SSL_SERVER_S_DN')
    SSL_SERVER_I_DN = https_env.get('SSL_SERVER_I_DN')

    f.write("""You connected with cipher <strong>%s</strong>, key size <strong>%s Bit</strong>, actually used key size <strong>%s Bit</strong>.<p>
<h3>Server certificate</h3>
<table summary="Server certificate">
  <tr>
    <td>
      <dl>
	<dt>This certificate belongs to:</dt>
	<dd>%s</dd>
      </dl>
    </td>
    <td>
      <dl>
	<dt>This certificate was issued by:</dt>
	<dd>%s</dd>
      </dl>
    </td>
  </tr>
</table>
""" % (
  SSL_CIPHER,
  SSL_CIPHER_ALGKEYSIZE,
  SSL_CIPHER_USEKEYSIZE,
  string.join(string.split(asn12html4(SSL_SERVER_S_DN),'/'),'<br>'),
  string.join(string.split(asn12html4(SSL_SERVER_I_DN),'/'),'<br>')
))

  if seclevel>=2:

    SSL_CLIENT_I_DN = https_env.get('SSL_CLIENT_I_DN',
			 https_env.get('SSL_CLIENT_IDN',
			 ''))
    SSL_CLIENT_S_DN = https_env.get('SSL_CLIENT_S_DN',
		      https_env.get('SSL_CLIENT_DN',
		      ''))

    f.write("""<h3>Your client certificate</h3>
<table summary="Client certificate">
  <tr>
    <td>
      <dl>
	<dt>This certificate belongs to:</dt>
	<dd>%s</dd>
      </dl>
    </td>
    <td>
      <dl>
	<dt>This certificate was issued by:</dt>
	<dd>%s</dd>
      </dl>
    </td>
  </tr>
</table>
""" % (
  string.join(string.split(asn12html4(SSL_CLIENT_S_DN),'/'),'<br>'),
  string.join(string.split(asn12html4(SSL_CLIENT_I_DN),'/'),'<br>')
))

