github.com/fisco-bcos/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/x509/cert_pool.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package x509 6 7 import ( 8 "encoding/pem" 9 "errors" 10 "runtime" 11 ) 12 13 // CertPool is a set of certificates. 14 type CertPool struct { 15 bySubjectKeyId map[string][]int 16 byName map[string][]int 17 certs []*Certificate 18 } 19 20 // NewCertPool returns a new, empty CertPool. 21 func NewCertPool() *CertPool { 22 return &CertPool{ 23 bySubjectKeyId: make(map[string][]int), 24 byName: make(map[string][]int), 25 } 26 } 27 28 func (s *CertPool) copy() *CertPool { 29 p := &CertPool{ 30 bySubjectKeyId: make(map[string][]int, len(s.bySubjectKeyId)), 31 byName: make(map[string][]int, len(s.byName)), 32 certs: make([]*Certificate, len(s.certs)), 33 } 34 for k, v := range s.bySubjectKeyId { 35 indexes := make([]int, len(v)) 36 copy(indexes, v) 37 p.bySubjectKeyId[k] = indexes 38 } 39 for k, v := range s.byName { 40 indexes := make([]int, len(v)) 41 copy(indexes, v) 42 p.byName[k] = indexes 43 } 44 copy(p.certs, s.certs) 45 return p 46 } 47 48 // SystemCertPool returns a copy of the system cert pool. 49 // 50 // Any mutations to the returned pool are not written to disk and do 51 // not affect any other pool returned by SystemCertPool. 52 // 53 // New changes in the system cert pool might not be reflected 54 // in subsequent calls. 55 func SystemCertPool() (*CertPool, error) { 56 if runtime.GOOS == "windows" { 57 // Issue 16736, 18609: 58 return nil, errors.New("crypto/x509: system root pool is not available on Windows") 59 } 60 61 if sysRoots := systemRootsPool(); sysRoots != nil { 62 return sysRoots.copy(), nil 63 } 64 65 return loadSystemRoots() 66 } 67 68 // findPotentialParents returns the indexes of certificates in s which might 69 // have signed cert. The caller must not modify the returned slice. 70 func (s *CertPool) findPotentialParents(cert *Certificate) []int { 71 if s == nil { 72 return nil 73 } 74 75 var candidates []int 76 if len(cert.AuthorityKeyId) > 0 { 77 candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] 78 } 79 if len(candidates) == 0 { 80 candidates = s.byName[string(cert.RawIssuer)] 81 } 82 return candidates 83 } 84 85 func (s *CertPool) contains(cert *Certificate) bool { 86 if s == nil { 87 return false 88 } 89 90 candidates := s.byName[string(cert.RawSubject)] 91 for _, c := range candidates { 92 if s.certs[c].Equal(cert) { 93 return true 94 } 95 } 96 97 return false 98 } 99 100 // AddCert adds a certificate to a pool. 101 func (s *CertPool) AddCert(cert *Certificate) { 102 if cert == nil { 103 panic("adding nil Certificate to CertPool") 104 } 105 106 // Check that the certificate isn't being added twice. 107 if s.contains(cert) { 108 return 109 } 110 111 n := len(s.certs) 112 s.certs = append(s.certs, cert) 113 114 if len(cert.SubjectKeyId) > 0 { 115 keyId := string(cert.SubjectKeyId) 116 s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) 117 } 118 name := string(cert.RawSubject) 119 s.byName[name] = append(s.byName[name], n) 120 } 121 122 // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. 123 // It appends any certificates found to s and reports whether any certificates 124 // were successfully parsed. 125 // 126 // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set 127 // of root CAs in a format suitable for this function. 128 func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { 129 for len(pemCerts) > 0 { 130 var block *pem.Block 131 block, pemCerts = pem.Decode(pemCerts) 132 if block == nil { 133 break 134 } 135 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 136 continue 137 } 138 139 cert, err := ParseCertificate(block.Bytes) 140 if err != nil { 141 continue 142 } 143 144 s.AddCert(cert) 145 ok = true 146 } 147 148 return 149 } 150 151 // Subjects returns a list of the DER-encoded subjects of 152 // all of the certificates in the pool. 153 func (s *CertPool) Subjects() [][]byte { 154 res := make([][]byte, len(s.certs)) 155 for i, c := range s.certs { 156 res[i] = c.RawSubject 157 } 158 return res 159 }