diff --git a/bccsp/mocks/mocks.go b/bccsp/mocks/mocks.go index a3c8fbcf474..1a751b2aff4 100644 --- a/bccsp/mocks/mocks.go +++ b/bccsp/mocks/mocks.go @@ -16,26 +16,109 @@ limitations under the License. package mocks -import "github.com/hyperledger/fabric/bccsp" +import ( + "crypto" + "errors" + "hash" + "reflect" -type MockKey struct{} + "github.com/hyperledger/fabric/bccsp" +) -func (*MockKey) Bytes() ([]byte, error) { +type MockBCCSP struct { + SignArgKey bccsp.Key + SignDigestArg []byte + SignOptsArg bccsp.SignerOpts + + SignValue []byte + SignErr error + + VerifyValue bool + VerifyErr error +} + +func (*MockBCCSP) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { panic("implement me") } -func (*MockKey) SKI() []byte { +func (*MockBCCSP) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { panic("implement me") } -func (*MockKey) Symmetric() bool { +func (*MockBCCSP) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { panic("implement me") } -func (*MockKey) Private() bool { +func (*MockBCCSP) GetKey(ski []byte) (k bccsp.Key, err error) { + panic("implement me") +} + +func (*MockBCCSP) Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) { + panic("implement me") +} + +func (*MockBCCSP) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) { + panic("implement me") +} + +func (b *MockBCCSP) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + if !reflect.DeepEqual(b.SignArgKey, k) { + return nil, errors.New("invalid key") + } + if !reflect.DeepEqual(b.SignDigestArg, digest) { + return nil, errors.New("invalid digest") + } + if !reflect.DeepEqual(b.SignOptsArg, opts) { + return nil, errors.New("invalid opts") + } + + return b.SignValue, b.SignErr +} + +func (b *MockBCCSP) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + return b.VerifyValue, b.VerifyErr +} + +func (*MockBCCSP) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) { panic("implement me") } -func (*MockKey) PublicKey() (bccsp.Key, error) { +func (*MockBCCSP) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) { panic("implement me") } + +type MockKey struct { + BytesValue []byte + BytesErr error + Symm bool + PK bccsp.Key + PKErr error +} + +func (m *MockKey) Bytes() ([]byte, error) { + return m.BytesValue, m.BytesErr +} + +func (*MockKey) SKI() []byte { + panic("implement me") +} + +func (m *MockKey) Symmetric() bool { + return m.Symm +} + +func (*MockKey) Private() bool { + panic("implement me") +} + +func (m *MockKey) PublicKey() (bccsp.Key, error) { + return m.PK, m.PKErr +} + +type SignerOpts struct { + HashFuncValue crypto.Hash +} + +func (o *SignerOpts) HashFunc() crypto.Hash { + return o.HashFuncValue +} diff --git a/bccsp/pkcs11/impl_test.go b/bccsp/pkcs11/impl_test.go index 219691dc356..3aaab770ef8 100644 --- a/bccsp/pkcs11/impl_test.go +++ b/bccsp/pkcs11/impl_test.go @@ -1004,8 +1004,7 @@ func TestKeyImportFromX509ECDSAPublicKey(t *testing.T) { }, } - cryptoSigner := &signer.CryptoSigner{} - err = cryptoSigner.Init(currentBCCSP, k) + cryptoSigner, err := signer.New(currentBCCSP, k) if err != nil { t.Fatalf("Failed initializing CyrptoSigner [%s]", err) } @@ -1815,8 +1814,7 @@ func TestKeyImportFromX509RSAPublicKey(t *testing.T) { }, } - cryptoSigner := &signer.CryptoSigner{} - err = cryptoSigner.Init(currentBCCSP, k) + cryptoSigner, err := signer.New(currentBCCSP, k) if err != nil { t.Fatalf("Failed initializing CyrptoSigner [%s]", err) } diff --git a/bccsp/signer/signer.go b/bccsp/signer/signer.go index f82243780e9..ef4f51b7e3c 100644 --- a/bccsp/signer/signer.go +++ b/bccsp/signer/signer.go @@ -25,54 +25,49 @@ import ( "github.com/hyperledger/fabric/bccsp/utils" ) -// CryptoSigner is the BCCSP-based implementation of a crypto.Signer -type CryptoSigner struct { +// bccspCryptoSigner is the BCCSP-based implementation of a crypto.Signer +type bccspCryptoSigner struct { csp bccsp.BCCSP key bccsp.Key pk interface{} } -// Init initializes this CryptoSigner. -func (s *CryptoSigner) Init(csp bccsp.BCCSP, key bccsp.Key) error { +// New returns a new BCCSP-based crypto.Signer +// for the given BCCSP instance and key. +func New(csp bccsp.BCCSP, key bccsp.Key) (crypto.Signer, error) { // Validate arguments if csp == nil { - return errors.New("Invalid BCCSP. Nil.") + return nil, errors.New("bccsp instance must be different from nil.") } if key == nil { - return errors.New("Invalid Key. Nil.") + return nil, errors.New("key must be different from nil.") } if key.Symmetric() { - return errors.New("Invalid Key. Symmetric.") + return nil, errors.New("key must be asymmetric.") } // Marshall the bccsp public key as a crypto.PublicKey pub, err := key.PublicKey() if err != nil { - return fmt.Errorf("Failed getting public key [%s]", err) + return nil, fmt.Errorf("failed getting public key [%s]", err) } raw, err := pub.Bytes() if err != nil { - return fmt.Errorf("Failed marshalling public key [%s]", err) + return nil, fmt.Errorf("failed marshalling public key [%s]", err) } pk, err := utils.DERToPublicKey(raw) if err != nil { - return fmt.Errorf("Failed marshalling public key [%s]", err) + return nil, fmt.Errorf("failed marshalling der to public key [%s]", err) } - // Init fields - s.csp = csp - s.key = key - s.pk = pk - - return nil - + return &bccspCryptoSigner{csp, key, pk}, nil } // Public returns the public key corresponding to the opaque, // private key. -func (s *CryptoSigner) Public() crypto.PublicKey { +func (s *bccspCryptoSigner) Public() crypto.PublicKey { return s.pk } @@ -89,15 +84,6 @@ func (s *CryptoSigner) Public() crypto.PublicKey { // Note that when a signature of a hash of a larger message is needed, // the caller is responsible for hashing the larger message and passing // the hash (as digest) and the hash function (as opts) to Sign. -func (s *CryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { - if opts == nil { - return s.csp.Sign(s.key, digest, nil) - } - - so, ok := opts.(bccsp.SignerOpts) - if !ok { - return nil, errors.New("Invalid opts type. Expecting bccsp.SignerOpts") - } - - return s.csp.Sign(s.key, digest, so) +func (s *bccspCryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { + return s.csp.Sign(s.key, digest, opts) } diff --git a/bccsp/signer/signer_test.go b/bccsp/signer/signer_test.go index 508e56ce07e..97ccb681a94 100644 --- a/bccsp/signer/signer_test.go +++ b/bccsp/signer/signer_test.go @@ -16,96 +16,106 @@ limitations under the License. package signer import ( + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" - "os" + "errors" "testing" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/sw" + "github.com/hyperledger/fabric/bccsp/mocks" + "github.com/hyperledger/fabric/bccsp/utils" + "github.com/stretchr/testify/assert" ) -var ( - swBCCSPInstance bccsp.BCCSP -) +func TestInitFailures(t *testing.T) { + _, err := New(nil, &mocks.MockKey{}) + assert.Error(t, err) + + _, err = New(&mocks.MockBCCSP{}, nil) + assert.Error(t, err) + + _, err = New(&mocks.MockBCCSP{}, &mocks.MockKey{Symm: true}) + assert.Error(t, err) + + _, err = New(&mocks.MockBCCSP{}, &mocks.MockKey{PKErr: errors.New("No PK")}) + assert.Error(t, err) + assert.Equal(t, "failed getting public key [No PK]", err.Error()) -func getBCCSP(t *testing.T) bccsp.BCCSP { - if swBCCSPInstance == nil { - var err error - swBCCSPInstance, err = sw.NewDefaultSecurityLevel(os.TempDir()) - if err != nil { - t.Fatalf("Failed initializing key store [%s]", err) - } - } + _, err = New(&mocks.MockBCCSP{}, &mocks.MockKey{PK: &mocks.MockKey{BytesErr: errors.New("No bytes")}}) + assert.Error(t, err) + assert.Equal(t, "failed marshalling public key [No bytes]", err.Error()) - return swBCCSPInstance + _, err = New(&mocks.MockBCCSP{}, &mocks.MockKey{PK: &mocks.MockKey{BytesValue: []byte{0, 1, 2, 3}}}) + assert.Error(t, err) } func TestInit(t *testing.T) { - csp := getBCCSP(t) - - k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) - if err != nil { - t.Fatalf("Failed generating ECDSA key [%s]", err) - } - - signer := &CryptoSigner{} - err = signer.Init(csp, k) - if err != nil { - t.Fatalf("Failed initializing CryptoSigner [%s]", err) - } + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + assert.NoError(t, err) + pkRaw, err := utils.PublicKeyToDER(&k.PublicKey) + assert.NoError(t, err) + + signer, err := New(&mocks.MockBCCSP{}, &mocks.MockKey{PK: &mocks.MockKey{BytesValue: pkRaw}}) + assert.NoError(t, err) + assert.NotNil(t, signer) + + // Test public key + R, S, err := ecdsa.Sign(rand.Reader, k, []byte{0, 1, 2, 3}) + assert.NoError(t, err) + + assert.True(t, ecdsa.Verify(signer.Public().(*ecdsa.PublicKey), []byte{0, 1, 2, 3}, R, S)) } func TestPublic(t *testing.T) { - csp := getBCCSP(t) - - k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) - if err != nil { - t.Fatalf("Failed generating ECDSA key [%s]", err) - } - - signer := &CryptoSigner{} - err = signer.Init(csp, k) - if err != nil { - t.Fatalf("Failed initializing CryptoSigner [%s]", err) - } - - pk := signer.Public() - if pk == nil { - t.Fatal("Failed getting PublicKey. Nil.") - } + pk := &mocks.MockKey{} + signer := &bccspCryptoSigner{pk: pk} + + pk2 := signer.Public() + assert.NotNil(t, pk, pk2) } func TestSign(t *testing.T) { - csp := getBCCSP(t) - - k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) - if err != nil { - t.Fatalf("Failed generating ECDSA key [%s]", err) - } - - signer := &CryptoSigner{} - err = signer.Init(csp, k) - if err != nil { - t.Fatalf("Failed initializing CryptoSigner [%s]", err) - } - - msg := []byte("Hello World") - - digest, err := csp.Hash(msg, nil) - if err != nil { - t.Fatalf("Failed generating digest [%s]", err) - } - - signature, err := signer.Sign(rand.Reader, digest, nil) - if err != nil { - t.Fatalf("Failed generating ECDSA signature [%s]", err) - } - - valid, err := csp.Verify(k, signature, digest, nil) - if err != nil { - t.Fatalf("Failed verifying ECDSA signature [%s]", err) - } - if !valid { - t.Fatal("Failed verifying ECDSA signature. Signature not valid.") - } + expectedSig := []byte{0, 1, 2, 3, 4} + expectedKey := &mocks.MockKey{} + expectedDigest := []byte{0, 1, 2, 3, 4, 5} + expectedOpts := &mocks.SignerOpts{} + + signer := &bccspCryptoSigner{ + key: expectedKey, + csp: &mocks.MockBCCSP{ + SignArgKey: expectedKey, SignDigestArg: expectedDigest, SignOptsArg: expectedOpts, + SignValue: expectedSig}} + signature, err := signer.Sign(nil, expectedDigest, expectedOpts) + assert.NoError(t, err) + assert.Equal(t, expectedSig, signature) + + signer = &bccspCryptoSigner{ + key: expectedKey, + csp: &mocks.MockBCCSP{ + SignArgKey: expectedKey, SignDigestArg: expectedDigest, SignOptsArg: expectedOpts, + SignErr: errors.New("no signature")}} + signature, err = signer.Sign(nil, expectedDigest, expectedOpts) + assert.Error(t, err) + assert.Equal(t, err.Error(), "no signature") + + signer = &bccspCryptoSigner{ + key: nil, + csp: &mocks.MockBCCSP{SignArgKey: expectedKey, SignDigestArg: expectedDigest, SignOptsArg: expectedOpts}} + _, err = signer.Sign(nil, expectedDigest, expectedOpts) + assert.Error(t, err) + assert.Equal(t, err.Error(), "invalid key") + + signer = &bccspCryptoSigner{ + key: expectedKey, + csp: &mocks.MockBCCSP{SignArgKey: expectedKey, SignDigestArg: expectedDigest, SignOptsArg: expectedOpts}} + _, err = signer.Sign(nil, nil, expectedOpts) + assert.Error(t, err) + assert.Equal(t, err.Error(), "invalid digest") + + signer = &bccspCryptoSigner{ + key: expectedKey, + csp: &mocks.MockBCCSP{SignArgKey: expectedKey, SignDigestArg: expectedDigest, SignOptsArg: expectedOpts}} + _, err = signer.Sign(nil, expectedDigest, nil) + assert.Error(t, err) + assert.Equal(t, err.Error(), "invalid opts") } diff --git a/bccsp/sw/impl_test.go b/bccsp/sw/impl_test.go index fb31d4e2d74..52e08aca623 100644 --- a/bccsp/sw/impl_test.go +++ b/bccsp/sw/impl_test.go @@ -974,8 +974,7 @@ func TestKeyImportFromX509ECDSAPublicKey(t *testing.T) { }, } - cryptoSigner := &signer.CryptoSigner{} - err = cryptoSigner.Init(currentBCCSP, k) + cryptoSigner, err := signer.New(currentBCCSP, k) if err != nil { t.Fatalf("Failed initializing CyrptoSigner [%s]", err) } @@ -1786,8 +1785,7 @@ func TestKeyImportFromX509RSAPublicKey(t *testing.T) { }, } - cryptoSigner := &signer.CryptoSigner{} - err = cryptoSigner.Init(currentBCCSP, k) + cryptoSigner, err := signer.New(currentBCCSP, k) if err != nil { t.Fatalf("Failed initializing CyrptoSigner [%s]", err) } diff --git a/common/tools/cryptogen/csp/csp.go b/common/tools/cryptogen/csp/csp.go index 658ce9ad9d7..a281ada9ec2 100644 --- a/common/tools/cryptogen/csp/csp.go +++ b/common/tools/cryptogen/csp/csp.go @@ -33,7 +33,7 @@ func GeneratePrivateKey(keystorePath string) (bccsp.Key, csp := factory.GetDefault() var response error var priv bccsp.Key - signer := &signer.CryptoSigner{} + var s crypto.Signer // generate a key priv, err := csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true}) @@ -47,11 +47,11 @@ func GeneratePrivateKey(keystorePath string) (bccsp.Key, response = err if err == nil { // create a crypto.Signer - err = signer.Init(csp, priv) + s, response = signer.New(csp, priv) } } } - return priv, signer, response + return priv, s, response } diff --git a/msp/identities.go b/msp/identities.go index fb05a917952..69f1eb55c07 100644 --- a/msp/identities.go +++ b/msp/identities.go @@ -17,6 +17,7 @@ limitations under the License. package msp import ( + "crypto" "crypto/rand" "crypto/x509" "encoding/hex" @@ -26,7 +27,6 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/signer" "github.com/hyperledger/fabric/protos/msp" "github.com/op/go-logging" ) @@ -187,10 +187,10 @@ type signingidentity struct { identity // signer corresponds to the object that can produce signatures from this identity - signer *signer.CryptoSigner + signer crypto.Signer } -func newSigningIdentity(id *IdentityIdentifier, cert *x509.Certificate, pk bccsp.Key, signer *signer.CryptoSigner, msp *bccspmsp) SigningIdentity { +func newSigningIdentity(id *IdentityIdentifier, cert *x509.Certificate, pk bccsp.Key, signer crypto.Signer, msp *bccspmsp) SigningIdentity { //mspLogger.Infof("Creating signing identity instance for ID %s", id) return &signingidentity{identity{id: id, cert: cert, pk: pk, msp: msp}, signer} } diff --git a/msp/mspimpl.go b/msp/mspimpl.go index b2c4c62795a..3840f8a5c98 100644 --- a/msp/mspimpl.go +++ b/msp/mspimpl.go @@ -153,10 +153,9 @@ func (msp *bccspmsp) getSigningIdentityFromConf(sidInfo *m.SigningIdentityInfo) } // get the peer signer - peerSigner := &signer.CryptoSigner{} - err = peerSigner.Init(msp.bccsp, privKey) + peerSigner, err := signer.New(msp.bccsp, privKey) if err != nil { - return nil, fmt.Errorf("getIdentityFromBytes error: Failed initializing CryptoSigner, err %s", err) + return nil, fmt.Errorf("getIdentityFromBytes error: Failed initializing bccspCryptoSigner, err %s", err) } // Use the hash of the identity's certificate as id in the IdentityIdentifier