Changeset 6835 for TI12-security


Ignore:
Timestamp:
21/04/10 15:04:59 (10 years ago)
Author:
pjkersha
Message:

Completed port to PyOpenSSL from M2Crypto with all unit tests passed. Merge back into the main trunk as next step.

Location:
TI12-security/branches/MyProxyClient-pyopenssl
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/branches/MyProxyClient-pyopenssl/myproxy/client.py

    r6829 r6835  
    2626import os 
    2727import socket 
    28 from M2Crypto import X509, RSA, EVP, m2, BIO, SSL, util 
    2928import base64 
     29import traceback 
     30from cStringIO import StringIO 
    3031from ConfigParser import SafeConfigParser 
     32 
     33from OpenSSL import crypto, SSL 
    3134 
    3235from myproxy.utils.openssl import OpenSSLConfig, OpenSSLConfigError 
     
    4346 
    4447 
    45 class _HostCheck(SSL.Checker.Checker): 
    46     """Override SSL.Checker.Checker to allow additional check of MyProxy  
    47     server identity.  If hostname doesn't match, allow match of host's   
    48     Distinguished Name against MYPROXY_SERVER_DN setting""" 
    49  
    50     def __init__(self,  
    51                  myProxyServerDN=os.environ.get('MYPROXY_SERVER_DN'), 
    52                  cnHostPfx='host/', 
    53                  **kw): 
    54         """Override parent class __init__ to enable setting of myProxyServerDN 
    55         setting 
    56          
    57         @type myProxyServerDN: string 
    58         @param myProxyServerDN: Set the expected Distinguished Name of the 
    59         MyProxy server to avoid errors matching hostnames.  This is useful 
    60         where the hostname is not fully qualified 
    61          
    62         @type cnHostPfx: string 
    63         @param cnHostPfx: globus host certificates are  
    64         generated by default with a 'host/' prefix to the host name.  Set 
    65         this keyword to '' or None to override and omit the prefix""" 
    66          
    67         SSL.Checker.Checker.__init__(self, **kw) 
    68          
    69         self.myProxyServerDN = myProxyServerDN 
    70         self.cnHostPfx = cnHostPfx 
    71          
    72          
    73     def __call__(self, peerCert, host=None): 
    74         """Carry out checks on server ID 
    75         @type peerCert: basestring 
    76         @param peerCert: MyProxy server host certificate as M2Crypto.X509.X509 
    77         instance 
    78         @type host: basestring 
    79         @param host: name of host to check 
    80         """ 
    81          
    82         # Globus host certificate has a "host/" prefix - see explanation in 
    83         # __init__.__doc__ 
    84         cnHostPfx = isinstance(self.cnHostPfx, basestring) \ 
    85                     and self.cnHostPfx or '' 
    86         host = None or cnHostPfx + self.host 
    87          
    88         try: 
    89             SSL.Checker.Checker.__call__(self, peerCert, host=host) 
    90              
    91         except SSL.Checker.WrongHost, e: 
    92             # Try match against DN set from MYPROXY_SERVER_DN / config 
    93             # file setting 
    94             peerCertDN = '/'+peerCert.get_subject().as_text().replace(', ','/') 
    95              
    96             # If they match drop the exception and return all OK instead 
    97             if peerCertDN != self.myProxyServerDN: 
    98                 raise 
    99              
    100         return True 
     48#class _HostCheck(SSL.Checker.Checker): 
     49#    """Override SSL.Checker.Checker to allow additional check of MyProxy  
     50#    server identity.  If hostname doesn't match, allow match of host's   
     51#    Distinguished Name against MYPROXY_SERVER_DN setting""" 
     52# 
     53#    def __init__(self,  
     54#                 myProxyServerDN=os.environ.get('MYPROXY_SERVER_DN'), 
     55#                 cnHostPfx='host/', 
     56#                 **kw): 
     57#        """Override parent class __init__ to enable setting of myProxyServerDN 
     58#        setting 
     59#         
     60#        @type myProxyServerDN: string 
     61#        @param myProxyServerDN: Set the expected Distinguished Name of the 
     62#        MyProxy server to avoid errors matching hostnames.  This is useful 
     63#        where the hostname is not fully qualified 
     64#         
     65#        @type cnHostPfx: string 
     66#        @param cnHostPfx: globus host certificates are  
     67#        generated by default with a 'host/' prefix to the host name.  Set 
     68#        this keyword to '' or None to override and omit the prefix""" 
     69#         
     70#        SSL.Checker.Checker.__init__(self, **kw) 
     71#         
     72#        self.myProxyServerDN = myProxyServerDN 
     73#        self.cnHostPfx = cnHostPfx 
     74#         
     75#         
     76#    def __call__(self, peerCert, host=None): 
     77#        """Carry out checks on server ID 
     78#        @type peerCert: basestring 
     79#        @param peerCert: MyProxy server host certificate as M2Crypto.X509.X509 
     80#        instance 
     81#        @type host: basestring 
     82#        @param host: name of host to check 
     83#        """ 
     84#         
     85#        # Globus host certificate has a "host/" prefix - see explanation in 
     86#        # __init__.__doc__ 
     87#        cnHostPfx = isinstance(self.cnHostPfx, basestring) \ 
     88#                    and self.cnHostPfx or '' 
     89#        host = None or cnHostPfx + self.host 
     90#         
     91#        try: 
     92#            SSL.Checker.Checker.__call__(self, peerCert, host=host) 
     93#             
     94#        except SSL.Checker.WrongHost, e: 
     95#            # Try match against DN set from MYPROXY_SERVER_DN / config 
     96#            # file setting 
     97#            peerCertDN = '/'+peerCert.get_subject().as_text().replace(', ','/') 
     98#             
     99#            # If they match drop the exception and return all OK instead 
     100#            if peerCertDN != self.myProxyServerDN: 
     101#                raise 
     102#             
     103#        return True 
    101104     
    102105     
     
    503506        not needed in the case of a proxy private key 
    504507        """ 
    505  
    506508        # Must be version 3 for MyProxy 
    507         context = SSL.Context(protocol='sslv3') 
    508  
     509        context = SSL.Context(SSL.SSLv3_METHOD) 
     510         
    509511        if self.caCertFilePath or self.caCertDir: 
    510             context.load_verify_locations(cafile=self.caCertFilePath, 
    511                                           capath=self.caCertDir) 
    512                              
    513             # Stop if peer's certificate can't be verified 
    514             context.set_allow_unknown_ca(False) 
    515         else: 
    516             context.set_allow_unknown_ca(True) 
     512            context.load_verify_locations(self.caCertFilePath, self.caCertDir) 
    517513             
    518514        if ownerCertFile: 
    519515            try: 
    520                 context.load_cert_chain(ownerCertFile, 
    521                                     keyfile=ownerKeyFile, 
    522                                     callback=lambda *ar, **kw: ownerPassphrase) 
    523             except Exception, e: 
     516#                context.use_certificate_file(ownerCertFile) 
     517                context.use_certificate_chain_file(ownerCertFile) 
     518                def pwdCallback(passphraseMaxLen,  
     519                                promptPassphraseTwice, 
     520                                passphrase): 
     521                    if passphrase is None: 
     522                        return True 
     523                    else: 
     524                        if len(passphrase) > passphraseMaxLen: 
     525                            log.error('Passphrase length %d is greater than ' 
     526                                      'the maximum length allowed %d', 
     527                                      len(passphrase), passphraseMaxLen) 
     528                            return '' 
     529                        return passphrase 
     530                     
     531                context.set_passwd_cb(pwdCallback, ownerPassphrase) 
     532                context.use_privatekey_file(ownerKeyFile) 
     533            except Exception: 
    524534                raise MyProxyClientConfigError("Loading certificate " 
    525535                                               "and private key for SSL " 
    526536                                               "connection [also check CA " 
    527                                                "certificate settings]: %s" % e)  
    528              
    529             # Verify peer's certificate 
    530             context.set_verify(SSL.verify_peer, 1)  
     537                                               "certificate settings]: %s" %  
     538                                               traceback.format_exc())  
     539             
     540        # Verify peer's certificate 
     541        def callback(connection, x509Cert, *arg, **kw): 
     542            return True 
     543         
     544        context.set_verify(SSL.VERIFY_PEER, callback)  
    531545         
    532546            
     
    534548        # globus doesn't handle this case, apparently, and instead 
    535549        # chokes in proxy delegation code 
    536         context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) 
     550        context.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS) 
    537551         
    538552        # connect to myproxy server 
    539         conn = SSL.Connection(context, sock=socket.socket()) 
     553        conn = SSL.Connection(context, socket.socket()) 
    540554         
    541555        # Check server host identity - if host doesn't match use explicit 
    542556        # 'serverDN'  
    543557        # host/<hostname> one 
    544         hostCheck = _HostCheck(host=self.hostname, 
    545                                myProxyServerDN=self.serverDN, 
    546                                cnHostPfx=self.serverCNPrefix) 
    547         conn.set_post_connection_check_callback(hostCheck) 
     558#        hostCheck = _HostCheck(host=self.hostname, 
     559#                               myProxyServerDN=self.serverDN, 
     560#                               cnHostPfx=self.serverCNPrefix) 
     561#        conn.set_post_connection_check_callback(hostCheck) 
    548562         
    549563        return conn 
    550564         
    551     def _createKeys(self, nBitsForKey=PRIKEY_NBITS): 
     565    def _createKeyPair(self, nBitsForKey=PRIKEY_NBITS): 
    552566        """Generate key pair and return as PEM encoded string 
    553567        @type nBitsForKey: int 
     
    557571        @return: public/private key pair 
    558572        """ 
    559         keyPair = RSA.gen_key(nBitsForKey, 65537L,#m2.RSA_F4,  
    560                               callback=lambda *arg, **kw: None) 
     573        keyPair = crypto.PKey() 
     574        keyPair.generate_key(crypto.TYPE_RSA, nBitsForKey) 
    561575         
    562576        return keyPair 
     
    578592        # Check all required certifcate request DN parameters are set                 
    579593        # Create certificate request 
    580         req = X509.Request() 
     594        certReq = crypto.X509Req() 
    581595         
    582596        # Create public key object 
    583         pubKey = EVP.PKey() 
    584         pubKey.assign_rsa(keyPair) 
     597        certReq.set_pubkey(keyPair) 
    585598         
    586599        # Add the public key to the request 
    587         req.set_version(0) 
    588         req.set_pubkey(pubKey) 
    589          
    590         defaultReqDN = self._openSSLConfig.reqDN 
    591               
    592         # Set DN 
    593         x509Name = X509.X509_Name() 
    594         x509Name.CN = CN 
    595          
    596         if defaultReqDN: 
    597             x509Name.OU = defaultReqDN['OU'] 
    598             x509Name.O = defaultReqDN['O'] 
    599                          
    600         req.set_subject_name(x509Name) 
    601         req.sign(pubKey, messageDigest) 
    602  
    603         return req.as_der() 
     600        certReq.sign(keyPair, messageDigest) 
     601         
     602        derCertReq = crypto.dump_certificate_request(crypto.FILETYPE_ASN1,  
     603                                                     certReq) 
     604 
     605        return derCertReq 
    604606     
    605607    def _deserializeResponse(self, msg, *fieldNames): 
     
    648650         
    649651        @return list containing the equivalent to the input in PEM format""" 
    650         pemCerts = []         
     652        pemCerts = [] 
    651653        dat = inputDat 
    652654         
    653         while dat:     
     655        while dat: 
    654656            # find start of cert, get length         
    655657            ind = dat.find('\x30\x82') 
     
    661663            # extract der-format cert, and convert to pem 
    662664            derCert = dat[ind:ind+len+4] 
    663              
    664             x509 = X509.load_cert_der_string(derCert) 
    665             pemCert = x509.as_pem() 
    666              
     665            x509Cert = crypto.load_certificate(crypto.FILETYPE_ASN1, derCert) 
     666            pemCert = crypto.dump_certificate(crypto.FILETYPE_PEM, x509Cert)         
    667667            pemCerts.append(pemCert) 
    668668     
     
    10091009         
    10101010        # Send certificate and private key 
    1011         certTxt = X509.load_cert(certFile).as_pem() 
     1011        certTxt = open(certFile).read() 
    10121012        keyTxt = open(keyFile).read() 
    10131013         
     
    10511051            # If no key pair was passed, generate here 
    10521052            if keyPair is None: 
    1053                 keyPair = self._createKeys(nBitsForKey=nBitsForKey) 
     1053                keyPair = self._createKeyPair(nBitsForKey=nBitsForKey) 
    10541054                 
    10551055            certReq = self._createCertReq(username, keyPair) 
    10561056 
    10571057        if keyPair is not None:  
    1058             pemKeyPair = keyPair.as_pem(cipher=None,  
    1059                                         callback=util.no_passphrase_callback) 
     1058            pemKeyPair = crypto.dump_privatekey(crypto.FILETYPE_PEM, keyPair) 
    10601059         
    10611060        # Set-up SSL connection 
     
    11471146            for tries in range(MyProxyClient.MAX_RECV_TRIES): 
    11481147                dat += conn.recv(MyProxyClient.SERVER_RESP_BLK_SIZE) 
    1149         except SSL.SSLError: 
     1148        except SSL.SysCallError: 
    11501149            # Expect this exception when response content exhausted 
    11511150            pass 
  • TI12-security/branches/MyProxyClient-pyopenssl/myproxy/test/proxy.crt

    r6829 r6835  
    11-----BEGIN CERTIFICATE----- 
    2 MIICfDCCAeWgAwIBAgIEFEquwTANBgkqhkiG9w0BAQUFADAlMRAwDgYDVQQKEwdH 
    3 YWJyaWVsMREwDwYDVQQDEwh0ZXN0dXNlcjAeFw0xMDA0MjEwOTI5MDNaFw0xMDA0 
    4 MjIwMzM0MDNaMDkxEDAOBgNVBAoTB0dhYnJpZWwxETAPBgNVBAMTCHRlc3R1c2Vy 
    5 MRIwEAYDVQQDEwkzNDA0Mzg3MjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 
    6 AoIBAQDySWTRVbS6L5T9UUoTpARD+Jk6H8NFp9Y1TjFWPaKySKa9ep0Gdj0vM83B 
    7 84Hz0U2R6FgdoaTBFIB2pbugjbm3pl8FIRZKaq7gdO6otmC21Y5XpjVA0s/fgyBG 
    8 y0iKqG78lSDnaBmVyaCra+2a7kkqsxGwUCMAlnxmZPqsHKXuRozRwTassH+BdUIt 
    9 A3oUe7M1PQLo3e5hwJWg/7igRHc7kHItaSRUcXeZ7RNnY/DNSU6ww/ovWFZajqpt 
    10 cCyFpmRZ6nPx2jhxWyKvu8xi+NeKlkwc9mmqcWdJD1iRomQWNJAgG85Bm2oZSlMV 
    11 xJwMoiEZRxNk1yzBTMlqRW+Tcu69AgMBAAGjITAfMB0GCCsGAQUFBwEOAQH/BA4w 
    12 DDAKBggrBgEFBQcVATANBgkqhkiG9w0BAQUFAAOBgQDcbaaHn/fP61V97xl+24v/ 
    13 qFaFG4F415QD6o7ZTV0o1dub1ygXO5FaVBYgDa7bxV72qZw24rxbLs5fxVkKBAWc 
    14 HYidDjG9FlDcgEC43Y6NSyugvuoPowBx/IPdRe2e/ub0qbZrAm7Xz8mNJKfVXkV8 
    15 vhj9yMRFrxmIyqFVoSI+QA== 
     2MIICfTCCAeagAwIBAgIEVdVpFTANBgkqhkiG9w0BAQUFADAlMRAwDgYDVQQKEwdH 
     3YWJyaWVsMREwDwYDVQQDEwh0ZXN0dXNlcjAeFw0xMDA0MjExMzU1MjFaFw0xMDA0 
     4MjIwODAwMjFaMDoxEDAOBgNVBAoTB0dhYnJpZWwxETAPBgNVBAMTCHRlc3R1c2Vy 
     5MRMwEQYDVQQDEwoxNDQwMDQ5NDI5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 
     6CgKCAQEAt6SUcdngNsLJLGw28UfGRHGL9y0YQJ3D4c7L6JnV2KSWleqi3BZr95HV 
     7O2BD2jFiH0aGShDqzdaB6SM4TVtxcW1XVrVhUNIIFrfGHo20qaWNQhV2zvosJXaI 
     8J7w2nGwKtHdiARdMKQ0xQKPeS4Ww6HPcsTljFi0Yix4zmIZUcXLtW97VxTN8nJ2t 
     9UvJD2Bu48i+z3pb1025ODReAr2XvxKoAVgBdwntc3/gjKVkrpX54lOLKeLQOOGxq 
     107GavctxfXiWQ7j4CiQZ/3AHiqimXbJnJWYU9v9tC2JQRrQ6gyepdUe2IDedavWfH 
     11tBLhTDSm8d+s6BgF4BetYaq64R11hwIDAQABoyEwHzAdBggrBgEFBQcBDgEB/wQO 
     12MAwwCgYIKwYBBQUHFQEwDQYJKoZIhvcNAQEFBQADgYEAI5I7ZIWMS0b53V0JaM4I 
     13IbzWZnRW0LK/grerRJd3VVmiG4odMsooY0jKjSokxZTnXme+YxtD4wrBwQ4Z6BSr 
     14D8/LTEwB/rkdEBlr23TSZnCZXBq0PuKKpSlcD3nT152/3QQ21VZaPJwgSsb0WadF 
     15vdYgtEd43hsOTkIsH7KG4lA= 
    1616-----END CERTIFICATE----- 
    1717-----BEGIN CERTIFICATE----- 
  • TI12-security/branches/MyProxyClient-pyopenssl/myproxy/test/proxy.key

    r6829 r6835  
    11-----BEGIN RSA PRIVATE KEY----- 
    2 MAMCAQA= 
     2MIIEpQIBAAKCAQEAt6SUcdngNsLJLGw28UfGRHGL9y0YQJ3D4c7L6JnV2KSWleqi 
     33BZr95HVO2BD2jFiH0aGShDqzdaB6SM4TVtxcW1XVrVhUNIIFrfGHo20qaWNQhV2 
     4zvosJXaIJ7w2nGwKtHdiARdMKQ0xQKPeS4Ww6HPcsTljFi0Yix4zmIZUcXLtW97V 
     5xTN8nJ2tUvJD2Bu48i+z3pb1025ODReAr2XvxKoAVgBdwntc3/gjKVkrpX54lOLK 
     6eLQOOGxq7GavctxfXiWQ7j4CiQZ/3AHiqimXbJnJWYU9v9tC2JQRrQ6gyepdUe2I 
     7DedavWfHtBLhTDSm8d+s6BgF4BetYaq64R11hwIDAQABAoIBAQCC3tarDAms/MNA 
     81R2SdQPmYsTMMWbHJacilKzb5kVvTlvCGqRVE+V9WIANAF1acTbr8uZggg3TArsx 
     92deVyUTfAHztXfUsE4GQLwcRXwsQmto/7evtNHuhdwcwygBhGN3IHgvJm0C7QJuI 
     105T7Vs0CPZ4IvCiaC90A2ZB+A4rnq3jbJqwXyw4vqqVGsP/5nggqT5F1/uqHe9pHW 
     11+9GNXbj2HR4DCP8VyNzaSA3tJh5RFtpAx0Tby6FZ6+yC+dORZG51ApuUam/5EqVp 
     12YS3SvGYWOyc6Cb3wKR5839K/ZXazN/V6swTbmnFMqerfgZ8OD1uFu2C7fmcHcz34 
     13N5rWs36BAoGBAOMm9o4eALXFyon47jrJxjiTteRvHKKCXu5jMhnCp41+xV1M2a1L 
     14qlVK44OnF+WoJPc8SAZGhGXagZKex2fXjpAYZZVZiyCuEjbAwpZpTI7aSH/Ygsj0 
     15zeBck1Nl3jOf3DhXZa2PlPamBTc6A08bIG9foB09VqP4QGCXqQ8wbrFDAoGBAM73 
     16EWn02YEJ7Qex+JNoUCPmPkDmAWBrUvypjuG+cP8mSY7zice2LlRNwKXh6jX9DuWi 
     17cNB1GXwijvyHpUuUVOoOqu5jHVPZAq1IdwlQ21Gcv0dIb90aeJAk1kxFTWwQdC5Z 
     18HR+cDnCBh57lVrRlnuhv1OGK1j3UDUtSs8ZyxlRtAoGBAMQAzOLYlLhEkX34ZGgp 
     19z3bmTh9smQLJB+0ffw2nXzjC2L6nH3VfQv0R/7uMJRyvuCX1yBhSJNBWeVPw2hOK 
     20dqNzycPTXi+2xFSmg8GR3tOtGr3mLwQD6NneR+nAjrlxCW88Sqo2qM0jeICs+En8 
     21GELB+sEAOpCGF9bBRsmqevlNAoGBAJTsp7UsoM3/jHX7FDlN2EzcwnMEjn0I/UAd 
     226lh6JukSbd/VUpFIgHHdOQCkXVnX7D5E8xStDleKroT8Pm7yH2AEie7blyDciNaT 
     23zEQB0K8bMXBjqUraX2KpfyKGw7084bzwFsrGCoXeTu6BbDCG5x+uSOq6cosu6RoI 
     24OqBTum7JAoGAJiykiLWkcwu6zDYly4c31gk42Am9I5i/ZKuFdIZrX2Vrwex/QTRR 
     25HGHqM2/7yyDDMeS6XRXEETA5zZzcTr3+s3oluLbD79dNUTh6PVh9mb2GF6fwJcgB 
     26M+a7tIqlxWJMN5erHvp13imHMLIhqtTiSm18lUDBIzDAL70W6Kor8co= 
    327-----END RSA PRIVATE KEY----- 
  • TI12-security/branches/MyProxyClient-pyopenssl/myproxy/test/test_myproxyclient.py

    r6829 r6835  
    2020from os import path 
    2121 
    22 from M2Crypto import X509 
     22from OpenSSL import crypto 
    2323 
    2424from myproxy.client import CaseSensitiveConfigParser, MyProxyClient 
     
    102102        print "proxy credentials:"  
    103103        print ''.join(creds) 
    104         open(proxyCertFile, 'w').write(creds[0]+''.join(creds[2:]))             
     104        open(proxyCertFile, 'w').write(creds[0]+''.join(creds[2:])) 
    105105        open(proxyKeyFile, 'w').write(creds[1]) 
    106106 
     
    117117 
    118118        credExists, errorTxt, fields = self.clnt.info( 
    119                                      thisSection['username'], 
    120                                      path.expandvars(thisSection['ownerCertFile']), 
    121                                      path.expandvars(thisSection['ownerKeyFile']), 
    122                                      ownerPassphrase=ownerPassphrase) 
     119                                 thisSection['username'], 
     120                                 path.expandvars(thisSection['ownerCertFile']), 
     121                                 path.expandvars(thisSection['ownerKeyFile']), 
     122                                 ownerPassphrase=ownerPassphrase) 
    123123        print "test3Info... " 
    124124        print "credExists: %s" % credExists 
     
    182182            if fileName.endswith('.0'): 
    183183                # test parsing certificate 
    184                 cert = X509.load_cert_string(fileContents, X509.FORMAT_PEM) 
     184                cert = crypto.load_certificate(crypto.FILETYPE_PEM, 
     185                                               fileContents) 
    185186                self.assert_(cert) 
    186                 self.assert_(isinstance(cert, X509.X509)) 
     187                self.assert_(isinstance(cert, crypto.X509)) 
    187188                subj = cert.get_subject() 
    188189                self.assert_(subj) 
Note: See TracChangeset for help on using the changeset viewer.