Changeset 1691


Ignore:
Timestamp:
11/11/06 10:35:11 (13 years ago)
Author:
pjkersha
Message:
  • Converted into class.
  • Store works with client authentication - pub/pri key are passed to

SSL Context object.

  • logon has bug getting response. Code needs removal of all use of OpenSSL
File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/Tests/MyProxyClient/m2CryptoMyPxClnt.py

    r1549 r1691  
    1 #!/bin/env python 
     1#!/usr/bin/env python 
    22# 
    33# myproxy client 
     
    2727    return debug >= level 
    2828 
    29  
    30 def createCertReq(CN, 
    31                   O='NDG', 
    32                   OU='BADC', 
    33                   bits=1024,  
    34                   messageDigest="md5"): 
    35     """ 
    36     Create certificate request. 
    37      
    38     Returns: certificate request PEM text, private key PEM text 
    39     """ 
    40                      
    41     # Create certificate request 
    42     req = X509.Request() 
    43  
    44     # Generate keys 
    45     key = RSA.gen_key(bits, m2.RSA_F4) 
    46  
    47     # Create public key object 
    48     pubKey = EVP.PKey() 
    49     pubKey.assign_rsa(key) 
    50      
    51     # Add the public key to the request 
    52     req.set_version(0)# Seems to default to 0, but we can now set it as well 
    53     req.set_pubkey(pubKey) 
    54      
    55     # Set DN 
    56     x509Name = X509.X509_Name() 
    57     x509Name.CN = CN 
    58     x509Name.OU = OU 
    59     x509Name.O = O 
    60     req.set_subject_name(x509Name) 
    61      
    62     req.sign(pubKey, messageDigest) 
    63      
    64     return (req.as_asn1(), key.as_pem(cipher=None)) 
    65  
    66      
    67 def deserializeResponse(msg): 
    68     """ 
    69     Deserialize a MyProxy server response 
    70      
    71     Returns: integer response, errortext (if any) 
    72     """ 
    73      
    74     lines = msg.split('\n') 
    75      
    76     # get response value 
    77     responselines = filter( lambda x: x.startswith('RESPONSE'), lines) 
    78     responseline = responselines[0] 
    79     response = int(responseline.split('=')[1]) 
    80      
    81     # get error text 
    82     errortext = "" 
    83     errorlines = filter( lambda x: x.startswith('ERROR'), lines) 
    84     for e in errorlines: 
    85         etext = e.split('=')[1] 
    86         errortext += etext 
    87      
    88     return response,errortext 
    89   
    90                 
    91 def deserialize_certs(inp_dat): 
    92      
    93     pemCerts = [] 
    94      
    95     dat = inp_dat 
    96      
    97     import base64 
    98     while dat: 
    99  
    100         # find start of cert, get length         
    101         ind = dat.find('\x30\x82') 
    102         if ind < 0: 
    103             break 
    104              
    105         len = 256*ord(dat[ind+2]) + ord(dat[ind+3]) 
    106  
    107         # extract der-format cert, and convert to pem 
    108         c = dat[ind:ind+len+4] 
    109         x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,c) 
    110         pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM,x509) 
    111         pemCerts.append(pem_cert) 
    112  
    113         # trim cert from data 
    114         dat = dat[ind + len + 4:] 
    115      
    116  
    117     return pemCerts 
    118  
    119  
    120 CMD_GET="""VERSION=MYPROXYv2 
     29class MyProxy(object): 
     30     
     31    __getCmd="""VERSION=MYPROXYv2 
    12132COMMAND=0 
    12233USERNAME=%s 
    12334PASSPHRASE=%s 
    12435LIFETIME=%d\0""" 
    125  
    126 CMD_STORE="""VERSION=MYPROXYv2 
     36     
     37    __storeCmd="""VERSION=MYPROXYv2 
    12738COMMAND=5 
    12839USERNAME=%s 
     
    13041LIFETIME=%d\0""" 
    13142 
    132  
    133 def myProxyStore(hostname,  
    134                  username,  
    135                  certFile, 
    136                  keyFile, 
    137                  lifetime=43200, 
    138                  port=7512): 
    139     """ 
    140     Function to store credentials in a MyProxy server 
    141      
    142     Exceptions:  GetException, StoreCredException 
    143     """ 
    144     import pdb; pdb.set_trace() 
    145     # Set to version 3? 
    146     context = Context() 
    147      
    148     # disable for compatibility with myproxy server (er, globus) 
    149     # globus doesn't handle this case, apparently, and instead 
    150     # chokes in proxy delegation code 
    151     context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)#0x00000800L) 
    152      
    153     # connect to myproxy server 
    154     if debuglevel(1):   print "debug: connect to myproxy server" 
    155     conn = Connection(context, sock=socket.socket()) 
    156      
    157     # Fudge to avoid checking client cert - seems to pick globus  
    158     # host/<hostname> one 
    159     conn.clientPostConnectionCheck = None 
    160     conn.connect((hostname,port)) 
    161      
    162     # send globus compatibility stuff 
    163     if debuglevel(1):    
    164         print "debug: send globus compat byte" 
    165     conn.write('0') 
    166  
    167     # send store command 
    168     if debuglevel(1):   
    169         print "debug: send store command" 
    170          
    171     cmd_store = CMD_STORE % (username, lifetime) 
    172     conn.write(cmd_store) 
    173  
    174     # process server response 
    175     if debuglevel(1):    
    176         print "debug: get server response for store command request" 
    177          
    178     dat = conn.recv(8192) 
    179     if debuglevel(1):    
    180         print dat 
    181          
    182     response, errortext = deserializeResponse(dat) 
    183     if response: 
    184         raise GetException, errortext 
    185     else: 
     43    def __init__(self): 
     44        pass 
     45     
     46     
     47    #_________________________________________________________________________         
     48    def _createCertReq(self, 
     49                       CN, 
     50                       O='NDG', 
     51                       OU='BADC', 
     52                       bits=1024,  
     53                       messageDigest="md5"): 
     54        """ 
     55        Create certificate request. 
     56         
     57        Returns: certificate request PEM text, private key PEM text 
     58        """ 
     59                         
     60        # Create certificate request 
     61        req = X509.Request() 
     62     
     63        # Generate keys 
     64        key = RSA.gen_key(bits, m2.RSA_F4) 
     65     
     66        # Create public key object 
     67        pubKey = EVP.PKey() 
     68        pubKey.assign_rsa(key) 
     69         
     70        # Add the public key to the request 
     71        req.set_version(0)# Seems to default to 0, but we can now set it as well 
     72        req.set_pubkey(pubKey) 
     73         
     74        # Set DN 
     75        x509Name = X509.X509_Name() 
     76        x509Name.CN = CN 
     77        x509Name.OU = OU 
     78        x509Name.O = O 
     79        req.set_subject_name(x509Name) 
     80         
     81        req.sign(pubKey, messageDigest) 
     82         
     83        return (req.as_asn1(), key.as_pem(cipher=None)) 
     84     
     85     
     86    #_________________________________________________________________________            
     87    def _deserializeResponse(self, msg): 
     88        """ 
     89        Deserialize a MyProxy server response 
     90         
     91        Returns: integer response, errorTxt (if any) 
     92        """ 
     93         
     94        lines = msg.split('\n') 
     95         
     96        # get response value 
     97        responselines = filter( lambda x: x.startswith('RESPONSE'), lines) 
     98        responseline = responselines[0] 
     99        response = int(responseline.split('=')[1]) 
     100         
     101        # get error text 
     102        errorTxt = "" 
     103        errorlines = filter( lambda x: x.startswith('ERROR'), lines) 
     104        for e in errorlines: 
     105            etext = e.split('=')[1] 
     106            errorTxt += etext 
     107         
     108        return response, errorTxt 
     109      
     110   
     111    #_________________________________________________________________________              
     112    def _deserializeCerts(self, inp_dat): 
     113         
     114        pemCerts = [] 
     115         
     116        dat = inp_dat 
     117         
     118        import base64 
     119        while dat: 
     120     
     121            # find start of cert, get length         
     122            ind = dat.find('\x30\x82') 
     123            if ind < 0: 
     124                break 
     125                 
     126            len = 256*ord(dat[ind+2]) + ord(dat[ind+3]) 
     127     
     128            # extract der-format cert, and convert to pem 
     129            c = dat[ind:ind+len+4] 
     130            x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,c) 
     131            pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM,x509) 
     132            pemCerts.append(pem_cert) 
     133     
     134            # trim cert from data 
     135            dat = dat[ind + len + 4:] 
     136         
     137     
     138        return pemCerts 
     139 
     140 
     141    #_________________________________________________________________________    
     142    def store(self, 
     143              hostname,  
     144              username,  
     145              certFile, 
     146              keyFile, 
     147              lifetime=43200, 
     148              port=7512): 
     149        """\ 
     150        store credentials in a MyProxy server 
     151         
     152        Exceptions:  GetException, StoreCredException 
     153        """ 
     154        import pdb; pdb.set_trace() 
     155        # Set to version 3? - YES! MyProxy requires it.  See  
     156        # http://grid.ncsa.uiuc.edu/myproxy/protocol/ 
     157        context = Context(protocol='sslv3') 
     158        context.load_cert('../hostcert.pem',  
     159                          keyfile='../hostkey.pem',  
     160                          callback=lambda *ar, **kw: None) 
     161     
     162        # disable for compatibility with myproxy server (er, globus) 
     163        # globus doesn't handle this case, apparently, and instead 
     164        # chokes in proxy delegation code 
     165        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)#0x00000800L) 
     166         
     167        # connect to myproxy server 
     168        if debuglevel(1):   print "debug: connect to myproxy server" 
     169        conn = Connection(context, sock=socket.socket()) 
     170         
     171        # Fudge to avoid checking client cert - seems to pick globus  
     172        # host/<hostname> one 
     173        conn.clientPostConnectionCheck = None 
     174        conn.connect((hostname, port)) 
     175         
     176        # send globus compatibility stuff 
    186177        if debuglevel(1):    
    187             print "debug: server response ok" 
    188      
    189     # Send certificate and private key 
    190     pat = re.compile(\ 
    191          '-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----',  
    192          re.S) 
    193      
    194     #certTxt = pat.findall(open(certFile).read())[0] 
    195     certTxt = X509.load_cert(certFile).as_pem() 
    196     keyTxt = open(keyFile).read() 
    197 #    PwdCB = lambda *ar, **kw: open('../tmp').read().strip()                                           
    198 #    keyTxt = EVP.load_key(keyFile, callback=PwdCB).as_pem(callback=PwdCB) 
    199      
    200     conn.send(certTxt + keyTxt) 
    201  
    202  
    203     # process server response 
    204     if debuglevel(1):    
    205         print "debug: get server response for store command completed" 
    206     resp = conn.recv(8192) 
    207     response, errortext = deserializeResponse(resp) 
    208     if response: 
    209         raise RetrieveProxyException, errortext 
    210     else: 
    211         if debuglevel(1): 
    212             print "debug: server response ok" 
    213      
    214      
    215 def myProxyLogon(hostname, 
    216                  username, 
    217                  passphrase, 
    218                  outfile, 
    219                  lifetime=43200, 
    220                  port=7512): 
    221     """ 
    222     Function to retrieve a proxy credential from a MyProxy server 
    223      
    224     Exceptions:  GetException, RetrieveProxyException 
    225     """ 
    226     import pdb;pdb.set_trace() 
    227  
    228     # Set to version 3? 
    229     context = Context() 
    230      
    231     # disable for compatibility with myproxy server (er, globus) 
    232     # globus doesn't handle this case, apparently, and instead 
    233     # chokes in proxy delegation code 
    234     context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)#0x00000800L) 
    235      
    236     # connect to myproxy server 
    237     if debuglevel(1):   print "debug: connect to myproxy server" 
    238     conn = Connection(context, sock=socket.socket()) 
    239      
    240     # Fudge to avoid checking client cert - seems to pick globus  
    241     # host/<hostname> one 
    242     conn.clientPostConnectionCheck = None 
    243     conn.connect((hostname,port)) 
    244      
    245     # send globus compatibility stuff 
    246     if debuglevel(1):   print "debug: send globus compat byte" 
    247     conn.write('0') 
    248  
    249     # send get command 
    250     if debuglevel(1):   print "debug: send get command" 
    251     cmd_get = CMD_GET % (username,passphrase,lifetime) 
    252     conn.write(cmd_get) 
    253  
    254     # process server response 
    255     if debuglevel(1):   print "debug: get server response" 
    256     dat = conn.recv(8192) 
    257     if debuglevel(1):   print dat 
    258     response,errortext = deserializeResponse(dat) 
    259     if response: 
    260         raise GetException(errortext) 
    261     else: 
    262         if debuglevel(1):   print "debug: server response ok" 
    263      
    264     # generate and send certificate request 
    265     # - The client will generate a public/private key pair and send a  
    266     #   NULL-terminated PKCS#10 certificate request to the server. 
    267     if debuglevel(1):   print "debug: send cert request" 
    268  
    269     certReq, priKey = createCertReq(username) 
    270     conn.send(certReq) 
    271  
    272     # process certificates 
    273     # - 1 byte , number of certs 
    274     dat = conn.recv(1) 
    275     nCerts = ord(dat[0]) 
    276      
    277     # - n certs 
    278     if debuglevel(1):   print "debug: receive certs" 
    279     dat = conn.recv(8192) 
    280     if debuglevel(2): 
    281         print "debug: dumping cert data to myproxy.dump" 
    282         f = file('myproxy.dump','w') 
    283         f.write(dat) 
     178            print "debug: send globus compat byte" 
     179        conn.write('0') 
     180     
     181        # send store command 
     182        if debuglevel(1):   
     183            print "debug: send store command" 
     184             
     185        storeCmd = MyProxy.__storeCmd % (username, lifetime) 
     186        conn.write(storeCmd) 
     187     
     188        # process server response 
     189        if debuglevel(1):    
     190            print "debug: get server response for store command request" 
     191             
     192        dat = conn.recv(8192) 
     193        if debuglevel(1):    
     194            print dat 
     195             
     196        response, errorTxt = self._deserializeResponse(dat) 
     197        if response: 
     198            raise GetException, errorTxt 
     199        else: 
     200            if debuglevel(1):    
     201                print "debug: server response ok" 
     202         
     203        # Send certificate and private key 
     204        pat = re.compile(\ 
     205             '-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----',  
     206             re.S) 
     207         
     208        #certTxt = pat.findall(open(certFile).read())[0] 
     209        certTxt = X509.load_cert(certFile).as_pem() 
     210        keyTxt = open(keyFile).read() 
     211    #    PwdCB = lambda *ar, **kw: open('../tmp').read().strip()                                           
     212    #    keyTxt = EVP.load_key(keyFile, callback=PwdCB).as_pem(callback=PwdCB) 
     213         
     214        conn.send(certTxt + keyTxt) 
     215     
     216     
     217        # process server response 
     218        if debuglevel(1):    
     219            print "debug: get server response for store command completed" 
     220        resp = conn.recv(8192) 
     221        response, errorTxt = self._deserializeResponse(resp) 
     222        if response: 
     223            raise RetrieveProxyException, errorTxt 
     224        else: 
     225            if debuglevel(1): 
     226                print "debug: server response ok" 
     227         
     228         
     229    def logon(self, 
     230              hostname, 
     231              username, 
     232              passphrase, 
     233              outfile, 
     234              lifetime=43200, 
     235              port=7512): 
     236        """ 
     237        Function to retrieve a proxy credential from a MyProxy server 
     238         
     239        Exceptions:  GetException, RetrieveProxyException 
     240        """ 
     241        import pdb;pdb.set_trace() 
     242     
     243        # Set to version 3? 
     244        context = Context() 
     245         
     246        # disable for compatibility with myproxy server (er, globus) 
     247        # globus doesn't handle this case, apparently, and instead 
     248        # chokes in proxy delegation code 
     249        context.set_options(m2.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)#0x00000800L) 
     250         
     251        # connect to myproxy server 
     252        if debuglevel(1):   print "debug: connect to myproxy server" 
     253        conn = Connection(context, sock=socket.socket()) 
     254         
     255        # Fudge to avoid checking client cert - seems to pick globus  
     256        # host/<hostname> one 
     257        conn.clientPostConnectionCheck = None 
     258        conn.connect((hostname,port)) 
     259         
     260        # send globus compatibility stuff 
     261        if debuglevel(1):   print "debug: send globus compat byte" 
     262        conn.write('0') 
     263     
     264        # send get command 
     265        if debuglevel(1):   print "debug: send get command" 
     266        getCmd = MyProxy.__getCmd % (username,passphrase,lifetime) 
     267        conn.write(getCmd) 
     268     
     269        # process server response 
     270        if debuglevel(1):   print "debug: get server response" 
     271        dat = conn.recv(8192) 
     272        if debuglevel(1):   print dat 
     273        response,errorTxt = self._deserializeResponse(dat) 
     274        if response: 
     275            raise GetException(errorTxt) 
     276        else: 
     277            if debuglevel(1):   print "debug: server response ok" 
     278         
     279        # generate and send certificate request 
     280        # - The client will generate a public/private key pair and send a  
     281        #   NULL-terminated PKCS#10 certificate request to the server. 
     282        if debuglevel(1):   print "debug: send cert request" 
     283     
     284        certReq, priKey = self._createCertReq(username) 
     285        conn.send(certReq) 
     286     
     287        # process certificates 
     288        # - 1 byte , number of certs 
     289        dat = conn.recv(1) 
     290        nCerts = ord(dat[0]) 
     291         
     292        # - n certs 
     293        if debuglevel(1):   print "debug: receive certs" 
     294        dat = conn.recv(8192) 
     295        if debuglevel(2): 
     296            print "debug: dumping cert data to myproxy.dump" 
     297            f = file('myproxy.dump','w') 
     298            f.write(dat) 
     299            f.close() 
     300     
     301        # process server response 
     302        if debuglevel(1):   print "debug: get server response" 
     303        resp = conn.recv(8192) 
     304        response, errorTxt = self._deserializeCerts(resp) 
     305        if response: 
     306            raise RetrieveProxyException(errorTxt) 
     307        else: 
     308            if debuglevel(1):   print "debug: server response ok" 
     309     
     310        # deserialize certs from received cert data 
     311        pemCerts = self._deserializeCerts(dat) 
     312        if len(pemCerts) != nCerts: 
     313            print "Warning: %d certs expected, %d received" % (nCerts,len(pemCerts)) 
     314     
     315        # write certs and private key to file 
     316        # - proxy cert 
     317        # - private key 
     318        # - rest of cert chain 
     319        if debuglevel(1):   print "debug: write proxy and certs to",outfile 
     320        f = file(outfile,'w') 
     321        f.write(pemCerts[0]) 
     322        f.write(priKey) 
     323        for c in pemCerts[1:]: 
     324            f.write(c) 
    284325        f.close() 
    285  
    286     # process server response 
    287     if debuglevel(1):   print "debug: get server response" 
    288     resp = conn.recv(8192) 
    289     response, errortext = deserializeResponse(resp) 
    290     if response: 
    291         raise RetrieveProxyException(errortext) 
    292     else: 
    293         if debuglevel(1):   print "debug: server response ok" 
    294  
    295     # deserialize certs from received cert data 
    296     pemCerts = deserialize_certs(dat) 
    297     if len(pemCerts) != nCerts: 
    298         print "Warning: %d certs expected, %d received" % (nCerts,len(pemCerts)) 
    299  
    300     # write certs and private key to file 
    301     # - proxy cert 
    302     # - private key 
    303     # - rest of cert chain 
    304     if debuglevel(1):   print "debug: write proxy and certs to",outfile 
    305     f = file(outfile,'w') 
    306     f.write(pemCerts[0]) 
    307     f.write(priKey) 
    308     for c in pemCerts[1:]: 
    309         f.write(c) 
    310     f.close() 
    311      
    312          
    313 if __name__ == '__main__': 
     326         
     327 
     328    def getDelegation(self, *arg, **kw): 
     329        """Retrieve proxy cert for user - same as logon""" 
     330        self.logon(*arg, **kw) 
     331 
     332 
     333#_____________________________________________________________________________    
     334def main(): 
    314335    import sys 
    315336    import optparse 
     
    327348                       help="Certificate to be stored") 
    328349     
    329     parser.add_option("-k", "--store-key", dest="keyFile", default=None, 
     350    parser.add_option("-y", "--store-key", dest="keyFile", default=None, 
    330351                       help="Private key to be stored") 
    331352 
     
    363384    lifetime = int(options.lifetime) 
    364385 
    365  
     386    myProxy = MyProxy() 
     387     
    366388    if options.getDelegation: 
    367389                 
     
    378400        # Retrieve proxy cert 
    379401        try: 
    380             ret = myProxyLogon(host, 
    381                                username, 
    382                                passphrase, 
    383                                outfile, 
    384                                lifetime=lifetime, 
    385                                port=port) 
     402            myProxy.logon(host, 
     403                          username, 
     404                          passphrase, 
     405                          outfile, 
     406                          lifetime=lifetime, 
     407                          port=port) 
    386408            print "A proxy has been received for user %s in %s." % \ 
    387409                (username, outfile) 
     
    395417    else: 
    396418        try: 
    397             myProxyStore(host,  
     419            myProxy.store(host,  
    398420                         username,  
    399421                         options.certFile, 
     
    408430            else: 
    409431                print "Error:", e 
    410             
     432 
     433 
     434if __name__ == '__main__': 
     435    main() 
Note: See TracChangeset for help on using the changeset viewer.