...

Source file src/github.com/google/certificate-transparency-go/ctutil/ctutil.go

Documentation: github.com/google/certificate-transparency-go/ctutil

     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  

View as plain text