github.com/Hyperledger-TWGC/tjfoc-gm@v1.4.0/x509/cert_pool.go (about) 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 x509 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 }