storj/pkg/peertls/peertls_test.go
2018-12-07 14:44:25 +01:00

296 lines
7.9 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package peertls
import (
"bytes"
"crypto/ecdsa"
"crypto/x509"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeebo/errs"
)
func TestNewCert_CA(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
assert.NotEmpty(t, caKey.(*ecdsa.PrivateKey))
assert.NotEmpty(t, caCert)
assert.NotEmpty(t, caCert.PublicKey.(*ecdsa.PublicKey))
err = caCert.CheckSignatureFrom(caCert)
assert.NoError(t, err)
}
func TestNewCert_Leaf(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
assert.NoError(t, err)
assert.NotEmpty(t, caKey.(*ecdsa.PrivateKey))
assert.NotEmpty(t, leafCert)
assert.NotEmpty(t, leafCert.PublicKey.(*ecdsa.PublicKey))
err = caCert.CheckSignatureFrom(caCert)
assert.NoError(t, err)
err = leafCert.CheckSignatureFrom(caCert)
assert.NoError(t, err)
}
func TestVerifyPeerFunc(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
assert.NoError(t, err)
testFunc := func(chain [][]byte, parsedChains [][]*x509.Certificate) error {
switch {
case !bytes.Equal(chain[1], caCert.Raw):
return errs.New("CA cert doesn't match")
case !bytes.Equal(chain[0], leafCert.Raw):
return errs.New("leaf's CA cert doesn't match")
case leafCert.PublicKey.(*ecdsa.PublicKey).Curve != parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).Curve:
return errs.New("leaf public key doesn't match")
case leafCert.PublicKey.(*ecdsa.PublicKey).X.Cmp(parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).X) != 0:
return errs.New("leaf public key doesn't match")
case leafCert.PublicKey.(*ecdsa.PublicKey).Y.Cmp(parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).Y) != 0:
return errs.New("leaf public key doesn't match")
case !bytes.Equal(parsedChains[0][1].Raw, caCert.Raw):
return errs.New("parsed CA cert doesn't match")
case !bytes.Equal(parsedChains[0][0].Raw, leafCert.Raw):
return errs.New("parsed leaf cert doesn't match")
}
return nil
}
err = VerifyPeerFunc(testFunc)([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
}
func TestVerifyPeerCertChains(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
assert.NoError(t, err)
err = VerifyPeerFunc(VerifyPeerCertChains)([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
wrongKey, err := NewKey()
assert.NoError(t, err)
leafCert, err = NewCert(leafKey, wrongKey, leafTemplate, caCert)
assert.NoError(t, err)
err = VerifyPeerFunc(VerifyPeerCertChains)([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.True(t, ErrVerifyPeerCert.Has(err))
assert.True(t, ErrVerifyCertificateChain.Has(err))
}
func TestVerifyCAWhitelist(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
assert.NoError(t, err)
// empty whitelist
err = VerifyPeerFunc(VerifyCAWhitelist(nil))([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
// whitelist contains ca
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
rootKey, err := NewKey()
assert.NoError(t, err)
rootTemplate, err := CATemplate()
assert.NoError(t, err)
rootCert, err := NewCert(rootKey, nil, rootTemplate, nil)
assert.NoError(t, err)
// no valid signed extension, non-empty whitelist
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{rootCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.True(t, ErrVerifyCAWhitelist.Has(err))
// last cert in whitelist is signer
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{rootCert, caCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
// first cert in whitelist is signer
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert, rootCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
assert.NoError(t, err)
ca2Cert, err := NewCert(caKey, rootKey, caTemplate, rootCert)
assert.NoError(t, err)
leaf2Cert, err := NewCert(leafKey, caKey, leafTemplate, ca2Cert)
assert.NoError(t, err)
// length 3 chain; first cert in whitelist is signer
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{rootCert, caCert}))([][]byte{leaf2Cert.Raw, ca2Cert.Raw, rootCert.Raw}, nil)
assert.NoError(t, err)
// length 3 chain; last cert in whitelist is signer
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert, rootCert}))([][]byte{leaf2Cert.Raw, ca2Cert.Raw, rootCert.Raw}, nil)
assert.NoError(t, err)
}
func TestSignLeafExt(t *testing.T) {
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
caCert, err := NewCert(caKey, nil, caTemplate, nil)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
assert.NoError(t, err)
err = AddSignedLeafExt(caKey, leafCert)
assert.NoError(t, err)
assert.Equal(t, 1, len(leafCert.ExtraExtensions))
assert.True(t, ExtensionIDs[SignedCertExtID].Equal(leafCert.ExtraExtensions[0].Id))
caECKey, ok := caKey.(*ecdsa.PrivateKey)
if !assert.True(t, ok) {
t.FailNow()
}
err = VerifySignature(leafCert.ExtraExtensions[0].Value, leafCert.RawTBSCertificate, &caECKey.PublicKey)
assert.NoError(t, err)
}
func TestParseExtensions(t *testing.T) {
type result struct {
ok bool
err error
}
rootKey, err := NewKey()
assert.NoError(t, err)
caKey, err := NewKey()
assert.NoError(t, err)
caTemplate, err := CATemplate()
assert.NoError(t, err)
rootCert, err := NewCert(rootKey, nil, caTemplate, nil)
assert.NoError(t, err)
caCert, err := NewCert(caKey, rootKey, caTemplate, rootCert)
assert.NoError(t, err)
leafKey, err := NewKey()
assert.NoError(t, err)
leafTemplate, err := LeafTemplate()
assert.NoError(t, err)
leafCert, err := NewCert(leafKey, rootKey, leafTemplate, caCert)
assert.NoError(t, err)
err = AddSignedLeafExt(rootKey, leafCert)
assert.NoError(t, err)
whitelist := []*x509.Certificate{rootCert}
cases := []struct {
testID string
config TLSExtConfig
whitelist []*x509.Certificate
expected []result
}{
{
"leaf whitelist signature",
TLSExtConfig{WhitelistSignedLeaf: true},
whitelist,
[]result{{true, nil}},
},
}
for _, c := range cases {
t.Run(c.testID, func(t *testing.T) {
exts := ParseExtensions(c.config, c.whitelist)
assert.Equal(t, 1, len(exts))
for i, e := range exts {
ok, err := e.f(leafCert.ExtraExtensions[0], [][]*x509.Certificate{{leafCert, caCert, rootCert}})
assert.Equal(t, c.expected[i].err, err)
assert.Equal(t, c.expected[i].ok, ok)
}
})
}
}