-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprivatekey.go
119 lines (99 loc) · 4.08 KB
/
privatekey.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package keybox
import (
"crypto"
"crypto/x509"
"encoding/pem"
"errors"
"io/ioutil"
"github.com/youmark/pkcs8"
)
var (
// ErrKeyMustBePEMEncoded indicates that a given data block was not a PEM encoded block.
ErrKeyMustBePEMEncoded = errors.New("invalid Key: Key must be PEM encoded")
// ErrNotAPrivateKey indicates that a given PEM block did not contain a known private key format.
ErrNotAPrivateKey = errors.New("invalid Key: PEM block must be a PKCS #1, PKCS #8 or SEC 1 private key")
// ErrUnknownEncryption indicates that the given PEM block was not encrypted in a known format,
// or not encrypted in the first place.
ErrUnknownEncryption = errors.New("invalid encryption: PEM block is encrypted in a unknown format, or not encrypted at all")
)
// LoadPrivateKey tries to load a private key from a given path.
func LoadPrivateKey(path string) (crypto.PrivateKey, error) {
pemString, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return ParsePrivateKeyFromPEMBytes(pemString)
}
// LoadPrivateKeyWithPassword tries to load a private key from a given path with a password.
func LoadPrivateKeyWithPassword(path string, password []byte) (crypto.PrivateKey, error) {
pemString, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return ParsePrivateKeyFromEncryptedPEMBytes(pemString, password)
}
// ParsePrivateKeyFromPEMBytes parses a given byte array to a PEM block, and parses that block
// for a known private key (see ParsePrivateKeyFromDERBytes).
// Will return ErrKeyMustBePEMEncoded if the given byte array is not a valid PEM block.
func ParsePrivateKeyFromPEMBytes(pemBytes []byte) (crypto.PrivateKey, error) {
var block *pem.Block
if block, _ = pem.Decode(pemBytes); block == nil {
return nil, ErrKeyMustBePEMEncoded
}
return ParsePrivateKeyFromDERBytes(block.Bytes)
}
// ParsePrivateKeyFromEncryptedPEMBytes parses and decrypts a given byte array and password to
// a PEM block, and parses that block for a known private key (see ParsePrivateKeyFromDERBytes).
// Will return ErrKeyMustBePEMEncoded if the given byte array is not a valid PEM block, or
// ErrUnknownEncryption if the byte array was encrypted in an unknown format, or not encrypted
// at all.
// Note: Usage of RFC 1423 encrypted PEM blocks is deprecated since Go 1.16! Use PKCS #8 instead.
func ParsePrivateKeyFromEncryptedPEMBytes(pemBytes []byte, password []byte) (crypto.PrivateKey, error) {
var block *pem.Block
if block, _ = pem.Decode(pemBytes); block == nil {
return nil, ErrKeyMustBePEMEncoded
}
var blockDecrypted []byte
// nolint: staticcheck: Just passing through - deprecation is communicated in function signature
if x509.IsEncryptedPEMBlock(block) {
var err error
// nolint: staticcheck
if blockDecrypted, err = x509.DecryptPEMBlock(block, password); err != nil {
return nil, err
}
} else if pkcs8Decryption, err := tryPKCS8Decryption(block, password); err == nil {
blockDecrypted = pkcs8Decryption
} else {
// Either its not a password secured block, or is encrypted in a format
// we don't know.
return nil, ErrUnknownEncryption
}
return ParsePrivateKeyFromDERBytes(blockDecrypted)
}
// ParsePrivateKeyFromDERBytes parse a given byte array for a ASN.1 DER encoded
// PKCS #1, PKCS #8 or SEC 1 private key.
// Will return ErrNotAPrivateKey if the given byte array is not in properly
// encoded DER form, or is not a known private key format.
func ParsePrivateKeyFromDERBytes(derBytes []byte) (crypto.PrivateKey, error) {
var err error
var parsedKey crypto.PrivateKey
if parsedKey, err = x509.ParsePKCS1PrivateKey(derBytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(derBytes); err != nil {
if parsedKey, err = x509.ParseECPrivateKey(derBytes); err != nil {
return nil, ErrNotAPrivateKey
}
}
}
return parsedKey, nil
}
func tryPKCS8Decryption(block *pem.Block, password []byte) ([]byte, error) {
pkcs8PrivateKey, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, password)
if err != nil {
return nil, err
}
decryptedBytes, err := x509.MarshalPKCS8PrivateKey(pkcs8PrivateKey)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}