pqblocks-csr-pop¶
ML-KEM (FIPS 203) PKCS#10 Certificate Signing Request (CSR) generator with RFC 9883 Proof of Possession (PoP).
At a glance
| Area | Interoperability |
| Import | import pqblocks_csr_pop |
| Command line | library only |
| Version | 0.1.0 (Alpha) |
| Python | >=3.11 |
| Native dependency | none |
| Repository | PQBlocks/mlkem-csr-pop |
| Licence | Apache-2.0 |
What is pqblocks-csr-pop?¶
ML-KEM (FIPS 203) PKCS#10 Certificate Signing Request (CSR) generator with RFC 9883 Proof of Possession (PoP).
Install¶
PyPI release staged
pqblocks-csr-pop installs from its GitHub repository while the PyPI release is staged. The import name and API are identical either way.
Quickstart¶
Executed, not just written
This is the quickstart from the package README. It was run against the package source when this page was generated.
import datetime
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.x509.oid import NameOID
from pqblocks_csr_pop.csr_builder import build_csr_with_pop, parse_csr, verify_csr_signature
from pqblocks_csr_pop.mlkem import mlkem_keygen
# 1. Attestor Identity (e.g. Host/Device Ed25519 key)
attestor_key = ed25519.Ed25519PrivateKey.generate()
ca_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Device Attestor")])
now = datetime.datetime.now(datetime.timezone.utc)
attestor_cert = (
x509.CertificateBuilder()
.subject_name(ca_name).issuer_name(ca_name)
.public_key(attestor_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - datetime.timedelta(days=1))
.not_valid_after(now + datetime.timedelta(days=365))
.sign(attestor_key, None)
)
# 2. Generate ML-KEM Keypair (FIPS 203 ML-KEM-768)
ek, dk = mlkem_keygen("ML-KEM-768")
# 3. Construct PKCS#10 CSR with RFC 9883 PoP Extension
subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "pqc-server.internal.net")])
csr_der = build_csr_with_pop(ek, "ML-KEM-768", subject, attestor_key, attestor_cert)
# 4. CA parses CSR and verifies PoP signature
parsed = parse_csr(csr_der)
valid = verify_csr_signature(csr_der, attestor_cert)
assert valid
print(f"CSR verified successfully: {len(csr_der)} bytes DER")
Examples¶
Runnable scripts in the repository:
Documentation and evidence¶
Every PQBlocks package ships the same evidence set, so each claim can be checked against tests, sources and measurements.
-
What it does, install, usage and API.
-
Correct imports, pitfalls and rules for coding assistants.
-
What it protects, hostile input, constant-time and audit status.
-
Test suites, coverage, vectors and what is not covered.
-
Measured performance, including where it loses.
-
Primary sources and the method-to-code map.
-
Self-verification results, defects found and limits.
-
Worked scenarios and when to pick something else.
-
Every release and what changed.
Related packages in Interoperability¶
pqblocks-jwe: Compact five-part wire format, with a serializer and structural parser, for hybrid ML-KEM-768 + X25519 JWE-style…pqblocks-tls-interop: TLS 1.3 hybrid key exchange (X25519MLKEM768 / RFC 10024) endpoint probe, downgrade detector, and key material validator.pqblocks-wire: Length-prefixed container format (PQCWF1) for ML-KEM ciphertexts and ML-DSA / SLH-DSA signatures, with thin wrappers…