blob: b99e366519c7b077691b85d2ca3d341c2b199447 [file] [log] [blame]
sslobodrd046be82019-01-16 10:02:22 -05001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package cert
18
19import (
20 "crypto/ecdsa"
21 "crypto/rsa"
22 "crypto/x509"
23 "encoding/pem"
24 "errors"
25 "fmt"
26)
27
28const (
29 // ECPrivateKeyBlockType is a possible value for pem.Block.Type.
30 ECPrivateKeyBlockType = "EC PRIVATE KEY"
31 // RSAPrivateKeyBlockType is a possible value for pem.Block.Type.
32 RSAPrivateKeyBlockType = "RSA PRIVATE KEY"
33 // PrivateKeyBlockType is a possible value for pem.Block.Type.
34 PrivateKeyBlockType = "PRIVATE KEY"
35 // PublicKeyBlockType is a possible value for pem.Block.Type.
36 PublicKeyBlockType = "PUBLIC KEY"
37 // CertificateBlockType is a possible value for pem.Block.Type.
38 CertificateBlockType = "CERTIFICATE"
39 // CertificateRequestBlockType is a possible value for pem.Block.Type.
40 CertificateRequestBlockType = "CERTIFICATE REQUEST"
41)
42
43// EncodePublicKeyPEM returns PEM-encoded public data
44func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
45 der, err := x509.MarshalPKIXPublicKey(key)
46 if err != nil {
47 return []byte{}, err
48 }
49 block := pem.Block{
50 Type: PublicKeyBlockType,
51 Bytes: der,
52 }
53 return pem.EncodeToMemory(&block), nil
54}
55
56// EncodePrivateKeyPEM returns PEM-encoded private key data
57func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
58 block := pem.Block{
59 Type: RSAPrivateKeyBlockType,
60 Bytes: x509.MarshalPKCS1PrivateKey(key),
61 }
62 return pem.EncodeToMemory(&block)
63}
64
65// EncodeCertPEM returns PEM-endcoded certificate data
66func EncodeCertPEM(cert *x509.Certificate) []byte {
67 block := pem.Block{
68 Type: CertificateBlockType,
69 Bytes: cert.Raw,
70 }
71 return pem.EncodeToMemory(&block)
72}
73
74// ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data.
75// Recognizes PEM blocks for "EC PRIVATE KEY", "RSA PRIVATE KEY", or "PRIVATE KEY"
76func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) {
77 var privateKeyPemBlock *pem.Block
78 for {
79 privateKeyPemBlock, keyData = pem.Decode(keyData)
80 if privateKeyPemBlock == nil {
81 break
82 }
83
84 switch privateKeyPemBlock.Type {
85 case ECPrivateKeyBlockType:
86 // ECDSA Private Key in ASN.1 format
87 if key, err := x509.ParseECPrivateKey(privateKeyPemBlock.Bytes); err == nil {
88 return key, nil
89 }
90 case RSAPrivateKeyBlockType:
91 // RSA Private Key in PKCS#1 format
92 if key, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes); err == nil {
93 return key, nil
94 }
95 case PrivateKeyBlockType:
96 // RSA or ECDSA Private Key in unencrypted PKCS#8 format
97 if key, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes); err == nil {
98 return key, nil
99 }
100 }
101
102 // tolerate non-key PEM blocks for compatibility with things like "EC PARAMETERS" blocks
103 // originally, only the first PEM block was parsed and expected to be a key block
104 }
105
106 // we read all the PEM blocks and didn't recognize one
107 return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key")
108}
109
110// ParsePublicKeysPEM is a helper function for reading an array of rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
111// Reads public keys from both public and private key files.
112func ParsePublicKeysPEM(keyData []byte) ([]interface{}, error) {
113 var block *pem.Block
114 keys := []interface{}{}
115 for {
116 // read the next block
117 block, keyData = pem.Decode(keyData)
118 if block == nil {
119 break
120 }
121
122 // test block against parsing functions
123 if privateKey, err := parseRSAPrivateKey(block.Bytes); err == nil {
124 keys = append(keys, &privateKey.PublicKey)
125 continue
126 }
127 if publicKey, err := parseRSAPublicKey(block.Bytes); err == nil {
128 keys = append(keys, publicKey)
129 continue
130 }
131 if privateKey, err := parseECPrivateKey(block.Bytes); err == nil {
132 keys = append(keys, &privateKey.PublicKey)
133 continue
134 }
135 if publicKey, err := parseECPublicKey(block.Bytes); err == nil {
136 keys = append(keys, publicKey)
137 continue
138 }
139
140 // tolerate non-key PEM blocks for backwards compatibility
141 // originally, only the first PEM block was parsed and expected to be a key block
142 }
143
144 if len(keys) == 0 {
145 return nil, fmt.Errorf("data does not contain any valid RSA or ECDSA public keys")
146 }
147 return keys, nil
148}
149
150// ParseCertsPEM returns the x509.Certificates contained in the given PEM-encoded byte array
151// Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
152func ParseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) {
153 ok := false
154 certs := []*x509.Certificate{}
155 for len(pemCerts) > 0 {
156 var block *pem.Block
157 block, pemCerts = pem.Decode(pemCerts)
158 if block == nil {
159 break
160 }
161 // Only use PEM "CERTIFICATE" blocks without extra headers
162 if block.Type != CertificateBlockType || len(block.Headers) != 0 {
163 continue
164 }
165
166 cert, err := x509.ParseCertificate(block.Bytes)
167 if err != nil {
168 return certs, err
169 }
170
171 certs = append(certs, cert)
172 ok = true
173 }
174
175 if !ok {
176 return certs, errors.New("data does not contain any valid RSA or ECDSA certificates")
177 }
178 return certs, nil
179}
180
181// parseRSAPublicKey parses a single RSA public key from the provided data
182func parseRSAPublicKey(data []byte) (*rsa.PublicKey, error) {
183 var err error
184
185 // Parse the key
186 var parsedKey interface{}
187 if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
188 if cert, err := x509.ParseCertificate(data); err == nil {
189 parsedKey = cert.PublicKey
190 } else {
191 return nil, err
192 }
193 }
194
195 // Test if parsed key is an RSA Public Key
196 var pubKey *rsa.PublicKey
197 var ok bool
198 if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
199 return nil, fmt.Errorf("data doesn't contain valid RSA Public Key")
200 }
201
202 return pubKey, nil
203}
204
205// parseRSAPrivateKey parses a single RSA private key from the provided data
206func parseRSAPrivateKey(data []byte) (*rsa.PrivateKey, error) {
207 var err error
208
209 // Parse the key
210 var parsedKey interface{}
211 if parsedKey, err = x509.ParsePKCS1PrivateKey(data); err != nil {
212 if parsedKey, err = x509.ParsePKCS8PrivateKey(data); err != nil {
213 return nil, err
214 }
215 }
216
217 // Test if parsed key is an RSA Private Key
218 var privKey *rsa.PrivateKey
219 var ok bool
220 if privKey, ok = parsedKey.(*rsa.PrivateKey); !ok {
221 return nil, fmt.Errorf("data doesn't contain valid RSA Private Key")
222 }
223
224 return privKey, nil
225}
226
227// parseECPublicKey parses a single ECDSA public key from the provided data
228func parseECPublicKey(data []byte) (*ecdsa.PublicKey, error) {
229 var err error
230
231 // Parse the key
232 var parsedKey interface{}
233 if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
234 if cert, err := x509.ParseCertificate(data); err == nil {
235 parsedKey = cert.PublicKey
236 } else {
237 return nil, err
238 }
239 }
240
241 // Test if parsed key is an ECDSA Public Key
242 var pubKey *ecdsa.PublicKey
243 var ok bool
244 if pubKey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
245 return nil, fmt.Errorf("data doesn't contain valid ECDSA Public Key")
246 }
247
248 return pubKey, nil
249}
250
251// parseECPrivateKey parses a single ECDSA private key from the provided data
252func parseECPrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
253 var err error
254
255 // Parse the key
256 var parsedKey interface{}
257 if parsedKey, err = x509.ParseECPrivateKey(data); err != nil {
258 return nil, err
259 }
260
261 // Test if parsed key is an ECDSA Private Key
262 var privKey *ecdsa.PrivateKey
263 var ok bool
264 if privKey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
265 return nil, fmt.Errorf("data doesn't contain valid ECDSA Private Key")
266 }
267
268 return privKey, nil
269}