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