X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=pygost%2Fasn1schemas%2Fcert-selfsigned-example.py;h=edce6969a92feef39d3d629fc575f26d40c64efa;hb=f7d7f4e37cc84e0b188b8445009f2ee11d8a250b;hp=20e873b325e9d4425db57120551cf9f005e52b28;hpb=3156e810672903cc21746b0e3697a1438f9d3903;p=pygost.git diff --git a/pygost/asn1schemas/cert-selfsigned-example.py b/pygost/asn1schemas/cert-selfsigned-example.py index 20e873b..edce696 100755 --- a/pygost/asn1schemas/cert-selfsigned-example.py +++ b/pygost/asn1schemas/cert-selfsigned-example.py @@ -3,6 +3,7 @@ """ from argparse import ArgumentParser +from base64 import standard_b64decode from base64 import standard_b64encode from datetime import datetime from datetime import timedelta @@ -19,7 +20,9 @@ from pyderasn import PrintableString from pyderasn import UTCTime from pygost.asn1schemas.oids import id_at_commonName +from pygost.asn1schemas.oids import id_ce_authorityKeyIdentifier from pygost.asn1schemas.oids import id_ce_basicConstraints +from pygost.asn1schemas.oids import id_ce_keyUsage from pygost.asn1schemas.oids import id_ce_subjectAltName from pygost.asn1schemas.oids import id_ce_subjectKeyIdentifier from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256 @@ -40,6 +43,7 @@ from pygost.asn1schemas.x509 import AlgorithmIdentifier from pygost.asn1schemas.x509 import AttributeType from pygost.asn1schemas.x509 import AttributeTypeAndValue from pygost.asn1schemas.x509 import AttributeValue +from pygost.asn1schemas.x509 import AuthorityKeyIdentifier from pygost.asn1schemas.x509 import BasicConstraints from pygost.asn1schemas.x509 import Certificate from pygost.asn1schemas.x509 import CertificateSerialNumber @@ -47,6 +51,8 @@ from pygost.asn1schemas.x509 import Extension from pygost.asn1schemas.x509 import Extensions from pygost.asn1schemas.x509 import GeneralName from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters +from pygost.asn1schemas.x509 import KeyIdentifier +from pygost.asn1schemas.x509 import KeyUsage from pygost.asn1schemas.x509 import Name from pygost.asn1schemas.x509 import RDNSequence from pygost.asn1schemas.x509 import RelativeDistinguishedName @@ -81,8 +87,12 @@ parser.add_argument( required=True, help="Signing algorithm: {256[ABCD],512[ABC]}", ) +parser.add_argument( + "--issue-with", + help="Path to PEM with CA to issue the child", +) args = parser.parse_args() -ai = { +AIs = { "256A": { "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetA, "key_algorithm": id_tc26_gost3410_2012_256, @@ -139,7 +149,36 @@ ai = { "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512, "hasher": GOST34112012512, }, -}[args.ai] +} +ai = AIs[args.ai] + +ca_prv = None +ca_cert = None +ca_subj = None +ca_ai = None +if args.issue_with is not None: + with open(args.issue_with, "rb") as fd: + lines = fd.read().decode("ascii").split("-----") + idx = lines.index("BEGIN PRIVATE KEY") + if idx == -1: + raise ValueError("PEM has no PRIVATE KEY") + prv_raw = standard_b64decode(lines[idx + 1]) + idx = lines.index("BEGIN CERTIFICATE") + if idx == -1: + raise ValueError("PEM has no CERTIFICATE") + cert_raw = standard_b64decode(lines[idx + 1]) + pki = PrivateKeyInfo().decod(prv_raw) + ca_prv = prv_unmarshal(bytes(OctetString().decod(bytes(pki["privateKey"])))) + ca_cert = Certificate().decod(cert_raw) + tbs = ca_cert["tbsCertificate"] + ca_subj = tbs["subject"] + curve_oid = GostR34102012PublicKeyParameters().decod(bytes( + tbs["subjectPublicKeyInfo"]["algorithm"]["parameters"] + ))["publicKeyParamSet"] + ca_ai = next(iter([ + params for params in AIs.values() + if params["publicKeyParamSet"] == curve_oid + ])) def pem(obj): @@ -174,13 +213,14 @@ subj = Name(("rdnSequence", RDNSequence([ )) ]))) not_before = datetime.utcnow() -not_after = not_before + timedelta(days=365) +not_after = not_before + timedelta(days=365 * (10 if args.ca else 1)) ai_sign = AlgorithmIdentifier(( - ("algorithm", ai["sign_algorithm"],), + ("algorithm", (ai if ca_ai is None else ca_ai)["sign_algorithm"]), )) exts = [ Extension(( ("extnID", id_ce_subjectKeyIdentifier), + ("extnValue", OctetString( SubjectKeyIdentifier(GOST34112012256(pub_raw).digest()[:20]).encode() )), @@ -197,13 +237,34 @@ exts = [ if args.ca: exts.append(Extension(( ("extnID", id_ce_basicConstraints), - ("extnValue", OctetString(BasicConstraints((("cA", Boolean(True)),)).encode())), + ("critical", Boolean(True)), + ("extnValue", OctetString(BasicConstraints(( + ("cA", Boolean(True)), + )).encode())), + ))) + exts.append(Extension(( + ("extnID", id_ce_keyUsage), + ("critical", Boolean(True)), + ("extnValue", OctetString(KeyUsage(("keyCertSign",)).encode())), ))) +if ca_ai is not None: + caKeyId = [ + bytes(SubjectKeyIdentifier().decod(bytes(ext["extnValue"]))) + for ext in ca_cert["tbsCertificate"]["extensions"] + if ext["extnID"] == id_ce_subjectKeyIdentifier + ][0] + exts.append(Extension(( + ("extnID", id_ce_authorityKeyIdentifier), + ("extnValue", OctetString(AuthorityKeyIdentifier(( + ("keyIdentifier", KeyIdentifier(caKeyId)), + )).encode())), + ))) + tbs = TBSCertificate(( ("version", Version("v3")), ("serialNumber", CertificateSerialNumber(12345)), ("signature", ai_sign), - ("issuer", subj), + ("issuer", subj if ca_ai is None else ca_subj), ("validity", Validity(( ("notBefore", Time(("utcTime", UTCTime(not_before)))), ("notAfter", Time(("utcTime", UTCTime(not_after)))), @@ -221,11 +282,11 @@ tbs = TBSCertificate(( cert = Certificate(( ("tbsCertificate", tbs), ("signatureAlgorithm", ai_sign), - ("signatureValue", BitString(sign( - curve, - prv, - ai["hasher"](tbs.encode()).digest()[::-1], - ))), + ("signatureValue", BitString( + sign(curve, prv, ai["hasher"](tbs.encode()).digest()[::-1]) + if ca_ai is None else + sign(ca_ai["curve"], ca_prv, ca_ai["hasher"](tbs.encode()).digest()[::-1]) + )), )) print("-----BEGIN CERTIFICATE-----") print(pem(cert))