"""
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 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
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
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
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_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):
))
])))
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()
)),
("extnID", id_ce_basicConstraints),
("extnValue", OctetString(BasicConstraints((("cA", Boolean(True)),)).encode())),
)))
+ exts.append(Extension((
+ ("extnID", id_ce_keyUsage),
+ ("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)))),
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))