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	"errors"
10	"runtime"
11)
12
13// CertPool is a set of certificates.
14type CertPool struct {
15	bySubjectKeyId map[string][]int
16	byName         map[string][]int
17	certs          []*Certificate
18}
19
20// NewCertPool returns a new, empty CertPool.
21func 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.
32func 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.
45func (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
69func (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.
85func (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.
112func (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.
137func (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