github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/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  		return nil, errors.New("crypto/x509: system root pool is not available on Windows")
    35  	}
    36  	return loadSystemRoots()
    37  }
    38  
    39  // findVerifiedParents attempts to find certificates in s which have signed the
    40  // given certificate. If any candidates were rejected then errCert will be set
    41  // to one of them, arbitrarily, and err will contain the reason that it was
    42  // rejected.
    43  func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
    44  	if s == nil {
    45  		return
    46  	}
    47  	var candidates []int
    48  
    49  	if len(cert.AuthorityKeyId) > 0 {
    50  		candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
    51  	}
    52  	if len(candidates) == 0 {
    53  		candidates = s.byName[string(cert.RawIssuer)]
    54  	}
    55  
    56  	for _, c := range candidates {
    57  		if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
    58  			parents = append(parents, c)
    59  		} else {
    60  			errCert = s.certs[c]
    61  		}
    62  	}
    63  
    64  	return
    65  }
    66  
    67  func (s *CertPool) contains(cert *Certificate) bool {
    68  	if s == nil {
    69  		return false
    70  	}
    71  
    72  	candidates := s.byName[string(cert.RawSubject)]
    73  	for _, c := range candidates {
    74  		if s.certs[c].Equal(cert) {
    75  			return true
    76  		}
    77  	}
    78  
    79  	return false
    80  }
    81  
    82  // AddCert adds a certificate to a pool.
    83  func (s *CertPool) AddCert(cert *Certificate) {
    84  	if cert == nil {
    85  		panic("adding nil Certificate to CertPool")
    86  	}
    87  
    88  	// Check that the certificate isn't being added twice.
    89  	for _, c := range s.certs {
    90  		if c.Equal(cert) {
    91  			return
    92  		}
    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  }