synta 0.1.8

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
"""PyCA (cryptography) public-key access test for ML-DSA certificates.

Loads each of the three LAMPS WG ML-DSA test certificates and calls
cert.public_key() via cryptography.x509.  ML-DSA support was added in
cryptography 44.0 (PEP 738 / FIPS 204); older versions raise
UnsupportedAlgorithm.  The test passes in both cases and reports which
path was taken.

Run:
    uv run --with cryptography python -m pytest tests/python/test_pyca_mldsa.py -v
    uv run --with cryptography python  tests/python/test_pyca_mldsa.py
"""

import sys
from pathlib import Path

import pytest

try:
    from cryptography.x509 import load_der_x509_certificate, load_pem_x509_certificate
    from cryptography.exceptions import UnsupportedAlgorithm
    _HAS_CRYPTOGRAPHY = True
except ImportError:
    _HAS_CRYPTOGRAPHY = False

pytestmark = pytest.mark.skipif(
    not _HAS_CRYPTOGRAPHY,
    reason="cryptography package not installed",
)

_WORKSPACE = Path(__file__).resolve().parent.parent.parent
_CERT_DIR = _WORKSPACE / "tests" / "vectors" / "dilithium-certificates" / "examples"

_CERTS = [
    ("ML-DSA-44", _CERT_DIR / "ML-DSA-44.crt"),
    ("ML-DSA-65", _CERT_DIR / "ML-DSA-65.crt"),
    ("ML-DSA-87", _CERT_DIR / "ML-DSA-87.crt"),
]


def _load_cert(path: Path):
    """Load a PEM or DER certificate file into a cryptography.x509.Certificate."""
    if not path.exists():
        pytest.skip(f"certificate not found: {path} — run the Rust benchmark first")
    raw = path.read_bytes()
    if raw.lstrip().startswith(b"-----"):
        return load_pem_x509_certificate(raw)
    return load_der_x509_certificate(raw)


@pytest.mark.parametrize("variant,path", _CERTS)
def test_pyca_mldsa_public_key(variant: str, path: Path) -> None:
    """Load an ML-DSA certificate and access its public key via PyCA."""
    cert = _load_cert(path)

    assert cert.subject is not None
    assert cert.not_valid_before_utc is not None

    try:
        key = cert.public_key()
        key_type = type(key).__name__
        print(f"\n  {variant}: public_key() returned {key_type}")
    except UnsupportedAlgorithm as exc:
        # Older cryptography versions don't know ML-DSA key types.
        print(f"\n  {variant}: public_key() raised UnsupportedAlgorithm: {exc}")


# ── Manual runner ─────────────────────────────────────────────────────────────

def main() -> None:
    if not _HAS_CRYPTOGRAPHY:
        print("SKIP: cryptography package not installed.")
        print("      Run with: uv run --with cryptography python tests/python/test_pyca_mldsa.py")
        sys.exit(0)

    print("PyCA ML-DSA public-key access test")
    print(f"cryptography version: ", end="")
    import cryptography
    print(cryptography.__version__)
    print()

    failed = 0
    for variant, path in _CERTS:
        if not path.exists():
            print(f"  SKIP {variant}: {path} not found")
            continue
        raw = path.read_bytes()
        cert = (load_pem_x509_certificate(raw) if raw.lstrip().startswith(b"-----")
                else load_der_x509_certificate(raw))
        print(f"  {variant}:")
        print(f"    subject:    {cert.subject.rfc4514_string()}")
        print(f"    not_before: {cert.not_valid_before_utc}")
        print(f"    not_after:  {cert.not_valid_after_utc}")
        try:
            key = cert.public_key()
            print(f"    public_key: {type(key).__name__}  [OK]")
        except UnsupportedAlgorithm as exc:
            print(f"    public_key: UnsupportedAlgorithm — {exc}")
        except Exception as exc:
            print(f"    public_key: ERROR — {exc}")
            failed += 1
        print()

    sys.exit(1 if failed else 0)


if __name__ == "__main__":
    main()