def _construct_extra_parameters(extra_data): """ Given a dictionary of extra key-value pairs (all str), return a string that may be appended to a google authenticator / oathtoken URL. Values that are non-strings will be converted to str. Keys and values are converted to UTF-8 and urlquoted. :return: a string (may be empty if ``extra_data`` is empty) """ extra_data_list = [] for key, value in extra_data.items(): encoded_key = quote(to_byte_string(key)) encoded_value = quote(to_byte_string(value)) extra_data_list.append('{key}={value}'.format(key=encoded_key, value=encoded_value)) return ('&' if extra_data_list else '') + '&'.join(extra_data_list)
def _construct_extra_parameters(extra_data): """ Given a dictionary of extra key-value pairs (all str), return a string that may be appended to a google authenticator / oathtoken URL. Values that are non-strings will be converted to str. Keys and values are converted to UTF-8 and urlquoted. :return: a string (may be empty if ``extra_data`` is empty) """ extra_data_list = [] for key, value in extra_data.items(): encoded_key = quote(to_byte_string(key)) encoded_value = quote(to_byte_string(value)) extra_data_list.append('{key}={value}'.format(key=encoded_key, value=encoded_value)) return ('&' if extra_data_list else '') + '&'.join(extra_data_list)
def verify_certificate_path(certificate, trusted_ca_paths): """ Verify a certificate against the list of directories each containing files with a certificate chain. :param certificate: The PEM certificate to verify :param trusted_ca_paths: A list of directories :return: True or False """ from os import listdir from os.path import isfile, join, isdir for capath in trusted_ca_paths: if isdir(capath): chainfiles = [ join(capath, f) for f in listdir(capath) if isfile(join(capath, f)) ] for chainfile in chainfiles: chain = parse_chainfile(chainfile) try: verify_certificate(to_byte_string(certificate), chain) return True except Exception as exx: log.debug( u"Can not verify attestation certificate against chain {0!s}." .format(chain)) else: log.warning( "The configured attestation CA directory does not exist.") return False
def test_25_encodings(self): u = u'Hello Wörld' b = b'Hello World' self.assertEquals(to_utf8(None), None) self.assertEquals(to_utf8(u), u.encode('utf8')) self.assertEquals(to_utf8(b), b) self.assertEquals(to_unicode(u), u) self.assertEquals(to_unicode(b), b.decode('utf8')) self.assertEquals(to_unicode(None), None) self.assertEquals(to_unicode(10), 10) self.assertEquals(to_bytes(u), u.encode('utf8')) self.assertEquals(to_bytes(b), b) self.assertEquals(to_bytes(10), 10) self.assertEquals(to_byte_string(u), u.encode('utf8')) self.assertEquals(to_byte_string(b), b) self.assertEquals(to_byte_string(10), b'10')
def test_25_encodings(self): u = u'Hello Wörld' b = b'Hello World' self.assertEquals(to_utf8(None), None) self.assertEquals(to_utf8(u), u.encode('utf8')) self.assertEquals(to_utf8(b), b) self.assertEquals(to_unicode(u), u) self.assertEquals(to_unicode(b), b.decode('utf8')) self.assertEquals(to_unicode(None), None) self.assertEquals(to_unicode(10), 10) self.assertEquals(to_bytes(u), u.encode('utf8')) self.assertEquals(to_bytes(b), b) self.assertEquals(to_bytes(10), 10) self.assertEquals(to_byte_string(u), u.encode('utf8')) self.assertEquals(to_byte_string(b), b) self.assertEquals(to_byte_string(10), b'10')
def verify_certificate(certificate, chain): """ Verify a certificate against the certificate chain, which can be of any length The certificate chain starts with the root certificate and contains further intermediate certificates :param certificate: The certificate :type certificate: PEM encoded string :param chain: A list of PEM encoded certificates :type chain: list :return: raises an exception """ # first reverse the list, since it can be popped better chain = list(reversed(chain)) if not chain: raise privacyIDEAError( "Can not verify certificate against an empty chain.") certificate = load_pem_x509_certificate(to_byte_string(certificate), default_backend()) chain = [ load_pem_x509_certificate(to_byte_string(c), default_backend()) for c in chain ] # verify chain while chain: signer = chain.pop() if chain: # There is another element in the list, so we check the intermediate: signee = chain.pop() signer.public_key().verify(signee.signature, signee.tbs_certificate_bytes, padding.PKCS1v15(), signee.signature_hash_algorithm) signer = signee # This was the last certificate in the chain, so we check the certificate signer.public_key().verify(certificate.signature, certificate.tbs_certificate_bytes, padding.PKCS1v15(), certificate.signature_hash_algorithm)
def update(self, param): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) request = getParam(param, "request", optional) spkac = getParam(param, "spkac", optional) certificate = getParam(param, "certificate", optional) generate = getParam(param, "genkey", optional) template_name = getParam(param, "template", optional) if request or generate: # If we do not upload a user certificate, then we need a CA do # sign the uploaded request or generated certificate. ca = getParam(param, "ca", required) self.add_tokeninfo("CA", ca) cacon = get_caconnector_object(ca) if request: if not spkac: # We only do the whole attestation checking in case we have no SPKAC request_csr = load_pem_x509_csr(to_byte_string(request), default_backend()) if not request_csr.is_signature_valid: raise privacyIDEAError("request has invalid signature.") # If a request is sent, we can have an attestation certificate attestation = getParam(param, "attestation", optional) verify_attestation = getParam(param, "verify_attestation", optional) if attestation: request_numbers = request_csr.public_key().public_numbers() attestation_cert = load_pem_x509_certificate( to_byte_string(attestation), default_backend()) attestation_numbers = attestation_cert.public_key( ).public_numbers() if request_numbers != attestation_numbers: log.warning( "certificate request does not match attestation certificate." ) raise privacyIDEAError( "certificate request does not match attestation certificate." ) try: verified = verify_certificate_path( attestation, param.get(ACTION.TRUSTED_CA_PATH)) except Exception as exx: # We could have file system errors during verification. log.debug("{0!s}".format(traceback.format_exc())) verified = False if not verified: log.warning( "Failed to verify certificate chain of attestation certificate." ) if verify_attestation: raise privacyIDEAError( "Failed to verify certificate chain of attestation certificate." ) # During the initialization process, we need to create the # certificate x509object = cacon.sign_request(request, options={ "spkac": spkac, "template": template_name }) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) elif generate: # Create the certificate on behalf of another user. # Now we need to create the key pair, # the request # and the certificate # We need the user for whom the certificate should be created user = get_user_from_param(param, optionalOrRequired=required) keysize = getParam(param, "keysize", optional, 2048) key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, keysize) req = crypto.X509Req() req.get_subject().CN = user.login # Add email to subject if user.info.get("email"): req.get_subject().emailAddress = user.info.get("email") req.get_subject().organizationalUnitName = user.realm # TODO: Add Country, Organization, Email # req.get_subject().countryName = 'xxx' # req.get_subject().stateOrProvinceName = 'xxx' # req.get_subject().localityName = 'xxx' # req.get_subject().organizationName = 'xxx' req.set_pubkey(key) req.sign(key, "sha256") csr = to_unicode( crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)) x509object = cacon.sign_request( csr, options={"template": template_name}) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) # Save the private key to the encrypted key field of the token s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key) self.add_tokeninfo("privatekey", s, value_type="password") if "pin" in param: self.set_pin(param.get("pin"), encrypt=True) if certificate: self.add_tokeninfo("certificate", certificate)