]> Cypherpunks.ru repositories - pygost.git/blobdiff - pygost/asn1schemas/cert-selfsigned-example.py
Make Go's crypto/x509 compatible example certificates
[pygost.git] / pygost / asn1schemas / cert-selfsigned-example.py
index 89da091dd7190f373e3164f1eed07fe7a12346cc..3a0a64a29a916168f9a0e989237d41596105df37 100644 (file)
@@ -1,25 +1,36 @@
 """Create example self-signed X.509 certificate
 """
 
 """Create example self-signed X.509 certificate
 """
 
+from argparse import ArgumentParser
 from base64 import standard_b64encode
 from datetime import datetime
 from datetime import timedelta
 from os import urandom
 from base64 import standard_b64encode
 from datetime import datetime
 from datetime import timedelta
 from os import urandom
-from sys import argv
-from sys import exit as sys_exit
 from textwrap import fill
 
 from pyderasn import Any
 from pyderasn import BitString
 from textwrap import fill
 
 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 pyderasn import UTCTime
 
 from pygost.asn1schemas.oids import id_at_commonName
 from pyderasn import Integer
 from pyderasn import OctetString
 from pyderasn import PrintableString
 from pyderasn import UTCTime
 
 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_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.oids import id_tc26_gost3410_2012_256_paramSetB
+from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetC
+from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetD
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
+from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetB
+from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetC
+from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_256
 from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
 from pygost.asn1schemas.prvkey import PrivateKey
 from pygost.asn1schemas.prvkey import PrivateKeyAlgorithmIdentifier
 from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
 from pygost.asn1schemas.prvkey import PrivateKey
 from pygost.asn1schemas.prvkey import PrivateKeyAlgorithmIdentifier
@@ -28,14 +39,17 @@ 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 AttributeType
 from pygost.asn1schemas.x509 import AttributeTypeAndValue
 from pygost.asn1schemas.x509 import AttributeValue
+from pygost.asn1schemas.x509 import BasicConstraints
 from pygost.asn1schemas.x509 import Certificate
 from pygost.asn1schemas.x509 import CertificateSerialNumber
 from pygost.asn1schemas.x509 import Extension
 from pygost.asn1schemas.x509 import Extensions
 from pygost.asn1schemas.x509 import Certificate
 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 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
 from pygost.asn1schemas.x509 import SubjectKeyIdentifier
 from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
 from pygost.asn1schemas.x509 import TBSCertificate
@@ -47,48 +61,143 @@ from pygost.gost3410 import prv_unmarshal
 from pygost.gost3410 import pub_marshal
 from pygost.gost3410 import public_key
 from pygost.gost3410 import sign
 from pygost.gost3410 import pub_marshal
 from pygost.gost3410 import public_key
 from pygost.gost3410 import sign
+from pygost.gost34112012256 import GOST34112012256
 from pygost.gost34112012512 import GOST34112012512
 
 from pygost.gost34112012512 import GOST34112012512
 
-if len(argv) != 2:
-    sys_exit("Usage: cert-selfsigned-example.py COMMON-NAME")
+parser = ArgumentParser(description="Self-signed X.509 certificate creator")
+parser.add_argument(
+    "--ca",
+    action="store_true",
+    help="Enable BasicConstraints.cA",
+)
+parser.add_argument(
+    "--cn",
+    required=True,
+    help="Subject's CommonName",
+)
+parser.add_argument(
+    "--ai",
+    required=True,
+    help="Signing algorithm: {256[ABCD],512[ABC]}",
+)
+args = parser.parse_args()
+ai = {
+    "256A": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetA,
+        "key_algorithm": id_tc26_gost3410_2012_256,
+        "prv_len": 32,
+        "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetA"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
+        "hasher": GOST34112012256,
+    },
+    "256B": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetB,
+        "key_algorithm": id_tc26_gost3410_2012_256,
+        "prv_len": 32,
+        "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetB"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
+        "hasher": GOST34112012256,
+    },
+    "256C": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetC,
+        "key_algorithm": id_tc26_gost3410_2012_256,
+        "prv_len": 32,
+        "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetC"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
+        "hasher": GOST34112012256,
+    },
+    "256D": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetD,
+        "key_algorithm": id_tc26_gost3410_2012_256,
+        "prv_len": 32,
+        "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetD"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
+        "hasher": GOST34112012256,
+    },
+    "512A": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetA,
+        "key_algorithm": id_tc26_gost3410_2012_512,
+        "prv_len": 64,
+        "curve": CURVES["id-tc26-gost-3410-12-512-paramSetA"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
+        "hasher": GOST34112012512,
+    },
+    "512B": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetB,
+        "key_algorithm": id_tc26_gost3410_2012_512,
+        "prv_len": 64,
+        "curve": CURVES["id-tc26-gost-3410-12-512-paramSetB"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
+        "hasher": GOST34112012512,
+    },
+    "512C": {
+        "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetC,
+        "key_algorithm": id_tc26_gost3410_2012_512,
+        "prv_len": 64,
+        "curve": CURVES["id-tc26-gost-3410-2012-512-paramSetC"],
+        "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
+        "hasher": GOST34112012512,
+    },
+}[args.ai]
 
 
 def pem(obj):
 
 
 def pem(obj):
-    return fill(standard_b64encode(obj.encode()).decode('ascii'), 64)
+    return fill(standard_b64encode(obj.encode()).decode("ascii"), 64)
 
 
 key_params = GostR34102012PublicKeyParameters((
 
 
 key_params = GostR34102012PublicKeyParameters((
-    ("publicKeyParamSet", id_tc26_gost3410_2012_512_paramSetA),
+    ("publicKeyParamSet", ai["publicKeyParamSet"]),
 ))
 
 ))
 
-prv_raw = urandom(64)
+prv_raw = urandom(ai["prv_len"])
 print("-----BEGIN PRIVATE KEY-----")
 print(pem(PrivateKeyInfo((
     ("version", Integer(0)),
     ("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier((
 print("-----BEGIN PRIVATE KEY-----")
 print(pem(PrivateKeyInfo((
     ("version", Integer(0)),
     ("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier((
-        ("algorithm", id_tc26_gost3410_2012_512),
+        ("algorithm", ai["key_algorithm"]),
         ("parameters", Any(key_params)),
     ))),
         ("parameters", Any(key_params)),
     ))),
-    ("privateKey", PrivateKey(prv_raw)),
+    ("privateKey", PrivateKey(OctetString(prv_raw).encode())),
 ))))
 print("-----END PRIVATE KEY-----")
 
 prv = prv_unmarshal(prv_raw)
 ))))
 print("-----END PRIVATE KEY-----")
 
 prv = prv_unmarshal(prv_raw)
-curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
-pub_raw = pub_marshal(public_key(curve, prv), mode=2012)
+curve = ai["curve"]
+pub_raw = pub_marshal(public_key(curve, prv))
 subj = Name(("rdnSequence", RDNSequence([
     RelativeDistinguishedName((
         AttributeTypeAndValue((
             ("type", AttributeType(id_at_commonName)),
 subj = Name(("rdnSequence", RDNSequence([
     RelativeDistinguishedName((
         AttributeTypeAndValue((
             ("type", AttributeType(id_at_commonName)),
-            ("value", AttributeValue(PrintableString(argv[1]))),
+            ("value", AttributeValue(PrintableString(args.cn))),
         )),
     ))
 ])))
 not_before = datetime.utcnow()
 not_after = not_before + timedelta(days=365)
 ai_sign = AlgorithmIdentifier((
         )),
     ))
 ])))
 not_before = datetime.utcnow()
 not_after = not_before + timedelta(days=365)
 ai_sign = AlgorithmIdentifier((
-    ("algorithm", id_tc26_signwithdigest_gost3410_2012_512),
+    ("algorithm", 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((
+        ("extnID", id_ce_basicConstraints),
+        ("extnValue", OctetString(BasicConstraints((("cA", Boolean(True)),)).encode())),
+    )))
 tbs = TBSCertificate((
     ("version", Version("v3")),
     ("serialNumber", CertificateSerialNumber(12345)),
 tbs = TBSCertificate((
     ("version", Version("v3")),
     ("serialNumber", CertificateSerialNumber(12345)),
@@ -101,19 +210,12 @@ tbs = TBSCertificate((
     ("subject", subj),
     ("subjectPublicKeyInfo", SubjectPublicKeyInfo((
         ("algorithm", AlgorithmIdentifier((
     ("subject", subj),
     ("subjectPublicKeyInfo", SubjectPublicKeyInfo((
         ("algorithm", AlgorithmIdentifier((
-            ("algorithm", id_tc26_gost3410_2012_512),
+            ("algorithm", ai["key_algorithm"]),
             ("parameters", Any(key_params)),
         ))),
         ("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
     ))),
             ("parameters", Any(key_params)),
         ))),
         ("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
     ))),
-    ("extensions", Extensions((
-        Extension((
-            ("extnID", id_ce_subjectKeyIdentifier),
-            ("extnValue", OctetString(
-                SubjectKeyIdentifier(GOST34112012512(pub_raw).digest()[:20]).encode()
-            )),
-        )),
-    ))),
+    ("extensions", Extensions(exts)),
 ))
 cert = Certificate((
     ("tbsCertificate", tbs),
 ))
 cert = Certificate((
     ("tbsCertificate", tbs),
@@ -121,8 +223,7 @@ cert = Certificate((
     ("signatureValue", BitString(sign(
         curve,
         prv,
     ("signatureValue", BitString(sign(
         curve,
         prv,
-        GOST34112012512(tbs.encode()).digest()[::-1],
-        mode=2012,
+        ai["hasher"](tbs.encode()).digest()[::-1],
     ))),
 ))
 print("-----BEGIN CERTIFICATE-----")
     ))),
 ))
 print("-----BEGIN CERTIFICATE-----")