@@ -13,9 +13,180 @@ limitations under the License.
1313
1414package ca
1515
16+ import (
17+ "crypto/ecdsa"
18+ "crypto/elliptic"
19+ "crypto/rand"
20+ "crypto/rsa"
21+ "crypto/x509"
22+ "encoding/pem"
23+ "fmt"
24+ "os"
25+ "path"
26+ "strings"
27+ )
28+
1629type CA interface {
17- CreateKey () error
30+ GenerateKey () error
1831 CreateCert () error
1932 Write (keyPath , certPath , chainPath string ) error
20- //Load(keyPath, certPath string) (interface{}, error)
33+ //Load(keyPath, certPath string) (any, error)
34+ }
35+
36+ // BaseCA represents common functionality for all CA types
37+ type BaseCA struct {
38+ Key any // *rsa.PrivateKey or *ecdsa.PrivateKey
39+ Cert * x509.Certificate
40+ KeyBits int
41+ Curve string
42+ }
43+
44+ // GenerateKey generates a new private key based on key type
45+ func (b * BaseCA ) GenerateKey (keyType string ) error {
46+ switch strings .ToLower (keyType ) {
47+ case "ec" , "ecdsa" :
48+ var curve elliptic.Curve
49+ switch b .Curve {
50+ case "P224" :
51+ curve = elliptic .P224 ()
52+ case "P256" :
53+ curve = elliptic .P256 ()
54+ case "P384" :
55+ curve = elliptic .P384 ()
56+ case "P521" :
57+ curve = elliptic .P521 ()
58+ default :
59+ return fmt .Errorf ("unsupported curve %s" , b .Curve )
60+ }
61+ key , err := ecdsa .GenerateKey (curve , rand .Reader )
62+ if err != nil {
63+ return err
64+ }
65+ b .Key = key
66+ case "rsa" :
67+ key , err := rsa .GenerateKey (rand .Reader , b .KeyBits )
68+ if err != nil {
69+ return err
70+ }
71+ b .Key = key
72+ default :
73+ return fmt .Errorf ("unsupported key type %s" , keyType )
74+ }
75+ return nil
76+ }
77+
78+ // GetPublicKey extracts the public key from the private key
79+ func (b * BaseCA ) GetPublicKey () (any , error ) {
80+ switch k := b .Key .(type ) {
81+ case * rsa.PrivateKey :
82+ return k .Public (), nil
83+ case * ecdsa.PrivateKey :
84+ return k .Public (), nil
85+ default :
86+ return nil , fmt .Errorf ("unsupported key type" )
87+ }
88+ }
89+
90+ // WriteKey writes the private key to a PEM file
91+ func (b * BaseCA ) WriteKey (keyPath string ) error {
92+ // Create directory if it doesn't exist
93+ err := os .MkdirAll (path .Dir (keyPath ), 0700 )
94+ if err != nil && ! os .IsExist (err ) {
95+ return err
96+ }
97+
98+ keyFile , err := os .OpenFile (keyPath , os .O_CREATE | os .O_EXCL | os .O_WRONLY , 0600 )
99+ if err != nil {
100+ return err
101+ }
102+ defer keyFile .Close ()
103+
104+ var keyType string
105+ var keyBytes []byte
106+ switch k := b .Key .(type ) {
107+ case * rsa.PrivateKey :
108+ keyType = "RSA PRIVATE KEY"
109+ keyBytes = x509 .MarshalPKCS1PrivateKey (k )
110+ case * ecdsa.PrivateKey :
111+ keyType = "EC PRIVATE KEY"
112+ var err error
113+ keyBytes , err = x509 .MarshalECPrivateKey (k )
114+ if err != nil {
115+ return err
116+ }
117+ default :
118+ return fmt .Errorf ("unsupported key type" )
119+ }
120+
121+ return pem .Encode (keyFile , & pem.Block {
122+ Type : keyType ,
123+ Bytes : keyBytes ,
124+ })
125+ }
126+
127+ // WriteCert writes the certificate to a PEM file
128+ func (b * BaseCA ) WriteCert (certPath string ) error {
129+ // Create directory if it doesn't exist
130+ err := os .MkdirAll (path .Dir (certPath ), 0700 )
131+ if err != nil && ! os .IsExist (err ) {
132+ return err
133+ }
134+
135+ certFile , err := os .OpenFile (certPath , os .O_CREATE | os .O_EXCL | os .O_WRONLY , 0600 )
136+ if err != nil {
137+ return err
138+ }
139+ defer certFile .Close ()
140+
141+ return pem .Encode (certFile , & pem.Block {
142+ Type : "CERTIFICATE" ,
143+ Bytes : b .Cert .Raw ,
144+ })
145+ }
146+
147+ // LoadKey loads a private key from a PEM file
148+ func (b * BaseCA ) LoadKey (keyPath string ) error {
149+ keyBytes , err := os .ReadFile (keyPath )
150+ if err != nil {
151+ return err
152+ }
153+
154+ keyBlock , _ := pem .Decode (keyBytes )
155+ if keyBlock == nil {
156+ return fmt .Errorf ("decode key is nil" )
157+ }
158+
159+ // Check if encrypted
160+ isEncrypted := len (keyBlock .Headers ) > 0 && keyBlock .Headers ["Proc-Type" ] == "4,ENCRYPTED"
161+ if isEncrypted {
162+ return fmt .Errorf ("encrypted PEM blocks are not supported - please decrypt your key first, using: openssl rsa -in encrypted.key -out decrypted.key" )
163+ }
164+
165+ switch keyBlock .Type {
166+ case "RSA PRIVATE KEY" :
167+ b .Key , err = x509 .ParsePKCS1PrivateKey (keyBlock .Bytes )
168+ case "EC PRIVATE KEY" :
169+ b .Key , err = x509 .ParseECPrivateKey (keyBlock .Bytes )
170+ default :
171+ return fmt .Errorf ("unsupported PEM type %s" , keyBlock .Type )
172+ }
173+ return err
174+ }
175+
176+ // LoadCert loads a certificate from a PEM file
177+ func (b * BaseCA ) LoadCert (certPath string ) error {
178+ certBytes , err := os .ReadFile (certPath )
179+ if err != nil {
180+ return err
181+ }
182+
183+ certBlock , _ := pem .Decode (certBytes )
184+ if certBlock == nil {
185+ return fmt .Errorf ("decode cert is nil" )
186+ } else if certBlock .Type != "CERTIFICATE" {
187+ return fmt .Errorf ("unsupported PEM type %s" , certBlock .Type )
188+ }
189+
190+ b .Cert , err = x509 .ParseCertificate (certBlock .Bytes )
191+ return err
21192}
0 commit comments