Skip to content

Instantly share code, notes, and snippets.

@joostd
Last active May 22, 2023 13:05
Show Gist options
  • Save joostd/9f9dea983ed6a7b926c5ad09f51cb807 to your computer and use it in GitHub Desktop.
Save joostd/9f9dea983ed6a7b926c5ad09f51cb807 to your computer and use it in GitHub Desktop.
Check CSR with attestation to be generated on a YubiKey
import sys
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import padding
def verify_signature(parent, child):
parent.public_key().verify(
child.signature,
child.tbs_certificate_bytes,
padding.PKCS1v15(),
child.signature_hash_algorithm
)
csr_file = input('Certificate Signing Request Path [csr.pem]: ')
if csr_file == '':
csr_file = 'csr.pem'
attestation_file = input('PIV Attestation Certificate Path [attestation.pem]: ')
if attestation_file == '':
attestation_file = 'attestation.pem'
intermediate_file = input('PIV Intermediate Attestation Certificate Path [intermediate.pem]: ')
if intermediate_file == '':
intermediate_file = 'intermediate.pem'
ca_file = input('PIV Root Attestation Certificate Path [piv-attestation-ca.pem]: ')
if ca_file == '':
ca_file = 'piv-attestation-ca.pem'
try:
with open(csr_file, 'rb') as f:
csr = x509.load_pem_x509_csr(f.read(), default_backend())
with open(attestation_file, 'rb') as f:
attestation_cert = x509.load_pem_x509_certificate(f.read(), default_backend())
with open(intermediate_file, 'rb') as f:
intermediate_cert = x509.load_pem_x509_certificate(f.read(), default_backend())
with open(ca_file, 'rb') as f:
ca_cert = x509.load_pem_x509_certificate(f.read(), default_backend())
verify_signature(ca_cert, intermediate_cert)
verify_signature(intermediate_cert, attestation_cert)
if csr.public_key().public_numbers() == attestation_cert.public_key().public_numbers():
print("✅ Public keys match")
else:
sys.exit("❌ CSR public key does not match attestation public key")
print('✅ Signature validation succeeded.')
except FileNotFoundError:
print('❌ One or more of the supplied files was not found.')
except:
print('❌ CA path validation failed.')
@joostd
Copy link
Author

joostd commented May 22, 2023

Generate keys, csr, attestation crt, retrieve intermediate cert

SLOT=9a
PIN=123456
KEY=010203040506070801020304050607080102030405060708
SUBJ="CN=John"
ykman piv keys generate $SLOT pub.pem --management-key $KEY
ykman piv certificates request --subject $SUBJ $SLOT pub.pem csr.pem --pin $PIN
ykman piv keys attest $SLOT attestation.pem
ykman piv certificates export f9 intermediate.pem

To verify, retrieve root cert and validate the CSR and attestation:

wget https://developers.yubico.com/PIV/Introduction/piv-attestation-ca.pem
$ ykman script check_attested_csr.py 

WARNING: Never run a script without fully understanding what it does!

Scripts are very powerful, and have the power to harm to both your YubiKey and
your computer.

ONLY run scripts that you fully trust!

You can bypass this message by running the command with the --force flag.

Run script? [y/N]: y
Certificate Signing Request Path [csr.pem]: 
PIV Attestation Certificate Path [attestation.pem]: 
PIV Intermediate Attestation Certificate Path [intermediate.pem]: 
PIV Root Attestation Certificate Path [piv-attestation-ca.pem]: 
✅ Public keys match
✅ Signature validation succeeded.

@joostd
Copy link
Author

joostd commented May 22, 2023

On systems where openssl is installed, better use:

openssl req -in csr.pem -noout -pubkey -out pub.pem
openssl x509 -in attestation.pem -noout -pubkey | diff - pub.pem 
openssl verify -CAfile piv-attestation-ca.pem -untrusted intermediate.pem attestation.pem 

as this will do an actual CA path validation (i.e. check constraints instead of only checking signatures).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment