1 // Copyright 2018 Google LLC. All Rights Reserved. 2 // 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 // Package ctutil contains utilities for Certificate Transparency. 16 package ctutil 17 18 import ( 19 "bytes" 20 "crypto" 21 "crypto/sha256" 22 "encoding/base64" 23 "errors" 24 "fmt" 25 26 ct "github.com/google/certificate-transparency-go" 27 "github.com/google/certificate-transparency-go/tls" 28 "github.com/google/certificate-transparency-go/x509" 29 ) 30 31 var emptyHash = [sha256.Size]byte{} 32 33 // LeafHashB64 does as LeafHash does, but returns the leaf hash base64-encoded. 34 // The base64-encoded leaf hash returned by B64LeafHash can be used with the 35 // get-proof-by-hash API endpoint of Certificate Transparency Logs. 36 func LeafHashB64(chain []*x509.Certificate, sct *ct.SignedCertificateTimestamp, embedded bool) (string, error) { 37 hash, err := LeafHash(chain, sct, embedded) 38 if err != nil { 39 return "", err 40 } 41 return base64.StdEncoding.EncodeToString(hash[:]), nil 42 } 43 44 // LeafHash calculates the leaf hash of the certificate or precertificate at 45 // chain[0] that sct was issued for. 46 // 47 // sct is required because the SCT timestamp is used to calculate the leaf hash. 48 // Leaf hashes are unique to (pre)certificate-SCT pairs. 49 // 50 // This function can be used with three different types of leaf certificate: 51 // - X.509 Certificate: 52 // If using this function to calculate the leaf hash for a normal X.509 53 // certificate then it is enough to just provide the end entity 54 // certificate in chain. This case assumes that the SCT being provided is 55 // not embedded within the leaf certificate provided, i.e. the certificate 56 // is what was submitted to the Certificate Transparency Log in order to 57 // obtain the SCT. For this case, set embedded to false. 58 // - Precertificate: 59 // If using this function to calculate the leaf hash for a precertificate 60 // then the issuing certificate must also be provided in chain. The 61 // precertificate should be at chain[0], and its issuer at chain[1]. For 62 // this case, set embedded to false. 63 // - X.509 Certificate containing the SCT embedded within it: 64 // If using this function to calculate the leaf hash for a certificate 65 // where the SCT provided is embedded within the certificate you 66 // are providing at chain[0], set embedded to true. LeafHash will 67 // calculate the leaf hash by building the corresponding precertificate. 68 // LeafHash will return an error if the provided SCT cannot be found 69 // embedded within chain[0]. As with the precertificate case, the issuing 70 // certificate must also be provided in chain. The certificate containing 71 // the embedded SCT should be at chain[0], and its issuer at chain[1]. 72 // 73 // Note: LeafHash doesn't check that the provided SCT verifies for the given 74 // chain. It simply calculates what the leaf hash would be for the given 75 // (pre)certificate-SCT pair. 76 func LeafHash(chain []*x509.Certificate, sct *ct.SignedCertificateTimestamp, embedded bool) ([sha256.Size]byte, error) { 77 leaf, err := createLeaf(chain, sct, embedded) 78 if err != nil { 79 return emptyHash, err 80 } 81 return ct.LeafHashForLeaf(leaf) 82 } 83 84 // VerifySCT takes the public key of a Certificate Transparency Log, a 85 // certificate chain, and an SCT and verifies whether the SCT is a valid SCT for 86 // the certificate at chain[0], signed by the Log that the public key belongs 87 // to. If the SCT does not verify, an error will be returned. 88 // 89 // This function can be used with three different types of leaf certificate: 90 // - X.509 Certificate: 91 // If using this function to verify an SCT for a normal X.509 certificate 92 // then it is enough to just provide the end entity certificate in chain. 93 // This case assumes that the SCT being provided is not embedded within 94 // the leaf certificate provided, i.e. the certificate is what was 95 // submitted to the Certificate Transparency Log in order to obtain the 96 // SCT. For this case, set embedded to false. 97 // - Precertificate: 98 // If using this function to verify an SCT for a precertificate then the 99 // issuing certificate must also be provided in chain. The precertificate 100 // should be at chain[0], and its issuer at chain[1]. For this case, set 101 // embedded to false. 102 // - X.509 Certificate containing the SCT embedded within it: 103 // If the SCT you wish to verify is embedded within the certificate you 104 // are providing at chain[0], set embedded to true. VerifySCT will 105 // verify the provided SCT by building the corresponding precertificate. 106 // VerifySCT will return an error if the provided SCT cannot be found 107 // embedded within chain[0]. As with the precertificate case, the issuing 108 // certificate must also be provided in chain. The certificate containing 109 // the embedded SCT should be at chain[0], and its issuer at chain[1]. 110 func VerifySCT(pubKey crypto.PublicKey, chain []*x509.Certificate, sct *ct.SignedCertificateTimestamp, embedded bool) error { 111 s, err := ct.NewSignatureVerifier(pubKey) 112 if err != nil { 113 return fmt.Errorf("error creating signature verifier: %s", err) 114 } 115 116 return VerifySCTWithVerifier(s, chain, sct, embedded) 117 } 118 119 // VerifySCTWithVerifier takes a ct.SignatureVerifier, a certificate chain, and 120 // an SCT and verifies whether the SCT is a valid SCT for the certificate at 121 // chain[0], signed by the Log whose public key was used to set up the 122 // ct.SignatureVerifier. If the SCT does not verify, an error will be returned. 123 // 124 // This function can be used with three different types of leaf certificate: 125 // - X.509 Certificate: 126 // If using this function to verify an SCT for a normal X.509 certificate 127 // then it is enough to just provide the end entity certificate in chain. 128 // This case assumes that the SCT being provided is not embedded within 129 // the leaf certificate provided, i.e. the certificate is what was 130 // submitted to the Certificate Transparency Log in order to obtain the 131 // SCT. For this case, set embedded to false. 132 // - Precertificate: 133 // If using this function to verify an SCT for a precertificate then the 134 // issuing certificate must also be provided in chain. The precertificate 135 // should be at chain[0], and its issuer at chain[1]. For this case, set 136 // embedded to false. 137 // - X.509 Certificate containing the SCT embedded within it: 138 // If the SCT you wish to verify is embedded within the certificate you 139 // are providing at chain[0], set embedded to true. VerifySCT will 140 // verify the provided SCT by building the corresponding precertificate. 141 // VerifySCT will return an error if the provided SCT cannot be found 142 // embedded within chain[0]. As with the precertificate case, the issuing 143 // certificate must also be provided in chain. The certificate containing 144 // the embedded SCT should be at chain[0], and its issuer at chain[1]. 145 func VerifySCTWithVerifier(sv *ct.SignatureVerifier, chain []*x509.Certificate, sct *ct.SignedCertificateTimestamp, embedded bool) error { 146 if sv == nil { 147 return errors.New("ct.SignatureVerifier is nil") 148 } 149 150 leaf, err := createLeaf(chain, sct, embedded) 151 if err != nil { 152 return err 153 } 154 155 return sv.VerifySCTSignature(*sct, ct.LogEntry{Leaf: *leaf}) 156 } 157 158 func createLeaf(chain []*x509.Certificate, sct *ct.SignedCertificateTimestamp, embedded bool) (*ct.MerkleTreeLeaf, error) { 159 if len(chain) == 0 { 160 return nil, errors.New("chain is empty") 161 } 162 if sct == nil { 163 return nil, errors.New("sct is nil") 164 } 165 166 if embedded { 167 sctPresent, err := ContainsSCT(chain[0], sct) 168 if err != nil { 169 return nil, fmt.Errorf("error checking for SCT in leaf certificate: %s", err) 170 } 171 if !sctPresent { 172 return nil, errors.New("SCT provided is not embedded within leaf certificate") 173 } 174 } 175 176 certType := ct.X509LogEntryType 177 if chain[0].IsPrecertificate() || embedded { 178 certType = ct.PrecertLogEntryType 179 } 180 181 var leaf *ct.MerkleTreeLeaf 182 var err error 183 if embedded { 184 leaf, err = ct.MerkleTreeLeafForEmbeddedSCT(chain, sct.Timestamp) 185 } else { 186 leaf, err = ct.MerkleTreeLeafFromChain(chain, certType, sct.Timestamp) 187 } 188 if err != nil { 189 return nil, fmt.Errorf("error creating MerkleTreeLeaf: %s", err) 190 } 191 return leaf, nil 192 } 193 194 // ContainsSCT checks to see whether the given SCT is embedded within the given 195 // certificate. 196 func ContainsSCT(cert *x509.Certificate, sct *ct.SignedCertificateTimestamp) (bool, error) { 197 if cert == nil || sct == nil { 198 return false, nil 199 } 200 201 sctBytes, err := tls.Marshal(*sct) 202 if err != nil { 203 return false, fmt.Errorf("error tls.Marshalling SCT: %s", err) 204 } 205 for _, s := range cert.SCTList.SCTList { 206 if bytes.Equal(sctBytes, s.Val) { 207 return true, nil 208 } 209 } 210 return false, nil 211 } 212