OSDN Git Service

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