italia / eudi-wallet-it-python

Python toolchain for building an OpenID4VP RP with a SATOSA backend compliant with the Italian Wallet implementation profile
Apache License 2.0
16 stars 8 forks source link

feat: x509 certificate chain evaluation #143

Closed peppelinux closed 7 months ago

peppelinux commented 8 months ago

@PascalDR this is an example of how to create an X509 certificate chain. Hope this helps for unit tests of the trust evaluation

import base64
import json

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import Encoding
from datetime import datetime, timedelta

# Generate a private key for the CA
ca_private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Generate a private key for the intermediate
intermediate_private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Generate a private key for the leaf
leaf_private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Generate the CA's certificate
ca = x509.CertificateBuilder().subject_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, u"ca.example.com"),
])).issuer_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, u"ca.example.com"),
])).public_key(
    ca_private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.utcnow()
).not_valid_after(
    datetime.utcnow() + timedelta(days=365)
).add_extension(
    x509.BasicConstraints(ca=True, path_length=1), critical=True,
).sign(ca_private_key, hashes.SHA256())

# Generate the intermediate's certificate
intermediate = x509.CertificateBuilder().subject_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, u"intermediate.example.net"),
])).issuer_name(ca.subject).public_key(
    intermediate_private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.utcnow()
).not_valid_after(
    datetime.utcnow() + timedelta(days=365)
).add_extension(
    x509.BasicConstraints(ca=True, path_length=0), critical=True,
).sign(ca_private_key, hashes.SHA256())

# Generate the leaf's certificate
leaf = x509.CertificateBuilder().subject_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, u"leaf.example.org"),
])).issuer_name(intermediate.subject).public_key(
    leaf_private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.utcnow()
).not_valid_after(
    datetime.utcnow() + timedelta(days=365)
).add_extension(
    x509.BasicConstraints(ca=False, path_length=None), critical=True,
).sign(intermediate_private_key, hashes.SHA256())

# Write the certificates to disk
with open("ca.pem", "wb") as f:
    f.write(ca.public_bytes(Encoding.PEM))

with open("intermediate.pem", "wb") as f:
    f.write(intermediate.public_bytes(Encoding.PEM))

with open("leaf.pem", "wb") as f:
    f.write(leaf.public_bytes(Encoding.PEM))

# Here the certificate chain in DER format, then encoded in base64 to use it according to RFC 9360:

# Create a certificate chain
certificate_chain = [
    ca.public_bytes(Encoding.DER),
    intermediate.public_bytes(Encoding.DER),
    leaf.public_bytes(Encoding.DER)
]

# Convert the bytes to base64 strings
certificate_chain_base64 = [base64.b64encode(cert).decode('utf-8') for cert in certificate_chain]

# Convert the list to JSON
certificate_chain_json = json.dumps(certificate_chain_base64)
print(certificate_chain_json)
peppelinux commented 7 months ago

Resolved by https://github.com/italia/eudi-wallet-it-python/pull/152