Skip to content

Fix no-op Subject field validation in TPM attestation certificate check#279

Merged
dainnilsson merged 1 commit intoYubico:mainfrom
dorakemon:main
Mar 5, 2026
Merged

Fix no-op Subject field validation in TPM attestation certificate check#279
dainnilsson merged 1 commit intoYubico:mainfrom
dorakemon:main

Conversation

@dorakemon
Copy link
Contributor

@dorakemon dorakemon commented Mar 5, 2026

Summary

_validate_tpm_cert() in fido2/attestation/tpm.py is intended to enforce
the WebAuthn spec requirement that TPM attestation certificates have an empty
Subject field (§8.3 "tpm-cert-requirements").

However, the current code passes x509.NameOID (a class) to
cert.subject.get_attributes_for_oid(), which expects an OID instance.
This always returns [], so the check never rejects any certificate.

Bug

# Current (broken):
s = cert.subject.get_attributes_for_oid(x509.NameOID)  # always []
if s:
    raise InvalidData("Certificate should not have Subject")

x509.NameOID is cryptography.x509.oid.NameOID, a class containing OID
constants like NameOID.COMMON_NAME. Passing the class itself to
get_attributes_for_oid() never matches any attribute, so the function
silently returns an empty list.

Fix

# Fixed:
if len(cert.subject) > 0:
    raise InvalidData("Certificate should not have Subject")

PoC

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
import datetime

key = ec.generate_private_key(ec.SECP256R1(), default_backend())
subject = x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, "EVIL"),
    x509.NameAttribute(NameOID.COUNTRY_NAME, "XX"),
])
cert = (
    x509.CertificateBuilder()
    .subject_name(subject)
    .issuer_name(subject)
    .public_key(key.public_key())
    .serial_number(x509.random_serial_number())
    .not_valid_before(datetime.datetime.utcnow())
    .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
    .sign(key, hashes.SHA256(), default_backend())
)

# BUG: always returns []
print(cert.subject.get_attributes_for_oid(x509.NameOID))  # []

# Correct: detects Subject fields
print(len(cert.subject) > 0)  # True

@dainnilsson
Copy link
Member

Good catch, thank you!

@dorakemon
Copy link
Contributor Author

Thank you so much for a quick reply!

@dainnilsson dainnilsson merged commit da779ab into Yubico:main Mar 5, 2026
22 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants