1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // Example X.509 certificate issuing utility.
31 "crypto/go.cypherpunks.ru/gogost/v5/gost3410"
32 "crypto/go.cypherpunks.ru/gogost/v5/gost34112012256"
36 PEMKey = "PRIVATE KEY"
37 PEMCer = "CERTIFICATE"
40 func loadKeypair(filename string) (cer *x509.Certificate, prv any, err error) {
42 data, err = os.ReadFile(filename)
48 block, data = pem.Decode(data)
54 cer, err = x509.ParseCertificate(block.Bytes)
56 prv, err = x509.ParsePKCS8PrivateKey(block.Bytes)
66 ca := flag.Bool("ca", false, "Enable BasicConstraints.cA")
67 cn := flag.String("cn", "", "Subject's CommonName")
68 country := flag.String("country", "", "Subject's Country")
69 serial := flag.Int64("serial", -1, "Serial number")
70 ai := flag.String("ai", "", "Signing algorithm: {256[ABCD],512[ABC]}")
71 issueWith := flag.String("issue-with", "", "Path to PEM with CA to issue the child")
72 reuseKey := flag.String("reuse-key", "", "Path to PEM with the key to reuse")
73 outKey := flag.String("out-key", "", "Path to PEM with the resulting key")
74 onlyKey := flag.Bool("only-key", false, "Only generate the key")
75 outCer := flag.String("out-cert", "", "Path to PEM with the resulting certificate")
77 log.SetFlags(log.Lshortfile)
80 log.Fatalln("no CommonName is set")
82 var curve *gost3410.Curve
83 var sigAlg x509.SignatureAlgorithm
86 curve = gost3410.CurveIdtc26gost341012256paramSetA()
89 curve = gost3410.CurveIdtc26gost341012256paramSetB()
92 curve = gost3410.CurveIdtc26gost341012256paramSetC()
95 curve = gost3410.CurveIdtc26gost341012256paramSetD()
98 curve = gost3410.CurveIdtc26gost341012512paramSetA()
101 curve = gost3410.CurveIdtc26gost341012512paramSetB()
102 sigAlg = x509.GOST512
104 curve = gost3410.CurveIdtc26gost341012512paramSetC()
105 sigAlg = x509.GOST512
107 log.Fatalln("unknown curve name")
111 var caCer *x509.Certificate
113 if *issueWith != "" {
114 caCer, caPrv, err = loadKeypair(*issueWith)
118 sigAlg = caCer.SignatureAlgorithm
123 prvRaw := make([]byte, curve.PointSize())
124 if _, err := io.ReadFull(rand.Reader, prvRaw); err != nil {
127 prv, err = gost3410.NewPrivateKey(curve, prvRaw)
131 data, err := x509.MarshalPKCS8PrivateKey(prv)
135 data = pem.EncodeToMemory(&pem.Block{Type: PEMKey, Bytes: data})
137 _, err = os.Stdout.Write(data)
139 err = os.WriteFile(*outKey, data, 0o666)
148 _, prv, err = loadKeypair(*reuseKey)
154 notBefore := time.Now().UTC()
155 days := 365 * 24 * time.Hour
159 notAfter := notBefore.Add(days)
163 data := make([]byte, 16, gost34112012256.Size)
164 if _, err = io.ReadFull(rand.Reader, data); err != nil {
167 hasher := gost34112012256.New()
168 if _, err = hasher.Write(data); err != nil {
171 data = hasher.Sum(data[:0])
172 sn = sn.SetBytes(data[:20])
174 sn = sn.SetInt64(*serial)
177 subj := pkix.Name{CommonName: *cn}
179 subj.Country = []string{*country}
182 pub, err := prv.(*gost3410.PrivateKey).PublicKey()
186 hasher := gost34112012256.New()
187 if _, err = hasher.Write(pub.Raw()); err != nil {
190 spki := hasher.Sum(nil)
193 cerTmpl := x509.Certificate{
194 NotBefore: notBefore,
197 SignatureAlgorithm: sigAlg,
202 cerTmpl.BasicConstraintsValid = true
204 cerTmpl.KeyUsage = x509.KeyUsageCertSign
206 cerTmpl.DNSNames = []string{*cn}
207 cerTmpl.KeyUsage = x509.KeyUsageDigitalSignature
214 data, err := x509.CreateCertificate(
216 &cerTmpl, caCer, pub,
217 &gost3410.PrivateKeyReverseDigest{Prv: caPrv.(*gost3410.PrivateKey)},
222 data = pem.EncodeToMemory(&pem.Block{Type: PEMCer, Bytes: data})
224 _, err = os.Stdout.Write(data)
226 err = os.WriteFile(*outCer, data, 0o666)