Unite all cryptographic signing and verifying (#1244)

this change removes the cryptopasta dependency.

a couple possible sources of problem with this change:

 * the encoding used for ECDSA signatures on SignedMessage has changed.
   the encoding employed by cryptopasta was workable, but not the same
   as the encoding used for such signatures in the rest of the world
   (most particularly, on ECDSA signatures in X.509 certificates). I
   think we'll be best served by using one ECDSA signature encoding from
   here on, but if we need to use the old encoding for backwards
   compatibility with existing nodes, that can be arranged.

 * since there's already a breaking change in SignedMessage, I changed
   it to send and receive public keys in raw PKIX format, instead of
   PEM. PEM just adds unhelpful overhead for this case.
This commit is contained in:
paul cannon 2019-02-07 14:39:20 -06:00 committed by GitHub
parent 0b35762105
commit c35b93766d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 317 additions and 253 deletions

View File

@ -7,7 +7,7 @@ import (
"archive/tar"
"bytes"
"context"
"crypto/ecdsa"
"crypto"
"fmt"
"io"
"io/ioutil"
@ -81,7 +81,7 @@ func cmdKeyGenerate(cmd *cobra.Command, args []string) (err error) {
return err
}
return identity.GenerateKeys(ctx, uint16(keyCfg.MinDifficulty), keyCfg.Concurrency,
func(k *ecdsa.PrivateKey, id storj.NodeID) (done bool, err error) {
func(k crypto.PrivateKey, id storj.NodeID) (done bool, err error) {
difficulty, err := id.Difficulty()
if err != nil {
return false, err
@ -103,7 +103,7 @@ func cmdKeyGenerate(cmd *cobra.Command, args []string) (err error) {
})
}
func saveIdentityTar(path string, key *ecdsa.PrivateKey, id storj.NodeID) error {
func saveIdentityTar(path string, key crypto.PrivateKey, id storj.NodeID) error {
ct, err := peertls.CATemplate()
if err != nil {
return err

1
go.mod
View File

@ -48,7 +48,6 @@ require (
github.com/google/go-cmp v0.2.0
github.com/gorilla/handlers v1.4.0 // indirect
github.com/gorilla/rpc v1.1.0 // indirect
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
github.com/hashicorp/raft v1.0.0 // indirect

2
go.sum
View File

@ -132,8 +132,6 @@ github.com/gorilla/rpc v1.1.0 h1:marKfvVP0Gpd/jHlVBKCQ8RAoUPdX7K1Nuh6l1BNh7A=
github.com/gorilla/rpc v1.1.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=
github.com/graphql-go/graphql v0.7.6 h1:3Bn1IFB5OvPoANEfu03azF8aMyks0G/H6G1XeTfYbM4=
github.com/graphql-go/graphql v0.7.6/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI=
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0=
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hanwen/go-fuse v0.0.0-20181027161220-c029b69a13a7 h1:+INF0+TK4ga3O+6Y0Z2ftiujA13KaCO/+kHN9V6Mj4A=
github.com/hanwen/go-fuse v0.0.0-20181027161220-c029b69a13a7/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=

View File

@ -5,6 +5,7 @@ package debugging
import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"fmt"
@ -42,7 +43,7 @@ func PrintJSON(data interface{}, label string) {
data = NewDebugCert(d)
case *x509.Certificate:
data = NewDebugCert(*d)
case ecdsa.PublicKey:
case *ecdsa.PublicKey:
data = struct {
X *big.Int
Y *big.Int
@ -57,6 +58,22 @@ func PrintJSON(data interface{}, label string) {
}{
d.X, d.Y, d.D,
}
case *rsa.PublicKey:
data = struct {
N *big.Int
E int
}{
d.N, d.E,
}
case *rsa.PrivateKey:
data = struct {
N *big.Int
E int
D *big.Int
Primes []*big.Int
}{
d.N, d.E, d.D, d.Primes,
}
}
jsonBytes, err = json.MarshalIndent(data, "", "\t\t")

View File

@ -5,7 +5,6 @@ package tally_test
import (
"context"
"crypto/ecdsa"
"testing"
"time"
@ -72,7 +71,7 @@ func sendGeneratedAgreements(ctx context.Context, t *testing.T, db satellite.DB,
for i, action := range actions {
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(action, satID, upID, time.Hour)
require.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
rba, err := testbwagreement.GenerateRenterBandwidthAllocation(pba, snID.ID, upID, 1000)
require.NoError(t, err)

View File

@ -4,10 +4,6 @@
package auth
import (
"crypto/ecdsa"
"github.com/gtank/cryptopasta"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pkcrypto"
@ -15,29 +11,12 @@ import (
// GenerateSignature creates signature from identity id
func GenerateSignature(data []byte, identity *identity.FullIdentity) ([]byte, error) {
if len(data) == 0 {
return nil, nil
}
k, ok := identity.Key.(*ecdsa.PrivateKey)
if !ok {
return nil, pkcrypto.ErrUnsupportedKey.New("%T", identity.Key)
}
signature, err := cryptopasta.Sign(data, k)
if err != nil {
return nil, err
}
return signature, nil
return pkcrypto.HashAndSign(identity.Key, data)
}
// NewSignedMessage creates instance of signed message
func NewSignedMessage(signature []byte, identity *identity.FullIdentity) (*pb.SignedMessage, error) {
k, ok := identity.Leaf.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, pkcrypto.ErrUnsupportedKey.New("%T", identity.Leaf.PublicKey)
}
encodedKey, err := cryptopasta.EncodePublicKey(k)
encodedKey, err := pkcrypto.PublicKeyToPKIX(identity.Leaf.PublicKey)
if err != nil {
return nil, err
}
@ -67,13 +46,10 @@ func NewSignedMessageVerifier() SignedMessageVerifier {
return Error.New("missing public key for verification")
}
k, err := cryptopasta.DecodePublicKey(signedMessage.GetPublicKey())
k, err := pkcrypto.PublicKeyFromPKIX(signedMessage.GetPublicKey())
if err != nil {
return Error.Wrap(err)
}
if ok := cryptopasta.Verify(signedMessage.GetData(), signedMessage.GetSignature(), k); !ok {
return Error.New("failed to verify message")
}
return nil
return pkcrypto.HashAndVerifySignature(k, signedMessage.GetData(), signedMessage.GetSignature())
}
}

View File

@ -5,13 +5,12 @@ package auth
import (
"context"
"crypto/ecdsa"
"testing"
"github.com/gtank/cryptopasta"
"github.com/stretchr/testify/assert"
"storj.io/storj/internal/testidentity"
"storj.io/storj/pkg/pkcrypto"
)
func TestGenerateSignature(t *testing.T) {
@ -21,9 +20,6 @@ func TestGenerateSignature(t *testing.T) {
identity, err := ca.NewIdentity()
assert.NoError(t, err)
k, ok := identity.Leaf.PublicKey.(*ecdsa.PublicKey)
assert.Equal(t, true, ok)
for _, tt := range []struct {
data []byte
verified bool
@ -34,8 +30,12 @@ func TestGenerateSignature(t *testing.T) {
signature, err := GenerateSignature(identity.ID.Bytes(), identity)
assert.NoError(t, err)
verified := cryptopasta.Verify(tt.data, signature, k)
assert.Equal(t, tt.verified, verified)
verifyError := pkcrypto.HashAndVerifySignature(identity.Leaf.PublicKey, tt.data, signature)
if tt.verified {
assert.NoError(t, verifyError)
} else {
assert.Error(t, verifyError)
}
}
}
@ -63,7 +63,7 @@ func TestSignedMessageVerifier(t *testing.T) {
{signedMessage.Signature, nil, signedMessage.PublicKey, "auth error: missing data for verification"},
{signedMessage.Signature, signedMessage.Data, nil, "auth error: missing public key for verification"},
{signedMessage.Signature, []byte("malformed data"), signedMessage.PublicKey, "auth error: failed to verify message"},
{signedMessage.Signature, []byte("malformed data"), signedMessage.PublicKey, "signature verification error: signature is not valid"},
} {
signedMessage.Signature = tt.signature
signedMessage.Data = tt.data

View File

@ -4,10 +4,7 @@
package auth
import (
"crypto/ecdsa"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs"
"storj.io/storj/pkg/identity"
@ -17,8 +14,6 @@ import (
)
var (
//ErrECDSA indicates a key was not an ECDSA key
ErrECDSA = errs.New("Key is not ecdsa key")
//ErrSign indicates a failure during signing
ErrSign = errs.Class("Failed to sign message")
//ErrVerify indicates a failure during signature validation
@ -63,11 +58,7 @@ func SignMessage(msg SignableMessage, ID identity.FullIdentity) error {
if err != nil {
return ErrMarshal.Wrap(err)
}
privECDSA, ok := ID.Key.(*ecdsa.PrivateKey)
if !ok {
return ErrECDSA
}
signature, err := cryptopasta.Sign(msgBytes, privECDSA)
signature, err := pkcrypto.HashAndSign(ID.Key, msgBytes)
if err != nil {
return ErrSign.Wrap(err)
}
@ -102,39 +93,23 @@ func VerifyMsg(msg SignableMessage, signer storj.NodeID) error {
if err != nil {
return ErrVerify.Wrap(err)
}
leafPubKey, err := parseECDSA(certs[0])
leaf, err := pkcrypto.CertFromDER(certs[0])
if err != nil {
return err
}
caPubKey, err := parseECDSA(certs[1])
ca, err := pkcrypto.CertFromDER(certs[1])
if err != nil {
return err
}
// verify signature
signatureLength := leafPubKey.Curve.Params().P.BitLen() / 8
if len(signature) < signatureLength {
return ErrSigLen.New("%d vs %d", len(signature), signatureLength)
}
if id, err := identity.NodeIDFromECDSAKey(caPubKey); err != nil || id != signer {
if id, err := identity.NodeIDFromKey(ca.PublicKey); err != nil || id != signer {
return ErrSigner.New("%+v vs %+v", id, signer)
}
if ok := cryptopasta.Verify(msgBytes, signature, leafPubKey); !ok {
return ErrVerify.New("%+v", ok)
if err := pkcrypto.HashAndVerifySignature(leaf.PublicKey, msgBytes, signature); err != nil {
return ErrVerify.New("%+v", err)
}
//cleanup
msg.SetSignature(signature)
msg.SetCerts(certs)
return nil
}
func parseECDSA(rawCert []byte) (*ecdsa.PublicKey, error) {
cert, err := pkcrypto.CertFromDER(rawCert)
if err != nil {
return nil, ErrVerify.Wrap(err)
}
ecdsa, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, ErrECDSA
}
return ecdsa, nil
}

View File

@ -6,12 +6,10 @@ package bwagreement
import (
"context"
"crypto"
"crypto/ecdsa"
"strings"
"time"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs"
"go.uber.org/zap"
monkit "gopkg.in/spacemonkeygo/monkit.v2"
@ -20,6 +18,7 @@ import (
"storj.io/storj/pkg/certdb"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj"
)
@ -120,11 +119,6 @@ func (s *Server) verifySignature(ctx context.Context, rba *pb.RenterBandwidthAll
return pb.ErrRenter.Wrap(auth.ErrVerify.New("Failed to unmarshal PayerBandwidthAllocation: %+v", err))
}
signatureLength := uplinkInfo.Curve.Params().P.BitLen() / 8
if len(rba.GetSignature()) < signatureLength {
return pb.ErrRenter.Wrap(auth.ErrSigLen.New("%d vs %d", len(rba.GetSignature()), signatureLength))
}
// verify Renter's (uplink) signature
rbad := *rba
rbad.SetSignature(nil)
@ -134,19 +128,8 @@ func (s *Server) verifySignature(ctx context.Context, rba *pb.RenterBandwidthAll
return Error.New("marshalling error: %+v", err)
}
if ok := cryptopasta.Verify(rbadBytes, rba.GetSignature(), uplinkInfo); !ok {
return pb.ErrRenter.Wrap(auth.ErrVerify.New("%+v", ok))
}
// satellite public key
k, ok := s.pkey.(*ecdsa.PublicKey)
if !ok {
return Error.New("UnsupportedKey error: %+v", s.pkey)
}
signatureLength = k.Curve.Params().P.BitLen() / 8
if len(pba.GetSignature()) < signatureLength {
return pb.ErrPayer.Wrap(auth.ErrSigLen.New("%d vs %d", len(pba.GetSignature()), signatureLength))
if err := pkcrypto.HashAndVerifySignature(uplinkInfo, rbadBytes, rba.GetSignature()); err != nil {
return pb.ErrRenter.Wrap(auth.ErrVerify.Wrap(err))
}
// verify Payer's (satellite) signature
@ -158,8 +141,8 @@ func (s *Server) verifySignature(ctx context.Context, rba *pb.RenterBandwidthAll
return Error.New("marshalling error: %+v", err)
}
if ok := cryptopasta.Verify(pbadBytes, pba.GetSignature(), k); !ok {
return pb.ErrPayer.Wrap(auth.ErrVerify.New("%+v", ok))
if err := pkcrypto.HashAndVerifySignature(s.pkey, pbadBytes, pba.GetSignature()); err != nil {
return pb.ErrPayer.Wrap(auth.ErrVerify.Wrap(err))
}
return nil
}

View File

@ -5,7 +5,7 @@ package bwagreement_test
import (
"context"
"crypto/ecdsa"
"crypto"
"crypto/tls"
"crypto/x509"
"net"
@ -13,7 +13,6 @@ import (
"time"
"github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
@ -27,6 +26,7 @@ import (
"storj.io/storj/pkg/bwagreement/testbwagreement"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj"
"storj.io/storj/satellite"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
@ -64,12 +64,12 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
assert.NoError(t, err)
satID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
satellite := bwagreement.NewServer(db.BandwidthAgreement(), db.CertDB(), satID.Leaf.PublicKey.(*ecdsa.PublicKey), zap.NewNop(), satID.ID)
satellite := bwagreement.NewServer(db.BandwidthAgreement(), db.CertDB(), satID.Leaf.PublicKey, zap.NewNop(), satID.ID)
{ // TestSameSerialNumberBandwidthAgreements
pbaFile1, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pbaFile1.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pbaFile1.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
@ -99,7 +99,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
{
pbaFile2, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pbaFile2.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pbaFile2.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
rbaNode1, err := testbwagreement.GenerateRenterBandwidthAllocation(pbaFile2, storageNode1, upID, 666)
@ -134,7 +134,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
{ // storage nodes can submit a bwagreement that will expire in 30 seconds
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 30*time.Second)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
@ -149,7 +149,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
{ // storage nodes can't submit a bwagreement that expires right now
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 0*time.Second)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
@ -164,7 +164,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
{ // storage nodes can't submit a bwagreement that expires yesterday
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, -23*time.Hour-55*time.Second)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
@ -182,7 +182,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
if !assert.NoError(t, err) {
t.Fatal(err)
}
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t)
@ -196,8 +196,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
manipID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err)
manipCerts := manipID.ChainRaw()
manipPrivKey, ok := manipID.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
manipPrivKey := manipID.Key
/* Storage node can't manipulate the bwagreement size (or any other field)
Satellite will verify Renter's Signature. */
@ -299,7 +298,7 @@ func testDatabase(ctx context.Context, t *testing.T, db satellite.DB) {
ctxSN2, storageNode2 := getPeerContext(ctx, t)
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err)
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err = db.CertDB().SavePublicKey(ctx, pba.UplinkId, upID.Leaf.PublicKey)
assert.NoError(t, err)
{ // Storage node sends an corrupted signuature to force a satellite crash
@ -330,7 +329,7 @@ func callBWA(ctx context.Context, t *testing.T, sat *bwagreement.Server, signatu
}
//GetSignature returns the signature of the signed message
func GetSignature(t *testing.T, msg auth.SignableMessage, privECDSA *ecdsa.PrivateKey) []byte {
func GetSignature(t *testing.T, msg auth.SignableMessage, privKey crypto.PrivateKey) []byte {
require.NotNil(t, msg)
oldSignature := msg.GetSignature()
certs := msg.GetCerts()
@ -338,7 +337,7 @@ func GetSignature(t *testing.T, msg auth.SignableMessage, privECDSA *ecdsa.Priva
msg.SetCerts(nil)
msgBytes, err := proto.Marshal(msg)
require.NoError(t, err)
signature, err := cryptopasta.Sign(msgBytes, privECDSA)
signature, err := pkcrypto.HashAndSign(privKey, msgBytes)
require.NoError(t, err)
msg.SetSignature(oldSignature)
msg.SetCerts(certs)

View File

@ -6,7 +6,6 @@ package certdb
import (
"context"
"crypto"
"crypto/ecdsa"
"storj.io/storj/pkg/storj"
)
@ -16,5 +15,5 @@ type DB interface {
// SavePublicKey adds a new bandwidth agreement.
SavePublicKey(context.Context, storj.NodeID, crypto.PublicKey) error
// GetPublicKey gets the public key of uplink corresponding to uplink id
GetPublicKey(context.Context, storj.NodeID) (*ecdsa.PublicKey, error)
GetPublicKey(context.Context, storj.NodeID) (crypto.PublicKey, error)
}

View File

@ -5,7 +5,6 @@ package certdb_test
import (
"context"
"crypto/ecdsa"
"crypto/x509"
"testing"
@ -32,12 +31,11 @@ func testDatabase(ctx context.Context, t *testing.T, upldb certdb.DB) {
//testing variables
upID, err := testidentity.NewTestIdentity(ctx)
require.NoError(t, err)
publicKeyEcdsa, _ := upID.Leaf.PublicKey.(*ecdsa.PublicKey)
upIDpubbytes, err := x509.MarshalPKIXPublicKey(publicKeyEcdsa)
upIDpubbytes, err := x509.MarshalPKIXPublicKey(upID.Leaf.PublicKey)
require.NoError(t, err)
{ // New entry
err := upldb.SavePublicKey(ctx, upID.ID, upID.Leaf.PublicKey.(*ecdsa.PublicKey))
err := upldb.SavePublicKey(ctx, upID.ID, upID.Leaf.PublicKey)
assert.NoError(t, err)
}

View File

@ -9,6 +9,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"encoding/gob"
"fmt"
"strconv"
@ -109,6 +110,7 @@ type Client struct {
func init() {
gob.Register(&ecdsa.PublicKey{})
gob.Register(&rsa.PublicKey{})
gob.Register(elliptic.P256())
}

View File

@ -7,7 +7,6 @@ import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/x509"
"fmt"
@ -91,7 +90,7 @@ func NewCA(ctx context.Context, opts NewCAOptions) (_ *FullCertificateAuthority,
i = new(uint32)
mu sync.Mutex
selectedKey *ecdsa.PrivateKey
selectedKey crypto.PrivateKey
selectedID storj.NodeID
)
@ -113,7 +112,7 @@ func NewCA(ctx context.Context, opts NewCAOptions) (_ *FullCertificateAuthority,
}
}
err = GenerateKeys(ctx, minimumLoggableDifficulty, int(opts.Concurrency),
func(k *ecdsa.PrivateKey, id storj.NodeID) (done bool, err error) {
func(k crypto.PrivateKey, id storj.NodeID) (done bool, err error) {
if opts.Logger != nil {
if atomic.AddUint32(i, 1)%100 == 0 {
updateStatus()

View File

@ -5,7 +5,7 @@ package identity
import (
"context"
"crypto/ecdsa"
"crypto"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj"
@ -14,7 +14,7 @@ import (
// GenerateKey generates a private key with a node id with difficulty at least
// minDifficulty. No parallelism is used.
func GenerateKey(ctx context.Context, minDifficulty uint16) (
k *ecdsa.PrivateKey, id storj.NodeID, err error) {
k crypto.PrivateKey, id storj.NodeID, err error) {
var d uint16
for {
err = ctx.Err()
@ -25,7 +25,7 @@ func GenerateKey(ctx context.Context, minDifficulty uint16) (
if err != nil {
break
}
id, err = NodeIDFromECDSAKey(&k.PublicKey)
id, err = NodeIDFromKey(pkcrypto.PublicKeyFromPrivate(k))
if err != nil {
break
}
@ -42,7 +42,7 @@ func GenerateKey(ctx context.Context, minDifficulty uint16) (
// GenerateCallback indicates that key generation is done when done is true.
// if err != nil key generation will stop with that error
type GenerateCallback func(*ecdsa.PrivateKey, storj.NodeID) (done bool, err error)
type GenerateCallback func(crypto.PrivateKey, storj.NodeID) (done bool, err error)
// GenerateKeys continues to generate keys until found returns done == false,
// or the ctx is canceled.

View File

@ -7,7 +7,6 @@ import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
@ -187,14 +186,6 @@ func NodeIDFromPEM(pemBytes []byte) (storj.NodeID, error) {
// NodeIDFromKey hashes a public key and creates a node ID from it
func NodeIDFromKey(k crypto.PublicKey) (storj.NodeID, error) {
if ek, ok := k.(*ecdsa.PublicKey); ok {
return NodeIDFromECDSAKey(ek)
}
return storj.NodeID{}, storj.ErrNodeID.New("invalid key type: %T", k)
}
// NodeIDFromECDSAKey hashes a public key and creates a node ID from it
func NodeIDFromECDSAKey(k *ecdsa.PublicKey) (storj.NodeID, error) {
// id = sha256(sha256(pkix(k)))
kb, err := x509.MarshalPKIXPublicKey(k)
if err != nil {

View File

@ -6,7 +6,6 @@ package identity_test
import (
"bytes"
"context"
"crypto/ecdsa"
"os"
"runtime"
"testing"
@ -95,8 +94,7 @@ func TestConfig_SaveIdentity(t *testing.T) {
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.Leaf))
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.CA))
privateKey, ok := fi.Key.(*ecdsa.PrivateKey)
assert.True(t, ok)
privateKey := fi.Key
assert.NotEmpty(t, privateKey)
keyPEM := bytes.NewBuffer([]byte{})

View File

@ -173,7 +173,7 @@ func AddRevocationExt(key crypto.PrivateKey, revokedCert, newCert *x509.Certific
// AddSignedCertExt generates a signed certificate extension for a cert and attaches
// it to that cert.
func AddSignedCertExt(key crypto.PrivateKey, cert *x509.Certificate) error {
signature, err := pkcrypto.SignHashOf(key, cert.RawTBSCertificate)
signature, err := pkcrypto.HashAndSign(key, cert.RawTBSCertificate)
if err != nil {
return err
}
@ -238,7 +238,7 @@ func (r Revocation) Verify(signingCert *x509.Certificate) error {
}
data := r.TBSBytes()
if err := pkcrypto.VerifySignature(r.Signature, data, pubKey); err != nil {
if err := pkcrypto.HashAndVerifySignature(pubKey, data, r.Signature); err != nil {
return err
}
return nil
@ -257,7 +257,7 @@ func (r *Revocation) TBSBytes() []byte {
// Sign generates a signature using the passed key and attaches it to the revocation.
func (r *Revocation) Sign(key crypto.PrivateKey) error {
data := r.TBSBytes()
sig, err := pkcrypto.SignHashOf(key, data)
sig, err := pkcrypto.HashAndSign(key, data)
if err != nil {
return err
}
@ -296,7 +296,7 @@ func verifyCAWhitelistSignedLeafFunc(caWhitelist []*x509.Certificate) extensionV
leaf := chains[0][LeafIndex]
for _, ca := range caWhitelist {
err := pkcrypto.VerifySignature(certExt.Value, leaf.RawTBSCertificate, ca.PublicKey)
err := pkcrypto.HashAndVerifySignature(ca.PublicKey, leaf.RawTBSCertificate, certExt.Value)
if err == nil {
return nil
}

View File

@ -6,7 +6,6 @@ package peertls
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/tls"
"crypto/x509"
@ -129,11 +128,6 @@ func ChainBytes(chain ...*x509.Certificate) ([]byte, error) {
// NewCert returns a new x509 certificate using the provided templates and key,
// signed by the parent cert if provided; otherwise, self-signed.
func NewCert(key, parentKey crypto.PrivateKey, template, parent *x509.Certificate) (*x509.Certificate, error) {
p, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, pkcrypto.ErrUnsupportedKey.New("%T", key)
}
var signingKey crypto.PrivateKey
if parentKey != nil {
signingKey = parentKey
@ -149,7 +143,7 @@ func NewCert(key, parentKey crypto.PrivateKey, template, parent *x509.Certificat
rand.Reader,
template,
parent,
&p.PublicKey,
pkcrypto.PublicKeyFromPrivate(key),
signingKey,
)
if err != nil {

View File

@ -5,7 +5,6 @@ package peertls_test
import (
"bytes"
"crypto/ecdsa"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
@ -34,7 +33,7 @@ func TestNewCert_CA(t *testing.T) {
assert.NotEmpty(t, caKey)
assert.NotEmpty(t, caCert)
assert.NotEmpty(t, caCert.PublicKey.(*ecdsa.PublicKey))
assert.NotEmpty(t, caCert.PublicKey)
err = caCert.CheckSignatureFrom(caCert)
assert.NoError(t, err)
@ -61,7 +60,7 @@ func TestNewCert_Leaf(t *testing.T) {
assert.NotEmpty(t, caKey)
assert.NotEmpty(t, leafCert)
assert.NotEmpty(t, leafCert.PublicKey.(*ecdsa.PublicKey))
assert.NotEmpty(t, leafCert.PublicKey)
err = caCert.CheckSignatureFrom(caCert)
assert.NoError(t, err)
@ -82,11 +81,7 @@ func TestVerifyPeerFunc(t *testing.T) {
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:
case !pkcrypto.PublicKeyEqual(leafCert.PublicKey, parsedChains[0][0].PublicKey):
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")
@ -214,15 +209,10 @@ func TestAddSignedCertExt(t *testing.T) {
assert.Len(t, chain[0].ExtraExtensions, 1)
assert.Equal(t, peertls.ExtensionIDs[peertls.SignedCertExtID], chain[0].ExtraExtensions[0].Id)
ecKey, ok := keys[0].(*ecdsa.PrivateKey)
if !assert.True(t, ok) {
t.FailNow()
}
err = pkcrypto.VerifySignature(
chain[0].ExtraExtensions[0].Value,
err = pkcrypto.HashAndVerifySignature(
pkcrypto.PublicKeyFromPrivate(keys[0]),
chain[0].RawTBSCertificate,
&ecKey.PublicKey,
chain[0].ExtraExtensions[0].Value,
)
assert.NoError(t, err)
}
@ -239,12 +229,11 @@ func TestSignLeafExt(t *testing.T) {
assert.Equal(t, 1, len(leafCert.ExtraExtensions))
assert.True(t, peertls.ExtensionIDs[peertls.SignedCertExtID].Equal(leafCert.ExtraExtensions[0].Id))
caECKey, ok := caKey.(*ecdsa.PrivateKey)
if !assert.True(t, ok) {
t.FailNow()
}
err = pkcrypto.VerifySignature(leafCert.ExtraExtensions[0].Value, leafCert.RawTBSCertificate, &caECKey.PublicKey)
err = pkcrypto.HashAndVerifySignature(
pkcrypto.PublicKeyFromPrivate(caKey),
leafCert.RawTBSCertificate,
leafCert.ExtraExtensions[0].Value,
)
assert.NoError(t, err)
}

View File

@ -45,7 +45,7 @@ func verifyChainSignatures(certs []*x509.Certificate) error {
}
func verifyCertSignature(parentCert, childCert *x509.Certificate) error {
return pkcrypto.VerifySignature(childCert.Signature, childCert.RawTBSCertificate, parentCert.PublicKey)
return pkcrypto.HashAndVerifySignature(parentCert.PublicKey, childCert.RawTBSCertificate, childCert.Signature)
}
func newSerialNumber() (*big.Int, error) {

View File

@ -6,7 +6,6 @@ package psserver
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/hmac"
"crypto/sha512"
"errors"
@ -64,7 +63,7 @@ type Server struct {
pkey crypto.PrivateKey
totalAllocated int64 // TODO: use memory.Size
totalBwAllocated int64 // TODO: use memory.Size
whitelist map[storj.NodeID]*ecdsa.PublicKey
whitelist map[storj.NodeID]crypto.PublicKey
verifier auth.SignedMessageVerifier
kad *kademlia.Kademlia
}
@ -123,7 +122,7 @@ func NewEndpoint(log *zap.Logger, config Config, storage *pstore.Storage, db *ps
}
// parse the comma separated list of approved satellite IDs into an array of storj.NodeIDs
whitelist := make(map[storj.NodeID]*ecdsa.PublicKey)
whitelist := make(map[storj.NodeID]crypto.PublicKey)
if config.SatelliteIDRestriction {
idStrings := strings.Split(config.WhitelistedSatelliteIDs, ",")
for _, s := range idStrings {
@ -346,16 +345,12 @@ func (s *Server) isWhitelisted(id storj.NodeID) bool {
return found
}
func (s *Server) getPublicKey(ctx context.Context, id storj.NodeID) (*ecdsa.PublicKey, error) {
func (s *Server) getPublicKey(ctx context.Context, id storj.NodeID) (crypto.PublicKey, error) {
pID, err := s.kad.FetchPeerIdentity(ctx, id)
if err != nil {
return nil, err
}
ecdsa, ok := pID.Leaf.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, auth.ErrECDSA
}
return ecdsa, nil
return pID.Leaf.PublicKey, nil
}
func getBeginningOfMonth() time.Time {

View File

@ -4,7 +4,7 @@
package psserver
import (
"crypto/ecdsa"
"crypto"
"fmt"
"io"
"io/ioutil"
@ -562,7 +562,7 @@ func NewTest(ctx context.Context, t *testing.T, snID, upID *identity.FullIdentit
verifier := func(authorization *pb.SignedMessage) error {
return nil
}
whitelist := make(map[storj.NodeID]*ecdsa.PublicKey)
whitelist := make(map[storj.NodeID]crypto.PublicKey)
for _, id := range ids {
whitelist[id] = nil
}

View File

@ -27,12 +27,12 @@ const (
var (
// ErrUnsupportedKey is used when key type is not supported.
ErrUnsupportedKey = errs.Class("unsupported key type")
// ErrParseCerts is used when an error occurs while parsing a certificate or cert chain.
ErrParseCerts = errs.Class("unable to parse certificate")
// ErrParse is used when an error occurs while parsing a certificate or key.
ErrParse = errs.Class("unable to parse")
// ErrSign is used when something goes wrong while generating a signature.
ErrSign = errs.Class("unable to generate signature")
// ErrVerifySignature is used when a cert-chain signature verificaion error occurs.
ErrVerifySignature = errs.Class("tls certificate signature verification error")
// ErrVerifySignature is used when a signature verification error occurs.
ErrVerifySignature = errs.Class("signature verification error")
// ErrChainLength is used when the length of a cert chain isn't what was expected
ErrChainLength = errs.Class("cert chain length error")
)

View File

@ -52,10 +52,10 @@ func PublicKeyFromPKIX(pkixData []byte) (crypto.PublicKey, error) {
func PublicKeyFromPEM(pemData []byte) (crypto.PublicKey, error) {
pb, _ := pem.Decode(pemData)
if pb == nil {
return nil, ErrParseCerts.New("could not parse PEM encoding")
return nil, ErrParse.New("could not parse PEM encoding")
}
if pb.Type != BlockLabelPublicKey {
return nil, ErrParseCerts.New("can not parse public key from PEM block labeled %q", pb.Type)
return nil, ErrParse.New("can not parse public key from PEM block labeled %q", pb.Type)
}
return PublicKeyFromPKIX(pb.Bytes)
}
@ -99,7 +99,7 @@ func PrivateKeyFromPKCS8(keyBytes []byte) (crypto.PrivateKey, error) {
func PrivateKeyFromPEM(keyBytes []byte) (crypto.PrivateKey, error) {
pb, _ := pem.Decode(keyBytes)
if pb == nil {
return nil, ErrParseCerts.New("could not parse PEM encoding")
return nil, ErrParse.New("could not parse PEM encoding")
}
switch pb.Type {
case BlockLabelEcPrivateKey:
@ -107,7 +107,7 @@ func PrivateKeyFromPEM(keyBytes []byte) (crypto.PrivateKey, error) {
case BlockLabelPrivateKey:
return PrivateKeyFromPKCS8(pb.Bytes)
}
return nil, ErrParseCerts.New("can not parse private key from PEM block labeled %q", pb.Type)
return nil, ErrParse.New("can not parse private key from PEM block labeled %q", pb.Type)
}
// WriteCertPEM writes the certificate to the writer, in a PEM-enveloped DER
@ -141,10 +141,10 @@ func CertFromDER(certDER []byte) (*x509.Certificate, error) {
func CertFromPEM(certPEM []byte) (*x509.Certificate, error) {
kb, _ := pem.Decode(certPEM)
if kb == nil {
return nil, ErrParseCerts.New("could not decode certificate as PEM")
return nil, ErrParse.New("could not decode certificate as PEM")
}
if kb.Type != BlockLabelCertificate {
return nil, ErrParseCerts.New("can not parse certificate from PEM block labeled %q", kb.Type)
return nil, ErrParse.New("can not parse certificate from PEM block labeled %q", kb.Type)
}
return CertFromDER(kb.Bytes)
}
@ -157,7 +157,7 @@ func CertsFromDER(rawCerts [][]byte) ([]*x509.Certificate, error) {
var err error
certs[i], err = CertFromDER(c)
if err != nil {
return nil, ErrParseCerts.New("unable to parse certificate at index %d", i)
return nil, ErrParse.New("unable to parse certificate at index %d", i)
}
}
return certs, nil
@ -270,7 +270,7 @@ func PKIXExtensionToASN1(extension *pkix.Extension) ([]byte, error) {
func PKIXExtensionFromASN1(extData []byte) (*pkix.Extension, error) {
var extension pkix.Extension
if _, err := asn1.Unmarshal(extData, &extension); err != nil {
return nil, ErrParseCerts.New("unable to unmarshal PKIX extension: %v", err)
return nil, ErrParse.New("unable to unmarshal PKIX extension: %v", err)
}
return &extension, nil
}
@ -280,10 +280,10 @@ func PKIXExtensionFromASN1(extData []byte) (*pkix.Extension, error) {
func PKIXExtensionFromPEM(pemBytes []byte) (*pkix.Extension, error) {
pb, _ := pem.Decode(pemBytes)
if pb == nil {
return nil, ErrParseCerts.New("unable to parse PEM block")
return nil, ErrParse.New("unable to parse PEM block")
}
if pb.Type != BlockLabelExtension {
return nil, ErrParseCerts.New("can not parse PKIX cert extension from PEM block labeled %q", pb.Type)
return nil, ErrParse.New("can not parse PKIX cert extension from PEM block labeled %q", pb.Type)
}
return PKIXExtensionFromASN1(pb.Bytes)
}

View File

@ -8,56 +8,164 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"math/big"
"reflect"
)
var authECCurve = elliptic.P256()
const (
// StorjPSSSaltLength holds the correct value for the PSS salt length
// when signing with RSA in Storj code and verifying RSA signatures
// from Storj.
StorjPSSSaltLength = rsa.PSSSaltLengthAuto
// StorjRSAKeyBits holds the number of bits to use for new RSA keys
// by default.
StorjRSAKeyBits = 2048
)
var (
authECCurve = elliptic.P256()
pssParams = rsa.PSSOptions{
SaltLength: StorjPSSSaltLength,
Hash: crypto.SHA256,
}
)
// GeneratePrivateKey returns a new PrivateKey for signing messages
func GeneratePrivateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(authECCurve, rand.Reader)
func GeneratePrivateKey() (crypto.PrivateKey, error) {
return GeneratePrivateECDSAKey(authECCurve)
// return GeneratePrivateRSAKey(StorjRSAKeyBits)
}
// VerifySignature checks the signature against the passed data and public key
func VerifySignature(signedData, data []byte, pubKey crypto.PublicKey) error {
key, ok := pubKey.(*ecdsa.PublicKey)
if !ok {
return ErrUnsupportedKey.New("%T", key)
}
// GeneratePrivateECDSAKey returns a new private ECDSA key for signing messages
func GeneratePrivateECDSAKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(curve, rand.Reader)
}
r, s, err := unmarshalECDSASignature(signedData)
// GeneratePrivateRSAKey returns a new private RSA key for signing messages
func GeneratePrivateRSAKey(bits int) (*rsa.PrivateKey, error) {
return rsa.GenerateKey(rand.Reader, bits)
}
// HashAndVerifySignature checks that signature was made by the private key
// corresponding to the given public key, over a SHA-256 digest of the given
// data. It returns an error if verification fails, or nil otherwise.
func HashAndVerifySignature(key crypto.PublicKey, data, signature []byte) error {
digest := SHA256Hash(data)
return VerifySignatureWithoutHashing(key, digest, signature)
}
// VerifySignatureWithoutHashing checks the signature against the passed data
// (which is normally a digest) and public key. It returns an error if
// verification fails, or nil otherwise.
func VerifySignatureWithoutHashing(pubKey crypto.PublicKey, digest, signature []byte) error {
switch key := pubKey.(type) {
case *ecdsa.PublicKey:
return verifyECDSASignatureWithoutHashing(key, digest, signature)
case *rsa.PublicKey:
return verifyRSASignatureWithoutHashing(key, digest, signature)
}
return ErrUnsupportedKey.New("%T", pubKey)
}
func verifyECDSASignatureWithoutHashing(pubKey *ecdsa.PublicKey, digest, signatureBytes []byte) error {
r, s, err := unmarshalECDSASignature(signatureBytes)
if err != nil {
return ErrVerifySignature.New("unable to unmarshal ecdsa signature: %v", err)
}
digest := SHA256Hash(data)
if !ecdsa.Verify(key, digest, r, s) {
if !ecdsa.Verify(pubKey, digest, r, s) {
return ErrVerifySignature.New("signature is not valid")
}
return nil
}
// SignBytes signs the given data with the private key and returns the new
// signature. Normally, data here is a digest of some longer string of bytes.
func SignBytes(key crypto.PrivateKey, data []byte) ([]byte, error) {
ecKey, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, ErrUnsupportedKey.New("%T", key)
func verifyRSASignatureWithoutHashing(pubKey *rsa.PublicKey, digest, signatureBytes []byte) error {
err := rsa.VerifyPSS(pubKey, pssParams.Hash, digest, signatureBytes, &pssParams)
if err != nil {
return ErrVerifySignature.New("signature is not valid")
}
return nil
}
r, s, err := ecdsa.Sign(rand.Reader, ecKey, data)
// PublicKeyFromPrivate returns the public key corresponding to a given private
// key.
func PublicKeyFromPrivate(privKey crypto.PrivateKey) crypto.PublicKey {
switch key := privKey.(type) {
case *ecdsa.PrivateKey:
return key.Public()
case *rsa.PrivateKey:
return key.Public()
}
return ErrUnsupportedKey.New("%T", privKey)
}
// SignWithoutHashing signs the given digest with the private key and returns
// the new signature.
func SignWithoutHashing(privKey crypto.PrivateKey, digest []byte) ([]byte, error) {
switch key := privKey.(type) {
case *ecdsa.PrivateKey:
return signECDSAWithoutHashing(key, digest)
case *rsa.PrivateKey:
return signRSAWithoutHashing(key, digest)
}
return nil, ErrUnsupportedKey.New("%T", privKey)
}
func signECDSAWithoutHashing(privKey *ecdsa.PrivateKey, digest []byte) ([]byte, error) {
r, s, err := ecdsa.Sign(rand.Reader, privKey, digest)
if err != nil {
return nil, ErrSign.Wrap(err)
}
return marshalECDSASignature(r, s)
}
// SignHashOf signs a SHA-256 digest of the given data and returns the new
func signRSAWithoutHashing(privKey *rsa.PrivateKey, digest []byte) ([]byte, error) {
return privKey.Sign(rand.Reader, digest, &pssParams)
}
// HashAndSign signs a SHA-256 digest of the given data and returns the new
// signature.
func SignHashOf(key crypto.PrivateKey, data []byte) ([]byte, error) {
hash := SHA256Hash(data)
signature, err := SignBytes(key, hash)
func HashAndSign(key crypto.PrivateKey, data []byte) ([]byte, error) {
digest := SHA256Hash(data)
signature, err := SignWithoutHashing(key, digest)
if err != nil {
return nil, ErrSign.Wrap(err)
}
return signature, nil
}
// PublicKeyEqual returns true if two public keys are the same.
func PublicKeyEqual(a, b crypto.PublicKey) bool {
switch aConcrete := a.(type) {
case *ecdsa.PublicKey:
bConcrete, ok := b.(*ecdsa.PublicKey)
if !ok {
return false
}
return publicECDSAKeyEqual(aConcrete, bConcrete)
case *rsa.PublicKey:
bConcrete, ok := b.(*rsa.PublicKey)
if !ok {
return false
}
return publicRSAKeyEqual(aConcrete, bConcrete)
}
// a best-effort here is probably better than adding an err return
return reflect.DeepEqual(a, b)
}
// publicECDSAKeyEqual returns true if two ECDSA public keys are the same.
func publicECDSAKeyEqual(a, b *ecdsa.PublicKey) bool {
return a.Curve == b.Curve && bigIntEq(a.X, b.X) && bigIntEq(a.Y, b.Y)
}
// publicRSAKeyEqual returns true if two RSA public keys are the same.
func publicRSAKeyEqual(a, b *rsa.PublicKey) bool {
return bigIntEq(a.N, b.N) && a.E == b.E
}
func bigIntEq(a, b *big.Int) bool {
return a.Cmp(b) == 0
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package pkcrypto
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSigningAndVerifyingECDSA(t *testing.T) {
tests := []struct {
name string
data string
}{
{"empty", ""},
{"single byte", "C"},
{"longnulls", string(make([]byte, 2000))},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
privKey, err := GeneratePrivateECDSAKey(authECCurve)
assert.NoError(t, err)
pubKey := PublicKeyFromPrivate(privKey)
// test signing and verifying a hash of the data
sig, err := HashAndSign(privKey, []byte(tt.data))
assert.NoError(t, err)
err = HashAndVerifySignature(pubKey, []byte(tt.data), sig)
assert.NoError(t, err)
// test signing and verifying the data directly
sig, err = SignWithoutHashing(privKey, []byte(tt.data))
assert.NoError(t, err)
err = VerifySignatureWithoutHashing(pubKey, []byte(tt.data), sig)
assert.NoError(t, err)
})
}
}
func TestSigningAndVerifyingRSA(t *testing.T) {
privKey, err := GeneratePrivateRSAKey(StorjRSAKeyBits)
assert.NoError(t, err)
pubKey := PublicKeyFromPrivate(privKey)
tests := []struct {
name string
data string
}{
{"empty", ""},
{"single byte", "C"},
{"longnulls", string(make([]byte, 2000))},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// test signing and verifying a hash of the data
sig, err := HashAndSign(privKey, []byte(tt.data))
assert.NoError(t, err)
err = HashAndVerifySignature(pubKey, []byte(tt.data), sig)
assert.NoError(t, err)
// don't test signing and verifying the data directly, as RSA can't
// handle messages of arbitrary size
})
}
}

View File

@ -5,7 +5,6 @@ package pointerdb
import (
"context"
"crypto/ecdsa"
"time"
"github.com/skyrings/skyring-common/tools/uuid"
@ -46,12 +45,8 @@ func (allocation *AllocationSigner) PayerBandwidthAllocation(ctx context.Context
ttl := allocation.bwExpiration
ttl *= 86400
pk, ok := peerIdentity.Leaf.PublicKey.(*ecdsa.PublicKey)
if !ok {
return nil, Error.New("UnsupportedKey error: %+v", peerIdentity.Leaf.PublicKey)
}
// store the corresponding uplink's id and public key into certDB db
err = allocation.certdb.SavePublicKey(ctx, peerIdentity.ID, pk)
err = allocation.certdb.SavePublicKey(ctx, peerIdentity.ID, peerIdentity.Leaf.PublicKey)
if err != nil {
return nil, err
}

View File

@ -5,8 +5,6 @@ package ecclient
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"errors"
"fmt"
@ -24,6 +22,7 @@ import (
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/piecestore/psclient"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/ranger"
"storj.io/storj/pkg/transport"
)
@ -51,7 +50,8 @@ func TestNewECClient(t *testing.T) {
mbm := 1234
privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
privKey, err := pkcrypto.GeneratePrivateKey()
assert.NoError(t, err)
identity := &identity.FullIdentity{Key: privKey}
ec := NewClient(identity, mbm)
assert.NotNil(t, ec)

View File

@ -6,11 +6,8 @@ package satellitedb
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/x509"
"github.com/zeebo/errs"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj"
"storj.io/storj/pkg/utils"
dbx "storj.io/storj/satellite/satellitedb/dbx"
@ -29,12 +26,7 @@ func (b *certDB) SavePublicKey(ctx context.Context, nodeID storj.NodeID, publicK
_, err = tx.Get_CertRecord_By_Id(ctx, dbx.CertRecord_Id(nodeID.Bytes()))
if err != nil {
// no rows err, so create/insert an entry
publicKeyEcdsa, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
return Error.Wrap(utils.CombineErrors(errs.New("Uplink Private Key is not a valid *ecdsa.PrivateKey"), tx.Rollback()))
}
pubbytes, err := x509.MarshalPKIXPublicKey(publicKeyEcdsa)
pubbytes, err := pkcrypto.PublicKeyToPKIX(publicKey)
if err != nil {
return Error.Wrap(utils.CombineErrors(err, tx.Rollback()))
}
@ -57,22 +49,14 @@ func (b *certDB) SavePublicKey(ctx context.Context, nodeID storj.NodeID, publicK
return Error.Wrap(tx.Commit())
}
func (b *certDB) GetPublicKey(ctx context.Context, nodeID storj.NodeID) (*ecdsa.PublicKey, error) {
func (b *certDB) GetPublicKey(ctx context.Context, nodeID storj.NodeID) (crypto.PublicKey, error) {
dbxInfo, err := b.db.Get_CertRecord_By_Id(ctx, dbx.CertRecord_Id(nodeID.Bytes()))
if err != nil {
return nil, err
}
pubkey, err := x509.ParsePKIXPublicKey(dbxInfo.Publickey)
pubkey, err := pkcrypto.PublicKeyFromPKIX(dbxInfo.Publickey)
if err != nil {
return nil, Error.Wrap(Error.New("Failed to extract Public Key from RenterBandwidthAllocation: %+v", err))
return nil, Error.New("Failed to extract Public Key from RenterBandwidthAllocation: %+v", err)
}
// Typecast public key
pkey, ok := pubkey.(*ecdsa.PublicKey)
if !ok {
return nil, Error.Wrap(Error.New("UnsupportedKey error: %+v", pubkey))
}
return pkey, nil
return pubkey, nil
}

View File

@ -8,7 +8,6 @@ package satellitedb
import (
"context"
"crypto"
"crypto/ecdsa"
"sync"
"time"
@ -148,7 +147,7 @@ type lockedCertDB struct {
}
// GetPublicKey gets the public key of uplink corresponding to uplink id
func (m *lockedCertDB) GetPublicKey(ctx context.Context, a1 storj.NodeID) (*ecdsa.PublicKey, error) {
func (m *lockedCertDB) GetPublicKey(ctx context.Context, a1 storj.NodeID) (crypto.PublicKey, error) {
m.Lock()
defer m.Unlock()
return m.db.GetPublicKey(ctx, a1)