source: TI12-security/trunk/python/Tests/MyProxyClient/myProxyClient.py @ 1851

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/Tests/MyProxyClient/myProxyClient.py@1851
Revision 1851, 11.0 KB checked in by pjkersha, 14 years ago (diff)

Testing store method: if the cert/private key used for authentication has
a *different* OU to the server side then an error occurs:

SSLError: 'sslv3 alert unsupported certificate'

This happens with both pyOpenSSL (myProxyClient.py) and M2Crypto
(m2CryptoMyPxClnt.py) based code. When running myproxy-server in debug mode
it gives the corresponding message on the server side:

Error authenticating client: GSS Major Status: Authentication Failed
GSS Minor Status Error Chain:
globus_gsi_gssapi: SSLv3 handshake problems
globus_gsi_callback_module: Could not verify credential
globus_gsi_callback_module: Error with signing policy
globus_gsi_callback_module: Error in OLD GAA code: CA policy violation: <no reason given>

Exiting: authentication failed

Is this due to the globus-user-ssl.conf and globus-host-ssl.conf settings?

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2#
3# myproxy client
4#
5# Tom Uram <turam@mcs.anl.gov>
6# 2005/08/04
7#
8
9
10import os
11import socket
12from OpenSSL import crypto, SSL
13import re
14
15class GetException(Exception): pass
16class RetrieveProxyException(Exception): pass
17class StoreCredException(Exception): pass
18
19
20debug = 0
21def debuglevel(level):
22    global debug
23    return debug >= level
24
25
26def create_cert_req(keyType = crypto.TYPE_RSA,
27                    bits = 1024,
28                    messageDigest = "md5"):
29    """
30    Create certificate request.
31   
32    Returns: certificate request PEM text, private key PEM text
33    """
34                   
35    # Create certificate request
36    req = crypto.X509Req()
37
38    # Generate private key
39    pkey = crypto.PKey()
40    pkey.generate_key(keyType, bits)
41
42    req.set_pubkey(pkey)
43    req.sign(pkey, messageDigest)
44   
45    return (crypto.dump_certificate_request(crypto.FILETYPE_ASN1,req),
46           crypto.dump_privatekey(crypto.FILETYPE_PEM,pkey))
47   
48def deserialize_response(msg):
49    """
50    Deserialize a MyProxy server response
51   
52    Returns: integer response, errortext (if any)
53    """
54   
55    lines = msg.split('\n')
56   
57    # get response value
58    responselines = filter( lambda x: x.startswith('RESPONSE'), lines)
59    responseline = responselines[0]
60    response = int(responseline.split('=')[1])
61   
62    # get error text
63    errortext = ""
64    errorlines = filter( lambda x: x.startswith('ERROR'), lines)
65    for e in errorlines:
66        etext = e.split('=')[1]
67        errortext += etext
68   
69    return response,errortext
70 
71               
72def deserialize_certs(inp_dat):
73   
74    pem_certs = []
75   
76    dat = inp_dat
77   
78    import base64
79    while dat:
80
81        # find start of cert, get length       
82        ind = dat.find('\x30\x82')
83        if ind < 0:
84            break
85           
86        len = 256*ord(dat[ind+2]) + ord(dat[ind+3])
87
88        # extract der-format cert, and convert to pem
89        c = dat[ind:ind+len+4]
90        x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,c)
91        pem_cert = crypto.dump_certificate(crypto.FILETYPE_PEM,x509)
92        pem_certs.append(pem_cert)
93
94        # trim cert from data
95        dat = dat[ind + len + 4:]
96   
97
98    return pem_certs
99
100
101CMD_GET="""VERSION=MYPROXYv2
102COMMAND=0
103USERNAME=%s
104PASSPHRASE=%s
105LIFETIME=%d\0"""
106
107CMD_STORE="""VERSION=MYPROXYv2
108COMMAND=5
109USERNAME=%s
110PASSPHRASE=
111LIFETIME=%d\0"""
112
113
114def myProxyStore(hostname, 
115                 username, 
116                 certFile,
117                 keyFile,
118                 lifetime=43200,
119                 port=7512):
120    """
121    Function to store credentials in a MyProxy server
122   
123    Exceptions:  GetException, StoreCredException
124    """
125    import pdb; pdb.set_trace()
126    context = SSL.Context(SSL.SSLv3_METHOD)
127   
128    # disable for compatibility with myproxy server (er, globus)
129    # globus doesn't handle this case, apparently, and instead
130    # chokes in proxy delegation code
131    context.set_options(0x00000800L)
132   
133#    context.use_certificate_file(certFile)
134#    context.use_privatekey_file(keyFile)   
135
136    context.use_certificate_file('../hostcert.pem')
137    context.use_privatekey_file('../hostkey.pem')   
138     
139    # connect to myproxy server
140    if debuglevel(1):   
141        print "debug: connect to myproxy server"
142       
143    conn = SSL.Connection(context, socket.socket())
144    conn.connect((hostname, port))
145   
146    # send globus compatibility stuff
147    if debuglevel(1):   
148        print "debug: send globus compat byte"
149    conn.write('0')
150
151    # send store command
152    if debuglevel(1): 
153        print "debug: send store command"
154       
155    cmd_store = CMD_STORE % (username, lifetime)
156    conn.write(cmd_store)
157
158    # process server response
159    if debuglevel(1):   
160        print "debug: get server response for store command request"
161       
162    dat = conn.recv(8192)
163    if debuglevel(1):   
164        print dat
165       
166    response, errortext = deserialize_response(dat)
167    if response:
168        raise GetException, errortext
169    else:
170        if debuglevel(1):   
171            print "debug: server response ok"
172   
173    # Send certificate and private key
174    pat = re.compile(\
175         '-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----', 
176         re.S)
177   
178    certTxt = pat.findall(open(certFile).read())[0]
179    keyTxt = open(keyFile).read()
180   
181    conn.send("%s\n%s" % (certTxt, keyTxt))
182
183
184    # process server response
185    if debuglevel(1):   
186        print "debug: get server response for store command completed"
187    resp = conn.recv(8192)
188    response, errortext = deserialize_response(resp)
189    if response:
190        raise RetrieveProxyException, errortext
191    else:
192        if debuglevel(1):
193            print "debug: server response ok"
194   
195   
196def myProxyLogon(hostname,
197                 username,
198                 passphrase,
199                 outfile,
200                 lifetime=43200,
201                 port=7512):
202    """
203    Function to retrieve a proxy credential from a MyProxy server
204   
205    Exceptions:  GetException, RetrieveProxyException
206    """
207   
208    context = SSL.Context(SSL.SSLv3_METHOD)
209   
210    # disable for compatibility with myproxy server (er, globus)
211    # globus doesn't handle this case, apparently, and instead
212    # chokes in proxy delegation code
213    context.set_options(0x00000800L)
214   
215    # connect to myproxy server
216    if debuglevel(1):   print "debug: connect to myproxy server"
217    conn = SSL.Connection(context,socket.socket())
218    conn.connect((hostname,port))
219   
220    # send globus compatibility stuff
221    if debuglevel(1):   print "debug: send globus compat byte"
222    conn.write('0')
223
224    # send get command
225    if debuglevel(1):   print "debug: send get command"
226    cmd_get = CMD_GET % (username,passphrase,lifetime)
227    conn.write(cmd_get)
228
229    # process server response
230    if debuglevel(1):   print "debug: get server response"
231    dat = conn.recv(8192)
232    if debuglevel(1):   print dat
233    response,errortext = deserialize_response(dat)
234    if response:
235        raise GetException(errortext)
236    else:
237        if debuglevel(1):   print "debug: server response ok"
238   
239    # generate and send certificate request
240    # - The client will generate a public/private key pair and send a
241    #   NULL-terminated PKCS#10 certificate request to the server.
242    if debuglevel(1):   print "debug: send cert request"
243    certreq,privatekey = create_cert_req()
244    conn.send(certreq)
245
246    # process certificates
247    # - 1 byte , number of certs
248    dat = conn.recv(1)
249    numcerts = ord(dat[0])
250   
251    # - n certs
252    if debuglevel(1):   print "debug: receive certs"
253    dat = conn.recv(8192)
254    if debuglevel(2):
255        print "debug: dumping cert data to myproxy.dump"
256        f = file('myproxy.dump','w')
257        f.write(dat)
258        f.close()
259
260    # process server response
261    if debuglevel(1):   print "debug: get server response"
262    resp = conn.recv(8192)
263    response,errortext = deserialize_response(resp)
264    if response:
265        raise RetrieveProxyException(errortext)
266    else:
267        if debuglevel(1):   print "debug: server response ok"
268
269    # deserialize certs from received cert data
270    pem_certs = deserialize_certs(dat)
271    if len(pem_certs) != numcerts:
272        print "Warning: %d certs expected, %d received" % (numcerts,len(pem_certs))
273
274    # write certs and private key to file
275    # - proxy cert
276    # - private key
277    # - rest of cert chain
278    if debuglevel(1):   print "debug: write proxy and certs to",outfile
279    f = file(outfile,'w')
280    f.write(pem_certs[0])
281    f.write(privatekey)
282    for c in pem_certs[1:]:
283        f.write(c)
284    f.close()
285   
286       
287if __name__ == '__main__':
288    import sys
289    import optparse
290    import getpass
291   
292    parser = optparse.OptionParser()
293    parser.add_option("-g", 
294                      "--get-delegation", 
295                      dest="getDelegation", 
296                      default=False,
297                      action="store_true",
298                      help="Get delegation / logon")
299   
300    parser.add_option("-c", "--store-cert", dest="certFile", default=None,
301                       help="Certificate to be stored")
302   
303    parser.add_option("-y", "--store-key", dest="keyFile", default=None,
304                       help="Private key to be stored")
305
306    parser.add_option("-s", "--pshost", dest="host", 
307                       help="The hostname of the MyProxy server to contact")
308    parser.add_option("-p", "--psport", dest="port", default=7512,
309                       help="The port of the MyProxy server to contact")
310    parser.add_option("-l", "--username", dest="username", 
311                       help="The username with which the credential is stored on the MyProxy server")
312    parser.add_option("-o", "--out", dest="outfile", 
313                       help="The username with which the credential is stored on the MyProxy server")
314    parser.add_option("-t", "--proxy-lifetime", dest="lifetime", default=43200,
315                       help="The username with which the credential is stored on the MyProxy server")
316    parser.add_option("-d", "--debug", dest="debug", default=0,
317                       help="Debug mode: 1=print debug info ; 2=print as in (1), and dump data to myproxy.dump")
318
319    (options,args) = parser.parse_args()
320   
321    debug = options.debug
322   
323    # process options
324    host = options.host
325    if not host:
326        print "Error: MyProxy host not specified"
327        sys.exit(1)
328    port = int(options.port)
329   
330    username = options.username
331    if not username:
332        if sys.platform == 'win32':
333            username = os.environ["USERNAME"]
334        else:
335            import pwd
336            username = pwd.getpwuid(os.geteuid())[0]
337    lifetime = int(options.lifetime)
338
339
340    if options.getDelegation:
341               
342        outfile = options.outfile
343        if not outfile:
344            if sys.platform == 'win32':
345                outfile = 'proxy'
346            elif sys.platform in ['linux2','darwin']:
347                outfile = '/tmp/x509up_u%s' % (os.getuid())
348   
349        # Get MyProxy password
350        passphrase = getpass.getpass()
351           
352        # Retrieve proxy cert
353        import pdb;pdb.set_trace()
354        try:
355            ret = myProxyLogon(host,
356                               username,
357                               passphrase,
358                               outfile,
359                               lifetime=lifetime,
360                               port=port)
361            print "A proxy has been received for user %s in %s." % \
362                (username, outfile)
363           
364        except Exception,e:
365            if debuglevel(1):
366                import traceback
367                traceback.print_exc()
368            else:
369                print "Error:", e
370    else:
371        try:
372            myProxyStore(host, 
373                         username, 
374                         options.certFile,
375                         options.keyFile,
376                         lifetime=lifetime,
377                         port=port)
378           
379        except Exception,e:
380            if debuglevel(1):
381                import traceback
382                traceback.print_exc()
383            else:
384                print "Error:", e
385           
Note: See TracBrowser for help on using the repository browser.