Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def verify(self, statement, auth_data, client_data_hash):
jwt = statement["response"]
header, payload, sig = (websafe_decode(x) for x in jwt.split(b"."))
data = json.loads(payload.decode("utf8"))
if not self.allow_rooted and data["ctsProfileMatch"] is not True:
raise InvalidData("ctsProfileMatch must be true!")
expected_nonce = sha256(auth_data + client_data_hash)
if not bytes_eq(expected_nonce, websafe_decode(data["nonce"])):
raise InvalidData("Nonce does not match!")
data = json.loads(header.decode("utf8"))
certs = [
x509.load_der_x509_certificate(websafe_decode(x), default_backend())
for x in data["x5c"]
]
certs.append(self._ca)
cert = certs.pop(0)
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if cn[0].value != "attest.android.com":
raise InvalidData("Certificate not issued to attest.android.com!")
raise InvalidData("ctsProfileMatch must be true!")
expected_nonce = sha256(auth_data + client_data_hash)
if not bytes_eq(expected_nonce, websafe_decode(data["nonce"])):
raise InvalidData("Nonce does not match!")
data = json.loads(header.decode("utf8"))
certs = [
x509.load_der_x509_certificate(websafe_decode(x), default_backend())
for x in data["x5c"]
]
certs.append(self._ca)
cert = certs.pop(0)
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if cn[0].value != "attest.android.com":
raise InvalidData("Certificate not issued to attest.android.com!")
CoseKey.for_name(data["alg"]).from_cryptography_key(cert.public_key()).verify(
jwt.rsplit(b".", 1)[0], sig
)
while certs:
child = cert
cert = certs.pop(0)
pub = cert.public_key()
if isinstance(pub, rsa.RSAPublicKey):
pub.verify(
child.signature,
child.tbs_certificate_bytes,
padding.PKCS1v15(),
child.signature_hash_algorithm,
)
ou = ous[0]
if ou.value != "Authenticator Attestation":
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if not cn:
raise InvalidData("Subject must have CN set!")
if enforce_empty_subject:
s = cert.subject.get_attributes_for_oid(x509.NameOID)
if s:
raise InvalidData("Certificate should not have Subject")
if has_subject_alternative_name:
s = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
if not s:
raise InvalidData("Certificate should have SubjectAlternativeName")
if has_aik_certificate:
ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
has_aik = [x == OID_AIK_CERTIFICATE for x in ext.value]
if True not in has_aik:
raise InvalidData(
'Extended key usage MUST contain the "joint-iso-itu-t(2) '
"internationalorganizations(23) 133 tcg-kp(8) "
'tcg-kp-AIKCertificate(3)" OID.'
)
bc = cert.extensions.get_extension_for_class(x509.BasicConstraints)
if bc.value.ca:
raise InvalidData("Attestation certificate must have CA=false!")
try:
ext = cert.extensions.get_extension_for_oid(OID_AAGUID)
if ext.critical:
raise InvalidData("Subject must have O set!")
ous = cert.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATIONAL_UNIT_NAME)
if not ous:
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
ou = ous[0]
if ou.value != "Authenticator Attestation":
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if not cn:
raise InvalidData("Subject must have CN set!")
if enforce_empty_subject:
s = cert.subject.get_attributes_for_oid(x509.NameOID)
if s:
raise InvalidData("Certificate should not have Subject")
if has_subject_alternative_name:
s = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
if not s:
raise InvalidData("Certificate should have SubjectAlternativeName")
if has_aik_certificate:
ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
has_aik = [x == OID_AIK_CERTIFICATE for x in ext.value]
if True not in has_aik:
raise InvalidData(
'Extended key usage MUST contain the "joint-iso-itu-t(2) '
"internationalorganizations(23) 133 tcg-kp(8) "
'tcg-kp-AIKCertificate(3)" OID.'
)
bc = cert.extensions.get_extension_for_class(x509.BasicConstraints)
check_subject=False,
enforce_empty_subject=True,
has_subject_alternative_name=True,
has_aik_certificate=True,
)
pub_key = CoseKey.for_alg(alg).from_cryptography_key(cert.public_key())
else:
pub_key = CoseKey.parse(auth_data.credential_data.public_key)
if pub_key.ALGORITHM != alg:
raise InvalidData("Wrong algorithm of public key!")
try:
pub_area = TpmPublicFormat.parse(statement["pubArea"])
except Exception as e:
raise InvalidData("unable to parse pubArea", e)
# Verify that the public key specified by the parameters and unique
# fields of pubArea is identical to the credentialPublicKey in the
# attestedCredentialData in authenticatorData.
if (
auth_data.credential_data.public_key.from_cryptography_key(
pub_area.public_key()
)
!= auth_data.credential_data.public_key
):
raise InvalidSignature(
"attestation pubArea does not match attestedCredentialData"
)
try:
# TpmAttestationFormat.parse is reponsible for:
s = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
if not s:
raise InvalidData("Certificate should have SubjectAlternativeName")
if has_aik_certificate:
ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
has_aik = [x == OID_AIK_CERTIFICATE for x in ext.value]
if True not in has_aik:
raise InvalidData(
'Extended key usage MUST contain the "joint-iso-itu-t(2) '
"internationalorganizations(23) 133 tcg-kp(8) "
'tcg-kp-AIKCertificate(3)" OID.'
)
bc = cert.extensions.get_extension_for_class(x509.BasicConstraints)
if bc.value.ca:
raise InvalidData("Attestation certificate must have CA=false!")
try:
ext = cert.extensions.get_extension_for_oid(OID_AAGUID)
if ext.critical:
raise InvalidData("AAGUID extension must not be marked as critical")
ext_aaguid = ext.value.value[2:]
if ext_aaguid != aaguid:
raise InvalidData(
"AAGUID in Authenticator data does not "
"match attestation certificate!"
)
except x509.ExtensionNotFound:
pass # If missing, ignore
if cert.version != x509.Version.v3:
raise InvalidData("Attestation certificate must use version 3!")
if check_subject:
c = cert.subject.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)
if not c:
raise InvalidData("Subject must have C set!")
o = cert.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)
if not o:
raise InvalidData("Subject must have O set!")
ous = cert.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATIONAL_UNIT_NAME)
if not ous:
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
ou = ous[0]
if ou.value != "Authenticator Attestation":
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if not cn:
raise InvalidData("Subject must have CN set!")
if enforce_empty_subject:
s = cert.subject.get_attributes_for_oid(x509.NameOID)
if s:
raise InvalidData("Certificate should not have Subject")
if has_subject_alternative_name:
s = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
if not s:
raise InvalidData("Certificate should have SubjectAlternativeName")
if has_aik_certificate:
ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
has_aik = [x == OID_AIK_CERTIFICATE for x in ext.value]
def _validate_attestation_certificate(
cert,
aaguid,
check_subject=True,
enforce_empty_subject=False,
has_subject_alternative_name=False,
has_aik_certificate=False,
):
if cert.version != x509.Version.v3:
raise InvalidData("Attestation certificate must use version 3!")
if check_subject:
c = cert.subject.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)
if not c:
raise InvalidData("Subject must have C set!")
o = cert.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)
if not o:
raise InvalidData("Subject must have O set!")
ous = cert.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATIONAL_UNIT_NAME)
if not ous:
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
ou = ous[0]
if ou.value != "Authenticator Attestation":
raise InvalidData('Subject must have OU = "Authenticator Attestation"!')
cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
if not cn:
ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
has_aik = [x == OID_AIK_CERTIFICATE for x in ext.value]
if True not in has_aik:
raise InvalidData(
'Extended key usage MUST contain the "joint-iso-itu-t(2) '
"internationalorganizations(23) 133 tcg-kp(8) "
'tcg-kp-AIKCertificate(3)" OID.'
)
bc = cert.extensions.get_extension_for_class(x509.BasicConstraints)
if bc.value.ca:
raise InvalidData("Attestation certificate must have CA=false!")
try:
ext = cert.extensions.get_extension_for_oid(OID_AAGUID)
if ext.critical:
raise InvalidData("AAGUID extension must not be marked as critical")
ext_aaguid = ext.value.value[2:]
if ext_aaguid != aaguid:
raise InvalidData(
"AAGUID in Authenticator data does not "
"match attestation certificate!"
)
except x509.ExtensionNotFound:
pass # If missing, ignore