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"
|
"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
1
go.mod
@ -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
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/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=
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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{})
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
)
|
)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
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 (
|
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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user