-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
x509.go
125 lines (120 loc) · 3.54 KB
/
x509.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
package jwkset
import (
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)
var (
// ErrX509Infer is returned when the key type cannot be inferred from the PEM block type.
ErrX509Infer = errors.New("failed to infer X509 key type")
)
// LoadCertificate loads an X509 certificate from a PEM block.
func LoadCertificate(pemBlock []byte) (*x509.Certificate, error) {
cert, err := x509.ParseCertificate(pemBlock)
if err != nil {
return nil, fmt.Errorf("failed to parse certificates: %w", err)
}
switch cert.PublicKey.(type) {
case *ecdsa.PublicKey, ed25519.PublicKey, *rsa.PublicKey:
default:
return nil, fmt.Errorf("%w: %T", ErrUnsupportedKey, cert.PublicKey)
}
return cert, nil
}
// LoadCertificates loads X509 certificates from raw PEM data. It can be useful in loading X5U remote resources.
func LoadCertificates(rawPEM []byte) ([]*x509.Certificate, error) {
b := make([]byte, 0)
for {
block, rest := pem.Decode(rawPEM)
if block == nil {
break
}
rawPEM = rest
if block.Type == "CERTIFICATE" {
b = append(b, block.Bytes...)
}
}
certs, err := x509.ParseCertificates(b)
if err != nil {
return nil, fmt.Errorf("failed to parse certificates: %w", err)
}
for _, cert := range certs {
switch cert.PublicKey.(type) {
case *ecdsa.PublicKey, ed25519.PublicKey, *rsa.PublicKey:
default:
return nil, fmt.Errorf("%w: %T", ErrUnsupportedKey, cert.PublicKey)
}
}
return certs, nil
}
// LoadX509KeyInfer loads an X509 key from a PEM block.
func LoadX509KeyInfer(pemBlock *pem.Block) (key any, err error) {
switch pemBlock.Type {
case "EC PRIVATE KEY":
key, err = loadECPrivate(pemBlock)
case "RSA PRIVATE KEY":
key, err = loadPKCS1Private(pemBlock)
case "RSA PUBLIC KEY":
key, err = loadPKCS1Public(pemBlock)
case "PRIVATE KEY":
key, err = loadPKCS8Private(pemBlock)
case "PUBLIC KEY":
key, err = loadPKIXPublic(pemBlock)
default:
return nil, ErrX509Infer
}
if err != nil {
return nil, fmt.Errorf("failed to load key from inferred format %q: %w", key, err)
}
return key, nil
}
func loadECPrivate(pemBlock *pem.Block) (priv *ecdsa.PrivateKey, err error) {
priv, err = x509.ParseECPrivateKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse EC private key: %w", err)
}
return priv, nil
}
func loadPKCS1Public(pemBlock *pem.Block) (pub *rsa.PublicKey, err error) {
pub, err = x509.ParsePKCS1PublicKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse PKCS1 public key: %w", err)
}
return pub, nil
}
func loadPKCS1Private(pemBlock *pem.Block) (priv *rsa.PrivateKey, err error) {
priv, err = x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse PKCS1 private key: %w", err)
}
return priv, nil
}
func loadPKCS8Private(pemBlock *pem.Block) (priv any, err error) {
priv, err = x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse PKCS8 private key: %w", err)
}
switch priv.(type) {
case *ecdh.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, *rsa.PrivateKey:
default:
return nil, fmt.Errorf("%w: %T", ErrUnsupportedKey, priv)
}
return priv, nil
}
func loadPKIXPublic(pemBlock *pem.Block) (pub any, err error) {
pub, err = x509.ParsePKIXPublicKey(pemBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse PKIX public key: %w", err)
}
switch pub.(type) {
case *ecdh.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey, *rsa.PublicKey:
default:
return nil, fmt.Errorf("%w: %T", ErrUnsupportedKey, pub)
}
return pub, nil
}