Source file
src/crypto/x509/cert_pool.go
1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "crypto/sha256"
10 "encoding/pem"
11 "errors"
12 "runtime"
13 "sync"
14 )
15
16 type sum224 [sha256.Size224]byte
17
18
19 type CertPool struct {
20 byName map[string][]int
21
22
23
24 lazyCerts []lazyCert
25
26
27
28
29
30
31 haveSum map[sum224]bool
32 }
33
34
35
36 type lazyCert struct {
37
38
39
40
41 rawSubject []byte
42
43
44
45
46
47
48
49
50
51 getCert func() (*Certificate, error)
52 }
53
54
55 func NewCertPool() *CertPool {
56 return &CertPool{
57 byName: make(map[string][]int),
58 haveSum: make(map[sum224]bool),
59 }
60 }
61
62
63
64 func (s *CertPool) len() int {
65 if s == nil {
66 return 0
67 }
68 return len(s.lazyCerts)
69 }
70
71
72 func (s *CertPool) cert(n int) (*Certificate, error) {
73 return s.lazyCerts[n].getCert()
74 }
75
76 func (s *CertPool) copy() *CertPool {
77 p := &CertPool{
78 byName: make(map[string][]int, len(s.byName)),
79 lazyCerts: make([]lazyCert, len(s.lazyCerts)),
80 haveSum: make(map[sum224]bool, len(s.haveSum)),
81 }
82 for k, v := range s.byName {
83 indexes := make([]int, len(v))
84 copy(indexes, v)
85 p.byName[k] = indexes
86 }
87 for k := range s.haveSum {
88 p.haveSum[k] = true
89 }
90 copy(p.lazyCerts, s.lazyCerts)
91 return p
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105 func SystemCertPool() (*CertPool, error) {
106 if runtime.GOOS == "windows" {
107
108 return nil, errors.New("crypto/x509: system root pool is not available on Windows")
109 }
110
111 if sysRoots := systemRootsPool(); sysRoots != nil {
112 return sysRoots.copy(), nil
113 }
114
115 return loadSystemRoots()
116 }
117
118
119
120 func (s *CertPool) findPotentialParents(cert *Certificate) []*Certificate {
121 if s == nil {
122 return nil
123 }
124
125
126
127
128
129
130
131 var matchingKeyID, oneKeyID, mismatchKeyID []*Certificate
132 for _, c := range s.byName[string(cert.RawIssuer)] {
133 candidate, err := s.cert(c)
134 if err != nil {
135 continue
136 }
137 kidMatch := bytes.Equal(candidate.SubjectKeyId, cert.AuthorityKeyId)
138 switch {
139 case kidMatch:
140 matchingKeyID = append(matchingKeyID, candidate)
141 case (len(candidate.SubjectKeyId) == 0 && len(cert.AuthorityKeyId) > 0) ||
142 (len(candidate.SubjectKeyId) > 0 && len(cert.AuthorityKeyId) == 0):
143 oneKeyID = append(oneKeyID, candidate)
144 default:
145 mismatchKeyID = append(mismatchKeyID, candidate)
146 }
147 }
148
149 found := len(matchingKeyID) + len(oneKeyID) + len(mismatchKeyID)
150 if found == 0 {
151 return nil
152 }
153 candidates := make([]*Certificate, 0, found)
154 candidates = append(candidates, matchingKeyID...)
155 candidates = append(candidates, oneKeyID...)
156 candidates = append(candidates, mismatchKeyID...)
157 return candidates
158 }
159
160 func (s *CertPool) contains(cert *Certificate) bool {
161 if s == nil {
162 return false
163 }
164 return s.haveSum[sha256.Sum224(cert.Raw)]
165 }
166
167
168 func (s *CertPool) AddCert(cert *Certificate) {
169 if cert == nil {
170 panic("adding nil Certificate to CertPool")
171 }
172 s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
173 return cert, nil
174 })
175 }
176
177
178
179
180
181
182 func (s *CertPool) addCertFunc(rawSum224 sum224, rawSubject string, getCert func() (*Certificate, error)) {
183 if getCert == nil {
184 panic("getCert can't be nil")
185 }
186
187
188 if s.haveSum[rawSum224] {
189 return
190 }
191
192 s.haveSum[rawSum224] = true
193 s.lazyCerts = append(s.lazyCerts, lazyCert{
194 rawSubject: []byte(rawSubject),
195 getCert: getCert,
196 })
197 s.byName[rawSubject] = append(s.byName[rawSubject], len(s.lazyCerts)-1)
198 }
199
200
201
202
203
204
205
206 func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
207 for len(pemCerts) > 0 {
208 var block *pem.Block
209 block, pemCerts = pem.Decode(pemCerts)
210 if block == nil {
211 break
212 }
213 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
214 continue
215 }
216
217 certBytes := block.Bytes
218 cert, err := ParseCertificate(certBytes)
219 if err != nil {
220 continue
221 }
222 var lazyCert struct {
223 sync.Once
224 v *Certificate
225 }
226 s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
227 lazyCert.Do(func() {
228
229 lazyCert.v, _ = ParseCertificate(certBytes)
230 certBytes = nil
231 })
232 return lazyCert.v, nil
233 })
234 ok = true
235 }
236
237 return ok
238 }
239
240
241
242 func (s *CertPool) Subjects() [][]byte {
243 res := make([][]byte, s.len())
244 for i, lc := range s.lazyCerts {
245 res[i] = lc.rawSubject
246 }
247 return res
248 }
249
View as plain text