diff options
| -rw-r--r-- | crypto.go | 4 | ||||
| -rw-r--r-- | crypto_test.go | 99 | ||||
| -rw-r--r-- | instance.go | 2 | ||||
| -rw-r--r-- | instance_test.go | 2 | ||||
| -rw-r--r-- | x509util/testdata/data.go | 27 | 
5 files changed, 129 insertions, 5 deletions
| @@ -30,8 +30,8 @@ func (lp *LogParameters) buildChainFromDerList(derChain [][]byte) ([]*x509.Certi  	if err != nil {  		return nil, fmt.Errorf("chain verification failed: %v", err)  	} -	if len(chains) == 0 { -		return nil, fmt.Errorf("bad certificate chain length: empty") +	if len(chains) == 0 { // better safe than sorry +		return nil, fmt.Errorf("chain verification failed: no path")  	}  	// there might be several valid chains diff --git a/crypto_test.go b/crypto_test.go index 577244a..b7179f3 100644 --- a/crypto_test.go +++ b/crypto_test.go @@ -7,14 +7,97 @@ import (  	"testing"  	cttestdata "github.com/google/certificate-transparency-go/trillian/testdata" +	"github.com/system-transparency/stfe/x509util" +	"github.com/system-transparency/stfe/x509util/testdata"  )  var (  	testLeaf = make([]byte, 64)  ) -// TODO: TestBuildChainFromDerList  func TestBuildChainFromDerList(t *testing.T) { +	for _, table := range []struct { +		description string +		maxChain    int64    // including trust anchor +		anchors     []byte   // pem block +		chain       [][]byte // der list +		wantErr     bool +	}{ +		{ +			description: "bad chain: cannot be parsed because empty", +			maxChain:    3, +			anchors:     testdata.RootCertificate, +			wantErr:     true, +		}, +		{ +			description: "bad chain: no path from end-entity to intermediate", +			maxChain:    3, +			anchors:     testdata.RootCertificate2, +			chain:       mustMakeDerList(t, testdata.ChainBadIntermediate)[:2], +			wantErr:     true, +		}, +		{ +			description: "bad chain: no path from intermediate to root", +			maxChain:    3, +			anchors:     testdata.RootCertificate2, +			chain:       mustMakeDerList(t, testdata.IntermediateChain), +			wantErr:     true, +		}, +		{ +			description: "bad chain: end-entity certificate expired", +			maxChain:    3, +			anchors:     testdata.RootCertificate, +			chain:       mustMakeDerList(t, testdata.ExpiredChain), +		}, +		{ +			description: "bad chain: too large", +			maxChain:    2, +			anchors:     testdata.RootCertificate, +			chain:       mustMakeDerList(t, testdata.IntermediateChain), +			wantErr:     true, +		}, +		{ +			description: "ok chain: one explicit trust anchor", +			maxChain:    3, +			anchors:     testdata.RootCertificate, +			chain:       mustMakeDerList(t, testdata.RootChain), +		}, +		{ +			description: "ok chain: unnecessary certificates are ignored", +			maxChain:    3, +			anchors:     testdata.RootCertificate, +			chain:       append(mustMakeDerList(t, testdata.IntermediateChain), mustMakeDerList(t, testdata.IntermediateChain2)...), +		}, +		{ +			description: "ok chain: multiple anchors but one valid path", +			maxChain:    3, +			anchors:     testdata.TrustAnchors, +			chain:       mustMakeDerList(t, testdata.IntermediateChain), +		}, +		// Note that the underlying verify function also checks name constraints +		// and extended key usages.  Not relied upon atm, so not tested. +	} { +		anchorList, err := x509util.NewCertificateList(table.anchors) +		if err != nil { +			t.Fatalf("must parse trust anchors: %v", err) +		} +		lp := &LogParameters{ +			LogId:      testLogId, +			TreeId:     testTreeId, +			Prefix:     testPrefix, +			MaxRange:   testMaxRange, +			MaxChain:   table.maxChain, +			AnchorPool: x509util.NewCertPool(anchorList), +			AnchorList: anchorList, +			KeyUsage:   testExtKeyUsage, +			Signer:     nil, +			HashType:   testHashType, +		} +		_, err = lp.buildChainFromDerList(table.chain) +		if got, want := err != nil, table.wantErr; got != want { +			t.Errorf("got error=%v but wanted %v in test %q: %v", got, want, table.description, err) +		} +	}  }  // TODO: TestVerifySignature @@ -133,3 +216,17 @@ func TestGenV1Sth(t *testing.T) {  }  // TODO: test that metrics are updated correctly? + +// mustMakeDerList must parse a PEM-encoded list of certificates to DER +func mustMakeDerList(t *testing.T, pem []byte) [][]byte { +	certs, err := x509util.NewCertificateList(pem) +	if err != nil { +		t.Fatalf("must parse pem-encoded certificates: %v", err) +	} + +	list := make([][]byte, 0, len(certs)) +	for _, cert := range certs { +		list = append(list, cert.Raw) +	} +	return list +} diff --git a/instance.go b/instance.go index 6732698..510c7ae 100644 --- a/instance.go +++ b/instance.go @@ -92,7 +92,7 @@ func NewLogParameters(treeId int64, prefix string, anchorPath, keyPath string, m  		MaxChain:   maxChain,  		AnchorPool: anchorPool,  		AnchorList: anchorList, -		KeyUsage:   []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, +		KeyUsage:   []x509.ExtKeyUsage{}, // placeholder, must be tested if used  		Signer:     key,  		HashType:   crypto.SHA256,  	}, nil diff --git a/instance_test.go b/instance_test.go index 40a0c57..f4a8fea 100644 --- a/instance_test.go +++ b/instance_test.go @@ -17,7 +17,7 @@ var (  	testTreeId      = int64(0)  	testPrefix      = "/test"  	testHashType    = crypto.SHA256 -	testExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} +	testExtKeyUsage = []x509.ExtKeyUsage{}  )  func makeTestLogParameters(t *testing.T, signer crypto.Signer) *LogParameters { diff --git a/x509util/testdata/data.go b/x509util/testdata/data.go index a1febdc..46f4ab5 100644 --- a/x509util/testdata/data.go +++ b/x509util/testdata/data.go @@ -154,6 +154,33 @@ MC4CAQAwBQYDK2VwBCIEIKQd3B84w9pB6zJLGljuDyGKfz9uPP6QBeLiFcw0EME4  		IntermediateCertificate2,  		RootCertificate2,  	}, []byte("\n")) +	 +	// TrustAnchors is composed of two PEM-encoded trust anchors, namely, +	// RootCertificate and RootCertificate2. +	TrustAnchors = bytes.Join([][]byte{ +		RootCertificate, +		RootCertificate2, +	}, []byte("\n")) + +	// ExpiredCertificate is a PEM-encoded certificate that is always expired, +	// i.e., `Not Before`=`Not After`.  It is signed by IntermediateCertificate. +	ExpiredCertificate = []byte(` +-----BEGIN CERTIFICATE----- +MIIBbDCCAR4CFDfeuu6XURfn7AE4WShuwZBHEaLIMAUGAytlcDBsMQswCQYDVQQG +EwJOQTELMAkGA1UECAwCTkExCzAJBgNVBAcMAk5BMQswCQYDVQQKDAJOQTELMAkG +A1UECwwCTkExFjAUBgNVBAMMDXN0ZmUgdGVzdGRhdGExETAPBgkqhkiG9w0BCQEW +Ak5BMB4XDTIwMTEwMzE4MzI0MFoXDTMyMDEyMTE4MzI0MFowRTELMAkGA1UEBhMC +QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp +dHMgUHR5IEx0ZDAqMAUGAytlcAMhAJvk390ZvwULplBri03Od4LLz+Sf/OUHu+20 +wik+T9y5MAUGAytlcANBANekliXq4ttoClBJDZoktIQxyHHNcWyXFrj1HlOaT5bC +I3GIqqZ60Ua3jKytnEsKsD2rLMPItDwmG6wYSecy2ws= +-----END CERTIFICATE-----`) +	// ExpiredChain is an expired PEM-encoded certificate chain.  It is composed +	// of two certificates: ExpiredCertificate and IntermediateCertificate. +	ExpiredChain = bytes.Join([][]byte{ +		ExpiredCertificate, +		IntermediateCertificate, +	}, []byte("\n"))  	// ChainBadIntermediate is a PEM-encoded certificate chain that contains  	// an end-entity certificate, an intermediate certificate, and a root | 
