2019-12-18 15:08:54 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package revocation_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/x509"
|
2022-10-11 12:39:08 +01:00
|
|
|
"os"
|
2019-12-18 15:08:54 +00:00
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/identity"
|
|
|
|
"storj.io/common/identity/testidentity"
|
|
|
|
"storj.io/common/peertls"
|
|
|
|
"storj.io/common/peertls/extensions"
|
|
|
|
"storj.io/common/peertls/testpeertls"
|
|
|
|
"storj.io/common/peertls/tlsopts"
|
|
|
|
"storj.io/common/storj"
|
|
|
|
"storj.io/common/testcontext"
|
2023-04-06 14:54:41 +01:00
|
|
|
"storj.io/storj/private/kvstore"
|
2021-04-23 14:13:51 +01:00
|
|
|
"storj.io/storj/private/revocation"
|
2019-12-18 15:08:54 +00:00
|
|
|
"storj.io/storj/private/testrevocation"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestNewOptions(t *testing.T) {
|
|
|
|
// TODO: this is not a great test...
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
fi, err := testidentity.PregeneratedIdentity(0, storj.LatestIDVersion())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
whitelistPath := ctx.File("whitelist.pem")
|
|
|
|
|
|
|
|
chainData, err := peertls.ChainBytes(fi.CA)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2022-10-11 12:39:08 +01:00
|
|
|
err = os.WriteFile(whitelistPath, chainData, 0644)
|
2019-12-18 15:08:54 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
testID string
|
|
|
|
config tlsopts.Config
|
|
|
|
clientVerificationFuncsLen int
|
|
|
|
serverVerificationFuncsLen int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"default",
|
|
|
|
tlsopts.Config{},
|
|
|
|
1, 1,
|
|
|
|
}, {
|
|
|
|
"revocation processing",
|
|
|
|
tlsopts.Config{
|
|
|
|
RevocationDBURL: "bolt://" + ctx.File("revocation1.db"),
|
|
|
|
Extensions: extensions.Config{
|
|
|
|
Revocation: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
1, 1,
|
|
|
|
}, {
|
|
|
|
"ca whitelist verification",
|
|
|
|
tlsopts.Config{
|
|
|
|
PeerCAWhitelistPath: whitelistPath,
|
|
|
|
UsePeerCAWhitelist: true,
|
|
|
|
},
|
|
|
|
2, 1,
|
|
|
|
}, {
|
|
|
|
"ca whitelist verification and whitelist signed leaf verification",
|
|
|
|
tlsopts.Config{
|
|
|
|
// NB: file doesn't actually exist
|
|
|
|
PeerCAWhitelistPath: whitelistPath,
|
|
|
|
UsePeerCAWhitelist: true,
|
|
|
|
Extensions: extensions.Config{
|
|
|
|
WhitelistSignedLeaf: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
2, 1,
|
|
|
|
}, {
|
|
|
|
"revocation processing and whitelist verification",
|
|
|
|
tlsopts.Config{
|
|
|
|
// NB: file doesn't actually exist
|
|
|
|
PeerCAWhitelistPath: whitelistPath,
|
|
|
|
UsePeerCAWhitelist: true,
|
|
|
|
RevocationDBURL: "bolt://" + ctx.File("revocation2.db"),
|
|
|
|
Extensions: extensions.Config{
|
|
|
|
Revocation: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
2, 1,
|
|
|
|
}, {
|
|
|
|
"revocation processing, whitelist, and signed leaf verification",
|
|
|
|
tlsopts.Config{
|
|
|
|
// NB: file doesn't actually exist
|
|
|
|
PeerCAWhitelistPath: whitelistPath,
|
|
|
|
UsePeerCAWhitelist: true,
|
|
|
|
RevocationDBURL: "bolt://" + ctx.File("revocation3.db"),
|
|
|
|
Extensions: extensions.Config{
|
|
|
|
Revocation: true,
|
|
|
|
WhitelistSignedLeaf: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
2, 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Log(c.testID)
|
|
|
|
|
2020-10-28 14:01:41 +00:00
|
|
|
revocationDB, err := revocation.OpenDBFromCfg(ctx, c.config)
|
2019-12-18 15:08:54 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tlsOptions, err := tlsopts.NewOptions(fi, c.config, revocationDB)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, reflect.DeepEqual(fi, tlsOptions.Ident))
|
|
|
|
assert.Equal(t, c.config, tlsOptions.Config)
|
|
|
|
assert.Len(t, tlsOptions.VerificationFuncs.Client(), c.clientVerificationFuncsLen)
|
|
|
|
assert.Len(t, tlsOptions.VerificationFuncs.Server(), c.serverVerificationFuncsLen)
|
|
|
|
|
|
|
|
require.NoError(t, revocationDB.Close())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestExtensionMap_HandleExtensions(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
testidentity.IdentityVersionsTest(t, func(t *testing.T, version storj.IDVersion, _ *identity.FullIdentity) {
|
|
|
|
keys, originalChain, err := testpeertls.NewCertChain(2, version.Number)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
rev := new(extensions.Revocation)
|
|
|
|
|
|
|
|
oldRevokedLeafChain, revocationExt, err := testpeertls.RevokeLeaf(keys[peertls.CAIndex], originalChain)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = rev.Unmarshal(revocationExt.Value)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = rev.Verify(oldRevokedLeafChain[peertls.CAIndex])
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// NB: node ID is the same, timestamp must change
|
|
|
|
// (see: identity.RevocationDB#Put)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
newRevokedLeafChain, revocationExt, err := testpeertls.RevokeLeaf(keys[peertls.CAIndex], oldRevokedLeafChain)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = rev.Unmarshal(revocationExt.Value)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = rev.Verify(newRevokedLeafChain[peertls.CAIndex])
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-04-06 14:54:41 +01:00
|
|
|
testrevocation.RunDBs(t, func(t *testing.T, revDB extensions.RevocationDB, db kvstore.Store) {
|
2019-12-18 15:08:54 +00:00
|
|
|
opts := &extensions.Options{
|
|
|
|
RevocationDB: revDB,
|
|
|
|
PeerIDVersions: "*",
|
|
|
|
}
|
|
|
|
|
|
|
|
testcases := []struct {
|
|
|
|
name string
|
|
|
|
chain []*x509.Certificate
|
|
|
|
}{
|
|
|
|
{"no extensions", originalChain},
|
|
|
|
{"leaf revocation", oldRevokedLeafChain},
|
|
|
|
{"double leaf revocation", newRevokedLeafChain},
|
|
|
|
// TODO: more and more diverse extensions in cases
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
handlerFuncMap := extensions.DefaultHandlers.WithOptions(opts)
|
|
|
|
for _, testcase := range testcases {
|
|
|
|
t.Log(testcase.name)
|
|
|
|
extensionsMap := tlsopts.NewExtensionsMap(testcase.chain...)
|
|
|
|
err := extensionsMap.HandleExtensions(handlerFuncMap, identity.ToChains(testcase.chain))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExtensionMap_HandleExtensions_error(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
2023-04-06 14:54:41 +01:00
|
|
|
testrevocation.RunDBs(t, func(t *testing.T, revDB extensions.RevocationDB, db kvstore.Store) {
|
2019-12-18 15:08:54 +00:00
|
|
|
keys, chain, oldRevocation, err := testpeertls.NewRevokedLeafChain()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// NB: node ID is the same, timestamp must change
|
|
|
|
// (see: identity.RevocationDB#Put)
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
_, newRevocation, err := testpeertls.RevokeLeaf(keys[peertls.CAIndex], chain)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.NotEqual(t, oldRevocation, newRevocation)
|
|
|
|
|
|
|
|
err = revDB.Put(ctx, chain, newRevocation)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
opts := &extensions.Options{RevocationDB: revDB}
|
|
|
|
handlerFuncMap := extensions.HandlerFactories{
|
|
|
|
extensions.RevocationUpdateHandler,
|
|
|
|
}.WithOptions(opts)
|
|
|
|
extensionsMap := tlsopts.NewExtensionsMap(chain[peertls.LeafIndex])
|
|
|
|
|
|
|
|
assert.Equal(t, oldRevocation, extensionsMap[extensions.RevocationExtID.String()])
|
|
|
|
|
|
|
|
err = extensionsMap.HandleExtensions(handlerFuncMap, identity.ToChains(chain))
|
|
|
|
assert.Errorf(t, err, extensions.ErrRevocationTimestamp.Error())
|
|
|
|
})
|
|
|
|
}
|