2018-07-09 18:43:13 +01:00
|
|
|
// 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"
|
|
|
|
)
|
|
|
|
|
2018-08-23 15:08:26 +01:00
|
|
|
func TestNewCert_CA(t *testing.T) {
|
2018-12-07 13:44:25 +00:00
|
|
|
caKey, err := NewKey()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
assert.NotEmpty(t, caKey.(*ecdsa.PrivateKey))
|
|
|
|
assert.NotEmpty(t, caCert)
|
|
|
|
assert.NotEmpty(t, caCert.PublicKey.(*ecdsa.PublicKey))
|
2018-07-09 18:43:13 +01:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = caCert.CheckSignatureFrom(caCert)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2018-08-23 15:08:26 +01:00
|
|
|
func TestNewCert_Leaf(t *testing.T) {
|
2018-12-07 13:44:25 +00:00
|
|
|
caKey, err := NewKey()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafKey, err := NewKey()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := LeafTemplate()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
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))
|
2018-07-09 18:43:13 +01:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = caCert.CheckSignatureFrom(caCert)
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
err = leafCert.CheckSignatureFrom(caCert)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2018-08-13 09:39:45 +01:00
|
|
|
func TestVerifyPeerFunc(t *testing.T) {
|
2018-12-07 13:44:25 +00:00
|
|
|
caKey, err := NewKey()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafKey, err := NewKey()
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := LeafTemplate()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
|
2018-07-09 18:43:13 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-08-13 09:39:45 +01:00
|
|
|
testFunc := func(chain [][]byte, parsedChains [][]*x509.Certificate) error {
|
|
|
|
switch {
|
2018-12-07 13:44:25 +00:00
|
|
|
case !bytes.Equal(chain[1], caCert.Raw):
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("CA cert doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case !bytes.Equal(chain[0], leafCert.Raw):
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("leaf's CA cert doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case leafCert.PublicKey.(*ecdsa.PublicKey).Curve != parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).Curve:
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("leaf public key doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case leafCert.PublicKey.(*ecdsa.PublicKey).X.Cmp(parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).X) != 0:
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("leaf public key doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case leafCert.PublicKey.(*ecdsa.PublicKey).Y.Cmp(parsedChains[0][0].PublicKey.(*ecdsa.PublicKey).Y) != 0:
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("leaf public key doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case !bytes.Equal(parsedChains[0][1].Raw, caCert.Raw):
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("parsed CA cert doesn't match")
|
2018-12-07 13:44:25 +00:00
|
|
|
case !bytes.Equal(parsedChains[0][0].Raw, leafCert.Raw):
|
2018-08-13 09:39:45 +01:00
|
|
|
return errs.New("parsed leaf cert doesn't match")
|
|
|
|
}
|
|
|
|
return nil
|
2018-07-09 18:43:13 +01:00
|
|
|
}
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = VerifyPeerFunc(testFunc)([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
2018-07-09 18:43:13 +01:00
|
|
|
}
|
2018-08-23 15:08:26 +01:00
|
|
|
|
|
|
|
func TestVerifyPeerCertChains(t *testing.T) {
|
2018-12-07 13:44:25 +00:00
|
|
|
caKey, err := NewKey()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafKey, err := NewKey()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := LeafTemplate()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
2018-10-26 14:52:37 +01:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = VerifyPeerFunc(VerifyPeerCertChains)([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
wrongKey, err := NewKey()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafCert, err = NewCert(leafKey, wrongKey, leafTemplate, caCert)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = VerifyPeerFunc(VerifyPeerCertChains)([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.True(t, ErrVerifyPeerCert.Has(err))
|
|
|
|
assert.True(t, ErrVerifyCertificateChain.Has(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVerifyCAWhitelist(t *testing.T) {
|
2018-12-07 13:44:25 +00:00
|
|
|
caKey, err := NewKey()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafKey, err := NewKey()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := LeafTemplate()
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// empty whitelist
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist(nil))([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// whitelist contains ca
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
rootKey, err := NewKey()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
rootTemplate, err := CATemplate()
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
rootCert, err := NewCert(rootKey, nil, rootTemplate, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// no valid signed extension, non-empty whitelist
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{rootCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.True(t, ErrVerifyCAWhitelist.Has(err))
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// last cert in whitelist is signer
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{rootCert, caCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// first cert in whitelist is signer
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert, rootCert}))([][]byte{leafCert.Raw, caCert.Raw}, nil)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
ca2Cert, err := NewCert(caKey, rootKey, caTemplate, rootCert)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leaf2Cert, err := NewCert(leafKey, caKey, leafTemplate, ca2Cert)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// 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)
|
2018-11-01 15:48:43 +00:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
// length 3 chain; last cert in whitelist is signer
|
|
|
|
err = VerifyPeerFunc(VerifyCAWhitelist([]*x509.Certificate{caCert, rootCert}))([][]byte{leaf2Cert.Raw, ca2Cert.Raw, rootCert.Raw}, nil)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
}
|
2018-11-01 15:48:43 +00:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
func TestSignLeafExt(t *testing.T) {
|
|
|
|
caKey, err := NewKey()
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := CATemplate()
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caCert, err := NewCert(caKey, nil, caTemplate, nil)
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafKey, err := NewKey()
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := LeafTemplate()
|
2018-11-01 15:48:43 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafCert, err := NewCert(leafKey, caKey, leafTemplate, caCert)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
err = AddSignedLeafExt(caKey, leafCert)
|
2018-10-26 14:52:37 +01:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-08-23 15:08:26 +01:00
|
|
|
}
|