1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package physicalmachine
17
18 import (
19 "crypto"
20 "crypto/ecdsa"
21 "crypto/elliptic"
22 cryptorand "crypto/rand"
23 "crypto/rsa"
24 "crypto/x509"
25 "crypto/x509/pkix"
26 "encoding/pem"
27 "fmt"
28 "math"
29 "math/big"
30 "path/filepath"
31 "time"
32
33 "github.com/pkg/errors"
34 certutil "k8s.io/client-go/util/cert"
35 "k8s.io/client-go/util/keyutil"
36 )
37
38 const (
39 rsaKeySize = 2048
40 ChaosdPkiName = "chaosd"
41
42 CertificateBlockType = "CERTIFICATE"
43
44 CertificateValidity = time.Hour * 24 * 1825
45 )
46
47 func ParseCertAndKey(certData, keyData []byte) (*x509.Certificate, crypto.Signer, error) {
48 caCert, err := ParseCert(certData)
49 if err != nil {
50 return nil, nil, errors.Wrap(err, "parse certs pem failed")
51 }
52
53 caKey, err := ParsePrivateKey(keyData)
54 if err != nil {
55 return nil, nil, errors.Wrap(err, "parse ca key file failed")
56 }
57 return caCert, caKey, nil
58 }
59
60 func ParsePrivateKey(data []byte) (crypto.Signer, error) {
61 privKey, err := keyutil.ParsePrivateKeyPEM(data)
62 if err != nil {
63 return nil, errors.Errorf("error reading private key file: %v", err)
64 }
65
66 var key crypto.Signer
67
68 switch k := privKey.(type) {
69 case *rsa.PrivateKey:
70 key = k
71 case *ecdsa.PrivateKey:
72 key = k
73 default:
74 return nil, errors.New("the private key file is neither in RSA nor ECDSA format")
75 }
76 return key, nil
77 }
78
79 func ParseCert(data []byte) (*x509.Certificate, error) {
80 caCerts, err := certutil.ParseCertsPEM(data)
81 if err != nil {
82 return nil, errors.Wrap(err, "parse certs pem failed")
83 }
84 return caCerts[0], nil
85 }
86
87
88 func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, crypto.Signer, error) {
89 key, err := NewPrivateKey(x509.RSA)
90 if err != nil {
91 return nil, nil, errors.Wrap(err, "unable to create private key")
92 }
93
94 cert, err := NewSignedCert(key, caCert, caKey, false)
95 if err != nil {
96 return nil, nil, errors.Wrap(err, "unable to sign certificate")
97 }
98
99 return cert, key, nil
100 }
101
102 func NewPrivateKey(keyType x509.PublicKeyAlgorithm) (crypto.Signer, error) {
103 if keyType == x509.ECDSA {
104 return ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
105 }
106
107 return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
108 }
109
110
111 func NewSignedCert(key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer, isCA bool) (*x509.Certificate, error) {
112 serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64))
113 if err != nil {
114 return nil, err
115 }
116
117 keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
118 if isCA {
119 keyUsage |= x509.KeyUsageCertSign
120 }
121
122 notAfter := time.Now().Add(CertificateValidity).UTC()
123
124 certTmpl := x509.Certificate{
125 Subject: pkix.Name{
126 CommonName: "chaosd.chaos-mesh.org",
127 },
128 DNSNames: []string{"chaosd.chaos-mesh.org", "localhost"},
129 SerialNumber: serial,
130 NotBefore: caCert.NotBefore,
131 NotAfter: notAfter,
132 KeyUsage: keyUsage,
133 BasicConstraintsValid: true,
134 IsCA: isCA,
135 }
136 certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, caCert, key.Public(), caKey)
137 if err != nil {
138 return nil, err
139 }
140 return x509.ParseCertificate(certDERBytes)
141 }
142
143
144 func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key crypto.Signer) error {
145 if err := WriteKey(pkiPath, name, key); err != nil {
146 return errors.Wrap(err, "couldn't write key")
147 }
148
149 return WriteCert(pkiPath, name, cert)
150 }
151
152
153 func WriteCert(pkiPath, name string, cert *x509.Certificate) error {
154 if cert == nil {
155 return errors.New("certificate cannot be nil when writing to file")
156 }
157
158 certificatePath := pathForCert(pkiPath, name)
159 if err := certutil.WriteCert(certificatePath, EncodeCertPEM(cert)); err != nil {
160 return errors.Wrapf(err, "unable to write certificate to file %s", certificatePath)
161 }
162
163 return nil
164 }
165
166
167 func WriteKey(pkiPath, name string, key crypto.Signer) error {
168 if key == nil {
169 return errors.New("private key cannot be nil when writing to file")
170 }
171
172 privateKeyPath := pathForKey(pkiPath, name)
173 encoded, err := keyutil.MarshalPrivateKeyToPEM(key)
174 if err != nil {
175 return errors.Wrapf(err, "unable to marshal private key to PEM")
176 }
177 if err := keyutil.WriteKey(privateKeyPath, encoded); err != nil {
178 return errors.Wrapf(err, "unable to write private key to file %s", privateKeyPath)
179 }
180
181 return nil
182 }
183
184
185 func EncodeCertPEM(cert *x509.Certificate) []byte {
186 block := pem.Block{
187 Type: CertificateBlockType,
188 Bytes: cert.Raw,
189 }
190 return pem.EncodeToMemory(&block)
191 }
192
193 func pathForCert(pkiPath, name string) string {
194 return filepath.Join(pkiPath, fmt.Sprintf("%s.crt", name))
195 }
196
197 func pathForKey(pkiPath, name string) string {
198 return filepath.Join(pkiPath, fmt.Sprintf("%s.key", name))
199 }
200