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" "archive/tar"
"bytes" "bytes"
"context" "context"
"crypto/ecdsa" "crypto"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -81,7 +81,7 @@ func cmdKeyGenerate(cmd *cobra.Command, args []string) (err error) {
return err return err
} }
return identity.GenerateKeys(ctx, uint16(keyCfg.MinDifficulty), keyCfg.Concurrency, 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() difficulty, err := id.Difficulty()
if err != nil { if err != nil {
return false, err 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() ct, err := peertls.CATemplate()
if err != nil { if err != nil {
return err return err

1
go.mod
View File

@ -48,7 +48,6 @@ require (
github.com/google/go-cmp v0.2.0 github.com/google/go-cmp v0.2.0
github.com/gorilla/handlers v1.4.0 // indirect github.com/gorilla/handlers v1.4.0 // indirect
github.com/gorilla/rpc v1.1.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-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
github.com/hashicorp/raft v1.0.0 // 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/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 h1:3Bn1IFB5OvPoANEfu03azF8aMyks0G/H6G1XeTfYbM4=
github.com/graphql-go/graphql v0.7.6/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= 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/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 h1:+INF0+TK4ga3O+6Y0Z2ftiujA13KaCO/+kHN9V6Mj4A=
github.com/hanwen/go-fuse v0.0.0-20181027161220-c029b69a13a7/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok= github.com/hanwen/go-fuse v0.0.0-20181027161220-c029b69a13a7/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=

View File

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

View File

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

View File

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

View File

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

View File

@ -4,10 +4,7 @@
package auth package auth
import ( import (
"crypto/ecdsa"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs" "github.com/zeebo/errs"
"storj.io/storj/pkg/identity" "storj.io/storj/pkg/identity"
@ -17,8 +14,6 @@ import (
) )
var ( 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 indicates a failure during signing
ErrSign = errs.Class("Failed to sign message") ErrSign = errs.Class("Failed to sign message")
//ErrVerify indicates a failure during signature validation //ErrVerify indicates a failure during signature validation
@ -63,11 +58,7 @@ func SignMessage(msg SignableMessage, ID identity.FullIdentity) error {
if err != nil { if err != nil {
return ErrMarshal.Wrap(err) return ErrMarshal.Wrap(err)
} }
privECDSA, ok := ID.Key.(*ecdsa.PrivateKey) signature, err := pkcrypto.HashAndSign(ID.Key, msgBytes)
if !ok {
return ErrECDSA
}
signature, err := cryptopasta.Sign(msgBytes, privECDSA)
if err != nil { if err != nil {
return ErrSign.Wrap(err) return ErrSign.Wrap(err)
} }
@ -102,39 +93,23 @@ func VerifyMsg(msg SignableMessage, signer storj.NodeID) error {
if err != nil { if err != nil {
return ErrVerify.Wrap(err) return ErrVerify.Wrap(err)
} }
leafPubKey, err := parseECDSA(certs[0]) leaf, err := pkcrypto.CertFromDER(certs[0])
if err != nil { if err != nil {
return err return err
} }
caPubKey, err := parseECDSA(certs[1]) ca, err := pkcrypto.CertFromDER(certs[1])
if err != nil { if err != nil {
return err return err
} }
// verify signature // verify signature
signatureLength := leafPubKey.Curve.Params().P.BitLen() / 8 if id, err := identity.NodeIDFromKey(ca.PublicKey); err != nil || id != signer {
if len(signature) < signatureLength {
return ErrSigLen.New("%d vs %d", len(signature), signatureLength)
}
if id, err := identity.NodeIDFromECDSAKey(caPubKey); err != nil || id != signer {
return ErrSigner.New("%+v vs %+v", id, signer) return ErrSigner.New("%+v vs %+v", id, signer)
} }
if ok := cryptopasta.Verify(msgBytes, signature, leafPubKey); !ok { if err := pkcrypto.HashAndVerifySignature(leaf.PublicKey, msgBytes, signature); err != nil {
return ErrVerify.New("%+v", ok) return ErrVerify.New("%+v", err)
} }
//cleanup //cleanup
msg.SetSignature(signature) msg.SetSignature(signature)
msg.SetCerts(certs) msg.SetCerts(certs)
return nil 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 ( import (
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"strings" "strings"
"time" "time"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/zeebo/errs" "github.com/zeebo/errs"
"go.uber.org/zap" "go.uber.org/zap"
monkit "gopkg.in/spacemonkeygo/monkit.v2" monkit "gopkg.in/spacemonkeygo/monkit.v2"
@ -20,6 +18,7 @@ import (
"storj.io/storj/pkg/certdb" "storj.io/storj/pkg/certdb"
"storj.io/storj/pkg/identity" "storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb" "storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj" "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)) 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 // verify Renter's (uplink) signature
rbad := *rba rbad := *rba
rbad.SetSignature(nil) rbad.SetSignature(nil)
@ -134,19 +128,8 @@ func (s *Server) verifySignature(ctx context.Context, rba *pb.RenterBandwidthAll
return Error.New("marshalling error: %+v", err) return Error.New("marshalling error: %+v", err)
} }
if ok := cryptopasta.Verify(rbadBytes, rba.GetSignature(), uplinkInfo); !ok { if err := pkcrypto.HashAndVerifySignature(uplinkInfo, rbadBytes, rba.GetSignature()); err != nil {
return pb.ErrRenter.Wrap(auth.ErrVerify.New("%+v", ok)) return pb.ErrRenter.Wrap(auth.ErrVerify.Wrap(err))
}
// 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))
} }
// verify Payer's (satellite) signature // 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) return Error.New("marshalling error: %+v", err)
} }
if ok := cryptopasta.Verify(pbadBytes, pba.GetSignature(), k); !ok { if err := pkcrypto.HashAndVerifySignature(s.pkey, pbadBytes, pba.GetSignature()); err != nil {
return pb.ErrPayer.Wrap(auth.ErrVerify.New("%+v", ok)) return pb.ErrPayer.Wrap(auth.ErrVerify.Wrap(err))
} }
return nil return nil
} }

View File

@ -5,7 +5,7 @@ package bwagreement_test
import ( import (
"context" "context"
"crypto/ecdsa" "crypto"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"net" "net"
@ -13,7 +13,6 @@ import (
"time" "time"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/gtank/cryptopasta"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap" "go.uber.org/zap"
@ -27,6 +26,7 @@ import (
"storj.io/storj/pkg/bwagreement/testbwagreement" "storj.io/storj/pkg/bwagreement/testbwagreement"
"storj.io/storj/pkg/identity" "storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb" "storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj" "storj.io/storj/pkg/storj"
"storj.io/storj/satellite" "storj.io/storj/satellite"
"storj.io/storj/satellite/satellitedb/satellitedbtest" "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) assert.NoError(t, err)
satID, err := testidentity.NewTestIdentity(ctx) satID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err) 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 { // TestSameSerialNumberBandwidthAgreements
pbaFile1, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour) pbaFile1, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err) 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) assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t) 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) pbaFile2, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err) 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) assert.NoError(t, err)
rbaNode1, err := testbwagreement.GenerateRenterBandwidthAllocation(pbaFile2, storageNode1, upID, 666) 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 { // storage nodes can submit a bwagreement that will expire in 30 seconds
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 30*time.Second) pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 30*time.Second)
assert.NoError(t, err) 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) assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t) 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 { // storage nodes can't submit a bwagreement that expires right now
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 0*time.Second) pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, 0*time.Second)
assert.NoError(t, err) 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) assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t) 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 { // 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) pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, -23*time.Hour-55*time.Second)
assert.NoError(t, err) 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) assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t) 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) { if !assert.NoError(t, err) {
t.Fatal(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) assert.NoError(t, err)
ctxSN1, storageNode1 := getPeerContext(ctx, t) 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) manipID, err := testidentity.NewTestIdentity(ctx)
assert.NoError(t, err) assert.NoError(t, err)
manipCerts := manipID.ChainRaw() manipCerts := manipID.ChainRaw()
manipPrivKey, ok := manipID.Key.(*ecdsa.PrivateKey) manipPrivKey := manipID.Key
assert.True(t, ok)
/* Storage node can't manipulate the bwagreement size (or any other field) /* Storage node can't manipulate the bwagreement size (or any other field)
Satellite will verify Renter's Signature. */ 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) ctxSN2, storageNode2 := getPeerContext(ctx, t)
pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour) pba, err := testbwagreement.GeneratePayerBandwidthAllocation(pb.BandwidthAction_GET, satID, upID, time.Hour)
assert.NoError(t, err) 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) assert.NoError(t, err)
{ // Storage node sends an corrupted signuature to force a satellite crash { // 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 //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) require.NotNil(t, msg)
oldSignature := msg.GetSignature() oldSignature := msg.GetSignature()
certs := msg.GetCerts() certs := msg.GetCerts()
@ -338,7 +337,7 @@ func GetSignature(t *testing.T, msg auth.SignableMessage, privECDSA *ecdsa.Priva
msg.SetCerts(nil) msg.SetCerts(nil)
msgBytes, err := proto.Marshal(msg) msgBytes, err := proto.Marshal(msg)
require.NoError(t, err) require.NoError(t, err)
signature, err := cryptopasta.Sign(msgBytes, privECDSA) signature, err := pkcrypto.HashAndSign(privKey, msgBytes)
require.NoError(t, err) require.NoError(t, err)
msg.SetSignature(oldSignature) msg.SetSignature(oldSignature)
msg.SetCerts(certs) msg.SetCerts(certs)

View File

@ -6,7 +6,6 @@ package certdb
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"storj.io/storj/pkg/storj" "storj.io/storj/pkg/storj"
) )
@ -16,5 +15,5 @@ type DB interface {
// SavePublicKey adds a new bandwidth agreement. // SavePublicKey adds a new bandwidth agreement.
SavePublicKey(context.Context, storj.NodeID, crypto.PublicKey) error SavePublicKey(context.Context, storj.NodeID, crypto.PublicKey) error
// GetPublicKey gets the public key of uplink corresponding to uplink id // 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 ( import (
"context" "context"
"crypto/ecdsa"
"crypto/x509" "crypto/x509"
"testing" "testing"
@ -32,12 +31,11 @@ func testDatabase(ctx context.Context, t *testing.T, upldb certdb.DB) {
//testing variables //testing variables
upID, err := testidentity.NewTestIdentity(ctx) upID, err := testidentity.NewTestIdentity(ctx)
require.NoError(t, err) require.NoError(t, err)
publicKeyEcdsa, _ := upID.Leaf.PublicKey.(*ecdsa.PublicKey) upIDpubbytes, err := x509.MarshalPKIXPublicKey(upID.Leaf.PublicKey)
upIDpubbytes, err := x509.MarshalPKIXPublicKey(publicKeyEcdsa)
require.NoError(t, err) require.NoError(t, err)
{ // New entry { // 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) assert.NoError(t, err)
} }

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ import (
"bytes" "bytes"
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/sha256" "crypto/sha256"
"crypto/tls" "crypto/tls"
"crypto/x509" "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 // NodeIDFromKey hashes a public key and creates a node ID from it
func NodeIDFromKey(k crypto.PublicKey) (storj.NodeID, error) { 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))) // id = sha256(sha256(pkix(k)))
kb, err := x509.MarshalPKIXPublicKey(k) kb, err := x509.MarshalPKIXPublicKey(k)
if err != nil { if err != nil {

View File

@ -6,7 +6,6 @@ package identity_test
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/ecdsa"
"os" "os"
"runtime" "runtime"
"testing" "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.Leaf))
assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.CA)) assert.NoError(t, pkcrypto.WriteCertPEM(chainPEM, fi.CA))
privateKey, ok := fi.Key.(*ecdsa.PrivateKey) privateKey := fi.Key
assert.True(t, ok)
assert.NotEmpty(t, privateKey) assert.NotEmpty(t, privateKey)
keyPEM := bytes.NewBuffer([]byte{}) 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 // AddSignedCertExt generates a signed certificate extension for a cert and attaches
// it to that cert. // it to that cert.
func AddSignedCertExt(key crypto.PrivateKey, cert *x509.Certificate) error { 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 { if err != nil {
return err return err
} }
@ -238,7 +238,7 @@ func (r Revocation) Verify(signingCert *x509.Certificate) error {
} }
data := r.TBSBytes() 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 err
} }
return nil 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. // Sign generates a signature using the passed key and attaches it to the revocation.
func (r *Revocation) Sign(key crypto.PrivateKey) error { func (r *Revocation) Sign(key crypto.PrivateKey) error {
data := r.TBSBytes() data := r.TBSBytes()
sig, err := pkcrypto.SignHashOf(key, data) sig, err := pkcrypto.HashAndSign(key, data)
if err != nil { if err != nil {
return err return err
} }
@ -296,7 +296,7 @@ func verifyCAWhitelistSignedLeafFunc(caWhitelist []*x509.Certificate) extensionV
leaf := chains[0][LeafIndex] leaf := chains[0][LeafIndex]
for _, ca := range caWhitelist { 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 { if err == nil {
return nil return nil
} }

View File

@ -6,7 +6,6 @@ package peertls
import ( import (
"bytes" "bytes"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/rand" "crypto/rand"
"crypto/tls" "crypto/tls"
"crypto/x509" "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, // NewCert returns a new x509 certificate using the provided templates and key,
// signed by the parent cert if provided; otherwise, self-signed. // signed by the parent cert if provided; otherwise, self-signed.
func NewCert(key, parentKey crypto.PrivateKey, template, parent *x509.Certificate) (*x509.Certificate, error) { 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 var signingKey crypto.PrivateKey
if parentKey != nil { if parentKey != nil {
signingKey = parentKey signingKey = parentKey
@ -149,7 +143,7 @@ func NewCert(key, parentKey crypto.PrivateKey, template, parent *x509.Certificat
rand.Reader, rand.Reader,
template, template,
parent, parent,
&p.PublicKey, pkcrypto.PublicKeyFromPrivate(key),
signingKey, signingKey,
) )
if err != nil { if err != nil {

View File

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

View File

@ -45,7 +45,7 @@ func verifyChainSignatures(certs []*x509.Certificate) error {
} }
func verifyCertSignature(parentCert, childCert *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) { func newSerialNumber() (*big.Int, error) {

View File

@ -6,7 +6,6 @@ package psserver
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/hmac" "crypto/hmac"
"crypto/sha512" "crypto/sha512"
"errors" "errors"
@ -64,7 +63,7 @@ type Server struct {
pkey crypto.PrivateKey pkey crypto.PrivateKey
totalAllocated int64 // TODO: use memory.Size totalAllocated int64 // TODO: use memory.Size
totalBwAllocated 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 verifier auth.SignedMessageVerifier
kad *kademlia.Kademlia 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 // 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 { if config.SatelliteIDRestriction {
idStrings := strings.Split(config.WhitelistedSatelliteIDs, ",") idStrings := strings.Split(config.WhitelistedSatelliteIDs, ",")
for _, s := range idStrings { for _, s := range idStrings {
@ -346,16 +345,12 @@ func (s *Server) isWhitelisted(id storj.NodeID) bool {
return found 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) pID, err := s.kad.FetchPeerIdentity(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ecdsa, ok := pID.Leaf.PublicKey.(*ecdsa.PublicKey) return pID.Leaf.PublicKey, nil
if !ok {
return nil, auth.ErrECDSA
}
return ecdsa, nil
} }
func getBeginningOfMonth() time.Time { func getBeginningOfMonth() time.Time {

View File

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

View File

@ -27,12 +27,12 @@ const (
var ( var (
// ErrUnsupportedKey is used when key type is not supported. // ErrUnsupportedKey is used when key type is not supported.
ErrUnsupportedKey = errs.Class("unsupported key type") ErrUnsupportedKey = errs.Class("unsupported key type")
// ErrParseCerts is used when an error occurs while parsing a certificate or cert chain. // ErrParse is used when an error occurs while parsing a certificate or key.
ErrParseCerts = errs.Class("unable to parse certificate") ErrParse = errs.Class("unable to parse")
// ErrSign is used when something goes wrong while generating a signature. // ErrSign is used when something goes wrong while generating a signature.
ErrSign = errs.Class("unable to generate signature") ErrSign = errs.Class("unable to generate signature")
// ErrVerifySignature is used when a cert-chain signature verificaion error occurs. // ErrVerifySignature is used when a signature verification error occurs.
ErrVerifySignature = errs.Class("tls certificate signature verification error") ErrVerifySignature = errs.Class("signature verification error")
// ErrChainLength is used when the length of a cert chain isn't what was expected // ErrChainLength is used when the length of a cert chain isn't what was expected
ErrChainLength = errs.Class("cert chain length error") 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) { func PublicKeyFromPEM(pemData []byte) (crypto.PublicKey, error) {
pb, _ := pem.Decode(pemData) pb, _ := pem.Decode(pemData)
if pb == nil { 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 { 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) return PublicKeyFromPKIX(pb.Bytes)
} }
@ -99,7 +99,7 @@ func PrivateKeyFromPKCS8(keyBytes []byte) (crypto.PrivateKey, error) {
func PrivateKeyFromPEM(keyBytes []byte) (crypto.PrivateKey, error) { func PrivateKeyFromPEM(keyBytes []byte) (crypto.PrivateKey, error) {
pb, _ := pem.Decode(keyBytes) pb, _ := pem.Decode(keyBytes)
if pb == nil { if pb == nil {
return nil, ErrParseCerts.New("could not parse PEM encoding") return nil, ErrParse.New("could not parse PEM encoding")
} }
switch pb.Type { switch pb.Type {
case BlockLabelEcPrivateKey: case BlockLabelEcPrivateKey:
@ -107,7 +107,7 @@ func PrivateKeyFromPEM(keyBytes []byte) (crypto.PrivateKey, error) {
case BlockLabelPrivateKey: case BlockLabelPrivateKey:
return PrivateKeyFromPKCS8(pb.Bytes) 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 // 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) { func CertFromPEM(certPEM []byte) (*x509.Certificate, error) {
kb, _ := pem.Decode(certPEM) kb, _ := pem.Decode(certPEM)
if kb == nil { 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 { 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) return CertFromDER(kb.Bytes)
} }
@ -157,7 +157,7 @@ func CertsFromDER(rawCerts [][]byte) ([]*x509.Certificate, error) {
var err error var err error
certs[i], err = CertFromDER(c) certs[i], err = CertFromDER(c)
if err != nil { 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 return certs, nil
@ -270,7 +270,7 @@ func PKIXExtensionToASN1(extension *pkix.Extension) ([]byte, error) {
func PKIXExtensionFromASN1(extData []byte) (*pkix.Extension, error) { func PKIXExtensionFromASN1(extData []byte) (*pkix.Extension, error) {
var extension pkix.Extension var extension pkix.Extension
if _, err := asn1.Unmarshal(extData, &extension); err != nil { 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 return &extension, nil
} }
@ -280,10 +280,10 @@ func PKIXExtensionFromASN1(extData []byte) (*pkix.Extension, error) {
func PKIXExtensionFromPEM(pemBytes []byte) (*pkix.Extension, error) { func PKIXExtensionFromPEM(pemBytes []byte) (*pkix.Extension, error) {
pb, _ := pem.Decode(pemBytes) pb, _ := pem.Decode(pemBytes)
if pb == nil { 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 { 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) return PKIXExtensionFromASN1(pb.Bytes)
} }

View File

@ -8,56 +8,164 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "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 // GeneratePrivateKey returns a new PrivateKey for signing messages
func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { func GeneratePrivateKey() (crypto.PrivateKey, error) {
return ecdsa.GenerateKey(authECCurve, rand.Reader) return GeneratePrivateECDSAKey(authECCurve)
// return GeneratePrivateRSAKey(StorjRSAKeyBits)
} }
// VerifySignature checks the signature against the passed data and public key // GeneratePrivateECDSAKey returns a new private ECDSA key for signing messages
func VerifySignature(signedData, data []byte, pubKey crypto.PublicKey) error { func GeneratePrivateECDSAKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) {
key, ok := pubKey.(*ecdsa.PublicKey) return ecdsa.GenerateKey(curve, rand.Reader)
if !ok { }
return ErrUnsupportedKey.New("%T", key)
}
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 { if err != nil {
return ErrVerifySignature.New("unable to unmarshal ecdsa signature: %v", err) return ErrVerifySignature.New("unable to unmarshal ecdsa signature: %v", err)
} }
digest := SHA256Hash(data) if !ecdsa.Verify(pubKey, digest, r, s) {
if !ecdsa.Verify(key, digest, r, s) {
return ErrVerifySignature.New("signature is not valid") return ErrVerifySignature.New("signature is not valid")
} }
return nil return nil
} }
// SignBytes signs the given data with the private key and returns the new func verifyRSASignatureWithoutHashing(pubKey *rsa.PublicKey, digest, signatureBytes []byte) error {
// signature. Normally, data here is a digest of some longer string of bytes. err := rsa.VerifyPSS(pubKey, pssParams.Hash, digest, signatureBytes, &pssParams)
func SignBytes(key crypto.PrivateKey, data []byte) ([]byte, error) { if err != nil {
ecKey, ok := key.(*ecdsa.PrivateKey) return ErrVerifySignature.New("signature is not valid")
if !ok {
return nil, ErrUnsupportedKey.New("%T", key)
} }
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 { if err != nil {
return nil, ErrSign.Wrap(err) return nil, ErrSign.Wrap(err)
} }
return marshalECDSASignature(r, s) 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. // signature.
func SignHashOf(key crypto.PrivateKey, data []byte) ([]byte, error) { func HashAndSign(key crypto.PrivateKey, data []byte) ([]byte, error) {
hash := SHA256Hash(data) digest := SHA256Hash(data)
signature, err := SignBytes(key, hash) signature, err := SignWithoutHashing(key, digest)
if err != nil { if err != nil {
return nil, ErrSign.Wrap(err) return nil, ErrSign.Wrap(err)
} }
return signature, nil 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 ( import (
"context" "context"
"crypto/ecdsa"
"time" "time"
"github.com/skyrings/skyring-common/tools/uuid" "github.com/skyrings/skyring-common/tools/uuid"
@ -46,12 +45,8 @@ func (allocation *AllocationSigner) PayerBandwidthAllocation(ctx context.Context
ttl := allocation.bwExpiration ttl := allocation.bwExpiration
ttl *= 86400 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 // 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 { if err != nil {
return nil, err return nil, err
} }

View File

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

View File

@ -6,11 +6,8 @@ package satellitedb
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/x509"
"github.com/zeebo/errs"
"storj.io/storj/pkg/pkcrypto"
"storj.io/storj/pkg/storj" "storj.io/storj/pkg/storj"
"storj.io/storj/pkg/utils" "storj.io/storj/pkg/utils"
dbx "storj.io/storj/satellite/satellitedb/dbx" 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())) _, err = tx.Get_CertRecord_By_Id(ctx, dbx.CertRecord_Id(nodeID.Bytes()))
if err != nil { if err != nil {
// no rows err, so create/insert an entry // no rows err, so create/insert an entry
publicKeyEcdsa, ok := publicKey.(*ecdsa.PublicKey) pubbytes, err := pkcrypto.PublicKeyToPKIX(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)
if err != nil { if err != nil {
return Error.Wrap(utils.CombineErrors(err, tx.Rollback())) 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()) 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())) dbxInfo, err := b.db.Get_CertRecord_By_Id(ctx, dbx.CertRecord_Id(nodeID.Bytes()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
pubkey, err := pkcrypto.PublicKeyFromPKIX(dbxInfo.Publickey)
pubkey, err := x509.ParsePKIXPublicKey(dbxInfo.Publickey)
if err != nil { 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)
} }
return pubkey, nil
// Typecast public key
pkey, ok := pubkey.(*ecdsa.PublicKey)
if !ok {
return nil, Error.Wrap(Error.New("UnsupportedKey error: %+v", pubkey))
}
return pkey, nil
} }

View File

@ -8,7 +8,6 @@ package satellitedb
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/ecdsa"
"sync" "sync"
"time" "time"
@ -148,7 +147,7 @@ type lockedCertDB struct {
} }
// GetPublicKey gets the public key of uplink corresponding to uplink id // 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() m.Lock()
defer m.Unlock() defer m.Unlock()
return m.db.GetPublicKey(ctx, a1) return m.db.GetPublicKey(ctx, a1)