🔑
Python:JWK(s)の有効期限とx5cチェーンの検証
はじめに
-
x5c
フィールドを利用して,jwk(s)の公開鍵データの有効期限および証明書チェーンを検証するプログラムをpython3で記述しました. - なお,公開鍵はサーバー証明書で登録された公開鍵を想定しています.
ライブラリ
- pyca/cryptography(バージョン43.0.1を使用している)
プログラム
- 検証のロジックを司っている関数は,
verify_jwk()
です.
import json
from cryptography.x509 import DNSName, load_pem_x509_certificates
from cryptography.x509.verification import PolicyBuilder, Store, VerificationError
def verify_jwk(jwk, dns):
cert_chain = ""
# Extract the certificate data from the x5c field in the JWK
for cert in jwk["x5c"]:
pem_data_serialized = '-----BEGIN CERTIFICATE-----' + cert + '-----END CERTIFICATE-----'
cert_chain += pem_data_serialized
cert_chain = cert_chain.encode()
# Load the certificate chain to a list of Certificate objects
pem_x509_cert_list = load_pem_x509_certificates(cert_chain)
server_cert, intermediate_cert, root_cert = pem_x509_cert_list
store = Store([root_cert])
builder = PolicyBuilder().store(store)
verifier = builder.build_server_verifier(DNSName(dns))
try:
chain_cert_list = verifier.verify(server_cert,[intermediate_cert])
print("\nVerification successful:\n", chain_cert_list)
return True
except VerificationError:
return False
def verify_jwks(jwks, DNSs):
for jwk, DNS in zip(jwks["keys"], DNSs):
if "x5c" not in jwk:
return False
elif verify_jwk(jwk, DNS) == False:
return False
return True
if __name__ == "__main__":
with open("jwks.json", "r") as jwks_file:
jwks = json.load(jwks_file)
"""
jwks内の各jwkに対応するドメインを順にリストに格納する.
例:DNSs = ["example.com", "example.org"]
"""
DNSs = []
jwks_verification_result = verify_jwks(jwks, DNSs)
print(f"JWKS Verification Result: {jwks_verification_result}")
verify_jwk
関数の解説
x5c
から証明書を取得する
cert_chain = ""
# Extract the certificate data from the x5c field in the JWK
for cert in jwk["x5c"]:
"""
- x5cから各証明書データ(プログラムでは,3つを想定)を取得し,
ヘッダーとフッターの追加を行います.
"""
pem_data_serialized = '-----BEGIN CERTIFICATE-----' + cert + '-----END CERTIFICATE-----'
"""
- ヘッダーとフッターを追加した証明書データをそれぞれ結合させます.
"""
cert_chain += pem_data_serialized
cryptography
ライブラリで扱えるようにする.
証明書データを-
cryptography.x509.load_pem_x509_certificates
メソッドを利用する.
from cryptography.x509 import DNSName, load_pem_x509_certificates
# ....
"""証明書データをバイナリ化する"""
cert_chain = cert_chain.encode()
# Load the certificate chain to a list of Certificate objects
"""
複数のpem形式証明書が含まれたバイナリデータを引数として,
cryptography.x509.Certificatクラスの証明書データを取得する.
"""
pem_x509_cert_list = load_pem_x509_certificates(cert_chain)
server_cert, intermediate_cert, root_cert = pem_x509_cert_list
サーバー証明書の有効期限と証明書チェーンの検証
-
cryptography.x509.verification
内のメソッドやクラスとcryptography.x509.DNSName
クラスを利用する. -
(cryptography.x509.DNSName)
- (cryptography.x509.verification)
from cryptography.x509 import DNSName, load_pem_x509_certificates
from cryptography.x509.verification import PolicyBuilder, Store, VerificationError
# ....
"""ルート証明書を引数に,証明書ストアを生成"""
store = Store([root_cert])
"""
- 証明書ストアを元に,証明書検証者
(
cryptography.x509.verification.ClientVerifierや
cryptography.x509.verification.ServerVerifier
)を構築するためのインターフェースであるPolicybuilderを生成.
"""
builder = PolicyBuilder().store(store)
"""
- 証明書検証時の時刻を設定したい場合,
time()メソッドを使う.
builder = builder.time(verification_time)
※verification_timeは,datetime.datetimeのインスタンスを使う.
- time()メソッドが明示的に呼ばれなかった場合,
検証時の時刻は,(build_server_verifier()
またはbuild_client_verifier()メソッドが呼ばれた時に)
datetime.datetime.now()と設定される.
"""
"""
- build_server_verifier()メソッドを用いて,サーバー証明書を検証する
cryptography.x509.verification.ServerVerifierを構築する.
- 引数には,cryptography.x509.DNSNameまたは
cryptography.x509.IPAddressが必要.
サーバー証明書の対象となるであろうドメインまたは,ipアドレスが必要となる.
"""
verifier = builder.build_server_verifier(DNSName(dns))
try:
"""
verifyメソッドを用いて,サーバー証明書を検証する.
第一引数をサーバー証明書のデータ,
第二引数を中間証明書のデータが含まれたリストにする.
"""
chain_cert_list = verifier.verify(server_cert,[intermediate_cert])
print("\nVerification successful:\n", chain_cert_list)
return True
except VerificationError:
return False
参考資料
- Welcome to pyca/cryptography — Cryptography 43.0.1 documentation
Discussion