GGSheng's picture
feat: deploy Gemma 4 to hf space
08c964e verified
import hashlib
from typing import List
from cryptography import x509
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.x509 import (
Extension,
ExtensionNotFound,
ObjectIdentifier,
UnrecognizedExtension,
)
from webauthn.helpers import (
decode_credential_public_key,
decoded_public_key_to_cryptography,
parse_cbor,
validate_certificate_chain,
verify_signature,
)
from webauthn.helpers.asn1.android_key import (
AuthorizationList,
KeyDescription,
KeyOrigin,
KeyPurpose,
)
from webauthn.helpers.exceptions import (
InvalidCertificateChain,
InvalidRegistrationResponse,
)
from webauthn.helpers.known_root_certs import (
google_hardware_attestation_root_1,
google_hardware_attestation_root_2,
)
from webauthn.helpers.structs import AttestationStatement
def verify_android_key(
*,
attestation_statement: AttestationStatement,
attestation_object: bytes,
client_data_json: bytes,
credential_public_key: bytes,
pem_root_certs_bytes: List[bytes],
) -> bool:
"""Verify an "android-key" attestation statement
See https://www.w3.org/TR/webauthn-2/#sctn-android-key-attestation
Also referenced: https://source.android.com/security/keystore/attestation
"""
if not attestation_statement.sig:
raise InvalidRegistrationResponse(
"Attestation statement was missing signature (Android Key)"
)
if not attestation_statement.alg:
raise InvalidRegistrationResponse(
"Attestation statement was missing algorithm (Android Key)"
)
if not attestation_statement.x5c:
raise InvalidRegistrationResponse("Attestation statement was missing x5c (Android Key)")
# Validate certificate chain
try:
# Include known root certificates for this attestation format
pem_root_certs_bytes.append(google_hardware_attestation_root_1)
pem_root_certs_bytes.append(google_hardware_attestation_root_2)
validate_certificate_chain(
x5c=attestation_statement.x5c,
pem_root_certs_bytes=pem_root_certs_bytes,
)
except InvalidCertificateChain as err:
raise InvalidRegistrationResponse(f"{err} (Android Key)")
# Extract attStmt bytes from attestation_object
attestation_dict = parse_cbor(attestation_object)
authenticator_data_bytes = attestation_dict["authData"]
# Generate a hash of client_data_json
client_data_hash = hashlib.sha256()
client_data_hash.update(client_data_json)
client_data_hash_bytes = client_data_hash.digest()
verification_data = b"".join(
[
authenticator_data_bytes,
client_data_hash_bytes,
]
)
# Verify that sig is a valid signature over the concatenation of authenticatorData
# and clientDataHash using the public key in the first certificate in x5c with the
# algorithm specified in alg.
attestation_cert_bytes = attestation_statement.x5c[0]
attestation_cert = x509.load_der_x509_certificate(attestation_cert_bytes, default_backend())
attestation_cert_pub_key = attestation_cert.public_key()
try:
verify_signature(
public_key=attestation_cert_pub_key,
signature_alg=attestation_statement.alg,
signature=attestation_statement.sig,
data=verification_data,
)
except InvalidSignature:
raise InvalidRegistrationResponse(
"Could not verify attestation statement signature (Android Key)"
)
# Verify that the public key in the first certificate in x5c matches the
# credentialPublicKey in the attestedCredentialData in authenticatorData.
attestation_cert_pub_key_bytes = attestation_cert_pub_key.public_bytes(
Encoding.DER,
PublicFormat.SubjectPublicKeyInfo,
)
# Convert our raw public key bytes into the same format cryptography generates for
# the cert subject key
decoded_pub_key = decode_credential_public_key(credential_public_key)
pub_key_crypto = decoded_public_key_to_cryptography(decoded_pub_key)
pub_key_crypto_bytes = pub_key_crypto.public_bytes(
Encoding.DER,
PublicFormat.SubjectPublicKeyInfo,
)
if attestation_cert_pub_key_bytes != pub_key_crypto_bytes:
raise InvalidRegistrationResponse(
"Certificate public key did not match credential public key (Android Key)"
)
# Verify that the attestationChallenge field in the attestation certificate
# extension data is identical to clientDataHash.
ext_key_description_oid = "1.3.6.1.4.1.11129.2.1.17"
try:
cert_extensions = attestation_cert.extensions
ext_key_description: Extension = cert_extensions.get_extension_for_oid(
ObjectIdentifier(ext_key_description_oid)
)
except ExtensionNotFound:
raise InvalidRegistrationResponse(
f"Certificate missing extension {ext_key_description_oid} (Android Key)"
)
# Peel apart the Extension into an UnrecognizedExtension, then the bytes we actually
# want
ext_value_wrapper: UnrecognizedExtension = ext_key_description.value
ext_value: bytes = ext_value_wrapper.value
parsed_ext = KeyDescription.load(ext_value)
# Verify the following using the appropriate authorization list from the attestation
# certificate extension data:
software_enforced: AuthorizationList = parsed_ext["softwareEnforced"]
tee_enforced: AuthorizationList = parsed_ext["teeEnforced"]
# The AuthorizationList.allApplications field is not present on either authorization
# list (softwareEnforced nor teeEnforced), since PublicKeyCredential MUST be scoped
# to the RP ID.
if software_enforced["allApplications"].native is not None:
raise InvalidRegistrationResponse(
"allApplications field was present in softwareEnforced (Android Key)"
)
if tee_enforced["allApplications"].native is not None:
raise InvalidRegistrationResponse(
"allApplications field was present in teeEnforced (Android Key)"
)
# The value in the AuthorizationList.origin field is equal to KM_ORIGIN_GENERATED.
origin = tee_enforced["origin"].native
if origin != KeyOrigin.GENERATED:
raise InvalidRegistrationResponse(
f"teeEnforced.origin {origin} was not {KeyOrigin.GENERATED}"
)
# The value in the AuthorizationList.purpose field is equal to KM_PURPOSE_SIGN.
purpose = tee_enforced["purpose"].native
if purpose != [KeyPurpose.SIGN]:
raise InvalidRegistrationResponse(
f"teeEnforced.purpose {purpose} was not [{KeyPurpose.SIGN}]"
)
return True