def verify_certificate(jwt: JWT) -> JWK:
    """Get (and verify) the signing key from JWT."""
    # First element in the header is our actual key
    try:
        decoding_key = JWK.from_pem(
            PEM_CERT_TEMPLATE.format(jwt.token.jose_header['x5c'][0]).encode())
    except ValueError:
        raise InvalidCert('Cannot decode key.')
    if SETTINGS.metadata_service['disable_cert_verification']:
        return decoding_key
    if not SETTINGS.metadata_service['certificate']:
        raise CommandError(
            "Certificate verification enabled, but no certificate set. "
            "Please set certificate or disable validation.")
    # Create context and verify
    store = _prepare_crypto_store(jwt)
    decoding_cert = crypto.load_certificate(
        crypto.FILETYPE_PEM,
        PEM_CERT_TEMPLATE.format(jwt.token.jose_header['x5c'][0]).encode())
    store_ctx = crypto.X509StoreContext(store, decoding_cert)
    try:
        store_ctx.verify_certificate()
    except crypto.X509StoreContextError:
        raise InvalidCert('Key could not be verified.')
    else:
        return decoding_key
Exemplo n.º 2
0
 def metadata(self) -> Optional['AuthenticatorMetadata']:
     """Verify and return the appropriate metada for this authenticator."""
     metadata = self._get_metadata()
     if metadata is not None and 'x5c' in self.attestation.att_statement:
         # Take the device certificate and try to validate against all certs in MDS
         device_cert = crypto.load_certificate(
             crypto.FILETYPE_ASN1, self.attestation.att_statement['x5c'][0])
         root_certs = json.loads(metadata.detailed_metadata_entry
                                 )['attestationRootCertificates']
         store = crypto.X509Store()
         for root_cert in root_certs:
             cert = crypto.load_certificate(
                 crypto.FILETYPE_PEM, PEM_CERT_TEMPLATE.format(root_cert))
             store.add_cert(cert)
         if len(self.attestation.att_statement['x5c']) > 1:
             for interm_cert in self.attestation.att_statement['x5c'][1:]:
                 store.add_cert(
                     crypto.load_certificate(crypto.FILETYPE_ASN1,
                                             interm_cert))
         store_ctx = crypto.X509StoreContext(store, device_cert)
         try:
             store_ctx.verify_certificate()
         except crypto.X509StoreContextError:
             # The device certificate cannot be verified using the MDS certificate, do not trust the metadata
             return None
     return metadata
Exemplo n.º 3
0
 def _prepare_store(self, root_certs: List[str]) -> crypto.X509Store:
     """Prepare crypto store for verification."""
     store = crypto.X509Store()
     for root_cert in root_certs:
         cert = crypto.load_certificate(
             crypto.FILETYPE_PEM,
             PEM_CERT_TEMPLATE.format(root_cert).encode())
         store.add_cert(cert)
     if len(self.attestation.att_statement['x5c']) > 1:
         for interm_cert in self.attestation.att_statement['x5c'][1:]:
             try:
                 store.add_cert(
                     crypto.load_certificate(crypto.FILETYPE_ASN1,
                                             interm_cert))
             except crypto.Error:
                 # The certificate failed to load, ignore as if it is a missing link, the verification will fail
                 # It is possible that it is defined here as well as in metadata
                 pass
     return store
def _prepare_crypto_store(jwt: JWT) -> crypto.X509Store:
    """Prepare crytpographic store for verification."""
    # Create crypto context
    store = crypto.X509Store()
    for key in jwt.token.jose_header['x5c'][1:]:
        cert = crypto.load_certificate(crypto.FILETYPE_PEM,
                                       PEM_CERT_TEMPLATE.format(key).encode())
        store.add_cert(cert)
    for root_cert_file in SETTINGS.metadata_service['certificate']:
        with open(str(root_cert_file), 'rb') as root_file:
            root_cert = crypto.load_certificate(crypto.FILETYPE_PEM,
                                                root_file.read())
    store.add_cert(root_cert)
    # CRL handling
    # FIXME: This part is not tested in unittests (intentionally) as it might be more suited for integration testing
    for crl_file in SETTINGS.metadata_service['crl_list']:
        with open(str(crl_file), 'rb') as file:
            crl_list = x509.load_pem_x509_crl(file.read(), default_backend())
        store.add_crl(crypto.CRL.from_cryptography(crl_list))
    if SETTINGS.metadata_service['crl_list']:
        store.set_flags(crypto.X509StoreFlags.CRL_CHECK)
    return store