...
Run Format

Source file src/crypto/x509/cert_pool.go

Documentation: crypto/x509

  // 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),
  	}
  }
  
  // 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.
  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")
  	}
  
  	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
  }
  

View as plain text