+#!/usr/bin/env python3
"""Create example self-signed X.509 certificate
"""
from argparse import ArgumentParser
+from base64 import standard_b64decode
from base64 import standard_b64encode
from datetime import datetime
from datetime import timedelta
from pyderasn import Any
from pyderasn import BitString
from pyderasn import Boolean
+from pyderasn import IA5String
from pyderasn import Integer
from pyderasn import OctetString
from pyderasn import PrintableString
from pygost.asn1schemas.oids import id_at_commonName
from pygost.asn1schemas.oids import id_ce_basicConstraints
+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
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetA
from pygost.asn1schemas.x509 import CertificateSerialNumber
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 Name
from pygost.asn1schemas.x509 import RDNSequence
from pygost.asn1schemas.x509 import RelativeDistinguishedName
+from pygost.asn1schemas.x509 import SubjectAltName
from pygost.asn1schemas.x509 import SubjectKeyIdentifier
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
from pygost.asn1schemas.x509 import TBSCertificate
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,
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
"hasher": GOST34112012512,
},
-}[args.ai]
+}
+ai = AIs[args.ai]
+
+ca_prv = 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"]))))
+ tbs = Certificate().decod(cert_raw)["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):
not_before = datetime.utcnow()
not_after = not_before + timedelta(days=365)
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()
)),
)),
+ Extension((
+ ("extnID", id_ce_subjectAltName),
+ ("extnValue", OctetString(
+ SubjectAltName((
+ GeneralName(("dNSName", IA5String(args.cn))),
+ )).encode()
+ )),
+ )),
]
if args.ca:
exts.append(Extension((
("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)))),
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))