aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto.go4
-rw-r--r--crypto_test.go99
-rw-r--r--instance.go2
-rw-r--r--instance_test.go2
-rw-r--r--x509util/testdata/data.go27
5 files changed, 129 insertions, 5 deletions
diff --git a/crypto.go b/crypto.go
index 47c16bb..34451cc 100644
--- a/crypto.go
+++ b/crypto.go
@@ -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