...
Run Format

Source file src/crypto/x509/cert_pool.go

Documentation: crypto/x509

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

View as plain text