]> Cypherpunks.ru repositories - pygost.git/blob - pygost/asn1schemas/cert-selfsigned-example.py
cert-selfsigned-example is executable
[pygost.git] / pygost / asn1schemas / cert-selfsigned-example.py
1 #!/usr/bin/env python3
2 """Create example self-signed X.509 certificate
3 """
4
5 from argparse import ArgumentParser
6 from base64 import standard_b64encode
7 from datetime import datetime
8 from datetime import timedelta
9 from os import urandom
10 from textwrap import fill
11
12 from pyderasn import Any
13 from pyderasn import BitString
14 from pyderasn import Boolean
15 from pyderasn import IA5String
16 from pyderasn import Integer
17 from pyderasn import OctetString
18 from pyderasn import PrintableString
19 from pyderasn import UTCTime
20
21 from pygost.asn1schemas.oids import id_at_commonName
22 from pygost.asn1schemas.oids import id_ce_basicConstraints
23 from pygost.asn1schemas.oids import id_ce_subjectAltName
24 from pygost.asn1schemas.oids import id_ce_subjectKeyIdentifier
25 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
26 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetA
27 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetB
28 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetC
29 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetD
30 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
31 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
32 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetB
33 from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetC
34 from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_256
35 from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
36 from pygost.asn1schemas.prvkey import PrivateKey
37 from pygost.asn1schemas.prvkey import PrivateKeyAlgorithmIdentifier
38 from pygost.asn1schemas.prvkey import PrivateKeyInfo
39 from pygost.asn1schemas.x509 import AlgorithmIdentifier
40 from pygost.asn1schemas.x509 import AttributeType
41 from pygost.asn1schemas.x509 import AttributeTypeAndValue
42 from pygost.asn1schemas.x509 import AttributeValue
43 from pygost.asn1schemas.x509 import BasicConstraints
44 from pygost.asn1schemas.x509 import Certificate
45 from pygost.asn1schemas.x509 import CertificateSerialNumber
46 from pygost.asn1schemas.x509 import Extension
47 from pygost.asn1schemas.x509 import Extensions
48 from pygost.asn1schemas.x509 import GeneralName
49 from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
50 from pygost.asn1schemas.x509 import Name
51 from pygost.asn1schemas.x509 import RDNSequence
52 from pygost.asn1schemas.x509 import RelativeDistinguishedName
53 from pygost.asn1schemas.x509 import SubjectAltName
54 from pygost.asn1schemas.x509 import SubjectKeyIdentifier
55 from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
56 from pygost.asn1schemas.x509 import TBSCertificate
57 from pygost.asn1schemas.x509 import Time
58 from pygost.asn1schemas.x509 import Validity
59 from pygost.asn1schemas.x509 import Version
60 from pygost.gost3410 import CURVES
61 from pygost.gost3410 import prv_unmarshal
62 from pygost.gost3410 import pub_marshal
63 from pygost.gost3410 import public_key
64 from pygost.gost3410 import sign
65 from pygost.gost34112012256 import GOST34112012256
66 from pygost.gost34112012512 import GOST34112012512
67
68 parser = ArgumentParser(description="Self-signed X.509 certificate creator")
69 parser.add_argument(
70     "--ca",
71     action="store_true",
72     help="Enable BasicConstraints.cA",
73 )
74 parser.add_argument(
75     "--cn",
76     required=True,
77     help="Subject's CommonName",
78 )
79 parser.add_argument(
80     "--ai",
81     required=True,
82     help="Signing algorithm: {256[ABCD],512[ABC]}",
83 )
84 args = parser.parse_args()
85 ai = {
86     "256A": {
87         "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetA,
88         "key_algorithm": id_tc26_gost3410_2012_256,
89         "prv_len": 32,
90         "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetA"],
91         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
92         "hasher": GOST34112012256,
93     },
94     "256B": {
95         "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetB,
96         "key_algorithm": id_tc26_gost3410_2012_256,
97         "prv_len": 32,
98         "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetB"],
99         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
100         "hasher": GOST34112012256,
101     },
102     "256C": {
103         "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetC,
104         "key_algorithm": id_tc26_gost3410_2012_256,
105         "prv_len": 32,
106         "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetC"],
107         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
108         "hasher": GOST34112012256,
109     },
110     "256D": {
111         "publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetD,
112         "key_algorithm": id_tc26_gost3410_2012_256,
113         "prv_len": 32,
114         "curve": CURVES["id-tc26-gost-3410-2012-256-paramSetD"],
115         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
116         "hasher": GOST34112012256,
117     },
118     "512A": {
119         "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetA,
120         "key_algorithm": id_tc26_gost3410_2012_512,
121         "prv_len": 64,
122         "curve": CURVES["id-tc26-gost-3410-12-512-paramSetA"],
123         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
124         "hasher": GOST34112012512,
125     },
126     "512B": {
127         "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetB,
128         "key_algorithm": id_tc26_gost3410_2012_512,
129         "prv_len": 64,
130         "curve": CURVES["id-tc26-gost-3410-12-512-paramSetB"],
131         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
132         "hasher": GOST34112012512,
133     },
134     "512C": {
135         "publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetC,
136         "key_algorithm": id_tc26_gost3410_2012_512,
137         "prv_len": 64,
138         "curve": CURVES["id-tc26-gost-3410-2012-512-paramSetC"],
139         "sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
140         "hasher": GOST34112012512,
141     },
142 }[args.ai]
143
144
145 def pem(obj):
146     return fill(standard_b64encode(obj.encode()).decode("ascii"), 64)
147
148
149 key_params = GostR34102012PublicKeyParameters((
150     ("publicKeyParamSet", ai["publicKeyParamSet"]),
151 ))
152
153 prv_raw = urandom(ai["prv_len"])
154 print("-----BEGIN PRIVATE KEY-----")
155 print(pem(PrivateKeyInfo((
156     ("version", Integer(0)),
157     ("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier((
158         ("algorithm", ai["key_algorithm"]),
159         ("parameters", Any(key_params)),
160     ))),
161     ("privateKey", PrivateKey(OctetString(prv_raw).encode())),
162 ))))
163 print("-----END PRIVATE KEY-----")
164
165 prv = prv_unmarshal(prv_raw)
166 curve = ai["curve"]
167 pub_raw = pub_marshal(public_key(curve, prv))
168 subj = Name(("rdnSequence", RDNSequence([
169     RelativeDistinguishedName((
170         AttributeTypeAndValue((
171             ("type", AttributeType(id_at_commonName)),
172             ("value", AttributeValue(PrintableString(args.cn))),
173         )),
174     ))
175 ])))
176 not_before = datetime.utcnow()
177 not_after = not_before + timedelta(days=365)
178 ai_sign = AlgorithmIdentifier((
179     ("algorithm", ai["sign_algorithm"],),
180 ))
181 exts = [
182     Extension((
183         ("extnID", id_ce_subjectKeyIdentifier),
184         ("extnValue", OctetString(
185             SubjectKeyIdentifier(GOST34112012256(pub_raw).digest()[:20]).encode()
186         )),
187     )),
188     Extension((
189         ("extnID", id_ce_subjectAltName),
190         ("extnValue", OctetString(
191             SubjectAltName((
192                 GeneralName(("dNSName", IA5String(args.cn))),
193             )).encode()
194         )),
195     )),
196 ]
197 if args.ca:
198     exts.append(Extension((
199         ("extnID", id_ce_basicConstraints),
200         ("extnValue", OctetString(BasicConstraints((("cA", Boolean(True)),)).encode())),
201     )))
202 tbs = TBSCertificate((
203     ("version", Version("v3")),
204     ("serialNumber", CertificateSerialNumber(12345)),
205     ("signature", ai_sign),
206     ("issuer", subj),
207     ("validity", Validity((
208         ("notBefore", Time(("utcTime", UTCTime(not_before)))),
209         ("notAfter", Time(("utcTime", UTCTime(not_after)))),
210     ))),
211     ("subject", subj),
212     ("subjectPublicKeyInfo", SubjectPublicKeyInfo((
213         ("algorithm", AlgorithmIdentifier((
214             ("algorithm", ai["key_algorithm"]),
215             ("parameters", Any(key_params)),
216         ))),
217         ("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
218     ))),
219     ("extensions", Extensions(exts)),
220 ))
221 cert = Certificate((
222     ("tbsCertificate", tbs),
223     ("signatureAlgorithm", ai_sign),
224     ("signatureValue", BitString(sign(
225         curve,
226         prv,
227         ai["hasher"](tbs.encode()).digest()[::-1],
228     ))),
229 ))
230 print("-----BEGIN CERTIFICATE-----")
231 print(pem(cert))
232 print("-----END CERTIFICATE-----")