...

Source file src/github.com/google/certificate-transparency-go/trillian/integration/chains.go

Documentation: github.com/google/certificate-transparency-go/trillian/integration

     1  // Copyright 2017 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 integration
    16  
    17  import (
    18  	"crypto"
    19  	"crypto/ecdsa"
    20  	"crypto/elliptic"
    21  	"crypto/rand"
    22  	"errors"
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/google/certificate-transparency-go/trillian/ctfe/configpb"
    27  	"github.com/google/certificate-transparency-go/x509"
    28  
    29  	ct "github.com/google/certificate-transparency-go"
    30  )
    31  
    32  // ChainGenerator encapsulates objects that can generate certificate chains for testing.
    33  type ChainGenerator interface {
    34  	// CertChain generates a certificate chain.
    35  	CertChain() ([]ct.ASN1Cert, error)
    36  	// PreCertChain generates a precertificate chain, and also returns the leaf TBS data
    37  	PreCertChain() ([]ct.ASN1Cert, []byte, error)
    38  }
    39  
    40  // GeneratorFactory is a method that builds a Log-specific ChainGenerator.
    41  type GeneratorFactory func(c *configpb.LogConfig) (ChainGenerator, error)
    42  
    43  // SyntheticChainGenerator builds synthetic certificate chains based on
    44  // a template chain and intermediate CA private key.
    45  type SyntheticChainGenerator struct {
    46  	chain    []ct.ASN1Cert
    47  	leafCert *x509.Certificate
    48  	caCert   *x509.Certificate
    49  	// Signer which matches the caCert
    50  	signer   crypto.Signer
    51  	notAfter time.Time
    52  }
    53  
    54  // NewSyntheticChainGenerator returns a ChainGenerator that mints synthetic certificates based on the
    55  // given template chain.  The provided signer should match the public key of the first issuer cert.
    56  func NewSyntheticChainGenerator(chain []ct.ASN1Cert, signer crypto.Signer, notAfter time.Time) (ChainGenerator, error) {
    57  	if len(chain) < 2 {
    58  		return nil, fmt.Errorf("chain too short (%d)", len(chain))
    59  	}
    60  	leaf, err := x509.ParseCertificate(chain[0].Data)
    61  	if err != nil {
    62  		return nil, fmt.Errorf("failed to parse leaf cert: %v", err)
    63  	}
    64  	issuer, err := x509.ParseCertificate(chain[1].Data)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("failed to parse issuer cert: %v", err)
    67  	}
    68  	if notAfter.IsZero() {
    69  		notAfter = time.Now().Add(24 * time.Hour)
    70  	}
    71  	return &SyntheticChainGenerator{
    72  		chain:    chain,
    73  		leafCert: leaf,
    74  		caCert:   issuer,
    75  		signer:   signer,
    76  		notAfter: notAfter,
    77  	}, nil
    78  }
    79  
    80  // CertChain builds a new synthetic chain with a fresh leaf cert, changing SubjectKeyId and re-signing.
    81  func (g *SyntheticChainGenerator) CertChain() ([]ct.ASN1Cert, error) {
    82  	cert := *g.leafCert
    83  	cert.NotAfter = g.notAfter
    84  	chain := make([]ct.ASN1Cert, len(g.chain))
    85  	copy(chain[1:], g.chain[1:])
    86  
    87  	// Randomize the subject key ID.
    88  	randData := make([]byte, 128)
    89  	if _, err := rand.Read(randData); err != nil {
    90  		return nil, fmt.Errorf("failed to read random data: %v", err)
    91  	}
    92  	cert.SubjectKeyId = randData
    93  
    94  	// Create a fresh certificate, signed by the intermediate CA, for the leaf.
    95  	var err error
    96  	chain[0].Data, err = x509.CreateCertificate(rand.Reader, &cert, g.caCert, cert.PublicKey, g.signer)
    97  	if err != nil {
    98  		return nil, fmt.Errorf("failed to create certificate: %v", err)
    99  	}
   100  
   101  	return chain, nil
   102  }
   103  
   104  // PreCertChain builds a new synthetic precert chain; also returns the leaf TBS data.
   105  func (g *SyntheticChainGenerator) PreCertChain() ([]ct.ASN1Cert, []byte, error) {
   106  	prechain := make([]ct.ASN1Cert, len(g.chain))
   107  	copy(prechain[1:], g.chain[1:])
   108  
   109  	cert, err := x509.ParseCertificate(g.chain[0].Data)
   110  	if err != nil {
   111  		return nil, nil, fmt.Errorf("failed to parse certificate to build precert from: %v", err)
   112  	}
   113  	cert.NotAfter = g.notAfter
   114  
   115  	prechain[0].Data, err = buildNewPrecertData(cert, g.caCert, g.signer)
   116  	if err != nil {
   117  		return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
   118  	}
   119  
   120  	// For later verification, build the leaf TBS data that is included in the log.
   121  	tbs, err := buildLeafTBS(prechain[0].Data, nil)
   122  	if err != nil {
   123  		return nil, nil, fmt.Errorf("failed to build leaf TBSCertificate: %v", err)
   124  	}
   125  	return prechain, tbs, nil
   126  }
   127  
   128  // buildLeafTBS builds the raw pre-cert data (a DER-encoded TBSCertificate) that is included
   129  // in the log.
   130  func buildLeafTBS(precertData []byte, preIssuer *x509.Certificate) ([]byte, error) {
   131  	reparsed, err := x509.ParseCertificate(precertData)
   132  	if err != nil {
   133  		return nil, fmt.Errorf("failed to re-parse created precertificate: %v", err)
   134  	}
   135  	return x509.BuildPrecertTBS(reparsed.RawTBSCertificate, preIssuer)
   136  }
   137  
   138  // makePreIssuerPrecertChain builds a precert chain where the pre-cert is signed by a new
   139  // pre-issuer intermediate.
   140  func makePreIssuerPrecertChain(chain []ct.ASN1Cert, issuer *x509.Certificate, signer crypto.Signer) ([]ct.ASN1Cert, []byte, error) {
   141  	prechain := make([]ct.ASN1Cert, len(chain)+1)
   142  	copy(prechain[2:], chain[1:])
   143  
   144  	// Create a new private key and intermediate CA cert to go with it.
   145  	preSigner, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   146  	if err != nil {
   147  		return nil, nil, fmt.Errorf("failed to create pre-issuer private key: %v", err)
   148  	}
   149  
   150  	preIssuerTemplate := *issuer
   151  	preIssuerTemplate.RawSubject = nil
   152  	preIssuerTemplate.Subject.CommonName += "PrecertIssuer"
   153  	preIssuerTemplate.PublicKeyAlgorithm = x509.ECDSA
   154  	preIssuerTemplate.PublicKey = preSigner.Public()
   155  	preIssuerTemplate.ExtKeyUsage = append(preIssuerTemplate.ExtKeyUsage, x509.ExtKeyUsageCertificateTransparency)
   156  
   157  	// Set a new subject-key-id for the intermediate (to ensure it's different from the true
   158  	// issuer's subject-key-id).
   159  	randData := make([]byte, 128)
   160  	if _, err := rand.Read(randData); err != nil {
   161  		return nil, nil, fmt.Errorf("failed to read random data: %v", err)
   162  	}
   163  	preIssuerTemplate.SubjectKeyId = randData
   164  	prechain[1].Data, err = x509.CreateCertificate(rand.Reader, &preIssuerTemplate, issuer, preIssuerTemplate.PublicKey, signer)
   165  	if err != nil {
   166  		return nil, nil, fmt.Errorf("failed to create pre-issuer certificate: %v", err)
   167  	}
   168  
   169  	// Parse the pre-issuer back to a fully-populated x509.Certificate.
   170  	preIssuer, err := x509.ParseCertificate(prechain[1].Data)
   171  	if err != nil {
   172  		return nil, nil, fmt.Errorf("failed to re-parse generated pre-issuer: %v", err)
   173  	}
   174  
   175  	cert, err := x509.ParseCertificate(chain[0].Data)
   176  	if err != nil {
   177  		return nil, nil, fmt.Errorf("failed to parse certificate to build precert from: %v", err)
   178  	}
   179  
   180  	prechain[0].Data, err = buildNewPrecertData(cert, preIssuer, preSigner)
   181  	if err != nil {
   182  		return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
   183  	}
   184  
   185  	if err := verifyChain(prechain); err != nil {
   186  		return nil, nil, fmt.Errorf("failed to verify just-created prechain: %v", err)
   187  	}
   188  
   189  	// The leaf data has the poison removed and the issuance information changed.
   190  	tbs, err := buildLeafTBS(prechain[0].Data, preIssuer)
   191  	if err != nil {
   192  		return nil, nil, fmt.Errorf("failed to build leaf TBSCertificate: %v", err)
   193  	}
   194  	return prechain, tbs, nil
   195  }
   196  
   197  // verifyChain checks that a chain of certificates validates locally.
   198  func verifyChain(rawChain []ct.ASN1Cert) error {
   199  	chain := make([]*x509.Certificate, 0, len(rawChain))
   200  	for i, c := range rawChain {
   201  		cert, err := x509.ParseCertificate(c.Data)
   202  		if err != nil {
   203  			return fmt.Errorf("failed to parse rawChain[%d]: %v", i, err)
   204  		}
   205  		chain = append(chain, cert)
   206  	}
   207  
   208  	// First verify signatures cert-by-cert.
   209  	for i := 1; i < len(chain); i++ {
   210  		issuer := chain[i]
   211  		cert := chain[i-1]
   212  		if err := cert.CheckSignatureFrom(issuer); err != nil {
   213  			return fmt.Errorf("failed to check signature on rawChain[%d] using rawChain[%d]: %v", i-1, i, err)
   214  		}
   215  	}
   216  
   217  	// Now verify the chain as a whole
   218  	intermediatePool := x509.NewCertPool()
   219  	for i := 1; i < len(chain); i++ {
   220  		// Don't check path-len constraints
   221  		chain[i].MaxPathLen = -1
   222  		intermediatePool.AddCert(chain[i])
   223  	}
   224  	rootPool := x509.NewCertPool()
   225  	rootPool.AddCert(chain[len(chain)-1])
   226  	opts := x509.VerifyOptions{
   227  		Roots:             rootPool,
   228  		Intermediates:     intermediatePool,
   229  		DisableTimeChecks: true,
   230  		KeyUsages:         []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
   231  	}
   232  
   233  	chain[0].UnhandledCriticalExtensions = nil
   234  	chains, err := chain[0].Verify(opts)
   235  	if err != nil {
   236  		return fmt.Errorf("chain[0].Verify(%+v) failed: %v", opts, err)
   237  	}
   238  	if len(chains) == 0 {
   239  		return errors.New("no path to root found when trying to validate chains")
   240  	}
   241  
   242  	return nil
   243  }
   244  
   245  // SyntheticGeneratorFactory returns a function that creates per-Log ChainGenerator instances
   246  // that create synthetic certificates (details of which are specified by the arguments).
   247  func SyntheticGeneratorFactory(testDir, leafNotAfter string) (GeneratorFactory, error) {
   248  	leafChain, err := GetChain(testDir, "leaf01.chain")
   249  	if err != nil {
   250  		return nil, fmt.Errorf("failed to load certificate: %v", err)
   251  	}
   252  	signer, err := MakeSigner(testDir)
   253  	if err != nil {
   254  		return nil, fmt.Errorf("failed to retrieve signer for re-signing: %v", err)
   255  	}
   256  	var notAfterOverride time.Time
   257  	if leafNotAfter != "" {
   258  		notAfterOverride, err = time.Parse(time.RFC3339, leafNotAfter)
   259  		if err != nil {
   260  			return nil, fmt.Errorf("failed to parse leaf notAfter: %v", err)
   261  		}
   262  	}
   263  	// Build a synthetic generator for each target log.
   264  	return func(c *configpb.LogConfig) (ChainGenerator, error) {
   265  		notAfter := notAfterOverride
   266  		if notAfter.IsZero() {
   267  			var err error
   268  			notAfter, err = NotAfterForLog(c)
   269  			if err != nil {
   270  				return nil, fmt.Errorf("failed to determine notAfter for %s: %v", c.Prefix, err)
   271  			}
   272  		}
   273  		return NewSyntheticChainGenerator(leafChain, signer, notAfter)
   274  	}, nil
   275  }
   276  

View as plain text