forked from spiffe/go-spiffe
/
pem.go
123 lines (107 loc) · 2.55 KB
/
pem.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
package pemutil
import (
"crypto"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
const (
certType string = "CERTIFICATE"
keyType string = "PRIVATE KEY"
)
func ParseCertificates(certsBytes []byte) ([]*x509.Certificate, error) {
objects, err := parseBlocks(certsBytes, certType)
if err != nil {
return nil, err
}
certs := []*x509.Certificate{}
for _, object := range objects {
cert, ok := object.(*x509.Certificate)
if !ok {
return nil, fmt.Errorf("expected *x509.Certificate; got %T", object)
}
certs = append(certs, cert)
}
return certs, nil
}
func ParsePrivateKey(keyBytes []byte) (crypto.PrivateKey, error) {
objects, err := parseBlocks(keyBytes, keyType)
if err != nil {
return nil, err
}
if len(objects) == 0 {
return nil, nil
}
privateKey, ok := objects[0].(crypto.PrivateKey)
if !ok {
return nil, fmt.Errorf("expected crypto.PrivateKey; got %T", objects[0])
}
return privateKey, nil
}
func EncodePKCS8PrivateKey(privateKey interface{}) ([]byte, error) {
keyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{
Type: keyType,
Bytes: keyBytes,
}), nil
}
func EncodeCertificates(certificates []*x509.Certificate) []byte {
pemBytes := []byte{}
for _, cert := range certificates {
pemBytes = append(pemBytes, pem.EncodeToMemory(&pem.Block{
Type: certType,
Bytes: cert.Raw,
})...)
}
return pemBytes
}
func parseBlocks(blocksBytes []byte, expectedType string) ([]interface{}, error) {
objects := []interface{}{}
var foundBlocks = false
for {
if len(blocksBytes) == 0 {
if len(objects) == 0 && !foundBlocks {
return nil, errors.New("no PEM blocks found")
}
return objects, nil
}
object, rest, foundBlock, err := parseBlock(blocksBytes, expectedType)
blocksBytes = rest
if foundBlock {
foundBlocks = true
}
switch {
case err != nil:
return nil, err
case object != nil:
objects = append(objects, object)
}
}
}
func parseBlock(pemBytes []byte, pemType string) (interface{}, []byte, bool, error) {
pemBlock, rest := pem.Decode(pemBytes)
if pemBlock == nil {
return nil, nil, false, nil
}
if pemBlock.Type != pemType {
return nil, rest, true, nil
}
var object interface{}
var err error
switch pemType {
case certType:
object, err = x509.ParseCertificate(pemBlock.Bytes)
case keyType:
object, err = x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
default:
err = fmt.Errorf("PEM type not supported: %q", pemType)
}
if err != nil {
return nil, nil, false, err
}
return object, rest, true, nil
}