github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/crypto/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 // SystemCertPool returns a copy of the system cert pool. 29 // 30 // Any mutations to the returned pool are not written to disk and do 31 // not affect any other pool. 32 func SystemCertPool() (*CertPool, error) { 33 if runtime.GOOS == "windows" { 34 // Issue 16736, 18609: 35 return nil, errors.New("crypto/x509: system root pool is not available on Windows") 36 } 37 38 return loadSystemRoots() 39 } 40 41 // findVerifiedParents attempts to find certificates in s which have signed the 42 // given certificate. If any candidates were rejected then errCert will be set 43 // to one of them, arbitrarily, and err will contain the reason that it was 44 // rejected. 45 func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) { 46 if s == nil { 47 return 48 } 49 var candidates []int 50 51 if len(cert.AuthorityKeyId) > 0 { 52 candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] 53 } 54 if len(candidates) == 0 { 55 candidates = s.byName[string(cert.RawIssuer)] 56 } 57 58 for _, c := range candidates { 59 if err = cert.CheckSignatureFrom(s.certs[c]); err == nil { 60 parents = append(parents, c) 61 } else { 62 errCert = s.certs[c] 63 } 64 } 65 66 return 67 } 68 69 func (s *CertPool) contains(cert *Certificate) bool { 70 if s == nil { 71 return false 72 } 73 74 candidates := s.byName[string(cert.RawSubject)] 75 for _, c := range candidates { 76 if s.certs[c].Equal(cert) { 77 return true 78 } 79 } 80 81 return false 82 } 83 84 // AddCert adds a certificate to a pool. 85 func (s *CertPool) AddCert(cert *Certificate) { 86 if cert == nil { 87 panic("adding nil Certificate to CertPool") 88 } 89 90 // Check that the certificate isn't being added twice. 91 if s.contains(cert) { 92 return 93 } 94 95 n := len(s.certs) 96 s.certs = append(s.certs, cert) 97 98 if len(cert.SubjectKeyId) > 0 { 99 keyId := string(cert.SubjectKeyId) 100 s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) 101 } 102 name := string(cert.RawSubject) 103 s.byName[name] = append(s.byName[name], n) 104 } 105 106 // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. 107 // It appends any certificates found to s and reports whether any certificates 108 // were successfully parsed. 109 // 110 // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set 111 // of root CAs in a format suitable for this function. 112 func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { 113 for len(pemCerts) > 0 { 114 var block *pem.Block 115 block, pemCerts = pem.Decode(pemCerts) 116 if block == nil { 117 break 118 } 119 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 120 continue 121 } 122 123 cert, err := ParseCertificate(block.Bytes) 124 if err != nil { 125 continue 126 } 127 128 s.AddCert(cert) 129 ok = true 130 } 131 132 return 133 } 134 135 // Subjects returns a list of the DER-encoded subjects of 136 // all of the certificates in the pool. 137 func (s *CertPool) Subjects() [][]byte { 138 res := make([][]byte, len(s.certs)) 139 for i, c := range s.certs { 140 res[i] = c.RawSubject 141 } 142 return res 143 }