2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-08-13 09:39:45 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
2019-04-03 16:03:53 +01:00
|
|
|
package identity_test
|
2018-08-13 09:39:45 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-04-03 16:03:53 +01:00
|
|
|
"crypto/x509/pkix"
|
|
|
|
"encoding/asn1"
|
2018-12-17 15:09:52 +00:00
|
|
|
"fmt"
|
2019-04-03 16:03:53 +01:00
|
|
|
"math/rand"
|
2018-08-13 09:39:45 +01:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2019-04-03 16:03:53 +01:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-01-02 17:39:17 +00:00
|
|
|
|
|
|
|
"storj.io/storj/internal/testcontext"
|
2019-04-03 16:03:53 +01:00
|
|
|
"storj.io/storj/internal/testidentity"
|
|
|
|
"storj.io/storj/pkg/identity"
|
|
|
|
"storj.io/storj/pkg/peertls/extensions"
|
|
|
|
"storj.io/storj/pkg/peertls/tlsopts"
|
2019-04-08 19:15:19 +01:00
|
|
|
"storj.io/storj/pkg/storj"
|
2018-08-13 09:39:45 +01:00
|
|
|
)
|
|
|
|
|
2018-08-23 15:08:26 +01:00
|
|
|
func TestNewCA(t *testing.T) {
|
2018-12-17 15:09:52 +00:00
|
|
|
const expectedDifficulty = 4
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2019-04-08 19:15:19 +01:00
|
|
|
for _, version := range storj.IDVersions {
|
|
|
|
ca, err := identity.NewCA(context.Background(), identity.NewCAOptions{
|
|
|
|
VersionNumber: version.Number,
|
|
|
|
Difficulty: expectedDifficulty,
|
|
|
|
Concurrency: 4,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, ca)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2019-04-08 19:15:19 +01:00
|
|
|
assert.Equal(t, version.Number, ca.ID.Version().Number)
|
|
|
|
|
|
|
|
caVersion, err := ca.Version()
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, version.Number, caVersion.Number)
|
|
|
|
|
|
|
|
actualDifficulty, err := ca.ID.Difficulty()
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, actualDifficulty >= expectedDifficulty)
|
|
|
|
}
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
2018-08-27 23:23:48 +01:00
|
|
|
func TestFullCertificateAuthority_NewIdentity(t *testing.T) {
|
2019-01-02 17:39:17 +00:00
|
|
|
ctx := testcontext.New(t)
|
2019-04-03 16:03:53 +01:00
|
|
|
ca, err := identity.NewCA(ctx, identity.NewCAOptions{
|
2018-12-17 15:09:52 +00:00
|
|
|
Difficulty: 12,
|
|
|
|
Concurrency: 4,
|
|
|
|
})
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, ca)
|
2018-08-27 23:23:48 +01:00
|
|
|
|
|
|
|
fi, err := ca.NewIdentity()
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, fi)
|
2018-08-27 23:23:48 +01:00
|
|
|
|
|
|
|
assert.Equal(t, ca.Cert, fi.CA)
|
|
|
|
assert.Equal(t, ca.ID, fi.ID)
|
|
|
|
assert.NotEqual(t, ca.Key, fi.Key)
|
|
|
|
assert.NotEqual(t, ca.Cert, fi.Leaf)
|
|
|
|
|
|
|
|
err = fi.Leaf.CheckSignatureFrom(ca.Cert)
|
|
|
|
assert.NoError(t, err)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
2019-01-02 17:39:17 +00:00
|
|
|
func TestFullCertificateAuthority_Sign(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
2019-04-03 16:03:53 +01:00
|
|
|
caOpts := identity.NewCAOptions{
|
2019-01-02 17:39:17 +00:00
|
|
|
Difficulty: 12,
|
|
|
|
Concurrency: 4,
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:03:53 +01:00
|
|
|
ca, err := identity.NewCA(ctx, caOpts)
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, ca)
|
2019-01-02 17:39:17 +00:00
|
|
|
|
2019-04-03 16:03:53 +01:00
|
|
|
toSign, err := identity.NewCA(ctx, caOpts)
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, toSign)
|
2019-01-02 17:39:17 +00:00
|
|
|
|
|
|
|
signed, err := ca.Sign(toSign.Cert)
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, signed)
|
2019-01-02 17:39:17 +00:00
|
|
|
|
|
|
|
assert.Equal(t, toSign.Cert.RawTBSCertificate, signed.RawTBSCertificate)
|
|
|
|
assert.NotEqual(t, toSign.Cert.Signature, signed.Signature)
|
|
|
|
assert.NotEqual(t, toSign.Cert.Raw, signed.Raw)
|
|
|
|
|
|
|
|
err = signed.CheckSignatureFrom(ca.Cert)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2018-12-18 11:55:55 +00:00
|
|
|
func TestFullCAConfig_Save(t *testing.T) {
|
|
|
|
// TODO(bryanchriswhite): test with both
|
|
|
|
// TODO(bryanchriswhite): test with only cert path
|
|
|
|
// TODO(bryanchriswhite): test with only key path
|
|
|
|
t.SkipNow()
|
|
|
|
}
|
|
|
|
|
2019-04-08 19:15:19 +01:00
|
|
|
func TestFullCAConfig_Load_extensions(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
for versionNumber, version := range storj.IDVersions {
|
|
|
|
caCfg := identity.CASetupConfig{
|
|
|
|
VersionNumber: uint(versionNumber),
|
|
|
|
CertPath: ctx.File("ca.cert"),
|
|
|
|
KeyPath: ctx.File("ca.key"),
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ca, err := caCfg.Create(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
caVersion, err := ca.Version()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, version.Number, caVersion.Number)
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ca, err := caCfg.FullConfig().Load()
|
|
|
|
require.NoError(t, err)
|
|
|
|
caVersion, err := ca.Version()
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, version.Number, caVersion.Number)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
func BenchmarkNewCA(b *testing.B) {
|
|
|
|
ctx := context.Background()
|
|
|
|
for _, difficulty := range []uint16{8, 12} {
|
2019-05-29 14:30:16 +01:00
|
|
|
testDifficulty := difficulty
|
|
|
|
for _, testConcurrency := range []uint{1, 2, 5, 10} {
|
|
|
|
concurrency := testConcurrency
|
|
|
|
test := fmt.Sprintf("%d/%d", testDifficulty, concurrency)
|
2018-12-17 15:09:52 +00:00
|
|
|
b.Run(test, func(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
2019-04-03 16:03:53 +01:00
|
|
|
_, _ = identity.NewCA(ctx, identity.NewCAOptions{
|
2019-05-29 14:30:16 +01:00
|
|
|
Difficulty: testDifficulty,
|
2018-12-17 15:09:52 +00:00
|
|
|
Concurrency: concurrency,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-03 16:03:53 +01:00
|
|
|
|
|
|
|
func TestFullCertificateAuthority_AddExtension(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
ca, err := testidentity.NewTestCA(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
oldCert := ca.Cert
|
|
|
|
assert.Len(t, ca.Cert.ExtraExtensions, 0)
|
|
|
|
|
|
|
|
randBytes := make([]byte, 10)
|
|
|
|
rand.Read(randBytes)
|
|
|
|
randExt := pkix.Extension{
|
|
|
|
Id: asn1.ObjectIdentifier{2, 999, int(randBytes[0])},
|
|
|
|
Value: randBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ca.AddExtension(randExt)
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
2019-04-03 16:03:53 +01:00
|
|
|
|
|
|
|
assert.Len(t, ca.Cert.ExtraExtensions, 0)
|
|
|
|
assert.Len(t, ca.Cert.Extensions, len(oldCert.Extensions)+1)
|
|
|
|
|
|
|
|
assert.Equal(t, oldCert.SerialNumber, ca.Cert.SerialNumber)
|
|
|
|
assert.Equal(t, oldCert.IsCA, ca.Cert.IsCA)
|
|
|
|
assert.Equal(t, oldCert.PublicKey, ca.Cert.PublicKey)
|
|
|
|
assert.Equal(t, randExt, tlsopts.NewExtensionsMap(ca.Cert)[randExt.Id.String()])
|
|
|
|
|
|
|
|
assert.NotEqual(t, oldCert.Raw, ca.Cert.Raw)
|
|
|
|
assert.NotEqual(t, oldCert.RawTBSCertificate, ca.Cert.RawTBSCertificate)
|
|
|
|
assert.NotEqual(t, oldCert.Signature, ca.Cert.Signature)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFullCertificateAuthority_Revoke(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
ca, err := testidentity.NewTestCA(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
oldCert := ca.Cert
|
|
|
|
assert.Len(t, ca.Cert.ExtraExtensions, 0)
|
|
|
|
|
|
|
|
err = ca.Revoke()
|
2019-04-08 19:15:19 +01:00
|
|
|
require.NoError(t, err)
|
2019-04-03 16:03:53 +01:00
|
|
|
|
|
|
|
assert.Len(t, ca.Cert.ExtraExtensions, 0)
|
|
|
|
assert.Len(t, ca.Cert.Extensions, len(oldCert.Extensions)+1)
|
|
|
|
|
|
|
|
assert.Equal(t, oldCert.SerialNumber, ca.Cert.SerialNumber)
|
|
|
|
assert.Equal(t, oldCert.IsCA, ca.Cert.IsCA)
|
|
|
|
assert.Equal(t, oldCert.PublicKey, ca.Cert.PublicKey)
|
|
|
|
|
|
|
|
assert.NotEqual(t, oldCert.Raw, ca.Cert.Raw)
|
|
|
|
assert.NotEqual(t, oldCert.RawTBSCertificate, ca.Cert.RawTBSCertificate)
|
|
|
|
assert.NotEqual(t, oldCert.Signature, ca.Cert.Signature)
|
|
|
|
|
|
|
|
revocationExt := tlsopts.NewExtensionsMap(ca.Cert)[extensions.RevocationExtID.String()]
|
|
|
|
assert.True(t, extensions.RevocationExtID.Equal(revocationExt.Id))
|
|
|
|
|
|
|
|
var rev extensions.Revocation
|
|
|
|
err = rev.Unmarshal(revocationExt.Value)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = rev.Verify(ca.Cert)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|