config docs
[sfa.git] / util / sec / sec.py
1 import os, sys
2 from OpenSSL import crypto
3 from M2Crypto import X509
4 from M2Crypto import SSL
5 sys.path.append('../')
6 from certgen import *
7 from util import *
8 from db import *
9 from tree import *
10
11 CRED_GRANT_TIME = 3600000 #in seconds
12 ACC_GRANT_TIME = 10000000
13 TOP_LEVEL_CERTS_DIR = "trusted_certs"
14 MAX_CERT_SIZE = 1024
15 MAX_CERT_CHAIN = 9
16
17 creds= ["","","","","","","","","","","","","","","","","","","","","","","","",""]
18 creds[0] = "register"
19 creds[1] = "remove"
20 creds[2] = "remove_self"
21 creds[3] = "update"
22 creds[4] = "update_self"
23 creds[5] = "lookup"
24 creds[6] = "lookup_self"
25 creds[7] = "list"
26 creds[8] = "getCredential"
27 creds[9] = "getAccounting"
28 creds[10] = "getTicket"      # = embed privilege in the docs
29 creds[11] = "splitTicket"
30 creds[12] = "redeemTicket"
31 creds[13] = "stop"
32 creds[14] = "start"
33 creds[15] = "delete"
34 creds[16] = "listSlices"
35 creds[17] = "getStatus"
36 creds[18] = "getSlice"
37 creds[19] = "refresh"
38 creds[20] = "delegate"
39 creds[21] = "instantiate"
40 creds[22] = "bind"
41 creds[23] = "control"
42
43 class PeerInfo :
44     def __init__(self):
45         self.cert = None
46         self.acc = Accounting()   #accounting information
47         self.cred = Credential()  #credential information
48
49 #info_certs looks like: [{'hrn':None, 'uuid':0}]
50 class Accounting:
51     def __init__(self):
52         self.info_certs = []
53         self.cert_chain = []
54     def get_hrn(self):
55         return self.info_certs[0]['hrn']
56     def get_uuid(self):
57         return self.info_certs[0]['uuid']
58
59 #info_certs looks like: [{'operation_set':None, 'on_interfaces':None}]
60 #operation_set looks like: [0:['register','update','update_self',..], 1:['getTicket', 'splitTicket',..],..]
61 #on_interfaces looks like: [{'lbl':0, 'name':'planetlab.jp.jaist', 'type':'registry'},..{}]
62 class Credential: 
63     def __init__(self):
64         self.info_certs = [] #list of operations and list of sites on which operations can be performed
65         self.cert_chain = []
66     def get_cred(self):
67         return self.info_certs[0]
68         
69 #type: 'accounting' or 'credential' 
70 #folder: directory of that the certificate should reside
71 #reg_type: 'slice' or 'component'
72 #hrn: name of the object to get certificates for
73 #server: the server instance to do operations calls with in the internal tree
74 #internal_tree: tree for internal cert renewals
75 #auth_addr: authority to ask for certificates
76 #sec: security module to perform auth. protocol with the remote peer
77 #return 0: no renewal done, 1: renewal done, None: error
78 def renew_cert(type, folder, reg_type, hrn, server, internal_tree, auth_addr, sec):
79     #check if necessary to renew
80     if type == 'accounting':
81         fname = folder+'/acc_file'
82     else:
83         fname = folder+'/cred_file'
84     if os.path.exists(fname) and is_valid_chain(fname):
85         return 0
86     else:
87         parent_hrn = obtain_authority(hrn)
88         hrn_suffix = get_leaf(hrn)
89         id_file = folder+'/'+hrn_suffix+'.cert'
90         #check the id file
91         if not os.path.exists(folder) or not os.path.exists(id_file):
92             print 'Id file for '+hrn+' does not exist.\n'
93             return None
94         #decide if remote call
95         remote = True
96         if internal_tree:
97             dbinfo = determine_dbinfo(parent_hrn, internal_tree)
98             if dbinfo:
99                 remote = False
100         if not remote:
101             if type == 'accounting':
102                 #obtain the accounting from parent, write to file
103                 g = {"hrn":""}
104                 g["hrn"] = parent_hrn
105                 g['registry'] = reg_type
106                 g["account_name"] = hrn 
107                 p = {}
108                 record = {'g_params':g, 'p_params':p}
109                 dbinfo = determine_dbinfo(parent_hrn, internal_tree)
110                 parentkeyinfo = internal_tree.determine_keyinfo(parent_hrn, server, type)
111                 open(fname, 'w').write(server.getAccounting(record, dbinfo, parentkeyinfo, X509.load_cert(id_file)))
112             else:
113                 #obtain the credential from parent, write to file
114                 g = {"hrn":""}
115                 g["hrn"] = parent_hrn
116                 if reg_type == 'slice':
117                     g['cred_name'] = 'registry:slc'
118                 else:
119                     g['cred_name'] = 'registry:comp'
120                 p = {}
121                 record = {'g_params':g, 'p_params':p}
122                 dbinfo = determine_dbinfo(parent_hrn, internal_tree)
123                 id = crypto.load_certificate(crypto.FILETYPE_PEM, open(id_file).read())
124                 peerinfo = [hrn, id]
125                 parentkeyinfo = internal_tree.determine_keyinfo(parent_hrn, server, type)
126                 open(fname, 'w').write(server.getCredential(record, dbinfo, parentkeyinfo, peerinfo))
127         else: #if not local call
128             if obtain_authority(hrn) == '':  #we are at the root
129                 id_key_file = folder+'/'+hrn_suffix+'.pkey'
130                 id_cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(id_file).read())
131                 id_pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, open(id_key_file).read())
132                 peer_cred_str = open(fname).read()
133                 c_pem = X509.load_cert_string("-----BEGIN CERTIFICATE-----"+peer_cred_str.split("-----BEGIN CERTIFICATE-----")[1])
134                 if type == 'accounting':
135                     cert_uuid = c_pem.get_ext("subjectAltName").get_value().split('http://')[1].split('#')[2].split('uuid:')[1]
136                     acc = create_acc(id_cert, id_pkey, id_cert.get_pubkey(), hrn, cert_uuid)
137                     open(fname, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, acc))
138                 else:
139                     rights = c_pem.get_ext("subjectAltName").get_value().split('http://')[1].split('credential_set:')[1]
140                     cred = create_cred(id_cert, id_pkey, id_cert.get_pubkey(), 'Registry credentials', rights)
141                     open(fname, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cred))
142             else:
143                 operation = ''                    
144                 g = {"hrn":obtain_authority(hrn)}
145                 if type == 'accounting':
146                     operation = "getAccounting";
147                     #geni parameters
148                     g['registry'] = reg_type
149                     g["account_name"] = hrn
150                 else:
151                     operation = "getCredential"
152                     #geni parameters
153                     if reg_type == 'slice':
154                         g['cred_name'] = 'registry:slc'
155                     else:
156                         g['cred_name'] = 'registry:comp'
157                 p = {}
158                 message = {'opname':operation, 'g_params':g, 'p_params':p}
159                 #connect to authority
160                 server = SSL.Connection(sec.ctx)
161                 server.connect(auth_addr)
162                 peer = sec.auth_protocol(server)
163                 #do the query and get the result
164                 server.write(str(message))
165                 result = server.read(MAX_CERT_SIZE*MAX_CERT_CHAIN)
166                 open(fname, 'w').write(result)
167         return 1
168         
169 #obtains a data structure for credentials out of a given credential string
170 #return info_cert: {'operation_set':{'register','remove',..}, 'on_interfaces':{{'lbl':'0', 'type':'registry:slc','name':'planetlab.jp'}, ..}}
171 def get_cred_info(credstr):
172     info_cert = {'operation_set':{}, 'on_interfaces':{}}
173     set = credstr.split('#')[1].split('credential_set:')[1]
174     set_arr = set.split(')')
175     for item in set_arr[0:len(set_arr)-1]:
176         item = item.split('(')[1].split('-')
177         if info_cert['operation_set'].has_key(item[1]):
178             info_cert['operation_set'][item[1]].append(creds[int(item[0])])
179         else:
180             info_cert['operation_set'][item[1]] = [creds[int(item[0])]]
181     interface_list = []
182     arr = credstr.split('#')
183     intlist = arr[2:len(arr)]
184     for interface in intlist:
185         iarr = interface.split(':')
186         newint = {'lbl':iarr[0]}
187         if iarr[1] == 'reg':
188             if iarr[2] == 'slc':
189                 newint['type'] ='registry:slc'
190             else:
191                 newint['type'] ='registry:comp'
192             newint['name'] = iarr[3]
193         elif iarr[1] == 'comp':
194             newint['type'] ='component'
195             newint['name'] = iarr[2]
196         interface_list.append(newint)
197     info_cert['on_interfaces'] = interface_list
198     return info_cert
199
200 #given two credential statements, check if the first one can delegate the second one
201 #example: "'register' right on 'planetlab.jp' registry interface" is able to delegate a right called "'register' right on 'planetlab.jp.jaist' registry interface" 
202 def check_delegation(info_cert1, info_cert2):
203     passed = False
204     for interface in info_cert1['on_interfaces']:
205         is_reg = interface['type'] == 'registry:slc' or interface['type'] == 'registry:comp'
206         if is_reg and 'register' in info_cert1['operation_set'][interface['lbl']]:
207             found = True
208             for child_int in info_cert2['on_interfaces']:
209                 if child_int['type'] == interface['type'] and not check_authority(child_int['name'],interface['name']):
210                     found = False
211             if found:
212                 passed = True
213                 break
214     return passed
215
216     """
217 Create a credential certificate given the parameters: 
218     'authcert': the authority certificate
219     'authkey': the authority key
220     'pubkey': the public key belonging to the object to which the credential will be granted
221     'cname': the name of the credential being generated. It should be 'registry credentials' or a silce name like 'planetlab.jp.slice1'
222     'rights':  - the sequence representing the set of operations/rights on specific interfaces
223                                             ex: (2-0)(4-0)(6-0)(7-0)(8-0)(9-0)(0-0)(1-1)(2-1)(3-1)(4-1)(5-1)(6-1)(7-1)(8-1)(9-1)#0:reg:planetlab.jp#1:reg:planetlab.jp.jaist
224     'time': time in seconds how long the life of credential is
225 """
226 def create_cred(authcert, authkey, pubkey, cname, rights, time=CRED_GRANT_TIME):
227     #calculate the credset
228     if rights == "slice":
229         rights = "(10-1)(11-1)(12-1)(13-1)(14-1)(15-1)(16-1)(17-1)(18-1)(23-1)"
230     elif rights == "SA":
231         rights = "(0-0)(1-0)(2-0)(3-0)(4-0)(5-0)(6-0)(7-0)(8-0)(9-0)(16-1)(17-1)(18-1)(19-1)"
232     elif rights == "MA":
233         rights = "(0-0)(1-0)(2-0)(3-0)(4-0)(5-0)(6-0)(7-0)(8-0)(9-0)(16-1)(17-1)(18-1)"
234     else:
235         # check if the rights is in correct format ######################
236         rights = rights
237         #create the CSR for the credential certificate
238         key = createKeyPair(TYPE_RSA, 1024)
239         certReq = createCertRequest(key, {"CN" : cname})
240         certReq.set_pubkey(pubkey)
241         #create the credential certificate, return
242         content = "#credential_set:"+rights 
243         ext = ("subjectAltName", 1, "URI:http://"+content)
244         exts = [ext]
245         cert = createCertificate(certReq, (authcert, authkey), 0, (0, int(time)), exts)
246         return cert
247
248 """
249 Create an accountability certificate given the parameters: 
250     'authc': the name of the authority certificate file
251     'authk': the name of the authority key file
252     'pubkey': the name of the GID file belonging to the object to which the accountability will be assigned
253     'name': the name of the object, which is the accountability information itself
254     'uuid': the uuid of the object
255     'time': the date and time when the life of accounting information
256 """
257 def create_acc(authcert, authkey, pubkey, name, uuid, time=ACC_GRANT_TIME): 
258     #create the CSR for the credential certificate
259     key = createKeyPair(TYPE_RSA, 1024)
260     certReq = createCertRequest(key, {"CN" : "GENI Accounting"})
261     certReq.set_pubkey(pubkey)
262     #create the accountability certificate, write into file
263     content = "#hrn:"+name+"#uuid:"+uuid
264     ext = ("subjectAltName", 1, "URI:http://"+content)
265     exts = [ext]
266     cert = createCertificate(certReq, (authcert, authkey), 0, (0, int(time)), exts)
267     return cert
268     
269 """
270 Create self signed certificate and private key.
271 """
272 def create_self_cert(name):
273     key = createKeyPair(TYPE_RSA, 1024)
274     certReq = createCertRequest(key, {"CN":name})
275     cert = createCertificate(certReq, (certReq, key), 0, (0, 60*60*24*365*5)) # five years
276     open(name+'.pkey', 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
277     open(name+'.cert', 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
278
279 def verify_callback(preverify_ok, ctx):
280     return 1
281     
282 class Sec: 
283     def __init__(self, mode, id_file, id_key_file, acc_file, cred_file):
284         self.top_level_certs = []
285         self.mode = mode
286         file_list = os.listdir(TOP_LEVEL_CERTS_DIR)
287         for auth_file in file_list:
288             # XXX SMBAKER: fix .svn directory
289             if os.path.isfile(os.path.join(TOP_LEVEL_CERTS_DIR, auth_file)):
290                 self.top_level_certs.append(X509.load_cert(TOP_LEVEL_CERTS_DIR+"/"+auth_file))
291
292         self.id_file = id_file
293         self.id_key_file = id_key_file
294         self.my_cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(id_file).read())
295         self.my_key = crypto.load_privatekey(crypto.FILETYPE_PEM, open(id_key_file).read())
296         self.acc_file = acc_file
297         self.cred_file = cred_file
298         #ssl parameters
299         self.ctx = SSL.Context()
300         self.ctx.load_cert(self.id_file,self.id_key_file)
301         self.ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9, callback=verify_callback)
302
303     #   - exchange the accounting chains, store peer's accounting in peer.acc
304     #   - check TTLs in certificates
305     #   - check validity of the chain, but do not check top level's trustedness
306     #return 1: means there is a structural error in the chain
307     #return 2: one of the TTLs in the chain not valid
308     #return 3: public keys do not form a valid chain
309     def exchange_accounting(self, conn, peer):
310         peer_acc_str=None
311         if self.mode == 'server':
312             #receive acc chain
313             peer_acc_str = conn.read(MAX_CERT_SIZE*MAX_CERT_CHAIN)
314             #send the acc chain
315             acc_str = open(self.acc_file).read()  #read the certificate chain from file
316             conn.write(acc_str) 
317         elif self.mode == 'client':
318             #send the acc chain
319             acc_str = open(self.acc_file).read()  #read the certificate chain from file
320             conn.write(acc_str)
321             #receive acc chain
322             peer_acc_str = conn.read(MAX_CERT_SIZE*MAX_CERT_CHAIN) 
323             
324         #construct peer_acc data structure
325         peer_acc = peer.acc
326         if peer_acc_str[0:27] != "-----BEGIN CERTIFICATE-----":
327             peer_acc.info_certs = "anonymous"
328         else:
329             try: 
330                 #divide the received chain into certificates
331                 arr = peer_acc_str.split("-----BEGIN CERTIFICATE-----")
332                 arr = arr[1:len(arr)]
333                 for i in range(len(arr)):
334                     arr[i] = "-----BEGIN CERTIFICATE-----"+arr[i]
335                 for c_str in arr:
336                     c_pem = X509.load_cert_string(c_str)
337                     hrn = c_pem.get_ext("subjectAltName").get_value().split('http://')[1].split('#')[1].split('hrn:')[1]
338                     uuid = c_pem.get_ext("subjectAltName").get_value().split('http://')[1].split('#')[2].split('uuid:')[1]
339                     peer_acc.info_certs.append({'hrn':hrn, 'uuid':uuid})
340                     peer_acc.cert_chain.append(c_pem)
341             except: 
342                 print "No valid chain received.\n"
343                 return 1
344             #if structure is ok, go on with other checks
345             ttl_ok = True
346             chain_ok = True
347             #check ttl for the first certificate in the chain:
348             if not (check_valid(peer_acc.cert_chain[0])):
349                 ttl_ok = False
350             prevCert = None
351             curCert = None
352             for i in range(1, len(peer_acc.cert_chain)):
353                 prevCert = peer_acc.cert_chain[i-1] 
354                 curCert = peer_acc.cert_chain[i] 
355                 #check ttl
356                 if not check_valid(curCert):
357                     ttl_ok = False
358                 #chain validity checks
359                 if not prevCert.verify(curCert.get_pubkey()) :
360                     chain_ok = False
361             if ttl_ok == False:
362                 return 2
363             elif chain_ok == False:
364                 return 3
365         return 0
366
367     #   - check the pubkey of first certificate if it matches the peer public key
368     #   - check the name hierarchy
369     #   - check the top level authority's trustedness
370     # return 0: accounting verified
371     # return 1: pubkey does not match peer pubkey
372     # return 2: name hierarch does not imply hrn
373     # return 3: top level authority is unknown
374     # return 4: unidentified error
375     def verify_accounting(self, peer):
376         pubkey_ok = True
377         hierarchy_ok = True
378         trusted_auth = True
379         
380         if peer.acc.info_certs == 'anonymous':
381             return 0
382         try:
383             #check the pubkey of the peer
384             if peer.acc.cert_chain[0].get_pubkey().as_pem(cipher=None) != peer.cert.get_pubkey().as_pem(cipher=None):
385                     pubkey_ok = False
386             else:
387                 #check the name hierarchy
388                 for i in range(len(peer.acc.info_certs)-1):
389                     if check_authority(peer.acc.info_certs[i]['hrn'], peer.acc.info_certs[i+1]['hrn']) == False:
390                         hierarchy_ok = False
391                             
392                 #check if the certificate ends with a sign of a trusted top level authority
393                 if hierarchy_ok:
394                     found = False
395                     last_cert_pubkey_pem = peer.acc.cert_chain[len(peer.acc.cert_chain)-1].get_pubkey().as_pem(cipher=None)
396                     for cert in self.top_level_certs:
397                         auth_pubkey_pem = cert.get_pubkey().as_pem(cipher=None)
398                         if last_cert_pubkey_pem == auth_pubkey_pem:
399                             found = True 
400                             break
401                     if not found:
402                         trusted_auth = False
403                         
404             if pubkey_ok == False:
405                 return 1
406             elif hierarchy_ok == False:
407                 return 2
408             elif trusted_auth == False:
409                 return 3
410             return 0
411         except Exception, e:
412             print "Exception in verify_accounting:", e
413             return 4
414      
415     #   - exchange the credential chains, store peer's credential in peer.cred
416     #   - check TTLs in certificates
417     #   - check validity of the chain, but do not check top level's trustedness
418     #return 1: means there is a structural error in the chain
419     #return 2: one of the TTLs in the chain not valid
420     #return 3: public keys do not form a valid chain
421     def exchange_credential(self, conn, peer):
422         peer_cred_str = None
423         if self.mode == 'server':
424             #receive cred chain
425             peer_cred_str = conn.read(MAX_CERT_SIZE*MAX_CERT_CHAIN)
426             #send the cred chain
427             cred_str = open(self.cred_file).read()  #read the certificate chain from file
428             conn.write(cred_str)
429         elif self.mode == 'client':
430             #send the cred chain
431             cred_str = open(self.cred_file).read()  #read the certificate chain from file
432             conn.write(cred_str)
433             #receive cred chain
434             peer_cred_str = conn.read(MAX_CERT_SIZE*MAX_CERT_CHAIN)
435             
436         #construct peer_cred data structure
437         peer_cred = peer.cred
438         if peer_cred_str[0:27] != "-----BEGIN CERTIFICATE-----":
439             peer_cred.info_certs = "no_credential"
440         else:
441             try:
442                 #divide the received chain into certificates
443                 arr = peer_cred_str.split("-----BEGIN CERTIFICATE-----")
444                 arr = arr[1:len(arr)]
445                 for i in range(len(arr)):
446                     arr[i] = "-----BEGIN CERTIFICATE-----"+arr[i]
447                 for c_str in arr:
448                     c_pem = X509.load_cert_string(c_str)
449                     credstr = c_pem.get_ext("subjectAltName").get_value().split('http://')[1]
450                     peer_cred.info_certs.append(get_cred_info(credstr))
451                     peer_cred.cert_chain.append(c_pem)
452             except Exception, e:
453                 print "Exception in exchange_credential:", e
454                 print "No valid chain received.\n"
455                 return 1
456             #if structure is ok, go on with other checks
457             ttl_ok = True
458             chain_ok = True
459             #check ttl for the first certificate in the chain:
460             if not (check_valid(peer_cred.cert_chain[0])):
461                 ttl_ok = False
462             prevCert = None
463             curCert = None
464             for i in range(1, len(peer_cred.cert_chain)):
465                 prevCert = peer_cred.cert_chain[i-1] 
466                 curCert = peer_cred.cert_chain[i] 
467                 #check ttl
468                 if not check_valid(curCert):
469                     ttl_ok = False
470                 #chain validity check
471                 if not prevCert.verify(curCert.get_pubkey()) :
472                     chain_ok = False
473             if ttl_ok == False:
474                 return 2
475             elif chain_ok == False:
476                 return 3
477         return 0
478         
479     #   - check the pubkey of first certificate if it matches the peer public key
480     #   - check the delegation hierarchy: the delegated rights must be granted by an authority of the entity
481     #   - check the top level authority's trustedness
482     # return 0: credential verified
483     # return 1: pubkey does not match peer pubkey
484     # return 2: delegation hierarchy is invalid
485     # return 3: top level authority is unknown
486     # return 4: unidentified error
487     def verify_credential(self, peer):
488         pubkey_ok = True
489         hierarchy_ok = True
490         trusted_auth = True
491         
492         if peer.cred.info_certs == 'no_credential':
493             return 0
494         try:
495             #check the pubkey of the peer
496             if peer.cred.cert_chain[0].get_pubkey().as_pem(cipher=None) != peer.cert.get_pubkey().as_pem(cipher=None):
497                     pubkey_ok = False
498             else:
499                 #check the delegation hierarchy
500                 for i in range(len(peer.cred.info_certs)-1):
501                     if not check_delegation(peer.cred.info_certs[i+1], peer.cred.info_certs[i]) :
502                         hierarchy_ok = False
503                             
504                 #check if the certificate ends with a sign of a trusted top level authority
505                 if hierarchy_ok:
506                     found = False
507                     last_cert_pubkey_pem = peer.cred.cert_chain[len(peer.cred.cert_chain)-1].get_pubkey().as_pem(cipher=None)
508                     for cert in self.top_level_certs:
509                         auth_pubkey_pem = cert.get_pubkey().as_pem(cipher=None)
510                         if last_cert_pubkey_pem == auth_pubkey_pem:
511                             found = True 
512                             break
513                     if not found:
514                         trusted_auth = False
515                         
516             if pubkey_ok == False:
517                 return 1
518             elif hierarchy_ok == False:
519                 return 2
520             elif trusted_auth == False:
521                 return 3
522             return 0
523         except:
524             return 4
525
526     def check_authorization(self, acc, cred, op_request):
527         allow = False
528         allow_self = False #admission for ops on only the caller  itself
529         try:
530             opname = op_request['opname']
531             #anonymously callable functions are allowed always
532             if opname == 'getCredential' or opname == 'getAccounting':
533                 allow = True
534             else:
535                 g_params = op_request['g_params']
536                 p_params = op_request['p_params']
537                 target_hrn = g_params['hrn']
538                 reg_type = ''
539                 rec_type = g_params['type']
540                 #determine which registry the call is on (slice or component)
541                 if rec_type == 'user' or rec_type == 'slice' or rec_type == 'SA':
542                     reg_type = 'slc'
543                 else:
544                     reg_type = 'comp'
545                 operation_set = cred.get_cred()['operation_set']
546                 on_interfaces = cred.get_cred()['on_interfaces'] 
547                 is_self_op = False
548                 if opname == "update" or opname == "remove" or opname == "lookup":
549                     is_self_op = True
550                 #check callable operations within the credential
551                 for interface in on_interfaces:
552                     if interface['type'] == 'registry:'+reg_type and check_authority(target_hrn, interface['name']) and operation_set.has_key(interface['lbl']):
553                         if opname in operation_set[interface['lbl']]:
554                             allow = True
555                             break
556                         elif is_self_op and opname + '_self' in operation_set[interface['lbl']] and acc.get_hrn() == target_hrn:
557                             allow_self = True
558                 #if operation is allowed in name, perform additional checks for parameters
559                 if allow or allow_self:
560                     if opname == 'update':
561                         if  'ttl' in g_params or 'uuid' in g_params or 'pointer' in g_params or (not allow and 'rights' in g_params):
562                             allow = False
563                             allow_self = False
564             #return result
565             if allow or allow_self:
566                 return True
567             else:
568                 return False
569         except Exception, e:
570             print "exception in check_authorization:", e
571             return False
572
573     def auth_protocol(self, conn):
574         if not conn.verify_ok():
575             v = conn.get_verify_result()
576             print "peer verification failed\n"
577             
578         peer = PeerInfo()    #keep the peer data who is currently logged in
579         #set the gid field
580         peer_pem = conn.get_peer_cert()
581         peer.cert = peer_pem
582         #set the acc field and check it
583         result1 = result2 = -1
584         result1 = self.exchange_accounting(conn, peer)
585         peer_decision = None
586         if self.mode == 'server':
587             peer_decision = conn.read()
588         if result1 == 1:
589             conn.write("ACC CHAIN_STRUCTURE_ERROR")
590         elif result1 == 2:
591             conn.write("ACC TTL_EXPIRED")
592         elif result1 == 3:
593             conn.write("ACC CHAIN_VERIFY_ERROR")
594         else:   #result = 0
595             result2 = self.verify_accounting(peer)
596             if result2 == 1:
597                 conn.write("ACC SSL_PUBKEY_MISMATCH")
598             elif result2 == 2:
599                 conn.write("ACC HRN_HIERARCHY_MISMATCH")
600             elif result2 == 3:
601                 conn.write("ACC UNKNOWN_AUTHORITY")
602             elif result2 == 4:
603                 conn.write("ACC UN-IDENTIFIED_ERROR")
604             else:
605                 conn.write("ACC OK")
606         if self.mode == 'client':
607             peer_decision = conn.read()
608         if (result1 != 0)  or (result2 != 0) or peer_decision != "ACC OK" : 
609             #close the connection and exit
610             conn.close()
611             return None
612         
613         #set the credential field and check it
614         result1 = result2 = -1
615         result1 = self.exchange_credential(conn,peer)
616         peer_decision = None
617         if self.mode == 'server':
618             peer_decision = conn.read()
619         if result1 == 1:
620             conn.write("CRED CHAIN_STRUCTURE_ERROR")
621         elif result1 == 2:
622             conn.write("CRED TTL_EXPIRED")
623         elif result1 == 3:
624             conn.write("CRED CHAIN_VERIFY_ERROR")
625         else:   #result1 = 0
626             result2 = self.verify_credential(peer)
627             if result2 == 1:
628                 conn.write("CRED SSL_PUBKEY_MISMATCH")
629             elif result2 == 2:
630                 conn.write("CRED INVALID_DELEGATION")
631             elif result2 == 3:
632                 conn.write("CRED UNKNOWN_AUTHORITY")
633             elif result2 == 4:
634                 conn.write("CRED UN-IDENTIFIED_ERROR")
635             else:
636                 conn.write("CRED OK")
637         if self.mode == 'client':
638             peer_decision = conn.read()
639         if (result1 != 0)  or (result2 != 0) or peer_decision != "CRED OK" : 
640             #close the connection and exit
641             conn.close()
642             return None
643         return peer
644         
645 def is_valid_chain(chain_file):
646     chain_str = open(chain_file).read()    
647     if chain_str[0:27] != "-----BEGIN CERTIFICATE-----":
648         return False
649     try:
650         #divide the received chain into certificates
651         arr = chain_str.split("-----BEGIN CERTIFICATE-----")
652         arr = arr[1:len(arr)]
653         for i in range(len(arr)):
654             arr[i] = "-----BEGIN CERTIFICATE-----"+arr[i]
655         arr2 = []
656         for c_str in arr:
657             c_pem = X509.load_cert_string(c_str)
658             if not check_valid(c_pem):
659                 return False
660         return True
661     except:
662         return False
663