OSDN Git Service

8230c4d1859f963a8ae6def954aad314565dae70
[bytom/bytom.git] / crypto / sm2 / cert_pool.go
1 /*
2 Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7         http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 */
15
16 package sm2
17
18 import (
19         "encoding/pem"
20         "errors"
21         "io/ioutil"
22         "os"
23         "runtime"
24         "sync"
25 )
26
27 // Possible certificate files; stop after finding one.
28 var certFiles = []string{
29         "/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
30         "/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
31         "/etc/ssl/ca-bundle.pem",                            // OpenSUSE
32         "/etc/pki/tls/cacert.pem",                           // OpenELEC
33         "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
34 }
35
36 // CertPool is a set of certificates.
37 type CertPool struct {
38         bySubjectKeyId map[string][]int
39         byName         map[string][]int
40         certs          []*Certificate
41 }
42
43 // NewCertPool returns a new, empty CertPool.
44 func NewCertPool() *CertPool {
45         return &CertPool{
46                 bySubjectKeyId: make(map[string][]int),
47                 byName:         make(map[string][]int),
48         }
49 }
50
51 // Possible directories with certificate files; stop after successfully
52 // reading at least one file from a directory.
53 var certDirectories = []string{
54         "/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
55         "/system/etc/security/cacerts", // Android
56 }
57
58 var (
59         once           sync.Once
60         systemRoots    *CertPool
61         systemRootsErr error
62 )
63
64 func systemRootsPool() *CertPool {
65         once.Do(initSystemRoots)
66         return systemRoots
67 }
68
69 func initSystemRoots() {
70         systemRoots, systemRootsErr = loadSystemRoots()
71 }
72
73 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
74         return nil, nil
75 }
76
77 func loadSystemRoots() (*CertPool, error) {
78         roots := NewCertPool()
79         var firstErr error
80         for _, file := range certFiles {
81                 data, err := ioutil.ReadFile(file)
82                 if err == nil {
83                         roots.AppendCertsFromPEM(data)
84                         return roots, nil
85                 }
86                 if firstErr == nil && !os.IsNotExist(err) {
87                         firstErr = err
88                 }
89         }
90
91         for _, directory := range certDirectories {
92                 fis, err := ioutil.ReadDir(directory)
93                 if err != nil {
94                         if firstErr == nil && !os.IsNotExist(err) {
95                                 firstErr = err
96                         }
97                         continue
98                 }
99                 rootsAdded := false
100                 for _, fi := range fis {
101                         data, err := ioutil.ReadFile(directory + "/" + fi.Name())
102                         if err == nil && roots.AppendCertsFromPEM(data) {
103                                 rootsAdded = true
104                         }
105                 }
106                 if rootsAdded {
107                         return roots, nil
108                 }
109         }
110
111         return nil, firstErr
112 }
113
114 // SystemCertPool returns a copy of the system cert pool.
115 //
116 // Any mutations to the returned pool are not written to disk and do
117 // not affect any other pool.
118 func SystemCertPool() (*CertPool, error) {
119         if runtime.GOOS == "windows" {
120                 // Issue 16736, 18609:
121                 return nil, errors.New("crypto/x509: system root pool is not available on Windows")
122         }
123
124         return loadSystemRoots()
125 }
126
127 // findVerifiedParents attempts to find certificates in s which have signed the
128 // given certificate. If any candidates were rejected then errCert will be set
129 // to one of them, arbitrarily, and err will contain the reason that it was
130 // rejected.
131 func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
132         if s == nil {
133                 return
134         }
135         var candidates []int
136
137         if len(cert.AuthorityKeyId) > 0 {
138                 candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
139         }
140         if len(candidates) == 0 {
141                 candidates = s.byName[string(cert.RawIssuer)]
142         }
143
144         for _, c := range candidates {
145                 if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
146                         parents = append(parents, c)
147                 } else {
148                         errCert = s.certs[c]
149                 }
150         }
151
152         return
153 }
154
155 func (s *CertPool) contains(cert *Certificate) bool {
156         if s == nil {
157                 return false
158         }
159
160         candidates := s.byName[string(cert.RawSubject)]
161         for _, c := range candidates {
162                 if s.certs[c].Equal(cert) {
163                         return true
164                 }
165         }
166
167         return false
168 }
169
170 // AddCert adds a certificate to a pool.
171 func (s *CertPool) AddCert(cert *Certificate) {
172         if cert == nil {
173                 panic("adding nil Certificate to CertPool")
174         }
175
176         // Check that the certificate isn't being added twice.
177         if s.contains(cert) {
178                 return
179         }
180
181         n := len(s.certs)
182         s.certs = append(s.certs, cert)
183
184         if len(cert.SubjectKeyId) > 0 {
185                 keyId := string(cert.SubjectKeyId)
186                 s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
187         }
188         name := string(cert.RawSubject)
189         s.byName[name] = append(s.byName[name], n)
190 }
191
192 // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
193 // It appends any certificates found to s and reports whether any certificates
194 // were successfully parsed.
195 //
196 // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
197 // of root CAs in a format suitable for this function.
198 func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
199         for len(pemCerts) > 0 {
200                 var block *pem.Block
201                 block, pemCerts = pem.Decode(pemCerts)
202                 if block == nil {
203                         break
204                 }
205                 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
206                         continue
207                 }
208
209                 cert, err := ParseCertificate(block.Bytes)
210                 if err != nil {
211                         continue
212                 }
213
214                 s.AddCert(cert)
215                 ok = true
216         }
217
218         return
219 }
220
221 // Subjects returns a list of the DER-encoded subjects of
222 // all of the certificates in the pool.
223 func (s *CertPool) Subjects() [][]byte {
224         res := make([][]byte, len(s.certs))
225         for i, c := range s.certs {
226                 res[i] = c.RawSubject
227         }
228         return res
229 }