forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.go
162 lines (136 loc) · 4.83 KB
/
helpers.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package certutil
import (
"bytes"
"crypto"
"crypto/sha1"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"github.com/mitchellh/mapstructure"
)
// GetOctalFormatted returns the byte buffer formatted in octal with
// the specified separator between bytes.
func GetOctalFormatted(buf []byte, sep string) string {
var ret bytes.Buffer
for _, cur := range buf {
if ret.Len() > 0 {
fmt.Fprintf(&ret, sep)
}
fmt.Fprintf(&ret, "%02x", cur)
}
return ret.String()
}
// GetSubjKeyID returns the subject key ID, e.g. the SHA1 sum
// of the marshaled public key
func GetSubjKeyID(privateKey crypto.Signer) ([]byte, error) {
if privateKey == nil {
return nil, InternalError{"Passed-in private key is nil"}
}
marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
if err != nil {
return nil, InternalError{fmt.Sprintf("Error marshalling public key: %s", err)}
}
subjKeyID := sha1.Sum(marshaledKey)
return subjKeyID[:], nil
}
// ParsePKIMap takes a map (for instance, the Secret.Data
// returned from the PKI backend) and returns a ParsedCertBundle.
func ParsePKIMap(data map[string]interface{}) (*ParsedCertBundle, error) {
result := &CertBundle{}
err := mapstructure.Decode(data, result)
if err != nil {
return nil, UserError{err.Error()}
}
return result.ToParsedCertBundle()
}
// ParsePKIJSON takes a JSON-encoded string and returns a CertBundle
// ParsedCertBundle.
//
// This can be either the output of an
// issue call from the PKI backend or just its data member; or,
// JSON not coming from the PKI backend.
func ParsePKIJSON(input []byte) (*ParsedCertBundle, error) {
result := &CertBundle{}
err := json.Unmarshal(input, &result)
if err == nil {
return result.ToParsedCertBundle()
}
var secret Secret
err = json.Unmarshal(input, &secret)
if err == nil {
return ParsePKIMap(secret.Data)
}
return nil, UserError{"Unable to parse out of either secret data or a secret object"}
}
// ParsePEMBundle takes a string of concatenated PEM-format certificate
// and private key values and decodes/parses them, checking validity along
// the way. There must be at max two certificates (a certificate and its
// issuing certificate) and one private key.
func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
if len(pemBundle) == 0 {
return nil, UserError{"Empty PEM bundle"}
}
pemBytes := []byte(pemBundle)
var pemBlock *pem.Block
parsedBundle := &ParsedCertBundle{}
for {
pemBlock, pemBytes = pem.Decode(pemBytes)
if pemBlock == nil {
return nil, UserError{"No data found"}
}
if signer, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil {
if parsedBundle.PrivateKeyType != UnknownPrivateKey {
return nil, UserError{"More than one private key given; provide only one private key in the bundle"}
}
parsedBundle.PrivateKeyType = ECPrivateKey
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
parsedBundle.PrivateKey = signer
} else if signer, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil {
if parsedBundle.PrivateKeyType != UnknownPrivateKey {
return nil, UserError{"More than one private key given; provide only one private key in the bundle"}
}
parsedBundle.PrivateKeyType = RSAPrivateKey
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
parsedBundle.PrivateKey = signer
} else if certificates, err := x509.ParseCertificates(pemBlock.Bytes); err == nil {
switch len(certificates) {
case 0:
return nil, UserError{"PEM block cannot be decoded to a private key or certificate"}
case 1:
if parsedBundle.Certificate != nil {
switch {
// We just found the issuing CA
case bytes.Equal(parsedBundle.Certificate.AuthorityKeyId, certificates[0].SubjectKeyId) && certificates[0].IsCA:
parsedBundle.IssuingCABytes = pemBlock.Bytes
parsedBundle.IssuingCA = certificates[0]
// Our saved certificate is actually the issuing CA
case bytes.Equal(parsedBundle.Certificate.SubjectKeyId, certificates[0].AuthorityKeyId) && parsedBundle.Certificate.IsCA:
parsedBundle.IssuingCA = parsedBundle.Certificate
parsedBundle.IssuingCABytes = parsedBundle.CertificateBytes
parsedBundle.CertificateBytes = pemBlock.Bytes
parsedBundle.Certificate = certificates[0]
}
} else {
switch {
// If this case isn't correct, the caller needs to assign
// the values to Certificate/CertificateBytes; assumptions
// made here will not be valid for all cases.
case certificates[0].IsCA:
parsedBundle.IssuingCABytes = pemBlock.Bytes
parsedBundle.IssuingCA = certificates[0]
default:
parsedBundle.CertificateBytes = pemBlock.Bytes
parsedBundle.Certificate = certificates[0]
}
}
default:
return nil, UserError{"Too many certificates given; provide a maximum of two certificates in the bundle"}
}
}
if len(pemBytes) == 0 {
break
}
}
return parsedBundle, nil
}