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:
parent
0b35762105
commit
c35b93766d
@ -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
1
go.mod
@ -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
2
go.sum
@ -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=
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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{})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
67
pkg/pkcrypto/signing_test.go
Normal file
67
pkg/pkcrypto/signing_test.go
Normal 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
|
||||
})
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user