+from pygost.utils import bytes2long
+
+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(
+ "--country",
+ help="Subject's Country",
+)
+parser.add_argument(
+ "--serial",
+ help="Serial number",
+)
+parser.add_argument(
+ "--ai",
+ required=True,
+ help="Signing algorithm: {256[ABCD],512[ABC]}",
+)
+parser.add_argument(
+ "--issue-with",
+ help="Path to PEM with CA to issue the child",
+)
+parser.add_argument(
+ "--out-key",
+ help="Path to PEM with the resulting key",
+)
+parser.add_argument(
+ "--out-cert",
+ help="Path to PEM with the resulting certificate",
+)
+args = parser.parse_args()
+AIs = {
+ "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,
+ },
+}
+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
+ ]))