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 5package x509 6 7import ( 8 "encoding/pem" 9 "errors" 10 "runtime" 11) 12 13// CertPool is a set of certificates. 14type CertPool struct { 15 bySubjectKeyId map[string][]int 16 byName map[string][]int 17 certs []*Certificate 18} 19 20// NewCertPool returns a new, empty CertPool. 21func 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. 32func 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. 45func (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 69func (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. 85func (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. 112func (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. 137func (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} 144