@@ -23,6 +23,7 @@ import (
2323 "crypto/ecdsa"
2424 "crypto/elliptic"
2525 "crypto/rand"
26+ "crypto/rsa"
2627 "crypto/tls"
2728 "crypto/x509"
2829 "crypto/x509/pkix"
@@ -39,81 +40,35 @@ type Pair struct {
3940 Key []byte
4041}
4142
42- // NewRootCA generates a new x509 Certificate and returns:
43+ // NewRootCA generates a new x509 Certificate using ECDSA P-384 and returns:
4344// - the private key
4445// - the certificate
45- // - the certificate in PEM format as a byte slice.
46+ // - the certificate and its key in PEM format as a byte slice.
4647//
4748// If any error occurs during the generation process, a non-nil error is returned.
48- func NewRootCA () (* ecdsa .PrivateKey , * x509.Certificate , Pair , error ) {
49+ func NewRootCA () (crypto .PrivateKey , * x509.Certificate , Pair , error ) {
4950 rootKey , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
5051 if err != nil {
5152 return nil , nil , Pair {}, fmt .Errorf ("could not create private key: %w" , err )
5253 }
5354
54- notBefore , notAfter := makeNotBeforeAndAfter ()
55-
56- rootTemplate := x509.Certificate {
57- SerialNumber : big .NewInt (1653 ),
58- Subject : pkix.Name {
59- Country : []string {"Gallifrey" },
60- Locality : []string {"The Capitol" },
61- OrganizationalUnit : []string {"Time Lords" },
62- Organization : []string {"High Council of the Time Lords" },
63- CommonName : "High Council" ,
64- },
65- NotBefore : notBefore ,
66- NotAfter : notAfter ,
67- KeyUsage : x509 .KeyUsageDigitalSignature | x509 .KeyUsageCertSign ,
68- BasicConstraintsValid : true ,
69- IsCA : true ,
70- }
71-
72- rootCertRawBytes , err := x509 .CreateCertificate (
73- rand .Reader , & rootTemplate , & rootTemplate , & rootKey .PublicKey , rootKey )
74- if err != nil {
75- return nil , nil , Pair {}, fmt .Errorf ("could not create CA: %w" , err )
76- }
77-
78- rootPrivKeyDER , err := x509 .MarshalECPrivateKey (rootKey )
79- if err != nil {
80- return nil , nil , Pair {}, fmt .Errorf ("could not marshal private key: %w" , err )
81- }
82-
83- // PEM private key
84- var rootPrivBytesOut []byte
85- rootPrivateKeyBuff := bytes .NewBuffer (rootPrivBytesOut )
86- err = pem .Encode (rootPrivateKeyBuff , & pem.Block {
87- Type : "EC PRIVATE KEY" , Bytes : rootPrivKeyDER })
88- if err != nil {
89- return nil , nil , Pair {}, fmt .Errorf ("could not pem.Encode private key: %w" , err )
90- }
91-
92- // PEM certificate
93- var rootCertBytesOut []byte
94- rootCertPemBuff := bytes .NewBuffer (rootCertBytesOut )
95- err = pem .Encode (rootCertPemBuff , & pem.Block {
96- Type : "CERTIFICATE" , Bytes : rootCertRawBytes })
97- if err != nil {
98- return nil , nil , Pair {}, fmt .Errorf ("could not pem.Encode certificate: %w" , err )
99- }
100-
101- // tls.Certificate
102- rootTLSCert , err := tls .X509KeyPair (
103- rootCertPemBuff .Bytes (), rootPrivateKeyBuff .Bytes ())
104- if err != nil {
105- return nil , nil , Pair {}, fmt .Errorf ("could not create key pair: %w" , err )
106- }
55+ cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey )
56+ return rootKey , cert , pair , err
57+ }
10758
108- rootCACert , err := x509 .ParseCertificate (rootTLSCert .Certificate [0 ])
59+ // NewRSARootCA generates a new x509 Certificate using RSA with a 2048-bit key and returns:
60+ // - the private key
61+ // - the certificate
62+ // - the certificate and its key in PEM format as a byte slice.
63+ //
64+ // If any error occurs during the generation process, a non-nil error is returned.
65+ func NewRSARootCA () (crypto.PrivateKey , * x509.Certificate , Pair , error ) {
66+ rootKey , err := rsa .GenerateKey (rand .Reader , 2048 )
10967 if err != nil {
110- return nil , nil , Pair {}, fmt .Errorf ("could not parse certificate : %w" , err )
68+ return nil , nil , Pair {}, fmt .Errorf ("could not create private key : %w" , err )
11169 }
112-
113- return rootKey , rootCACert , Pair {
114- Cert : rootCertPemBuff .Bytes (),
115- Key : rootPrivateKeyBuff .Bytes (),
116- }, nil
70+ cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey )
71+ return rootKey , cert , pair , err
11772}
11873
11974// GenerateChildCert generates a x509 Certificate as a child of caCert and
@@ -123,7 +78,13 @@ func NewRootCA() (*ecdsa.PrivateKey, *x509.Certificate, Pair, error) {
12378// - the certificate and private key as a tls.Certificate
12479//
12580// If any error occurs during the generation process, a non-nil error is returned.
126- func GenerateChildCert (name string , ips []net.IP , caPrivKey crypto.PrivateKey , caCert * x509.Certificate ) (* tls.Certificate , Pair , error ) {
81+ func GenerateChildCert (
82+ name string ,
83+ ips []net.IP ,
84+ priv crypto.PrivateKey ,
85+ pub crypto.PublicKey ,
86+ caPrivKey crypto.PrivateKey ,
87+ caCert * x509.Certificate ) (* tls.Certificate , Pair , error ) {
12788
12889 notBefore , notAfter := makeNotBeforeAndAfter ()
12990
@@ -143,27 +104,22 @@ func GenerateChildCert(name string, ips []net.IP, caPrivKey crypto.PrivateKey, c
143104 x509 .ExtKeyUsageClientAuth , x509 .ExtKeyUsageServerAuth },
144105 }
145106
146- privateKey , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
147- if err != nil {
148- return nil , Pair {}, fmt .Errorf ("could not create private key: %w" , err )
149- }
150-
151107 certRawBytes , err := x509 .CreateCertificate (
152- rand .Reader , certTemplate , caCert , & privateKey . PublicKey , caPrivKey )
108+ rand .Reader , certTemplate , caCert , pub , caPrivKey )
153109 if err != nil {
154110 return nil , Pair {}, fmt .Errorf ("could not create CA: %w" , err )
155111 }
156112
157- privateKeyDER , err := x509 .MarshalECPrivateKey ( privateKey )
113+ privateKeyDER , err := x509 .MarshalPKCS8PrivateKey ( priv )
158114 if err != nil {
159115 return nil , Pair {}, fmt .Errorf ("could not marshal private key: %w" , err )
160116 }
161117
162118 // PEM private key
163119 var privBytesOut []byte
164120 privateKeyBuff := bytes .NewBuffer (privBytesOut )
165- err = pem .Encode (privateKeyBuff , & pem. Block {
166- Type : "EC PRIVATE KEY" , Bytes : privateKeyDER })
121+ err = pem .Encode (privateKeyBuff ,
122+ & pem. Block { Type : keyBlockType ( priv ) , Bytes : privateKeyDER })
167123 if err != nil {
168124 return nil , Pair {}, fmt .Errorf ("could not pem.Encode private key: %w" , err )
169125 }
@@ -191,28 +147,151 @@ func GenerateChildCert(name string, ips []net.IP, caPrivKey crypto.PrivateKey, c
191147 }, nil
192148}
193149
194- // NewRootAndChildCerts returns a root CA and a child certificate and their keys
195- // for "localhost" and "127.0.0.1".
150+ // NewRootAndChildCerts returns an ECDSA (P-384) root CA and a child certificate
151+ // and their keys for "localhost" and "127.0.0.1".
196152func NewRootAndChildCerts () (Pair , Pair , error ) {
197153 rootKey , rootCACert , rootPair , err := NewRootCA ()
198154 if err != nil {
199155 return Pair {}, Pair {}, fmt .Errorf ("could not generate root CA: %w" , err )
200156 }
201157
158+ priv , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
159+ if err != nil {
160+ return Pair {}, Pair {}, fmt .Errorf ("could not create private key: %w" , err )
161+ }
162+
163+ childPair , err := defaultChildCert (rootKey , priv , & priv .PublicKey , rootCACert )
164+ return rootPair , childPair , err
165+ }
166+
167+ // NewRSARootAndChildCerts returns an RSA (2048-bit) root CA and a child
168+ // certificate and their keys for "localhost" and "127.0.0.1".
169+ func NewRSARootAndChildCerts () (Pair , Pair , error ) {
170+ rootKey , rootCACert , rootPair , err := NewRSARootCA ()
171+ if err != nil {
172+ return Pair {}, Pair {}, fmt .Errorf ("could not generate RSA root CA: %w" , err )
173+ }
174+
175+ priv , err := rsa .GenerateKey (rand .Reader , 2048 )
176+ if err != nil {
177+ return Pair {}, Pair {}, fmt .Errorf ("could not create RSA private key: %w" , err )
178+ }
179+
180+ childPair , err := defaultChildCert (rootKey , priv , & priv .PublicKey , rootCACert )
181+ return rootPair , childPair , err
182+ }
183+
184+ // newRootCert creates a new self-signed root certificate using the provided
185+ // private key and public key.
186+ // It returns:
187+ // - the private key,
188+ // - the certificate,
189+ // - a Pair containing the certificate and private key in PEM format.
190+ //
191+ // If an error occurs during certificate creation, it returns a non-nil error.
192+ func newRootCert (priv crypto.PrivateKey , pub crypto.PublicKey ) (* x509.Certificate , Pair , error ) {
193+ notBefore , notAfter := makeNotBeforeAndAfter ()
194+
195+ rootTemplate := x509.Certificate {
196+ SerialNumber : big .NewInt (1653 ),
197+ Subject : pkix.Name {
198+ Country : []string {"Gallifrey" },
199+ Locality : []string {"The Capitol" },
200+ OrganizationalUnit : []string {"Time Lords" },
201+ Organization : []string {"High Council of the Time Lords" },
202+ CommonName : "High Council" ,
203+ },
204+ NotBefore : notBefore ,
205+ NotAfter : notAfter ,
206+ KeyUsage : x509 .KeyUsageDigitalSignature | x509 .KeyUsageCertSign ,
207+ BasicConstraintsValid : true ,
208+ IsCA : true ,
209+ }
210+
211+ rootCertRawBytes , err := x509 .CreateCertificate (
212+ rand .Reader , & rootTemplate , & rootTemplate , pub , priv )
213+ if err != nil {
214+ return nil , Pair {}, fmt .Errorf ("could not create CA: %w" , err )
215+ }
216+
217+ rootPrivKeyDER , err := x509 .MarshalPKCS8PrivateKey (priv )
218+ if err != nil {
219+ return nil , Pair {}, fmt .Errorf ("could not marshal private key: %w" , err )
220+ }
221+
222+ // PEM private key
223+ var rootPrivBytesOut []byte
224+ rootPrivateKeyBuff := bytes .NewBuffer (rootPrivBytesOut )
225+ err = pem .Encode (rootPrivateKeyBuff ,
226+ & pem.Block {Type : keyBlockType (priv ), Bytes : rootPrivKeyDER })
227+ if err != nil {
228+ return nil , Pair {}, fmt .Errorf ("could not pem.Encode private key: %w" , err )
229+ }
230+
231+ // PEM certificate
232+ var rootCertBytesOut []byte
233+ rootCertPemBuff := bytes .NewBuffer (rootCertBytesOut )
234+ err = pem .Encode (rootCertPemBuff ,
235+ & pem.Block {Type : "CERTIFICATE" , Bytes : rootCertRawBytes })
236+ if err != nil {
237+ return nil , Pair {}, fmt .Errorf ("could not pem.Encode certificate: %w" , err )
238+ }
239+
240+ // tls.Certificate
241+ rootTLSCert , err := tls .X509KeyPair (
242+ rootCertPemBuff .Bytes (), rootPrivateKeyBuff .Bytes ())
243+ if err != nil {
244+ return nil , Pair {}, fmt .Errorf ("could not create key pair: %w" , err )
245+ }
246+
247+ rootCACert , err := x509 .ParseCertificate (rootTLSCert .Certificate [0 ])
248+ if err != nil {
249+ return nil , Pair {}, fmt .Errorf ("could not parse certificate: %w" , err )
250+ }
251+
252+ return rootCACert , Pair {
253+ Cert : rootCertPemBuff .Bytes (),
254+ Key : rootPrivateKeyBuff .Bytes (),
255+ }, nil
256+ }
257+
258+ // defaultChildCert generates a child certificate for localhost and 127.0.0.1.
259+ // It returns the certificate and its key as a Pair and an error if any happens.
260+ func defaultChildCert (
261+ rootPriv ,
262+ priv crypto.PrivateKey ,
263+ pub crypto.PublicKey ,
264+ rootCACert * x509.Certificate ) (Pair , error ) {
202265 _ , childPair , err :=
203266 GenerateChildCert (
204267 "localhost" ,
205268 []net.IP {net .ParseIP ("127.0.0.1" )},
206- rootKey ,
269+ priv ,
270+ pub ,
271+ rootPriv ,
207272 rootCACert )
208273 if err != nil {
209- return Pair {}, Pair {}, fmt .Errorf (
274+ return Pair {}, fmt .Errorf (
210275 "could not generate child TLS certificate CA: %w" , err )
211276 }
277+ return childPair , nil
278+ }
212279
213- return rootPair , childPair , nil
280+ // keyBlockType returns the correct PEM block type for the given private key.
281+ func keyBlockType (priv crypto.PrivateKey ) string {
282+ switch priv .(type ) {
283+ case * rsa.PrivateKey :
284+ return "RSA PRIVATE KEY"
285+ case * ecdsa.PrivateKey :
286+ return "EC PRIVATE KEY"
287+ default :
288+ panic (fmt .Errorf ("unsupported private key type: %T" , priv ))
289+ }
214290}
215291
292+ // makeNotBeforeAndAfter returns:
293+ // - notBefore: 1 minute before now
294+ // - notAfter: 7 days after now
216295func makeNotBeforeAndAfter () (time.Time , time.Time ) {
217296 now := time .Now ()
218297 notBefore := now .Add (- 1 * time .Minute )
0 commit comments