def verify_chain(self, trusted_certs = None): # do the normal certificate verification stuff trusted_root = Certificate.verify_chain(self, trusted_certs) if self.parent: # make sure the parent's hrn is a prefix of the child's hrn if not hrn_authfor_hrn(self.parent.get_hrn(), self.get_hrn()): raise GidParentHrn("This cert HRN %s isn't in the namespace for parent HRN %s" % (self.get_hrn(), self.parent.get_hrn())) # Parent must also be an authority (of some type) to sign a GID # There are multiple types of authority - accept them all here if not self.parent.get_type().find('authority') == 0: raise GidInvalidParentHrn("This cert %s's parent %s is not an authority (is a %s)" % (self.get_hrn(), self.parent.get_hrn(), self.parent.get_type())) # Then recurse up the chain - ensure the parent is a trusted # root or is in the namespace of a trusted root self.parent.verify_chain(trusted_certs) else: # make sure that the trusted root's hrn is a prefix of the child's trusted_gid = GID(string=trusted_root.save_to_string()) trusted_type = trusted_gid.get_type() trusted_hrn = trusted_gid.get_hrn() #if trusted_type == 'authority': # trusted_hrn = trusted_hrn[:trusted_hrn.rindex('.')] cur_hrn = self.get_hrn() if not hrn_authfor_hrn(trusted_hrn, cur_hrn): raise GidParentHrn("Trusted root with HRN %s isn't a namespace authority for this cert: %s" % (trusted_hrn, cur_hrn)) # There are multiple types of authority - accept them all here if not trusted_type.find('authority') == 0: raise GidInvalidParentHrn("This cert %s's trusted root signer %s is not an authority (is a %s)" % (self.get_hrn(), trusted_hrn, trusted_type)) return
def verify_chain(self, trusted_certs=None, crl_path=None): #<UT> #Certificate revocation check if crl_path: crl_file = os.path.join(crl_path, self.get_issuer()) if os.path.isfile(crl_file): with open(crl_file, 'r') as f: crl_obj = crypto.load_crl(crypto.FILETYPE_PEM, f.read()) revoked_certs = crl_obj.get_revoked() for rc in revoked_certs: serial = int(rc.get_serial(), 16) # conversion from hex to dec if serial == self.get_serial_number(): raise GidRevoked( "Certificate with serial number 0x%s for %s has been revoked by %s." % (rc.get_serial(), self.get_subject(), self.get_issuer())) # do the normal certificate verification stuff trusted_root = Certificate.verify_chain(self, trusted_certs) if self.parent: # make sure the parent's hrn is a prefix of the child's hrn if not hrn_authfor_hrn(self.parent.get_hrn(), self.get_hrn()): raise GidParentHrn( "This cert HRN %s isn't in the namespace for parent HRN %s" % (self.get_hrn(), self.parent.get_hrn())) # Parent must also be an authority (of some type) to sign a GID # There are multiple types of authority - accept them all here if not self.parent.get_type().find('authority') == 0: raise GidInvalidParentHrn( "This cert %s's parent %s is not an authority (is a %s)" % (self.get_hrn(), self.parent.get_hrn(), self.parent.get_type())) # Then recurse up the chain - ensure the parent is a trusted # root or is in the namespace of a trusted root self.parent.verify_chain(trusted_certs) else: # make sure that the trusted root's hrn is a prefix of the child's trusted_gid = GID(string=trusted_root.save_to_string()) trusted_type = trusted_gid.get_type() trusted_hrn = trusted_gid.get_hrn() #if trusted_type == 'authority': # trusted_hrn = trusted_hrn[:trusted_hrn.rindex('.')] cur_hrn = self.get_hrn() if not hrn_authfor_hrn(trusted_hrn, cur_hrn): raise GidParentHrn( "Trusted root with HRN %s isn't a namespace authority for this cert: %s" % (trusted_hrn, cur_hrn)) # There are multiple types of authority - accept them all here if not trusted_type.find('authority') == 0: raise GidInvalidParentHrn( "This cert %s's trusted root signer %s is not an authority (is a %s)" % (self.get_hrn(), trusted_hrn, trusted_type)) return
def verify_chain(self, trusted_certs = None, crl_path=None): #<UT> #Certificate revocation check if crl_path: crl_file = os.path.join(crl_path, self.get_issuer()) if os.path.isfile(crl_file): with open(crl_file, 'r') as f: crl_obj = crypto.load_crl(crypto.FILETYPE_PEM, f.read()) revoked_certs = crl_obj.get_revoked() for rc in revoked_certs: serial = int(rc.get_serial(), 16) # conversion from hex to dec if serial == self.get_serial_number(): raise GidRevoked("Certificate with serial number 0x%s for %s has been revoked by %s." % (rc.get_serial(), self.get_subject(), self.get_issuer())) # do the normal certificate verification stuff trusted_root = Certificate.verify_chain(self, trusted_certs) if self.parent: # make sure the parent's hrn is a prefix of the child's hrn if not hrn_authfor_hrn(self.parent.get_hrn(), self.get_hrn()): raise GidParentHrn("This cert HRN %s isn't in the namespace for parent HRN %s" % (self.get_hrn(), self.parent.get_hrn())) # Parent must also be an authority (of some type) to sign a GID # There are multiple types of authority - accept them all here if not self.parent.get_type().find('authority') == 0: raise GidInvalidParentHrn("This cert %s's parent %s is not an authority (is a %s)" % (self.get_hrn(), self.parent.get_hrn(), self.parent.get_type())) # Then recurse up the chain - ensure the parent is a trusted # root or is in the namespace of a trusted root self.parent.verify_chain(trusted_certs) else: # make sure that the trusted root's hrn is a prefix of the child's trusted_gid = GID(string=trusted_root.save_to_string()) trusted_type = trusted_gid.get_type() trusted_hrn = trusted_gid.get_hrn() #if trusted_type == 'authority': # trusted_hrn = trusted_hrn[:trusted_hrn.rindex('.')] cur_hrn = self.get_hrn() if not hrn_authfor_hrn(trusted_hrn, cur_hrn): raise GidParentHrn("Trusted root with HRN %s isn't a namespace authority for this cert: %s" % (trusted_hrn, cur_hrn)) # There are multiple types of authority - accept them all here if not trusted_type.find('authority') == 0: raise GidInvalidParentHrn("This cert %s's trusted root signer %s is not an authority (is a %s)" % (self.get_hrn(), trusted_hrn, trusted_type)) return
def verify_issuer(self, trusted_gids): root_cred = self.get_credential_list()[-1] root_target_gid = root_cred.get_gid_object() root_cred_signer = root_cred.get_signature().get_issuer_gid() # Case 1: # Allow non authority to sign target and cred about target. # # Why do we need to allow non authorities to sign? # If in the target gid validation step we correctly # checked that the target is only signed by an authority, # then this is just a special case of case 3. # This short-circuit is the common case currently - # and cause GID validation doesn't check 'authority', # this allows users to generate valid slice credentials. if root_target_gid.is_signed_by_cert(root_cred_signer): # cred signer matches target signer, return success return # Case 2: # Allow someone to sign credential about themeselves. Used? # If not, remove this. #root_target_gid_str = root_target_gid.save_to_string() #root_cred_signer_str = root_cred_signer.save_to_string() #if root_target_gid_str == root_cred_signer_str: # # cred signer is target, return success # return # Case 3: # root_cred_signer is not the target_gid # So this is a different gid that we have not verified. # xmlsec1 verified the cert chain on this already, but # it hasn't verified that the gid meets the HRN namespace # requirements. # Below we'll ensure that it is an authority. # But we haven't verified that it is _signed by_ an authority # We also don't know if xmlsec1 requires that cert signers # are marked as CAs. # Note that if verify() gave us no trusted_gids then this # call will fail. So skip it if we have no trusted_gids if trusted_gids and len(trusted_gids) > 0: root_cred_signer.verify_chain(trusted_gids) else: logger.debug("No trusted gids. Cannot verify that cred signer is signed by a trusted authority. Skipping that check.") # See if the signer is an authority over the domain of the target. # There are multiple types of authority - accept them all here # Maybe should be (hrn, type) = urn_to_hrn(root_cred_signer.get_urn()) root_cred_signer_type = root_cred_signer.get_type() if (root_cred_signer_type.find('authority') == 0): #logger.debug('Cred signer is an authority') # signer is an authority, see if target is in authority's domain signerhrn = root_cred_signer.get_hrn() if hrn_authfor_hrn(signerhrn, root_target_gid.get_hrn()): return # We've required that the credential be signed by an authority # for that domain. Reasonable and probably correct. # A looser model would also allow the signer to be an authority # in my control framework - eg My CA or CH. Even if it is not # the CH that issued these, eg, user credentials. # Give up, credential does not pass issuer verification raise CredentialNotVerifiable("Could not verify credential owned by %s for object %s. Cred signer %s not the trusted authority for Cred target %s" % (self.gidCaller.get_urn(), self.gidObject.get_urn(), root_cred_signer.get_hrn(), root_target_gid.get_hrn()))
def verify_issuer(self, trusted_gids): root_cred = self.get_credential_list()[-1] root_target_gid = root_cred.get_gid_object() root_cred_signer = root_cred.get_signature().get_issuer_gid() # Case 1: # Allow non authority to sign target and cred about target. # # Why do we need to allow non authorities to sign? # If in the target gid validation step we correctly # checked that the target is only signed by an authority, # then this is just a special case of case 3. # This short-circuit is the common case currently - # and cause GID validation doesn't check 'authority', # this allows users to generate valid slice credentials. if root_target_gid.is_signed_by_cert(root_cred_signer): # cred signer matches target signer, return success return # Case 2: # Allow someone to sign credential about themeselves. Used? # If not, remove this. #root_target_gid_str = root_target_gid.save_to_string() #root_cred_signer_str = root_cred_signer.save_to_string() #if root_target_gid_str == root_cred_signer_str: # # cred signer is target, return success # return # Case 3: # root_cred_signer is not the target_gid # So this is a different gid that we have not verified. # xmlsec1 verified the cert chain on this already, but # it hasn't verified that the gid meets the HRN namespace # requirements. # Below we'll ensure that it is an authority. # But we haven't verified that it is _signed by_ an authority # We also don't know if xmlsec1 requires that cert signers # are marked as CAs. # Note that if verify() gave us no trusted_gids then this # call will fail. So skip it if we have no trusted_gids if trusted_gids and len(trusted_gids) > 0: root_cred_signer.verify_chain(trusted_gids) else: logger.debug( "No trusted gids. Cannot verify that cred signer is signed by a trusted authority. Skipping that check." ) # See if the signer is an authority over the domain of the target. # There are multiple types of authority - accept them all here # Maybe should be (hrn, type) = urn_to_hrn(root_cred_signer.get_urn()) root_cred_signer_type = root_cred_signer.get_type() if (root_cred_signer_type.find('authority') == 0): #logger.debug('Cred signer is an authority') # signer is an authority, see if target is in authority's domain signerhrn = root_cred_signer.get_hrn() if hrn_authfor_hrn(signerhrn, root_target_gid.get_hrn()): return # We've required that the credential be signed by an authority # for that domain. Reasonable and probably correct. # A looser model would also allow the signer to be an authority # in my control framework - eg My CA or CH. Even if it is not # the CH that issued these, eg, user credentials. # Give up, credential does not pass issuer verification raise CredentialNotVerifiable( "Could not verify credential owned by %s for object %s. Cred signer %s not the trusted authority for Cred target %s" % (self.gidCaller.get_urn(), self.gidObject.get_urn(), root_cred_signer.get_hrn(), root_target_gid.get_hrn()))
def create_credential(caller_gid, object_gid, expiration, typename, issuer_keyfile, issuer_certfile, trusted_roots, delegatable=False): '''Create and Return a Credential object issued by given key/cert for the given caller and object GID objects, given life in seconds, and given type. Privileges are determined by type per sfa/trust/rights.py Privileges are delegatable if requested.''' # FIXME: Validate args: my gids, >0 life, # type of cred one I can issue # and readable key and cert files if caller_gid is None: raise ValueError("Missing Caller GID") if object_gid is None: raise ValueError("Missing Object GID") if expiration is None: raise ValueError("Missing expiration") naive_expiration = naiveUTC(expiration) duration = naive_expiration - datetime.datetime.utcnow() life_secs = duration.seconds + duration.days * 24 * 3600 if life_secs < 1: raise ValueError("Credential expiration is in the past") if trusted_roots is None: raise ValueError("Missing list of trusted roots") if typename is None or typename.strip() == '': raise ValueError("Missing credential type") typename = typename.strip().lower() if typename not in ("user", "sa", "ma", "authority", "slice", "component"): raise ValueError("Unknown credential type %s" % typename) if not os.path.isfile(issuer_keyfile): raise ValueError("Cant read issuer key file %s" % issuer_keyfile) if not os.path.isfile(issuer_certfile): raise ValueError("Cant read issuer cert file %s" % issuer_certfile) issuer_gid = gid.GID(filename=issuer_certfile) if not (object_gid.get_urn() == issuer_gid.get_urn() or (issuer_gid.get_type().find('authority') == 0 and hrn_authfor_hrn(issuer_gid.get_hrn(), object_gid.get_hrn()))): raise ValueError( "Issuer not authorized to issue credential: Issuer=%s Target=%s" % (issuer_gid.get_urn(), object_gid.get_urn())) ucred = cred.Credential() # FIXME: Validate the caller_gid and object_gid # are my user and slice # Do get_issuer and compare to the issuer cert? # Or do gid.is_signed_by_cert(issuer_certfile)? ucred.set_gid_caller(caller_gid) ucred.set_gid_object(object_gid) ucred.set_expiration(expiration) # Use sfa/trust/rights.py to figure out what privileges # the credential should have. # user means refresh, resolve, info # per the privilege_table that lets users do # remove, update, resolve, list, getcredential, # listslices, listnodes, getpolicy # Note that it does not allow manipulating slivers # And every right is delegatable if any are delegatable (default False) privileges = rights.determine_rights(typename, None) privileges.delegate_all_privileges(delegatable) ucred.set_privileges(privileges) ucred.encode() ucred.set_issuer_keys(issuer_keyfile, issuer_certfile) ucred.sign() try: ucred.verify(trusted_roots) except Exception, exc: raise Exception( "Create Credential failed to verify new credential from trusted roots: %s" % exc)
def create_credential(caller_gid, object_gid, expiration, typename, issuer_keyfile, issuer_certfile, trusted_roots, delegatable=False): '''Create and Return a Credential object issued by given key/cert for the given caller and object GID objects, given life in seconds, and given type. Privileges are determined by type per sfa/trust/rights.py Privileges are delegatable if requested.''' # FIXME: Validate args: my gids, >0 life, # type of cred one I can issue # and readable key and cert files if caller_gid is None: raise ValueError("Missing Caller GID") if object_gid is None: raise ValueError("Missing Object GID") if expiration is None: raise ValueError("Missing expiration") naive_expiration = naiveUTC(expiration) duration = naive_expiration - datetime.datetime.utcnow() life_secs = duration.seconds + duration.days * 24 * 3600 if life_secs < 1: raise ValueError("Credential expiration is in the past") if trusted_roots is None: raise ValueError("Missing list of trusted roots") if typename is None or typename.strip() == '': raise ValueError("Missing credential type") typename = typename.strip().lower() if typename not in ("user", "sa", "ma", "authority", "slice", "component"): raise ValueError("Unknown credential type %s" % typename) if not os.path.isfile(issuer_keyfile): raise ValueError("Cant read issuer key file %s" % issuer_keyfile) if not os.path.isfile(issuer_certfile): raise ValueError("Cant read issuer cert file %s" % issuer_certfile) issuer_gid = gid.GID(filename=issuer_certfile) if not (object_gid.get_urn() == issuer_gid.get_urn() or (issuer_gid.get_type().find('authority') == 0 and hrn_authfor_hrn(issuer_gid.get_hrn(), object_gid.get_hrn()))): raise ValueError("Issuer not authorized to issue credential: Issuer=%s Target=%s" % (issuer_gid.get_urn(), object_gid.get_urn())) ucred = cred.Credential() # FIXME: Validate the caller_gid and object_gid # are my user and slice # Do get_issuer and compare to the issuer cert? # Or do gid.is_signed_by_cert(issuer_certfile)? ucred.set_gid_caller(caller_gid) ucred.set_gid_object(object_gid) ucred.set_expiration(expiration) # Use sfa/trust/rights.py to figure out what privileges # the credential should have. # user means refresh, resolve, info # per the privilege_table that lets users do # remove, update, resolve, list, getcredential, # listslices, listnodes, getpolicy # Note that it does not allow manipulating slivers # And every right is delegatable if any are delegatable (default False) privileges = rights.determine_rights(typename, None) privileges.delegate_all_privileges(delegatable) ucred.set_privileges(privileges) ucred.encode() ucred.set_issuer_keys(issuer_keyfile, issuer_certfile) ucred.sign() try: ucred.verify(trusted_roots) except Exception, exc: raise Exception("Create Credential failed to verify new credential from trusted roots: %s" % exc)