package sm2 import ( "encoding/pem" "errors" "io/ioutil" "os" "runtime" "sync" ) // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 "/etc/ssl/ca-bundle.pem", // OpenSUSE "/etc/pki/tls/cacert.pem", // OpenELEC "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 } // CertPool is a set of certificates. type CertPool struct { bySubjectKeyId map[string][]int byName map[string][]int certs []*Certificate } // NewCertPool returns a new, empty CertPool. func NewCertPool() *CertPool { return &CertPool{ bySubjectKeyId: make(map[string][]int), byName: make(map[string][]int), } } // Possible directories with certificate files; stop after successfully // reading at least one file from a directory. var certDirectories = []string{ "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 "/system/etc/security/cacerts", // Android } var ( once sync.Once systemRoots *CertPool systemRootsErr error ) func systemRootsPool() *CertPool { once.Do(initSystemRoots) return systemRoots } func initSystemRoots() { systemRoots, systemRootsErr = loadSystemRoots() } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() var firstErr error for _, file := range certFiles { data, err := ioutil.ReadFile(file) if err == nil { roots.AppendCertsFromPEM(data) return roots, nil } if firstErr == nil && !os.IsNotExist(err) { firstErr = err } } for _, directory := range certDirectories { fis, err := ioutil.ReadDir(directory) if err != nil { if firstErr == nil && !os.IsNotExist(err) { firstErr = err } continue } rootsAdded := false for _, fi := range fis { data, err := ioutil.ReadFile(directory + "/" + fi.Name()) if err == nil && roots.AppendCertsFromPEM(data) { rootsAdded = true } } if rootsAdded { return roots, nil } } return nil, firstErr } // SystemCertPool returns a copy of the system cert pool. // // Any mutations to the returned pool are not written to disk and do // not affect any other pool. func SystemCertPool() (*CertPool, error) { if runtime.GOOS == "windows" { // Issue 16736, 18609: return nil, errors.New("crypto/x509: system root pool is not available on Windows") } return loadSystemRoots() } // findVerifiedParents attempts to find certificates in s which have signed the // given certificate. If any candidates were rejected then errCert will be set // to one of them, arbitrarily, and err will contain the reason that it was // rejected. func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) { if s == nil { return } var candidates []int if len(cert.AuthorityKeyId) > 0 { candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] } if len(candidates) == 0 { candidates = s.byName[string(cert.RawIssuer)] } for _, c := range candidates { if err = cert.CheckSignatureFrom(s.certs[c]); err == nil { parents = append(parents, c) } else { errCert = s.certs[c] } } return } func (s *CertPool) contains(cert *Certificate) bool { if s == nil { return false } candidates := s.byName[string(cert.RawSubject)] for _, c := range candidates { if s.certs[c].Equal(cert) { return true } } return false } // AddCert adds a certificate to a pool. func (s *CertPool) AddCert(cert *Certificate) { if cert == nil { panic("adding nil Certificate to CertPool") } // Check that the certificate isn't being added twice. if s.contains(cert) { return } n := len(s.certs) s.certs = append(s.certs, cert) if len(cert.SubjectKeyId) > 0 { keyId := string(cert.SubjectKeyId) s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n) } name := string(cert.RawSubject) s.byName[name] = append(s.byName[name], n) } // 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 (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { for len(pemCerts) > 0 { var block *pem.Block block, pemCerts = pem.Decode(pemCerts) if block == nil { break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { continue } cert, err := ParseCertificate(block.Bytes) if err != nil { continue } s.AddCert(cert) ok = true } return } // Subjects returns a list of the DER-encoded subjects of // all of the certificates in the pool. func (s *CertPool) Subjects() [][]byte { res := make([][]byte, len(s.certs)) for i, c := range s.certs { res[i] = c.RawSubject } return res }