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