如何使用根证书验证FIDO联盟Metadata的JWT签名?
解决FIDO联盟Metadata JWT签名验证失败问题
你的问题出在直接使用根证书公钥验证JWT签名——FIDO的Metadata JWT是由GlobalSign的中间CA证书签名的,而非根证书直接签名。正确的流程是先验证中间证书的合法性(用根证书),再用中间证书的公钥验证JWT签名。
以下是修正后的代码:
import requests from jwcrypto import jwt, jwk, jws from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization # 下载并加载GlobalSign根证书 root_cert_resp = requests.get("http://secure.globalsign.com/cacert/root-r3.crt") root_cert = x509.load_der_x509_certificate(root_cert_resp.content, default_backend()) # 下载FIDO Metadata JWT jwt_data = requests.get("https://mds3.fidoalliance.org/").content.decode("ascii") # 解析JWT头部,获取签名用的中间证书(x5c字段) jwt_obj = jws.JWS() jwt_obj.deserialize(jwt_data) header = jwt_obj.jose_header x5c_chain = header.get("x5c", []) if not x5c_chain: raise ValueError("JWT头部未包含证书链x5c字段") # 加载中间证书(链中的第一个是签名证书) intermediate_cert_pem = f"-----BEGIN CERTIFICATE-----\n{x5c_chain[0]}\n-----END CERTIFICATE-----".encode() intermediate_cert = x509.load_pem_x509_certificate(intermediate_cert_pem, default_backend()) # 验证中间证书是否由根证书签发 intermediate_cert.verify_directly_issued_by(root_cert) # 从中间证书提取公钥,转为JWK格式 pub_key_pem = intermediate_cert.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) public_key = jwk.JWK.from_pem(pub_key_pem) # 验证并解析JWT final_jwt = jwt.JWT(jwt=jwt_data, key=public_key) print(final_jwt.claims)
关键说明:
- 证书链验证:JWT头部的
x5c字段包含了签名证书链,第一个元素就是直接签名JWT的中间CA证书,需要先验证该证书是根证书的合法下属。 - 公钥格式:提取公钥时使用
SubjectPublicKeyInfo格式(而非PKCS1),这是JWK兼容的标准格式,避免格式不匹配导致的验证失败。
内容的提问来源于stack exchange,提问作者gřmězupť
相关产品推荐
相关产品推荐

