-
Notifications
You must be signed in to change notification settings - Fork 0
/
x509.go
153 lines (129 loc) · 3.93 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
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
package sortpem
import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"math/big"
"golang.org/x/crypto/ed25519"
)
// known PEM types
const (
certificate = "CERTIFICATE"
privateKey = "PRIVATE KEY"
dsaPrivateKey = "DSA " + privateKey
rsaPrivateKey = "RSA " + privateKey
ecPrivateKey = "EC " + privateKey
)
// KeyBelongsTo checks if the cert is signed by the key. The key can be any
// supported public or private key. See PrivateKeyBelongsTo for how private
// keys are handled.
func KeyBelongsTo(cert *x509.Certificate, key interface{}) (ok bool) {
switch key := key.(type) {
case *dsa.PublicKey:
if pub, ok := cert.PublicKey.(*dsa.PublicKey); ok {
return pub.P.Cmp(key.P) == 0 && pub.Q.Cmp(key.Q) == 0 && pub.G.Cmp(key.G) == 0
}
return false
case *ecdsa.PublicKey:
if pub, ok := cert.PublicKey.(*ecdsa.PublicKey); ok {
return pub.X.Cmp(key.X) == 0 && pub.Y.Cmp(key.Y) == 0
}
return false
case ed25519.PublicKey:
return KeyBelongsTo(cert, &key)
case *ed25519.PublicKey:
if pub, ok := cert.PublicKey.(*ed25519.PublicKey); ok {
return bytes.Equal(*pub, *key)
}
return false
case *rsa.PublicKey:
if pub, ok := cert.PublicKey.(*rsa.PublicKey); ok {
return pub.E == key.E && pub.N.Cmp(key.N) == 0
}
return false
default:
// Unsupported key, but maybe it's a private key
return PrivateKeyBelongTo(cert, key)
}
}
// PrivateKeyBelongTo is like KeyBelongsTo, but only for private keys. Note
// that we're just comparing public key parts of the passed key. There are no
// checks performed to see if the public key part of the private key is
// actually valid (since we should only be using this function for sorting).
func PrivateKeyBelongTo(cert *x509.Certificate, key interface{}) (ok bool) {
switch key := key.(type) {
case *dsa.PrivateKey:
return KeyBelongsTo(cert, &key.PublicKey)
case *ecdsa.PrivateKey:
return KeyBelongsTo(cert, &key.PublicKey)
case ed25519.PrivateKey:
return PrivateKeyBelongTo(cert, &key)
case *ed25519.PrivateKey:
return KeyBelongsTo(cert, key.Public())
case *rsa.PrivateKey:
return KeyBelongsTo(cert, key.Public())
default:
// Unsupported key
return
}
}
// IsSelfSigned checks for a self-signed certificate.
func IsSelfSigned(cert *x509.Certificate) bool {
return IsSignedBy(cert, cert)
}
// IsSignedBy does a check if cert is signed by root. Do not ever use this
// function for any other purpose than sorting, as it's skipping a lot of
// important steps from 5280 such as verifying basic constraints, validity or
// path depths (since we're only interested in sorting certificates).
func IsSignedBy(cert, root *x509.Certificate) (ok bool) {
/*
// Skipping this check, since the basic constraints may not even be
// properly configured.
if !root.IsCA {
// Root can't sign.
return
}
*/
if !bytes.Equal(cert.RawIssuer, root.RawSubject) {
// Subjects don't match
return
}
if cert.AuthorityKeyId != nil && root.SubjectKeyId != nil && !bytes.Equal(cert.AuthorityKeyId, root.SubjectKeyId) {
// Key id's don't match
return
}
if root.PublicKeyAlgorithm == x509.UnknownPublicKeyAlgorithm {
// We can't verify the signature, since we don't support the signing
// algorithm, so assume yes since all previous checks succeeded.
return true
}
if err := root.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
// Signature verification failed.
return
}
// All above checks passed, so it's not unlikely that cert is signed by root.
return true
}
// parseDSAPrivateKey parses a DSA ASN.1 structure DER sequence
func parseDSAPrivateKey(asn1Bytes []byte) (key *dsa.PrivateKey, err error) {
var src struct {
E1, P, Q, G, Y, X *big.Int
}
if _, err = asn1.Unmarshal(asn1Bytes, &src); err != nil {
return
}
return &dsa.PrivateKey{
X: src.X,
PublicKey: dsa.PublicKey{
Y: src.Y,
Parameters: dsa.Parameters{
P: src.P,
Q: src.Q,
G: src.G,
},
},
}, nil
}