|  | // Copyright 2011 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package x509 | 
|  |  | 
|  | import ( | 
|  | "encoding/pem" | 
|  | "errors" | 
|  | "runtime" | 
|  | ) | 
|  |  | 
|  | // CertPool is a set of certificates. | 
|  | type CertPool struct { | 
|  | bySubjectKeyId map[string][]int | 
|  | byName         map[string][]int | 
|  | certs          []*Certificate | 
|  | } | 
|  |  | 
|  | // NewCertPool returns a new, empty CertPool. | 
|  | func NewCertPool() *CertPool { | 
|  | return &CertPool{ | 
|  | bySubjectKeyId: make(map[string][]int), | 
|  | byName:         make(map[string][]int), | 
|  | } | 
|  | } | 
|  |  | 
|  | func (s *CertPool) copy() *CertPool { | 
|  | p := &CertPool{ | 
|  | bySubjectKeyId: make(map[string][]int, len(s.bySubjectKeyId)), | 
|  | byName:         make(map[string][]int, len(s.byName)), | 
|  | certs:          make([]*Certificate, len(s.certs)), | 
|  | } | 
|  | for k, v := range s.bySubjectKeyId { | 
|  | indexes := make([]int, len(v)) | 
|  | copy(indexes, v) | 
|  | p.bySubjectKeyId[k] = indexes | 
|  | } | 
|  | for k, v := range s.byName { | 
|  | indexes := make([]int, len(v)) | 
|  | copy(indexes, v) | 
|  | p.byName[k] = indexes | 
|  | } | 
|  | copy(p.certs, s.certs) | 
|  | return p | 
|  | } | 
|  |  | 
|  | // SystemCertPool returns a copy of the system cert pool. | 
|  | // | 
|  | // Any mutations to the returned pool are not written to disk and do | 
|  | // not affect any other pool returned by SystemCertPool. | 
|  | // | 
|  | // New changes in the system cert pool might not be reflected | 
|  | // in subsequent calls. | 
|  | func SystemCertPool() (*CertPool, error) { | 
|  | if runtime.GOOS == "windows" { | 
|  | // Issue 16736, 18609: | 
|  | return nil, errors.New("crypto/x509: system root pool is not available on Windows") | 
|  | } | 
|  |  | 
|  | if sysRoots := systemRootsPool(); sysRoots != nil { | 
|  | return sysRoots.copy(), nil | 
|  | } | 
|  |  | 
|  | return loadSystemRoots() | 
|  | } | 
|  |  | 
|  | // findVerifiedParents attempts to find certificates in s which have signed the | 
|  | // given certificate. If any candidates were rejected then errCert will be set | 
|  | // to one of them, arbitrarily, and err will contain the reason that it was | 
|  | // rejected. | 
|  | func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) { | 
|  | if s == nil { | 
|  | return | 
|  | } | 
|  | var candidates []int | 
|  |  | 
|  | if len(cert.AuthorityKeyId) > 0 { | 
|  | candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] | 
|  | } | 
|  | if len(candidates) == 0 { | 
|  | candidates = s.byName[string(cert.RawIssuer)] | 
|  | } | 
|  |  | 
|  | for _, c := range candidates { | 
|  | if err = cert.CheckSignatureFrom(s.certs[c]); err == nil { | 
|  | parents = append(parents, c) | 
|  | } else { | 
|  | errCert = s.certs[c] | 
|  | } | 
|  | } | 
|  |  | 
|  | return | 
|  | } | 
|  |  | 
|  | func (s *CertPool) contains(cert *Certificate) bool { | 
|  | if s == nil { | 
|  | return false | 
|  | } | 
|  |  | 
|  | candidates := s.byName[string(cert.RawSubject)] | 
|  | for _, c := range candidates { | 
|  | if s.certs[c].Equal(cert) { | 
|  | return true | 
|  | } | 
|  | } | 
|  |  | 
|  | return false | 
|  | } | 
|  |  | 
|  | // AddCert adds a certificate to a pool. | 
|  | func (s *CertPool) AddCert(cert *Certificate) { | 
|  | if cert == nil { | 
|  | panic("adding nil Certificate to CertPool") | 
|  | } | 
|  |  | 
|  | // Check that the certificate isn't being added twice. | 
|  | if s.contains(cert) { | 
|  | return | 
|  | } | 
|  |  | 
|  | n := len(s.certs) | 
|  | s.certs = append(s.certs, cert) | 
|  |  | 
|  | if len(cert.SubjectKeyId) > 0 { | 
|  | keyId := string(cert.SubjectKeyId) | 
|  | s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) | 
|  | } | 
|  | name := string(cert.RawSubject) | 
|  | s.byName[name] = append(s.byName[name], n) | 
|  | } | 
|  |  | 
|  | // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. | 
|  | // It appends any certificates found to s and reports whether any certificates | 
|  | // were successfully parsed. | 
|  | // | 
|  | // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set | 
|  | // of root CAs in a format suitable for this function. | 
|  | func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { | 
|  | for len(pemCerts) > 0 { | 
|  | var block *pem.Block | 
|  | block, pemCerts = pem.Decode(pemCerts) | 
|  | if block == nil { | 
|  | break | 
|  | } | 
|  | if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { | 
|  | continue | 
|  | } | 
|  |  | 
|  | cert, err := ParseCertificate(block.Bytes) | 
|  | if err != nil { | 
|  | continue | 
|  | } | 
|  |  | 
|  | s.AddCert(cert) | 
|  | ok = true | 
|  | } | 
|  |  | 
|  | return | 
|  | } | 
|  |  | 
|  | // Subjects returns a list of the DER-encoded subjects of | 
|  | // all of the certificates in the pool. | 
|  | func (s *CertPool) Subjects() [][]byte { | 
|  | res := make([][]byte, len(s.certs)) | 
|  | for i, c := range s.certs { | 
|  | res[i] = c.RawSubject | 
|  | } | 
|  | return res | 
|  | } |