github.com/Hyperledger-TWGC/tjfoc-gm@v1.4.0/x509/cert_pool.go (about)

     1  /*
     2  Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  	http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package x509
    17  
    18  import (
    19  	"encoding/pem"
    20  	"errors"
    21  	"io/ioutil"
    22  	"os"
    23  	"runtime"
    24  	"sync"
    25  )
    26  
    27  // Possible certificate files; stop after finding one.
    28  var certFiles = []string{
    29  	"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
    30  	"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
    31  	"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
    32  	"/etc/pki/tls/cacert.pem",                           // OpenELEC
    33  	"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
    34  }
    35  
    36  // CertPool is a set of certificates.
    37  type CertPool struct {
    38  	bySubjectKeyId map[string][]int
    39  	byName         map[string][]int
    40  	certs          []*Certificate
    41  }
    42  
    43  // NewCertPool returns a new, empty CertPool.
    44  func NewCertPool() *CertPool {
    45  	return &CertPool{
    46  		bySubjectKeyId: make(map[string][]int),
    47  		byName:         make(map[string][]int),
    48  	}
    49  }
    50  
    51  // Possible directories with certificate files; stop after successfully
    52  // reading at least one file from a directory.
    53  var certDirectories = []string{
    54  	"/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
    55  	"/system/etc/security/cacerts", // Android
    56  }
    57  
    58  var (
    59  	once           sync.Once
    60  	systemRoots    *CertPool
    61  	systemRootsErr error
    62  )
    63  
    64  func systemRootsPool() *CertPool {
    65  	once.Do(initSystemRoots)
    66  	return systemRoots
    67  }
    68  
    69  func initSystemRoots() {
    70  	systemRoots, systemRootsErr = loadSystemRoots()
    71  }
    72  
    73  func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
    74  	return nil, nil
    75  }
    76  
    77  func loadSystemRoots() (*CertPool, error) {
    78  	roots := NewCertPool()
    79  	var firstErr error
    80  	for _, file := range certFiles {
    81  		data, err := ioutil.ReadFile(file)
    82  		if err == nil {
    83  			roots.AppendCertsFromPEM(data)
    84  			return roots, nil
    85  		}
    86  		if firstErr == nil && !os.IsNotExist(err) {
    87  			firstErr = err
    88  		}
    89  	}
    90  
    91  	for _, directory := range certDirectories {
    92  		fis, err := ioutil.ReadDir(directory)
    93  		if err != nil {
    94  			if firstErr == nil && !os.IsNotExist(err) {
    95  				firstErr = err
    96  			}
    97  			continue
    98  		}
    99  		rootsAdded := false
   100  		for _, fi := range fis {
   101  			data, err := ioutil.ReadFile(directory + "/" + fi.Name())
   102  			if err == nil && roots.AppendCertsFromPEM(data) {
   103  				rootsAdded = true
   104  			}
   105  		}
   106  		if rootsAdded {
   107  			return roots, nil
   108  		}
   109  	}
   110  
   111  	return nil, firstErr
   112  }
   113  
   114  // SystemCertPool returns a copy of the system cert pool.
   115  //
   116  // Any mutations to the returned pool are not written to disk and do
   117  // not affect any other pool.
   118  func SystemCertPool() (*CertPool, error) {
   119  	if runtime.GOOS == "windows" {
   120  		// Issue 16736, 18609:
   121  		return nil, errors.New("crypto/x509: system root pool is not available on Windows")
   122  	}
   123  
   124  	return loadSystemRoots()
   125  }
   126  
   127  // findVerifiedParents attempts to find certificates in s which have signed the
   128  // given certificate. If any candidates were rejected then errCert will be set
   129  // to one of them, arbitrarily, and err will contain the reason that it was
   130  // rejected.
   131  func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
   132  	if s == nil {
   133  		return
   134  	}
   135  	var candidates []int
   136  
   137  	if len(cert.AuthorityKeyId) > 0 {
   138  		candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
   139  	}
   140  	if len(candidates) == 0 {
   141  		candidates = s.byName[string(cert.RawIssuer)]
   142  	}
   143  
   144  	for _, c := range candidates {
   145  		if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
   146  			parents = append(parents, c)
   147  		} else {
   148  			errCert = s.certs[c]
   149  		}
   150  	}
   151  
   152  	return
   153  }
   154  
   155  func (s *CertPool) contains(cert *Certificate) bool {
   156  	if s == nil {
   157  		return false
   158  	}
   159  
   160  	candidates := s.byName[string(cert.RawSubject)]
   161  	for _, c := range candidates {
   162  		if s.certs[c].Equal(cert) {
   163  			return true
   164  		}
   165  	}
   166  
   167  	return false
   168  }
   169  
   170  // AddCert adds a certificate to a pool.
   171  func (s *CertPool) AddCert(cert *Certificate) {
   172  	if cert == nil {
   173  		panic("adding nil Certificate to CertPool")
   174  	}
   175  
   176  	// Check that the certificate isn't being added twice.
   177  	if s.contains(cert) {
   178  		return
   179  	}
   180  
   181  	n := len(s.certs)
   182  	s.certs = append(s.certs, cert)
   183  
   184  	if len(cert.SubjectKeyId) > 0 {
   185  		keyId := string(cert.SubjectKeyId)
   186  		s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
   187  	}
   188  	name := string(cert.RawSubject)
   189  	s.byName[name] = append(s.byName[name], n)
   190  }
   191  
   192  // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
   193  // It appends any certificates found to s and reports whether any certificates
   194  // were successfully parsed.
   195  //
   196  // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
   197  // of root CAs in a format suitable for this function.
   198  func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
   199  	for len(pemCerts) > 0 {
   200  		var block *pem.Block
   201  		block, pemCerts = pem.Decode(pemCerts)
   202  		if block == nil {
   203  			break
   204  		}
   205  		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
   206  			continue
   207  		}
   208  
   209  		cert, err := ParseCertificate(block.Bytes)
   210  		if err != nil {
   211  			continue
   212  		}
   213  
   214  		s.AddCert(cert)
   215  		ok = true
   216  	}
   217  
   218  	return
   219  }
   220  
   221  // Subjects returns a list of the DER-encoded subjects of
   222  // all of the certificates in the pool.
   223  func (s *CertPool) Subjects() [][]byte {
   224  	res := make([][]byte, len(s.certs))
   225  	for i, c := range s.certs {
   226  		res[i] = c.RawSubject
   227  	}
   228  	return res
   229  }