// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package x509import ()type sum224 [sha256.Size224]byte// CertPool is a set of certificates.typeCertPoolstruct { byName map[string][]int// cert.RawSubject => index into lazyCerts// lazyCerts contains funcs that return a certificate, // lazily parsing/decompressing it as needed. lazyCerts []lazyCert// haveSum maps from sum224(cert.Raw) to true. It's used only // for AddCert duplicate detection, to avoid CertPool.contains // calls in the AddCert path (because the contains method can // call getCert and otherwise negate savings from lazy getCert // funcs). haveSum map[sum224]bool// systemPool indicates whether this is a special pool derived from the // system roots. If it includes additional roots, it requires doing two // verifications, one using the roots provided by the caller, and one using // the system platform verifier. systemPool bool}// lazyCert is minimal metadata about a Cert and a func to retrieve it// in its normal expanded *Certificate form.type lazyCert struct {// rawSubject is the Certificate.RawSubject value. // It's the same as the CertPool.byName key, but in []byte // form to make CertPool.Subjects (as used by crypto/tls) do // fewer allocations. rawSubject []byte// constraint is a function to run against a chain when it is a candidate to // be added to the chain. This allows adding arbitrary constraints that are // not specified in the certificate itself. constraint func([]*Certificate) error// getCert returns the certificate. // // It is not meant to do network operations or anything else // where a failure is likely; the func is meant to lazily // parse/decompress data that is already known to be good. The // error in the signature primarily is meant for use in the // case where a cert file existed on local disk when the program // started up is deleted later before it's read. getCert func() (*Certificate, error)}// NewCertPool returns a new, empty CertPool.func () *CertPool {return &CertPool{byName: make(map[string][]int),haveSum: make(map[sum224]bool), }}// len returns the number of certs in the set.// A nil set is a valid empty set.func ( *CertPool) () int {if == nil {return0 }returnlen(.lazyCerts)}// cert returns cert index n in s.func ( *CertPool) ( int) (*Certificate, func([]*Certificate) error, error) { , := .lazyCerts[].getCert()return , .lazyCerts[].constraint, }// Clone returns a copy of s.func ( *CertPool) () *CertPool { := &CertPool{byName: make(map[string][]int, len(.byName)),lazyCerts: make([]lazyCert, len(.lazyCerts)),haveSum: make(map[sum224]bool, len(.haveSum)),systemPool: .systemPool, }for , := range .byName { := make([]int, len())copy(, ) .byName[] = }for := range .haveSum { .haveSum[] = true }copy(.lazyCerts, .lazyCerts)return}// SystemCertPool returns a copy of the system cert pool.//// On Unix systems other than macOS the environment variables SSL_CERT_FILE and// SSL_CERT_DIR can be used to override the system default locations for the SSL// certificate file and SSL certificate files directory, respectively. The// latter can be a colon-separated list.//// Any mutations to the returned pool are not written to disk and do not affect// any other pool returned by SystemCertPool.//// New changes in the system cert pool might not be reflected in subsequent calls.func () (*CertPool, error) {if := systemRootsPool(); != nil {return .Clone(), nil }returnloadSystemRoots()}type potentialParent struct { cert *Certificate constraint func([]*Certificate) error}// findPotentialParents returns the certificates in s which might have signed// cert.func ( *CertPool) ( *Certificate) []potentialParent {if == nil {returnnil }// consider all candidates where cert.Issuer matches cert.Subject. // when picking possible candidates the list is built in the order // of match plausibility as to save cycles in buildChains: // AKID and SKID match // AKID present, SKID missing / AKID missing, SKID present // AKID and SKID don't matchvar , , []potentialParentfor , := range .byName[string(.RawIssuer)] { , , := .cert()if != nil {continue } := bytes.Equal(.SubjectKeyId, .AuthorityKeyId)switch {case : = append(, potentialParent{, })case (len(.SubjectKeyId) == 0 && len(.AuthorityKeyId) > 0) || (len(.SubjectKeyId) > 0 && len(.AuthorityKeyId) == 0): = append(, potentialParent{, })default: = append(, potentialParent{, }) } } := len() + len() + len()if == 0 {returnnil } := make([]potentialParent, 0, ) = append(, ...) = append(, ...) = append(, ...)return}func ( *CertPool) ( *Certificate) bool {if == nil {returnfalse }return .haveSum[sha256.Sum224(.Raw)]}// AddCert adds a certificate to a pool.func ( *CertPool) ( *Certificate) {if == nil {panic("adding nil Certificate to CertPool") } .addCertFunc(sha256.Sum224(.Raw), string(.RawSubject), func() (*Certificate, error) {return , nil }, nil)}// addCertFunc adds metadata about a certificate to a pool, along with// a func to fetch that certificate later when needed.//// The rawSubject is Certificate.RawSubject and must be non-empty.// The getCert func may be called 0 or more times.func ( *CertPool) ( sum224, string, func() (*Certificate, error), func([]*Certificate) error) {if == nil {panic("getCert can't be nil") }// Check that the certificate isn't being added twice.if .haveSum[] {return } .haveSum[] = true .lazyCerts = append(.lazyCerts, lazyCert{rawSubject: []byte(),getCert: ,constraint: , }) .byName[] = append(.byName[], len(.lazyCerts)-1)}// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.// It appends any certificates found to s and reports whether any certificates// were successfully parsed.//// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set// of root CAs in a format suitable for this function.func ( *CertPool) ( []byte) ( bool) {forlen() > 0 {var *pem.Block , = pem.Decode()if == nil {break }if .Type != "CERTIFICATE" || len(.Headers) != 0 {continue } := .Bytes , := ParseCertificate()if != nil {continue }varstruct {sync.Once *Certificate } .addCertFunc(sha256.Sum224(.Raw), string(.RawSubject), func() (*Certificate, error) { .Do(func() {// This can't fail, as the same bytes already parsed above. ., _ = ParseCertificate() = nil })return ., nil }, nil) = true }return}// Subjects returns a list of the DER-encoded subjects of// all of the certificates in the pool.//// Deprecated: if s was returned by [SystemCertPool], Subjects// will not include the system roots.func ( *CertPool) () [][]byte { := make([][]byte, .len())for , := range .lazyCerts { [] = .rawSubject }return}// Equal reports whether s and other are equal.func ( *CertPool) ( *CertPool) bool {if == nil || == nil {return == }if .systemPool != .systemPool || len(.haveSum) != len(.haveSum) {returnfalse }for := range .haveSum {if !.haveSum[] {returnfalse } }returntrue}// AddCertWithConstraint adds a certificate to the pool with the additional// constraint. When Certificate.Verify builds a chain which is rooted by cert,// it will additionally pass the whole chain to constraint to determine its// validity. If constraint returns a non-nil error, the chain will be discarded.// constraint may be called concurrently from multiple goroutines.func ( *CertPool) ( *Certificate, func([]*Certificate) error) {if == nil {panic("adding nil Certificate to CertPool") } .addCertFunc(sha256.Sum224(.Raw), string(.RawSubject), func() (*Certificate, error) {return , nil }, )}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.