39 lines
4.4 KiB
Python
39 lines
4.4 KiB
Python
"""Prepare a separate proposed local active certificate, without trusting or installing it."""
|
|
from pathlib import Path
|
|
from datetime import datetime,timedelta,timezone
|
|
import json
|
|
from cryptography import x509
|
|
from cryptography.x509.oid import NameOID,ExtendedKeyUsageOID
|
|
from cryptography.hazmat.primitives import hashes,serialization
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
ROOT=Path(__file__).resolve().parent.parent;PRIVATE=ROOT/'storage/app/private/investmoz-v2/portal-audit'
|
|
meta=json.loads((PRIVATE/'country-https-latest.json').read_text());work=Path(meta['work'])/'active-tls-prepared';work.mkdir(exist_ok=False)
|
|
out=ROOT/'outputs/investmoz-country02-https-20261011';now=datetime.now(timezone.utc)
|
|
ca_key=rsa.generate_private_key(public_exponent=65537,key_size=2048);key=rsa.generate_private_key(public_exponent=65537,key_size=2048)
|
|
name=x509.Name([x509.NameAttribute(NameOID.COMMON_NAME,'InvestMoz portal-investidor.test local 20261011')])
|
|
ca=(x509.CertificateBuilder().subject_name(name).issuer_name(name).public_key(ca_key.public_key()).serial_number(x509.random_serial_number())
|
|
.not_valid_before(now-timedelta(minutes=5)).not_valid_after(now+timedelta(days=365))
|
|
.add_extension(x509.BasicConstraints(ca=True,path_length=0),True).add_extension(x509.KeyUsage(False,False,False,False,False,True,True,False,False),True)
|
|
.add_extension(x509.NameConstraints([x509.DNSName('portal-investidor.test')],None),True).sign(ca_key,hashes.SHA256()))
|
|
leaf=(x509.CertificateBuilder().subject_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME,'portal-investidor.test')])).issuer_name(name)
|
|
.public_key(key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(now-timedelta(minutes=5)).not_valid_after(now+timedelta(days=90))
|
|
.add_extension(x509.BasicConstraints(ca=False,path_length=None),True).add_extension(x509.SubjectAlternativeName([x509.DNSName('portal-investidor.test')]),False)
|
|
.add_extension(x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]),False).add_extension(x509.KeyUsage(True,False,True,False,False,False,False,False,False),True)
|
|
.sign(ca_key,hashes.SHA256()))
|
|
assert key.public_key().public_bytes(serialization.Encoding.DER,serialization.PublicFormat.SubjectPublicKeyInfo)==leaf.public_key().public_bytes(serialization.Encoding.DER,serialization.PublicFormat.SubjectPublicKeyInfo)
|
|
(work/'portal-investidor.test-key.pem').write_bytes(key.private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()))
|
|
(work/'portal-investidor.test-fullchain.pem').write_bytes(leaf.public_bytes(serialization.Encoding.PEM)+ca.public_bytes(serialization.Encoding.PEM))
|
|
(work/'portal-investidor.test-ca.cer').write_bytes(ca.public_bytes(serialization.Encoding.DER))
|
|
public=out/'certificados-publicos';public.mkdir(exist_ok=True)
|
|
for name in ['portal-investidor.test-ca.cer','portal-investidor.test-fullchain.pem']:(public/name).write_bytes((work/name).read_bytes())
|
|
cert={'prepared_not_installed':True,'prepared_not_trusted':True,'SAN':['portal-investidor.test'],'issuer':ca.subject.rfc4514_string(),'root_thumbprint':ca.fingerprint(hashes.SHA1()).hex().upper(),
|
|
'root_sha256':ca.fingerprint(hashes.SHA256()).hex(),'leaf_sha256':leaf.fingerprint(hashes.SHA256()).hex(),'leaf_valid_until':leaf.not_valid_after_utc.isoformat(),
|
|
'root_valid_until':ca.not_valid_after_utc.isoformat(),'private_key_public_key_matches':True,'private_key_kept_out_of_bundle':True,'signing_key_not_persisted':True,
|
|
'deployment_private_directory':'C:/Users/macbook/.config/investmoz/tls','active_trust_store_changed':False,'qa_ca_not_reused':True,
|
|
'renewal':'Before leaf expiry prepare new certificate and trust chain, review/retest before replacement. If using an organization CA instead, seal another configuration hash before applying.'}
|
|
(out/'certificado-ativo-proposto.json').write_text(json.dumps(cert,ensure_ascii=False,indent=2),encoding='utf-8')
|
|
plan=json.loads((out/'plano-https-ativo.json').read_text());plan['certificate_required'].update(cert);plan['certificate_required'].pop('issuer_and_expiry',None)
|
|
plan['code_hash']=json.loads(Path(json.loads((PRIVATE/'country-https-backup-latest.json').read_text())['path']).read_text())['code_hash']
|
|
(out/'plano-https-ativo.json').write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8')
|
|
print(json.dumps({'result':'active certificate prepared privately; not installed/trusted','public_metadata':str(out/'certificado-ativo-proposto.json'),'active_changes':0}))
|