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-01-02 10:23:25 +00:00
|
|
|
package identity_test
|
2018-08-13 09:39:45 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-08-23 15:08:26 +01:00
|
|
|
"context"
|
2019-04-03 16:03:53 +01:00
|
|
|
"crypto/rand"
|
|
|
|
"crypto/x509/pkix"
|
|
|
|
"encoding/asn1"
|
2018-08-13 09:39:45 +01:00
|
|
|
"os"
|
2018-08-23 08:05:56 +01:00
|
|
|
"runtime"
|
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"
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
"storj.io/storj/internal/testcontext"
|
2019-04-03 16:03:53 +01:00
|
|
|
"storj.io/storj/internal/testidentity"
|
2019-01-02 10:23:25 +00:00
|
|
|
"storj.io/storj/pkg/identity"
|
2018-08-13 09:39:45 +01:00
|
|
|
"storj.io/storj/pkg/peertls"
|
2019-04-03 16:03:53 +01:00
|
|
|
"storj.io/storj/pkg/peertls/extensions"
|
|
|
|
"storj.io/storj/pkg/peertls/tlsopts"
|
2019-02-07 09:04:29 +00:00
|
|
|
"storj.io/storj/pkg/pkcrypto"
|
2018-08-13 09:39:45 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPeerIdentityFromCertChain(t *testing.T) {
|
2019-02-07 09:04:29 +00:00
|
|
|
caKey, err := pkcrypto.GeneratePrivateKey()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := peertls.CATemplate()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-04-04 00:21:32 +01:00
|
|
|
caCert, err := peertls.CreateSelfSignedCertificate(caKey, caTemplate)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := peertls.LeafTemplate()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-02-07 09:04:29 +00:00
|
|
|
leafKey, err := pkcrypto.GeneratePrivateKey()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-04-04 00:21:32 +01:00
|
|
|
leafCert, err := peertls.CreateCertificate(pkcrypto.PublicKeyFromPrivate(leafKey), caKey, leafTemplate, caTemplate)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
peerIdent, err := identity.PeerIdentityFromCerts(leafCert, caCert, nil)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
assert.Equal(t, caCert, peerIdent.CA)
|
|
|
|
assert.Equal(t, leafCert, peerIdent.Leaf)
|
|
|
|
assert.NotEmpty(t, peerIdent.ID)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestFullIdentityFromPEM(t *testing.T) {
|
2019-02-07 09:04:29 +00:00
|
|
|
caKey, err := pkcrypto.GeneratePrivateKey()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
caTemplate, err := peertls.CATemplate()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-04-04 00:21:32 +01:00
|
|
|
caCert, err := peertls.CreateSelfSignedCertificate(caKey, caTemplate)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
assert.NotEmpty(t, caCert)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2018-12-07 13:44:25 +00:00
|
|
|
leafTemplate, err := peertls.LeafTemplate()
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-02-07 09:04:29 +00:00
|
|
|
leafKey, err := pkcrypto.GeneratePrivateKey()
|
2018-08-23 15:08:26 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2019-04-04 00:21:32 +01:00
|
|
|
leafCert, err := peertls.CreateCertificate(pkcrypto.PublicKeyFromPrivate(leafKey), caKey, leafTemplate, caTemplate)
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
assert.NotEmpty(t, leafCert)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
|
|
|
chainPEM := bytes.NewBuffer([]byte{})
|
2019-02-07 18:40:28 +00:00
|
|
|
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, leafCert))
|
|
|
|
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, caCert))
|
2018-08-13 09:39:45 +01:00
|
|
|
|
|
|
|
keyPEM := bytes.NewBuffer([]byte{})
|
2019-02-07 18:40:28 +00:00
|
|
|
assert.NoError(t, pkcrypto.WritePrivateKeyPEM(keyPEM, leafKey))
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
fullIdent, err := identity.FullIdentityFromPEM(chainPEM.Bytes(), keyPEM.Bytes())
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
2018-12-07 13:44:25 +00:00
|
|
|
assert.Equal(t, leafCert.Raw, fullIdent.Leaf.Raw)
|
|
|
|
assert.Equal(t, caCert.Raw, fullIdent.CA.Raw)
|
|
|
|
assert.Equal(t, leafKey, fullIdent.Key)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
func TestConfig_SaveIdentity(t *testing.T) {
|
2018-12-17 15:09:52 +00:00
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
ic := &identity.Config{
|
2018-12-17 15:09:52 +00:00
|
|
|
CertPath: ctx.File("chain.pem"),
|
|
|
|
KeyPath: ctx.File("key.pem"),
|
|
|
|
}
|
|
|
|
fi := pregeneratedIdentity(t)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
|
|
|
chainPEM := bytes.NewBuffer([]byte{})
|
2019-02-07 18:40:28 +00:00
|
|
|
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.Leaf))
|
|
|
|
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.CA))
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2019-02-07 20:39:20 +00:00
|
|
|
privateKey := fi.Key
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NotEmpty(t, privateKey)
|
|
|
|
|
|
|
|
keyPEM := bytes.NewBuffer([]byte{})
|
2019-02-07 18:40:28 +00:00
|
|
|
assert.NoError(t, pkcrypto.WritePrivateKeyPEM(keyPEM, privateKey))
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
{ // test saving
|
2019-02-07 18:40:28 +00:00
|
|
|
err := ic.Save(fi)
|
2018-12-17 15:09:52 +00:00
|
|
|
assert.NoError(t, err)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2018-08-23 08:05:56 +01:00
|
|
|
certInfo, err := os.Stat(ic.CertPath)
|
|
|
|
assert.NoError(t, err)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2018-08-23 08:05:56 +01:00
|
|
|
keyInfo, err := os.Stat(ic.KeyPath)
|
|
|
|
assert.NoError(t, err)
|
2018-12-13 20:01:43 +00:00
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
// TODO (windows): ignoring for windows due to different default permissions
|
|
|
|
if runtime.GOOS != "windows" {
|
|
|
|
assert.Equal(t, os.FileMode(0644), certInfo.Mode())
|
|
|
|
assert.Equal(t, os.FileMode(0600), keyInfo.Mode())
|
|
|
|
}
|
|
|
|
}
|
2018-12-13 20:01:43 +00:00
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
{ // test loading
|
|
|
|
loadedFi, err := ic.Load()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, fi.Key, loadedFi.Key)
|
|
|
|
assert.Equal(t, fi.Leaf, loadedFi.Leaf)
|
|
|
|
assert.Equal(t, fi.CA, loadedFi.CA)
|
|
|
|
assert.Equal(t, fi.ID, loadedFi.ID)
|
|
|
|
}
|
2018-12-13 20:01:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestVerifyPeer(t *testing.T) {
|
2019-01-02 10:23:25 +00:00
|
|
|
ca, err := identity.NewCA(context.Background(), identity.NewCAOptions{
|
2018-12-17 15:09:52 +00:00
|
|
|
Difficulty: 12,
|
|
|
|
Concurrency: 4,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2018-12-13 20:01:43 +00:00
|
|
|
|
|
|
|
fi, err := ca.NewIdentity()
|
2018-12-17 15:09:52 +00:00
|
|
|
assert.NoError(t, err)
|
2018-12-13 20:01:43 +00:00
|
|
|
|
|
|
|
err = peertls.VerifyPeerFunc(peertls.VerifyPeerCertChains)([][]byte{fi.Leaf.Raw, fi.CA.Raw}, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:03:53 +01:00
|
|
|
func TestManageablePeerIdentity_AddExtension(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
manageablePeerIdentity, err := testidentity.NewTestManageablePeerIdentity(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
oldLeaf := manageablePeerIdentity.Leaf
|
|
|
|
assert.Len(t, manageablePeerIdentity.CA.Cert.ExtraExtensions, 0)
|
|
|
|
|
|
|
|
randBytes := make([]byte, 10)
|
|
|
|
_, err = rand.Read(randBytes)
|
|
|
|
require.NoError(t, err)
|
|
|
|
randExt := pkix.Extension{
|
|
|
|
Id: asn1.ObjectIdentifier{2, 999, int(randBytes[0])},
|
|
|
|
Value: randBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = manageablePeerIdentity.AddExtension(randExt)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Len(t, manageablePeerIdentity.Leaf.ExtraExtensions, 0)
|
|
|
|
assert.Len(t, manageablePeerIdentity.Leaf.Extensions, len(oldLeaf.Extensions)+1)
|
|
|
|
|
|
|
|
assert.Equal(t, oldLeaf.SerialNumber, manageablePeerIdentity.Leaf.SerialNumber)
|
|
|
|
assert.Equal(t, oldLeaf.IsCA, manageablePeerIdentity.Leaf.IsCA)
|
|
|
|
assert.Equal(t, oldLeaf.PublicKey, manageablePeerIdentity.Leaf.PublicKey)
|
|
|
|
|
|
|
|
assert.Equal(t, randExt, tlsopts.NewExtensionsMap(manageablePeerIdentity.Leaf)[randExt.Id.String()])
|
|
|
|
|
|
|
|
assert.NotEqual(t, oldLeaf.Raw, manageablePeerIdentity.Leaf.Raw)
|
|
|
|
assert.NotEqual(t, oldLeaf.RawTBSCertificate, manageablePeerIdentity.Leaf.RawTBSCertificate)
|
|
|
|
assert.NotEqual(t, oldLeaf.Signature, manageablePeerIdentity.Leaf.Signature)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestManageableFullIdentity_Revoke(t *testing.T) {
|
|
|
|
ctx := testcontext.New(t)
|
|
|
|
defer ctx.Cleanup()
|
|
|
|
|
|
|
|
manageableFullIdentity, err := testidentity.NewTestManageableFullIdentity(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
oldLeaf := manageableFullIdentity.Leaf
|
|
|
|
assert.Len(t, manageableFullIdentity.CA.Cert.ExtraExtensions, 0)
|
|
|
|
|
|
|
|
err = manageableFullIdentity.Revoke()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Len(t, manageableFullIdentity.Leaf.ExtraExtensions, 0)
|
|
|
|
assert.Len(t, manageableFullIdentity.Leaf.Extensions, len(oldLeaf.Extensions)+1)
|
|
|
|
|
|
|
|
assert.Equal(t, oldLeaf.IsCA, manageableFullIdentity.Leaf.IsCA)
|
|
|
|
|
|
|
|
assert.NotEqual(t, oldLeaf.PublicKey, manageableFullIdentity.Leaf.PublicKey)
|
|
|
|
assert.NotEqual(t, oldLeaf.SerialNumber, manageableFullIdentity.Leaf.SerialNumber)
|
|
|
|
assert.NotEqual(t, oldLeaf.Raw, manageableFullIdentity.Leaf.Raw)
|
|
|
|
assert.NotEqual(t, oldLeaf.RawTBSCertificate, manageableFullIdentity.Leaf.RawTBSCertificate)
|
|
|
|
assert.NotEqual(t, oldLeaf.Signature, manageableFullIdentity.Leaf.Signature)
|
|
|
|
|
|
|
|
revocationExt := tlsopts.NewExtensionsMap(manageableFullIdentity.Leaf)[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(manageableFullIdentity.CA.Cert)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
func pregeneratedIdentity(t *testing.T) *identity.FullIdentity {
|
2018-12-17 15:09:52 +00:00
|
|
|
const chain = `-----BEGIN CERTIFICATE-----
|
2018-08-14 00:05:31 +01:00
|
|
|
MIIBQDCB56ADAgECAhB+u3d03qyW/ROgwy/ZsPccMAoGCCqGSM49BAMCMAAwIhgP
|
|
|
|
MDAwMTAxMDEwMDAwMDBaGA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEG
|
|
|
|
CCqGSM49AwEHA0IABIZrEPV/ExEkF0qUF0fJ3qSeGt5oFUX231v02NSUywcQ/Ve0
|
|
|
|
v3nHbmcJdjWBis2AkfL25mYDVC25jLl4tylMKumjPzA9MA4GA1UdDwEB/wQEAwIF
|
|
|
|
oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAK
|
|
|
|
BggqhkjOPQQDAgNIADBFAiEA2ZvsR0ncw4mHRIg2Isavd+XVEoMo/etXQRAkDy9n
|
|
|
|
wyoCIDykUsqjshc9kCrXOvPSN8GuO2bNoLu5C7K1GlE/HI2X
|
2018-08-13 09:39:45 +01:00
|
|
|
-----END CERTIFICATE-----
|
|
|
|
-----BEGIN CERTIFICATE-----
|
2018-08-14 00:05:31 +01:00
|
|
|
MIIBODCB4KADAgECAhAOcvhKe5TWT44LqFfgA1f8MAoGCCqGSM49BAMCMAAwIhgP
|
|
|
|
MDAwMTAxMDEwMDAwMDBaGA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEG
|
|
|
|
CCqGSM49AwEHA0IABIZrEPV/ExEkF0qUF0fJ3qSeGt5oFUX231v02NSUywcQ/Ve0
|
|
|
|
v3nHbmcJdjWBis2AkfL25mYDVC25jLl4tylMKumjODA2MA4GA1UdDwEB/wQEAwIC
|
|
|
|
BDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
|
|
|
|
BAMCA0cAMEQCIGAZfPT1qvlnkTacojTtP20ZWf6XbnSztJHIKlUw6AE+AiB5Vcjj
|
|
|
|
awRaC5l1KBPGqiKB0coVXDwhW+K70l326MPUcg==
|
2018-08-13 09:39:45 +01:00
|
|
|
-----END CERTIFICATE-----`
|
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
const key = `-----BEGIN EC PRIVATE KEY-----
|
2018-08-14 00:05:31 +01:00
|
|
|
MHcCAQEEIKGjEetrxKrzl+AL1E5LXke+1ElyAdjAmr88/1Kx09+doAoGCCqGSM49
|
|
|
|
AwEHoUQDQgAEoLy/0hs5deTXZunRumsMkiHpF0g8wAc58aXANmr7Mxx9tzoIYFnx
|
|
|
|
0YN4VDKdCtUJa29yA6TIz1MiIDUAcB5YCA==
|
2018-08-13 09:39:45 +01:00
|
|
|
-----END EC PRIVATE KEY-----`
|
|
|
|
|
2019-01-02 10:23:25 +00:00
|
|
|
fi, err := identity.FullIdentityFromPEM([]byte(chain), []byte(key))
|
2018-08-13 09:39:45 +01:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-12-17 15:09:52 +00:00
|
|
|
return fi
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|