github.com/insolar/x-crypto@v0.0.0-20191031140942-75fab8a325f6/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  )
    10  
    11  // CertPool is a set of certificates.
    12  type CertPool struct {
    13  	bySubjectKeyId map[string][]int
    14  	byName         map[string][]int
    15  	certs          []*Certificate
    16  }
    17  
    18  // NewCertPool returns a new, empty CertPool.
    19  func NewCertPool() *CertPool {
    20  	return &CertPool{
    21  		bySubjectKeyId: make(map[string][]int),
    22  		byName:         make(map[string][]int),
    23  	}
    24  }
    25  
    26  func (s *CertPool) copy() *CertPool {
    27  	p := &CertPool{
    28  		bySubjectKeyId: make(map[string][]int, len(s.bySubjectKeyId)),
    29  		byName:         make(map[string][]int, len(s.byName)),
    30  		certs:          make([]*Certificate, len(s.certs)),
    31  	}
    32  	for k, v := range s.bySubjectKeyId {
    33  		indexes := make([]int, len(v))
    34  		copy(indexes, v)
    35  		p.bySubjectKeyId[k] = indexes
    36  	}
    37  	for k, v := range s.byName {
    38  		indexes := make([]int, len(v))
    39  		copy(indexes, v)
    40  		p.byName[k] = indexes
    41  	}
    42  	copy(p.certs, s.certs)
    43  	return p
    44  }
    45  
    46  // findVerifiedParents attempts to find certificates in s which have signed the
    47  // given certificate. If any candidates were rejected then errCert will be set
    48  // to one of them, arbitrarily, and err will contain the reason that it was
    49  // rejected.
    50  func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
    51  	if s == nil {
    52  		return
    53  	}
    54  	var candidates []int
    55  
    56  	if len(cert.AuthorityKeyId) > 0 {
    57  		candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
    58  	}
    59  	if len(candidates) == 0 {
    60  		candidates = s.byName[string(cert.RawIssuer)]
    61  	}
    62  
    63  	for _, c := range candidates {
    64  		if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
    65  			parents = append(parents, c)
    66  		} else {
    67  			errCert = s.certs[c]
    68  		}
    69  	}
    70  
    71  	return
    72  }
    73  
    74  func (s *CertPool) contains(cert *Certificate) bool {
    75  	if s == nil {
    76  		return false
    77  	}
    78  
    79  	candidates := s.byName[string(cert.RawSubject)]
    80  	for _, c := range candidates {
    81  		if s.certs[c].Equal(cert) {
    82  			return true
    83  		}
    84  	}
    85  
    86  	return false
    87  }
    88  
    89  // AddCert adds a certificate to a pool.
    90  func (s *CertPool) AddCert(cert *Certificate) {
    91  	if cert == nil {
    92  		panic("adding nil Certificate to CertPool")
    93  	}
    94  
    95  	// Check that the certificate isn't being added twice.
    96  	if s.contains(cert) {
    97  		return
    98  	}
    99  
   100  	n := len(s.certs)
   101  	s.certs = append(s.certs, cert)
   102  
   103  	if len(cert.SubjectKeyId) > 0 {
   104  		keyId := string(cert.SubjectKeyId)
   105  		s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
   106  	}
   107  	name := string(cert.RawSubject)
   108  	s.byName[name] = append(s.byName[name], n)
   109  }
   110  
   111  // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
   112  // It appends any certificates found to s and reports whether any certificates
   113  // were successfully parsed.
   114  //
   115  // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
   116  // of root CAs in a format suitable for this function.
   117  func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
   118  	for len(pemCerts) > 0 {
   119  		var block *pem.Block
   120  		block, pemCerts = pem.Decode(pemCerts)
   121  		if block == nil {
   122  			break
   123  		}
   124  		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
   125  			continue
   126  		}
   127  
   128  		cert, err := ParseCertificate(block.Bytes)
   129  		if err != nil {
   130  			continue
   131  		}
   132  
   133  		s.AddCert(cert)
   134  		ok = true
   135  	}
   136  
   137  	return
   138  }
   139  
   140  // Subjects returns a list of the DER-encoded subjects of
   141  // all of the certificates in the pool.
   142  func (s *CertPool) Subjects() [][]byte {
   143  	res := make([][]byte, len(s.certs))
   144  	for i, c := range s.certs {
   145  		res[i] = c.RawSubject
   146  	}
   147  	return res
   148  }