From 5440e980674ed06bd02b5280d576b1120b5e94a6 Mon Sep 17 00:00:00 2001 From: Angelo De Caro Date: Fri, 5 May 2017 13:35:20 +0200 Subject: [PATCH] [FAB-3441] bccsp/sw KeyImport test coverage Using the approach discussed in FAB-3465, this change-sets refactors the way key importation is done at bccsp/sw. Essentially, the switch has been replaced by a map. The approach decouples the testing of the bccsp interface implementation from the cryptographic algorithms. Test-coverage of the entire bccsp/sw is now at more than 90% Change-Id: I662b9b36f1571510f2797cb6396e106c9fd7f7a0 Signed-off-by: Angelo De Caro --- bccsp/sw/impl.go | 209 ++++++------------------------------- bccsp/sw/internals.go | 8 ++ bccsp/sw/keyimport.go | 162 ++++++++++++++++++++++++++++ bccsp/sw/keyimport_test.go | 195 ++++++++++++++++++++++++++++++++++ bccsp/sw/mocks/mocks.go | 19 ++++ bccsp/sw/sw_test.go | 6 +- bccsp/utils/keys.go | 13 ++- 7 files changed, 431 insertions(+), 181 deletions(-) create mode 100644 bccsp/sw/keyimport.go create mode 100644 bccsp/sw/keyimport_test.go diff --git a/bccsp/sw/impl.go b/bccsp/sw/impl.go index e8888dcf79a..77cedb9b70e 100644 --- a/bccsp/sw/impl.go +++ b/bccsp/sw/impl.go @@ -16,20 +16,15 @@ limitations under the License. package sw import ( - "crypto/ecdsa" "crypto/elliptic" - "crypto/rsa" - "crypto/x509" + "crypto/sha256" + "crypto/sha512" "errors" "fmt" "hash" "reflect" - "crypto/sha256" - "crypto/sha512" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/utils" "github.com/hyperledger/fabric/common/flogging" "golang.org/x/crypto/sha3" ) @@ -130,6 +125,18 @@ func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.B keyDerivers[reflect.TypeOf(&aesPrivateKey{})] = &aesPrivateKeyKeyDeriver{bccsp: impl} impl.keyDerivers = keyDerivers + // Set the key importers + keyImporters := make(map[reflect.Type]KeyImporter) + keyImporters[reflect.TypeOf(&bccsp.AES256ImportKeyOpts{})] = &aes256ImportKeyOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.HMACImportKeyOpts{})] = &hmacImportKeyOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAPKIXPublicKeyImportOpts{})] = &ecdsaPKIXPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAPrivateKeyImportOpts{})] = &ecdsaPrivateKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{})] = &ecdsaGoPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.RSAGoPublicKeyImportOpts{})] = &rsaGoPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.X509PublicKeyImportOpts{})] = &x509PublicKeyImportOptsKeyImporter{bccsp: impl} + + impl.keyImporters = keyImporters + return impl, nil } @@ -140,6 +147,7 @@ type impl struct { keyGenerators map[reflect.Type]KeyGenerator keyDerivers map[reflect.Type]KeyDeriver + keyImporters map[reflect.Type]KeyImporter encryptors map[reflect.Type]Encryptor decryptors map[reflect.Type]Decryptor signers map[reflect.Type]Signer @@ -214,185 +222,32 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { // Validate arguments if raw == nil { - return nil, errors.New("Invalid raw. Cannot be nil") + return nil, errors.New("Invalid raw. It must not be nil.") } - if opts == nil { - return nil, errors.New("Invalid Opts parameter. It must not be nil.") + return nil, errors.New("Invalid opts. It must not be nil.") } - switch opts.(type) { - - case *bccsp.AES256ImportKeyOpts: - aesRaw, ok := raw.([]byte) - if !ok { - return nil, errors.New("[AES256ImportKeyOpts] Invalid raw material. Expected byte array.") - } - - if len(aesRaw) != 32 { - return nil, fmt.Errorf("[AES256ImportKeyOpts] Invalid Key Length [%d]. Must be 32 bytes", len(aesRaw)) - } - - aesK := &aesPrivateKey{utils.Clone(aesRaw), false} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(aesK) - if err != nil { - return nil, fmt.Errorf("Failed storing AES key [%s]", err) - } - } - - return aesK, nil - - case *bccsp.HMACImportKeyOpts: - aesRaw, ok := raw.([]byte) - if !ok { - return nil, errors.New("[HMACImportKeyOpts] Invalid raw material. Expected byte array.") - } - - if len(aesRaw) == 0 { - return nil, errors.New("[HMACImportKeyOpts] Invalid raw. It must not be nil.") - } - - aesK := &aesPrivateKey{utils.Clone(aesRaw), false} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(aesK) - if err != nil { - return nil, fmt.Errorf("Failed storing AES key [%s]", err) - } - } - - return aesK, nil - - case *bccsp.ECDSAPKIXPublicKeyImportOpts: - der, ok := raw.([]byte) - if !ok { - return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw material. Expected byte array.") - } - - if len(der) == 0 { - return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw. It must not be nil.") - } - - lowLevelKey, err := utils.DERToPublicKey(der) - if err != nil { - return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) - } - - ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey) - if !ok { - return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") - } - - k = &ecdsaPublicKey{ecdsaPK} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } - } - - return k, nil - - case *bccsp.ECDSAPrivateKeyImportOpts: - der, ok := raw.([]byte) - if !ok { - return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") - } + keyImporter, found := csp.keyImporters[reflect.TypeOf(opts)] + if !found { + return nil, fmt.Errorf("Unsupported 'KeyImportOpts' provided [%v]", opts) + } - if len(der) == 0 { - return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.") - } + k, err = keyImporter.KeyImport(raw, opts) + if err != nil { + return nil, err + } - lowLevelKey, err := utils.DERToPrivateKey(der) + // If the key is not Ephemeral, store it. + if !opts.Ephemeral() { + // Store the key + err = csp.ks.StoreKey(k) if err != nil { - return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) - } - - ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey) - if !ok { - return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") - } - - k = &ecdsaPrivateKey{ecdsaSK} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } - } - - return k, nil - - case *bccsp.ECDSAGoPublicKeyImportOpts: - lowLevelKey, ok := raw.(*ecdsa.PublicKey) - if !ok { - return nil, errors.New("[ECDSAGoPublicKeyImportOpts] Invalid raw material. Expected *ecdsa.PublicKey.") - } - - k = &ecdsaPublicKey{lowLevelKey} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } - } - - return k, nil - - case *bccsp.RSAGoPublicKeyImportOpts: - lowLevelKey, ok := raw.(*rsa.PublicKey) - if !ok { - return nil, errors.New("[RSAGoPublicKeyImportOpts] Invalid raw material. Expected *rsa.PublicKey.") - } - - k = &rsaPublicKey{lowLevelKey} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing RSA publi key [%s]", err) - } - } - - return k, nil - - case *bccsp.X509PublicKeyImportOpts: - x509Cert, ok := raw.(*x509.Certificate) - if !ok { - return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate.") - } - - pk := x509Cert.PublicKey - - switch pk.(type) { - case *ecdsa.PublicKey: - return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) - case *rsa.PublicKey: - return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) - default: - return nil, errors.New("Certificate public key type not recognized. Supported keys: [ECDSA, RSA]") + return nil, fmt.Errorf("Failed storing key [%s]. [%s]", opts.Algorithm(), err) } - - default: - return nil, fmt.Errorf("Unsupported 'KeyImportOptions' provided [%v]", opts) } + + return k, nil } // GetKey returns the key this CSP associates to diff --git a/bccsp/sw/internals.go b/bccsp/sw/internals.go index cfca22fa4c7..df8a2b37ae1 100644 --- a/bccsp/sw/internals.go +++ b/bccsp/sw/internals.go @@ -37,6 +37,14 @@ type KeyDeriver interface { KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) } +// KeyImporter is a BCCSP-like interface that provides key import algorithms +type KeyImporter interface { + + // KeyImport imports a key from its raw representation using opts. + // The opts argument should be appropriate for the primitive used. + KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) +} + // Encryptor is a BCCSP-like interface that provides encryption algorithms type Encryptor interface { diff --git a/bccsp/sw/keyimport.go b/bccsp/sw/keyimport.go new file mode 100644 index 00000000000..bd526464608 --- /dev/null +++ b/bccsp/sw/keyimport.go @@ -0,0 +1,162 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sw + +import ( + "errors" + "fmt" + + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "reflect" + + "github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric/bccsp/utils" +) + +type aes256ImportKeyOptsKeyImporter struct{} + +func (*aes256ImportKeyOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + aesRaw, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if aesRaw == nil { + return nil, errors.New("Invalid raw material. It must not be nil.") + } + + if len(aesRaw) != 32 { + return nil, fmt.Errorf("Invalid Key Length [%d]. Must be 32 bytes", len(aesRaw)) + } + + return &aesPrivateKey{utils.Clone(aesRaw), false}, nil +} + +type hmacImportKeyOptsKeyImporter struct{} + +func (*hmacImportKeyOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + aesRaw, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if len(aesRaw) == 0 { + return nil, errors.New("Invalid raw material. It must not be nil.") + } + + return &aesPrivateKey{utils.Clone(aesRaw), false}, nil +} + +type ecdsaPKIXPublicKeyImportOptsKeyImporter struct{} + +func (*ecdsaPKIXPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPublicKey(der) + if err != nil { + return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) + } + + ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") + } + + return &ecdsaPublicKey{ecdsaPK}, nil +} + +type ecdsaPrivateKeyImportOptsKeyImporter struct{} + +func (*ecdsaPrivateKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPrivateKey(der) + if err != nil { + return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) + } + + ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA private key. Invalid raw material.") + } + + return &ecdsaPrivateKey{ecdsaSK}, nil +} + +type ecdsaGoPublicKeyImportOptsKeyImporter struct{} + +func (*ecdsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + lowLevelKey, ok := raw.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("Invalid raw material. Expected *ecdsa.PublicKey.") + } + + return &ecdsaPublicKey{lowLevelKey}, nil +} + +type rsaGoPublicKeyImportOptsKeyImporter struct{} + +func (*rsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + lowLevelKey, ok := raw.(*rsa.PublicKey) + if !ok { + return nil, errors.New("Invalid raw material. Expected *rsa.PublicKey.") + } + + return &rsaPublicKey{lowLevelKey}, nil +} + +type x509PublicKeyImportOptsKeyImporter struct { + bccsp *impl +} + +func (ki *x509PublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + x509Cert, ok := raw.(*x509.Certificate) + if !ok { + return nil, errors.New("Invalid raw material. Expected *x509.Certificate.") + } + + pk := x509Cert.PublicKey + + switch pk.(type) { + case *ecdsa.PublicKey: + return ki.bccsp.keyImporters[reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{})].KeyImport( + pk, + &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + case *rsa.PublicKey: + return ki.bccsp.keyImporters[reflect.TypeOf(&bccsp.RSAGoPublicKeyImportOpts{})].KeyImport( + pk, + &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + default: + return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") + } +} diff --git a/bccsp/sw/keyimport_test.go b/bccsp/sw/keyimport_test.go new file mode 100644 index 00000000000..52609d988d4 --- /dev/null +++ b/bccsp/sw/keyimport_test.go @@ -0,0 +1,195 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sw + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "errors" + "reflect" + "testing" + + mocks2 "github.com/hyperledger/fabric/bccsp/mocks" + "github.com/hyperledger/fabric/bccsp/sw/mocks" + "github.com/hyperledger/fabric/bccsp/utils" + "github.com/stretchr/testify/assert" +) + +func TestKeyImport(t *testing.T) { + expectedRaw := []byte{1, 2, 3} + expectedOpts := &mocks2.KeyDerivOpts{EphemeralValue: true} + expectetValue := &mocks2.MockKey{BytesValue: []byte{1, 2, 3, 4, 5}} + expectedErr := errors.New("no error") + + keyImporters := make(map[reflect.Type]KeyImporter) + keyImporters[reflect.TypeOf(&mocks2.KeyDerivOpts{})] = &mocks.KeyImporter{ + RawArg: expectedRaw, + OptsArg: expectedOpts, + Value: expectetValue, + Err: expectedErr, + } + csp := impl{keyImporters: keyImporters} + value, err := csp.KeyImport(expectedRaw, expectedOpts) + assert.Equal(t, nil, value) + assert.Equal(t, expectedErr, err) + + keyImporters = make(map[reflect.Type]KeyImporter) + keyImporters[reflect.TypeOf(&mocks2.KeyDerivOpts{})] = &mocks.KeyImporter{ + RawArg: expectedRaw, + OptsArg: expectedOpts, + Value: expectetValue, + Err: nil, + } + csp = impl{keyImporters: keyImporters} + value, err = csp.KeyImport(expectedRaw, expectedOpts) + assert.Equal(t, expectetValue, value) + assert.Equal(t, nil, err) +} + +func TestAES256ImportKeyOptsKeyImporter(t *testing.T) { + ki := aes256ImportKeyOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport([]byte(nil), &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. It must not be nil.") + + _, err = ki.KeyImport([]byte{0}, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid Key Length [") +} + +func TestHMACImportKeyOptsKeyImporter(t *testing.T) { + ki := hmacImportKeyOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport([]byte(nil), &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. It must not be nil.") +} + +func TestECDSAPKIXPublicKeyImportOptsKeyImporter(t *testing.T) { + ki := ecdsaPKIXPublicKeyImportOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport([]byte(nil), &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw. It must not be nil.") + + _, err = ki.KeyImport([]byte{0}, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed converting PKIX to ECDSA public key [") + + k, err := rsa.GenerateKey(rand.Reader, 512) + assert.NoError(t, err) + raw, err := utils.PublicKeyToDER(&k.PublicKey) + assert.NoError(t, err) + _, err = ki.KeyImport(raw, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed casting to ECDSA public key. Invalid raw material.") +} + +func TestECDSAPrivateKeyImportOptsKeyImporter(t *testing.T) { + ki := ecdsaPrivateKeyImportOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected byte array.") + + _, err = ki.KeyImport([]byte(nil), &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw. It must not be nil.") + + _, err = ki.KeyImport([]byte{0}, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed converting PKIX to ECDSA public key") + + k, err := rsa.GenerateKey(rand.Reader, 512) + assert.NoError(t, err) + raw := x509.MarshalPKCS1PrivateKey(k) + _, err = ki.KeyImport(raw, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Failed casting to ECDSA private key. Invalid raw material.") +} + +func TestECDSAGoPublicKeyImportOptsKeyImporter(t *testing.T) { + ki := ecdsaGoPublicKeyImportOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *ecdsa.PublicKey.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *ecdsa.PublicKey.") +} + +func TestRSAGoPublicKeyImportOptsKeyImporter(t *testing.T) { + ki := rsaGoPublicKeyImportOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *rsa.PublicKey.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *rsa.PublicKey.") +} + +func TestX509PublicKeyImportOptsKeyImporter(t *testing.T) { + ki := x509PublicKeyImportOptsKeyImporter{} + + _, err := ki.KeyImport("Hello World", &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *x509.Certificate.") + + _, err = ki.KeyImport(nil, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Invalid raw material. Expected *x509.Certificate.") + + cert := &x509.Certificate{} + cert.PublicKey = "Hello world" + _, err = ki.KeyImport(cert, &mocks2.KeyImportOpts{}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") +} diff --git a/bccsp/sw/mocks/mocks.go b/bccsp/sw/mocks/mocks.go index c146a2090f0..17b790b5a8a 100644 --- a/bccsp/sw/mocks/mocks.go +++ b/bccsp/sw/mocks/mocks.go @@ -158,3 +158,22 @@ func (kd *KeyDeriver) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.K return kd.Value, kd.Err } + +type KeyImporter struct { + RawArg []byte + OptsArg bccsp.KeyImportOpts + + Value bccsp.Key + Err error +} + +func (ki *KeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + if !reflect.DeepEqual(ki.RawArg, raw) { + return nil, errors.New("invalid raw") + } + if !reflect.DeepEqual(ki.OptsArg, opts) { + return nil, errors.New("invalid opts") + } + + return ki.Value, ki.Err +} diff --git a/bccsp/sw/sw_test.go b/bccsp/sw/sw_test.go index 8d40878a21d..cf6a95b558e 100644 --- a/bccsp/sw/sw_test.go +++ b/bccsp/sw/sw_test.go @@ -81,15 +81,15 @@ func TestKeyImportInvalidInputs(t *testing.T) { _, err = csp.KeyImport(nil, &bccsp.AES256ImportKeyOpts{}) assert.Error(t, err) - assert.Contains(t, err.Error(), "Invalid raw. Cannot be nil") + assert.Contains(t, err.Error(), "Invalid raw. It must not be nil.") _, err = csp.KeyImport([]byte{0, 1, 2, 3, 4}, nil) assert.Error(t, err) - assert.Contains(t, err.Error(), "Invalid Opts parameter. It must not be nil.") + assert.Contains(t, err.Error(), "Invalid opts. It must not be nil.") _, err = csp.KeyImport([]byte{0, 1, 2, 3, 4}, &mocks.KeyImportOpts{}) assert.Error(t, err) - assert.Contains(t, err.Error(), "Unsupported 'KeyImportOptions' provided [") + assert.Contains(t, err.Error(), "Unsupported 'KeyImportOpts' provided [") } func TestGetKeyInvalidInputs(t *testing.T) { diff --git a/bccsp/utils/keys.go b/bccsp/utils/keys.go index 4f3c95c1940..f11554c53a4 100644 --- a/bccsp/utils/keys.go +++ b/bccsp/utils/keys.go @@ -359,8 +359,19 @@ func PublicKeyToDER(publicKey interface{}) ([]byte, error) { return PubASN1, nil + case *rsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid rsa public key. It must be different from nil.") + } + PubASN1, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + return PubASN1, nil + default: - return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey") + return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") } }