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