68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
"""Task 6: one-shot generator for `tests/fixtures/test_cert.pfx` -- a
|
|
self-signed TEST-ONLY A1 certificate, NEVER a real one (design spec's "os 3
|
|
seguros de portabilidade", item (b)/(c) extended by the F2 emenda: goldens
|
|
ASSINADOS need a FIXED test certificate, committed as a binary fixture).
|
|
|
|
Re-running this script produces a DIFFERENT RSA key pair (key generation is
|
|
not seeded) -- that is fine and expected: this is meant to be run ONCE and
|
|
the output COMMITTED. The determinism `tests/test_signed_goldens.py` relies
|
|
on comes from every test run reusing the SAME committed `.pfx` file (so the
|
|
same private key signs the same canonicalized XML the same way every time,
|
|
RSA PKCS#1v1.5 having no random padding) -- NOT from this generator being
|
|
reproducible bit-for-bit across runs. Re-run only if the fixture needs to be
|
|
rotated, and regenerate `tests/goldens_signed/*.expected.xml`
|
|
(`scripts/generate_signed_goldens.py`) together with it, in the same commit.
|
|
|
|
uv run python scripts/generate_test_cert.py
|
|
"""
|
|
from datetime import datetime, timedelta, timezone
|
|
from pathlib import Path
|
|
|
|
from cryptography import x509
|
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
from cryptography.x509.oid import NameOID
|
|
|
|
# Mesmo CNPJ do emitente usado em TODOS os casos golden da lib
|
|
# (`sowai_fiscal.goldens/*.input.json`) -- ver esse pacote se algum caso
|
|
# novo usar um CNPJ diferente; este script/fixture precisaria acompanhar.
|
|
CNPJ = "12345678000190"
|
|
PASSWORD = "test-cert-password"
|
|
OUT_PATH = Path(__file__).resolve().parents[1] / "tests" / "fixtures" / "test_cert.pfx"
|
|
|
|
|
|
def main() -> None:
|
|
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
|
subject = issuer = x509.Name(
|
|
[
|
|
x509.NameAttribute(NameOID.COMMON_NAME, f"AUTOPECAS THIAGO LTDA:{CNPJ}"),
|
|
x509.NameAttribute(NameOID.SERIAL_NUMBER, CNPJ),
|
|
]
|
|
)
|
|
now = datetime.now(timezone.utc)
|
|
cert = (
|
|
x509.CertificateBuilder()
|
|
.subject_name(subject)
|
|
.issuer_name(issuer)
|
|
.public_key(key.public_key())
|
|
.serial_number(x509.random_serial_number())
|
|
.not_valid_before(now - timedelta(days=1))
|
|
.not_valid_after(now + timedelta(days=3650))
|
|
.sign(key, hashes.SHA256())
|
|
)
|
|
pfx_bytes = pkcs12.serialize_key_and_certificates(
|
|
name=b"sowai-fiscal-svc-test",
|
|
key=key,
|
|
cert=cert,
|
|
cas=None,
|
|
encryption_algorithm=serialization.BestAvailableEncryption(PASSWORD.encode("utf-8")),
|
|
)
|
|
OUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
OUT_PATH.write_bytes(pfx_bytes)
|
|
print(f"wrote {OUT_PATH} (cnpj={CNPJ}, password={PASSWORD!r})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|