forked from notaryproject/notary
-
Notifications
You must be signed in to change notification settings - Fork 0
/
x509memstore.go
203 lines (167 loc) · 5.23 KB
/
x509memstore.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package trustmanager
import (
"crypto/x509"
"errors"
"github.com/Sirupsen/logrus"
)
// X509MemStore implements X509Store as an in-memory object with no persistence
type X509MemStore struct {
validate Validator
fingerprintMap map[CertID]*x509.Certificate
nameMap map[string][]CertID
}
// NewX509MemStore returns a new X509MemStore.
func NewX509MemStore() *X509MemStore {
validate := ValidatorFunc(func(cert *x509.Certificate) bool { return true })
return &X509MemStore{
validate: validate,
fingerprintMap: make(map[CertID]*x509.Certificate),
nameMap: make(map[string][]CertID),
}
}
// NewX509FilteredMemStore returns a new X509Memstore that validates certificates
// that are added.
func NewX509FilteredMemStore(validate func(*x509.Certificate) bool) *X509MemStore {
s := &X509MemStore{
validate: ValidatorFunc(validate),
fingerprintMap: make(map[CertID]*x509.Certificate),
nameMap: make(map[string][]CertID),
}
return s
}
// AddCert adds a certificate to the store
func (s *X509MemStore) AddCert(cert *x509.Certificate) error {
if cert == nil {
return errors.New("adding nil Certificate to X509Store")
}
if !s.validate.Validate(cert) {
return &ErrCertValidation{}
}
certID, err := fingerprintCert(cert)
if err != nil {
return err
}
logrus.Debug("Adding cert with certID: ", certID)
// In this store we overwrite the certificate if it already exists
s.fingerprintMap[certID] = cert
name := string(cert.RawSubject)
s.nameMap[name] = append(s.nameMap[name], certID)
return nil
}
// RemoveCert removes a certificate from a X509MemStore.
func (s *X509MemStore) RemoveCert(cert *x509.Certificate) error {
if cert == nil {
return errors.New("removing nil Certificate to X509Store")
}
certID, err := fingerprintCert(cert)
if err != nil {
return err
}
delete(s.fingerprintMap, certID)
name := string(cert.RawSubject)
// Filter the fingerprint out of this name entry
fpList := s.nameMap[name]
newfpList := fpList[:0]
for _, x := range fpList {
if x != certID {
newfpList = append(newfpList, x)
}
}
s.nameMap[name] = newfpList
return nil
}
// RemoveAll removes all the certificates from the store
func (s *X509MemStore) RemoveAll() error {
for _, cert := range s.fingerprintMap {
if err := s.RemoveCert(cert); err != nil {
return err
}
}
return nil
}
// AddCertFromPEM adds a certificate to the store from a PEM blob
func (s *X509MemStore) AddCertFromPEM(pemBytes []byte) error {
cert, err := LoadCertFromPEM(pemBytes)
if err != nil {
return err
}
return s.AddCert(cert)
}
// AddCertFromFile tries to adds a X509 certificate to the store given a filename
func (s *X509MemStore) AddCertFromFile(originFilname string) error {
cert, err := LoadCertFromFile(originFilname)
if err != nil {
return err
}
return s.AddCert(cert)
}
// GetCertificates returns an array with all of the current X509 Certificates.
func (s *X509MemStore) GetCertificates() []*x509.Certificate {
certs := make([]*x509.Certificate, len(s.fingerprintMap))
i := 0
for _, v := range s.fingerprintMap {
certs[i] = v
i++
}
return certs
}
// GetCertificatePool returns an x509 CertPool loaded with all the certificates
// in the store.
func (s *X509MemStore) GetCertificatePool() *x509.CertPool {
pool := x509.NewCertPool()
for _, v := range s.fingerprintMap {
pool.AddCert(v)
}
return pool
}
// GetCertificateByCertID returns the certificate that matches a certain certID
func (s *X509MemStore) GetCertificateByCertID(certID string) (*x509.Certificate, error) {
return s.getCertificateByCertID(CertID(certID))
}
// getCertificateByCertID returns the certificate that matches a certain certID or error
func (s *X509MemStore) getCertificateByCertID(certID CertID) (*x509.Certificate, error) {
// If it does not look like a hex encoded sha256 hash, error
if len(certID) != 64 {
return nil, errors.New("invalid Subject Key Identifier")
}
// Check to see if this subject key identifier exists
if cert, ok := s.fingerprintMap[CertID(certID)]; ok {
return cert, nil
}
return nil, &ErrNoCertificatesFound{query: string(certID)}
}
// GetCertificatesByCN returns all the certificates that match a specific
// CommonName
func (s *X509MemStore) GetCertificatesByCN(cn string) ([]*x509.Certificate, error) {
var certs []*x509.Certificate
if ids, ok := s.nameMap[cn]; ok {
for _, v := range ids {
cert, err := s.getCertificateByCertID(v)
if err != nil {
// This error should never happen. This would mean that we have
// an inconsistent X509MemStore
return nil, err
}
certs = append(certs, cert)
}
}
if len(certs) == 0 {
return nil, &ErrNoCertificatesFound{query: cn}
}
return certs, nil
}
// GetVerifyOptions returns VerifyOptions with the certificates within the KeyStore
// as part of the roots list. This never allows the use of system roots, returning
// an error if there are no root CAs.
func (s *X509MemStore) GetVerifyOptions(dnsName string) (x509.VerifyOptions, error) {
// If we have no Certificates loaded return error (we don't want to revert to using
// system CAs).
if len(s.fingerprintMap) == 0 {
return x509.VerifyOptions{}, errors.New("no root CAs available")
}
opts := x509.VerifyOptions{
DNSName: dnsName,
Roots: s.GetCertificatePool(),
}
return opts, nil
}