From df396989c8b34b8029270edcaba750c151841287 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 17 May 2017 02:34:22 -0400 Subject: [PATCH] [FAB-3968] BCCSP/pkcs11 code de-duplication First pass, mostly all about rough code deletion. There is a bit further code duplication on ECDSA side, but on smaller scale, leaving for further patch sets. The intention is to help with testing. The deleted code is a copy of SW BCCSP. I either start copying even MORE changes from SW BCCSP, or clean things up like this. I believe this is preferable. Change-Id: Ic17177c46359ee830e68d19d6545d51b7653e997 Signed-off-by: Volodymyr Paprotski --- bccsp/pkcs11/aes.go | 137 ----------- bccsp/pkcs11/aes_test.go | 478 ------------------------------------ bccsp/pkcs11/aeskey.go | 65 ----- bccsp/pkcs11/dummyks.go | 44 ---- bccsp/pkcs11/fileks.go | 395 ----------------------------- bccsp/pkcs11/fileks_test.go | 56 ----- bccsp/pkcs11/impl.go | 365 ++------------------------- bccsp/pkcs11/impl_test.go | 157 +----------- bccsp/pkcs11/rsakey.go | 136 ---------- 9 files changed, 25 insertions(+), 1808 deletions(-) delete mode 100644 bccsp/pkcs11/aes.go delete mode 100644 bccsp/pkcs11/aes_test.go delete mode 100644 bccsp/pkcs11/aeskey.go delete mode 100644 bccsp/pkcs11/dummyks.go delete mode 100644 bccsp/pkcs11/fileks.go delete mode 100644 bccsp/pkcs11/fileks_test.go delete mode 100644 bccsp/pkcs11/rsakey.go diff --git a/bccsp/pkcs11/aes.go b/bccsp/pkcs11/aes.go deleted file mode 100644 index 3f06035ecb6..00000000000 --- a/bccsp/pkcs11/aes.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "errors" - "fmt" - "io" -) - -// GetRandomBytes returns len random looking bytes -func GetRandomBytes(len int) ([]byte, error) { - buffer := make([]byte, len) - - n, err := rand.Read(buffer) - if err != nil { - return nil, err - } - if n != len { - return nil, fmt.Errorf("Buffer not filled. Requested [%d], got [%d]", len, n) - } - - return buffer, nil -} - -func pkcs7Padding(src []byte) []byte { - padding := aes.BlockSize - len(src)%aes.BlockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(src, padtext...) -} - -func pkcs7UnPadding(src []byte) ([]byte, error) { - length := len(src) - unpadding := int(src[length-1]) - - if unpadding > aes.BlockSize || unpadding == 0 { - return nil, errors.New("Invalid pkcs7 padding (unpadding > aes.BlockSize || unpadding == 0)") - } - - pad := src[len(src)-unpadding:] - for i := 0; i < unpadding; i++ { - if pad[i] != byte(unpadding) { - return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)") - } - } - - return src[:(length - unpadding)], nil -} - -func aesCBCEncrypt(key, s []byte) ([]byte, error) { - if len(s)%aes.BlockSize != 0 { - return nil, errors.New("Invalid plaintext. It must be a multiple of the block size") - } - - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - ciphertext := make([]byte, aes.BlockSize+len(s)) - iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err - } - - mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(ciphertext[aes.BlockSize:], s) - - return ciphertext, nil -} - -func aesCBCDecrypt(key, src []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - if len(src) < aes.BlockSize { - return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size") - } - iv := src[:aes.BlockSize] - src = src[aes.BlockSize:] - - if len(src)%aes.BlockSize != 0 { - return nil, errors.New("Invalid ciphertext. It must be a multiple of the block size") - } - - mode := cipher.NewCBCDecrypter(block, iv) - - mode.CryptBlocks(src, src) - - return src, nil -} - -// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding -func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) { - // First pad - tmp := pkcs7Padding(src) - - // Then encrypt - return aesCBCEncrypt(key, tmp) -} - -// AESCBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding -func AESCBCPKCS7Decrypt(key, src []byte) ([]byte, error) { - // First decrypt - pt, err := aesCBCDecrypt(key, src) - if err != nil { - return nil, err - } - - // Then remove padding - original, err := pkcs7UnPadding(pt) - if err != nil { - return nil, err - } - - return original, nil -} diff --git a/bccsp/pkcs11/aes_test.go b/bccsp/pkcs11/aes_test.go deleted file mode 100644 index d84dff2d0cc..00000000000 --- a/bccsp/pkcs11/aes_test.go +++ /dev/null @@ -1,478 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "bytes" - "crypto/aes" - "crypto/rand" - "math/big" - "testing" - - "github.com/hyperledger/fabric/bccsp/utils" -) - -// TestCBCPKCS7EncryptCBCPKCS7Decrypt encrypts using CBCPKCS7Encrypt and decrypts using CBCPKCS7Decrypt. -func TestCBCPKCS7EncryptCBCPKCS7Decrypt(t *testing.T) { - - // Note: The purpose of this test is not to test AES-256 in CBC mode's strength - // ... but rather to verify the code wrapping/unwrapping the cipher. - key := make([]byte, 32) - rand.Reader.Read(key) - - // 123456789012345678901234567890123456789012 - var ptext = []byte("a message with arbitrary length (42 bytes)") - - encrypted, encErr := AESCBCPKCS7Encrypt(key, ptext) - if encErr != nil { - t.Fatalf("Error encrypting '%s': %s", ptext, encErr) - } - - decrypted, dErr := AESCBCPKCS7Decrypt(key, encrypted) - if dErr != nil { - t.Fatalf("Error decrypting the encrypted '%s': %v", ptext, dErr) - } - - if string(ptext[:]) != string(decrypted[:]) { - t.Fatal("Decrypt( Encrypt( ptext ) ) != ptext: Ciphertext decryption with the same key must result in the original plaintext!") - } - -} - -// TestPKCS7Padding verifies the PKCS#7 padding, using a human readable plaintext. -func TestPKCS7Padding(t *testing.T) { - - // 0 byte/length ptext - ptext := []byte("") - expected := []byte{16, 16, 16, 16, - 16, 16, 16, 16, - 16, 16, 16, 16, - 16, 16, 16, 16} - result := pkcs7Padding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("Padding error! Expected: ", expected, "', received: '", result, "'") - } - - // 1 byte/length ptext - ptext = []byte("1") - expected = []byte{'1', 15, 15, 15, - 15, 15, 15, 15, - 15, 15, 15, 15, - 15, 15, 15, 15} - result = pkcs7Padding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("Padding error! Expected: '", expected, "', received: '", result, "'") - } - - // 2 byte/length ptext - ptext = []byte("12") - expected = []byte{'1', '2', 14, 14, - 14, 14, 14, 14, - 14, 14, 14, 14, - 14, 14, 14, 14} - result = pkcs7Padding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("Padding error! Expected: '", expected, "', received: '", result, "'") - } - - // 3 to aes.BlockSize-1 byte plaintext - ptext = []byte("1234567890ABCDEF") - for i := 3; i < aes.BlockSize; i++ { - result := pkcs7Padding(ptext[:i]) - - padding := aes.BlockSize - i - expectedPadding := bytes.Repeat([]byte{byte(padding)}, padding) - expected = append(ptext[:i], expectedPadding...) - - if !bytes.Equal(result, expected) { - t.Fatal("Padding error! Expected: '", expected, "', received: '", result, "'") - } - - } - - // aes.BlockSize length ptext - ptext = bytes.Repeat([]byte{byte('x')}, aes.BlockSize) - result = pkcs7Padding(ptext) - - expectedPadding := bytes.Repeat([]byte{byte(aes.BlockSize)}, aes.BlockSize) - expected = append(ptext, expectedPadding...) - - if len(result) != 2*aes.BlockSize { - t.Fatal("Padding error: expected the length of the returned slice to be 2 times aes.BlockSize") - } - - if !bytes.Equal(expected, result) { - t.Fatal("Padding error! Expected: '", expected, "', received: '", result, "'") - } - -} - -// TestPKCS7UnPadding verifies the PKCS#7 unpadding, using a human readable plaintext. -func TestPKCS7UnPadding(t *testing.T) { - - // 0 byte/length ptext - expected := []byte("") - ptext := []byte{16, 16, 16, 16, - 16, 16, 16, 16, - 16, 16, 16, 16, - 16, 16, 16, 16} - - result, _ := pkcs7UnPadding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("UnPadding error! Expected: '", expected, "', received: '", result, "'") - } - - // 1 byte/length ptext - expected = []byte("1") - ptext = []byte{'1', 15, 15, 15, - 15, 15, 15, 15, - 15, 15, 15, 15, - 15, 15, 15, 15} - - result, _ = pkcs7UnPadding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("UnPadding error! Expected: '", expected, "', received: '", result, "'") - } - - // 2 byte/length ptext - expected = []byte("12") - ptext = []byte{'1', '2', 14, 14, - 14, 14, 14, 14, - 14, 14, 14, 14, - 14, 14, 14, 14} - - result, _ = pkcs7UnPadding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("UnPadding error! Expected: '", expected, "', received: '", result, "'") - } - - // 3 to aes.BlockSize-1 byte plaintext - base := []byte("1234567890ABCDEF") - for i := 3; i < aes.BlockSize; i++ { - iPad := aes.BlockSize - i - padding := bytes.Repeat([]byte{byte(iPad)}, iPad) - ptext = append(base[:i], padding...) - - expected := base[:i] - result, _ := pkcs7UnPadding(ptext) - - if !bytes.Equal(result, expected) { - t.Fatal("UnPadding error! Expected: '", expected, "', received: '", result, "'") - } - - } - - // aes.BlockSize length ptext - expected = bytes.Repeat([]byte{byte('x')}, aes.BlockSize) - padding := bytes.Repeat([]byte{byte(aes.BlockSize)}, aes.BlockSize) - ptext = append(expected, padding...) - - result, _ = pkcs7UnPadding(ptext) - - if !bytes.Equal(expected, result) { - t.Fatal("UnPadding error! Expected: '", expected, "', received: '", result, "'") - } -} - -// TestCBCEncryptCBCPKCS7Decrypt_BlockSizeLengthPlaintext verifies that CBCPKCS7Decrypt returns an error -// when attempting to decrypt ciphertext of an irreproducible length. -func TestCBCEncryptCBCPKCS7Decrypt_BlockSizeLengthPlaintext(t *testing.T) { - - // One of the purposes of this test is to also document and clarify the expected behavior, i.e., that an extra - // block is appended to the message at the padding stage, as per the spec of PKCS#7 v1.5 [see RFC-2315 p.21] - key := make([]byte, 32) - rand.Reader.Read(key) - - // 1234567890123456 - var ptext = []byte("a 16 byte messag") - - encrypted, encErr := aesCBCEncrypt(key, ptext) - if encErr != nil { - t.Fatalf("Error encrypting '%s': %v", ptext, encErr) - } - - decrypted, dErr := AESCBCPKCS7Decrypt(key, encrypted) - if dErr == nil { - t.Fatalf("Expected an error decrypting ptext '%s'. Decrypted to '%v'", dErr, decrypted) - } -} - -// TestCBCPKCS7EncryptCBCDecrypt_ExpectingCorruptMessage verifies that CBCDecrypt can decrypt the unpadded -// version of the ciphertext, of a message of BlockSize length. -func TestCBCPKCS7EncryptCBCDecrypt_ExpectingCorruptMessage(t *testing.T) { - - // One of the purposes of this test is to also document and clarify the expected behavior, i.e., that an extra - // block is appended to the message at the padding stage, as per the spec of PKCS#7 v1.5 [see RFC-2315 p.21] - key := make([]byte, 32) - rand.Reader.Read(key) - - // 0123456789ABCDEF - var ptext = []byte("a 16 byte messag") - - encrypted, encErr := AESCBCPKCS7Encrypt(key, ptext) - if encErr != nil { - t.Fatalf("Error encrypting ptext %v", encErr) - } - - decrypted, dErr := aesCBCDecrypt(key, encrypted) - if dErr != nil { - t.Fatalf("Error encrypting ptext %v, %v", dErr, decrypted) - } - - if string(ptext[:]) != string(decrypted[:aes.BlockSize]) { - t.Log("ptext: ", ptext) - t.Log("decrypted: ", decrypted[:aes.BlockSize]) - t.Fatal("Encryption->Decryption with same key should result in original ptext") - } - - if !bytes.Equal(decrypted[aes.BlockSize:], bytes.Repeat([]byte{byte(aes.BlockSize)}, aes.BlockSize)) { - t.Fatal("Expected extra block with padding in encrypted ptext", decrypted) - } - -} - -// TestCBCPKCS7Encrypt_EmptyPlaintext encrypts and pad an empty ptext. Verifying as well that the ciphertext length is as expected. -func TestCBCPKCS7Encrypt_EmptyPlaintext(t *testing.T) { - - key := make([]byte, 32) - rand.Reader.Read(key) - - t.Log("Generated key: ", key) - - var emptyPlaintext = []byte("") - t.Log("Plaintext length: ", len(emptyPlaintext)) - - ciphertext, encErr := AESCBCPKCS7Encrypt(key, emptyPlaintext) - if encErr != nil { - t.Fatalf("Error encrypting '%v'", encErr) - } - - // Expected ciphertext length: 32 (=32) - // As part of the padding, at least one block gets encrypted (while the first block is the IV) - const expectedLength = aes.BlockSize + aes.BlockSize - if len(ciphertext) != expectedLength { - t.Fatalf("Wrong ciphertext length. Expected %d, received %d", expectedLength, len(ciphertext)) - } - - t.Log("Ciphertext length: ", len(ciphertext)) - t.Log("Cipher: ", ciphertext) -} - -// TestCBCEncrypt_EmptyPlaintext encrypts an empty message. Verifying as well that the ciphertext length is as expected. -func TestCBCEncrypt_EmptyPlaintext(t *testing.T) { - - key := make([]byte, 32) - rand.Reader.Read(key) - t.Log("Generated key: ", key) - - var emptyPlaintext = []byte("") - t.Log("Message length: ", len(emptyPlaintext)) - - ciphertext, encErr := aesCBCEncrypt(key, emptyPlaintext) - if encErr != nil { - } - - t.Log("Ciphertext length: ", len(ciphertext)) - - // Expected cipher length: aes.BlockSize, the first and only block is the IV - var expectedLength = aes.BlockSize - - if len(ciphertext) != expectedLength { - t.Fatalf("Wrong ciphertext length. Expected: '%d', received: '%d'", expectedLength, len(ciphertext)) - } - t.Log("Ciphertext: ", ciphertext) -} - -// TestCBCPKCS7Encrypt_VerifyRandomIVs encrypts twice with same key. The first 16 bytes should be different if IV is generated randomly. -func TestCBCPKCS7Encrypt_VerifyRandomIVs(t *testing.T) { - - key := make([]byte, aes.BlockSize) - rand.Reader.Read(key) - t.Log("Key 1", key) - - var ptext = []byte("a message to encrypt") - - ciphertext1, err := AESCBCPKCS7Encrypt(key, ptext) - if err != nil { - t.Fatalf("Error encrypting '%s': %s", ptext, err) - } - - // Expecting a different IV if same message is encrypted with same key - ciphertext2, err := AESCBCPKCS7Encrypt(key, ptext) - if err != nil { - t.Fatalf("Error encrypting '%s': %s", ptext, err) - } - - iv1 := ciphertext1[:aes.BlockSize] - iv2 := ciphertext2[:aes.BlockSize] - - t.Log("Ciphertext1: ", iv1) - t.Log("Ciphertext2: ", iv2) - t.Log("bytes.Equal: ", bytes.Equal(iv1, iv2)) - - if bytes.Equal(iv1, iv2) { - t.Fatal("Error: ciphertexts contain identical initialization vectors (IVs)") - } -} - -// TestCBCPKCS7Encrypt_CorrectCiphertextLengthCheck verifies that the returned ciphertext lengths are as expected. -func TestCBCPKCS7Encrypt_CorrectCiphertextLengthCheck(t *testing.T) { - - key := make([]byte, aes.BlockSize) - rand.Reader.Read(key) - - // length of message (in bytes) == aes.BlockSize (16 bytes) - // The expected cipher length = IV length (1 block) + 1 block message - - var ptext = []byte("0123456789ABCDEF") - - for i := 1; i < aes.BlockSize; i++ { - ciphertext, err := AESCBCPKCS7Encrypt(key, ptext[:i]) - if err != nil { - t.Fatal("Error encrypting '", ptext, "'") - } - - expectedLength := aes.BlockSize + aes.BlockSize - if len(ciphertext) != expectedLength { - t.Fatalf("Incorrect ciphertext incorrect: expected '%d', received '%d'", expectedLength, len(ciphertext)) - } - } -} - -// TestCBCEncryptCBCDecrypt_KeyMismatch attempts to decrypt with a different key than the one used for encryption. -func TestCBCEncryptCBCDecrypt_KeyMismatch(t *testing.T) { - - // Generate a random key - key := make([]byte, aes.BlockSize) - rand.Reader.Read(key) - - // Clone & tamper with the key - wrongKey := make([]byte, aes.BlockSize) - copy(wrongKey, key[:]) - wrongKey[0] = key[0] + 1 - - var ptext = []byte("1234567890ABCDEF") - encrypted, encErr := aesCBCEncrypt(key, ptext) - if encErr != nil { - t.Fatalf("Error encrypting '%s': %v", ptext, encErr) - } - - decrypted, decErr := aesCBCDecrypt(wrongKey, encrypted) - if decErr != nil { - t.Fatalf("Error decrypting '%s': %v", ptext, decErr) - } - - if string(ptext[:]) == string(decrypted[:]) { - t.Fatal("Decrypting a ciphertext with a different key than the one used for encrypting it - should not result in the original plaintext.") - } -} - -// TestCBCEncryptCBCDecrypt encrypts with CBCEncrypt and decrypt with CBCDecrypt. -func TestCBCEncryptCBCDecrypt(t *testing.T) { - - key := make([]byte, 32) - rand.Reader.Read(key) - - // 1234567890123456 - var ptext = []byte("a 16 byte messag") - - encrypted, encErr := aesCBCEncrypt(key, ptext) - if encErr != nil { - t.Fatalf("Error encrypting '%s': %v", ptext, encErr) - } - - decrypted, decErr := aesCBCDecrypt(key, encrypted) - if decErr != nil { - t.Fatalf("Error decrypting '%s': %v", ptext, decErr) - } - - if string(ptext[:]) != string(decrypted[:]) { - t.Fatal("Encryption->Decryption with same key should result in the original plaintext.") - } -} - -// TestAESRelatedUtilFunctions tests various functions commonly used in fabric wrt AES -func TestAESRelatedUtilFunctions(t *testing.T) { - - key, err := GetRandomBytes(32) - if err != nil { - t.Fatalf("Failed generating AES key [%s]", err) - } - - for i := 1; i < 100; i++ { - l, err := rand.Int(rand.Reader, big.NewInt(1024)) - if err != nil { - t.Fatalf("Failed generating AES key [%s]", err) - } - msg, err := GetRandomBytes(int(l.Int64()) + 1) - if err != nil { - t.Fatalf("Failed generating AES key [%s]", err) - } - - ct, err := AESCBCPKCS7Encrypt(key, msg) - if err != nil { - t.Fatalf("Failed encrypting [%s]", err) - } - - msg2, err := AESCBCPKCS7Decrypt(key, ct) - if err != nil { - t.Fatalf("Failed decrypting [%s]", err) - } - - if 0 != bytes.Compare(msg, msg2) { - t.Fatalf("Wrong decryption output [%x][%x]", msg, msg2) - } - - } - -} - -// TestVariousAESKeyEncoding tests some AES <-> PEM conversions -func TestVariousAESKeyEncoding(t *testing.T) { - key, err := GetRandomBytes(32) - if err != nil { - t.Fatalf("Failed generating AES key [%s]", err) - } - - // PEM format - pem := utils.AEStoPEM(key) - keyFromPEM, err := utils.PEMtoAES(pem, nil) - if err != nil { - t.Fatalf("Failed converting PEM to AES key [%s]", err) - } - if 0 != bytes.Compare(key, keyFromPEM) { - t.Fatalf("Failed converting PEM to AES key. Keys are different [%x][%x]", key, keyFromPEM) - } - - // Encrypted PEM format - pem, err = utils.AEStoEncryptedPEM(key, []byte("passwd")) - if err != nil { - t.Fatalf("Failed converting AES key to Encrypted PEM [%s]", err) - } - keyFromPEM, err = utils.PEMtoAES(pem, []byte("passwd")) - if err != nil { - t.Fatalf("Failed converting encrypted PEM to AES key [%s]", err) - } - if 0 != bytes.Compare(key, keyFromPEM) { - t.Fatalf("Failed converting encrypted PEM to AES key. Keys are different [%x][%x]", key, keyFromPEM) - } -} diff --git a/bccsp/pkcs11/aeskey.go b/bccsp/pkcs11/aeskey.go deleted file mode 100644 index 3a5f899046c..00000000000 --- a/bccsp/pkcs11/aeskey.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "errors" - - "crypto/sha256" - - "github.com/hyperledger/fabric/bccsp" -) - -type aesPrivateKey struct { - privKey []byte - exportable bool -} - -// Bytes converts this key to its byte representation, -// if this operation is allowed. -func (k *aesPrivateKey) Bytes() (raw []byte, err error) { - if k.exportable { - return k.privKey, nil - } - - return nil, errors.New("Not supported.") -} - -// SKI returns the subject key identifier of this key. -func (k *aesPrivateKey) SKI() (ski []byte) { - hash := sha256.New() - hash.Write([]byte{0x01}) - hash.Write(k.privKey) - return hash.Sum(nil) -} - -// Symmetric returns true if this key is a symmetric key, -// false if this key is asymmetric -func (k *aesPrivateKey) Symmetric() bool { - return true -} - -// Private returns true if this key is a private key, -// false otherwise. -func (k *aesPrivateKey) Private() bool { - return true -} - -// PublicKey returns the corresponding public key part of an asymmetric public/private key pair. -// This method returns an error in symmetric key schemes. -func (k *aesPrivateKey) PublicKey() (bccsp.Key, error) { - return nil, errors.New("Cannot call this method on a symmetric key.") -} diff --git a/bccsp/pkcs11/dummyks.go b/bccsp/pkcs11/dummyks.go deleted file mode 100644 index 37e4827c802..00000000000 --- a/bccsp/pkcs11/dummyks.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "errors" - - "github.com/hyperledger/fabric/bccsp" -) - -// dummyKeyStore is a read-only KeyStore that neither loads nor stores keys. -type DummyKeyStore struct { -} - -// ReadOnly returns true if this KeyStore is read only, false otherwise. -// If ReadOnly is true then StoreKey will fail. -func (ks *DummyKeyStore) ReadOnly() bool { - return true -} - -// GetKey returns a key object whose SKI is the one passed. -func (ks *DummyKeyStore) GetKey(ski []byte) (k bccsp.Key, err error) { - return nil, errors.New("Key not found. This is a dummy KeyStore") -} - -// StoreKey stores the key k in this KeyStore. -// If this KeyStore is read only then the method will fail. -func (ks *DummyKeyStore) StoreKey(k bccsp.Key) (err error) { - return errors.New("Cannot store key. This is a dummy read-only KeyStore") -} diff --git a/bccsp/pkcs11/fileks.go b/bccsp/pkcs11/fileks.go deleted file mode 100644 index 945632f3bc2..00000000000 --- a/bccsp/pkcs11/fileks.go +++ /dev/null @@ -1,395 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "bytes" - "crypto/rsa" - "encoding/hex" - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "sync" - - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/utils" -) - -// FileBasedKeyStore is a folder-based KeyStore. -// Each key is stored in a separated file whose name contains the key's SKI -// and flags to identity the key's type. All the keys are stored in -// a folder whose path is provided at initialization time. -// The KeyStore can be initialized with a password, this password -// is used to encrypt and decrypt the files storing the keys. -// A KeyStore can be read only to avoid the overwriting of keys. -type FileBasedKeyStore struct { - path string - - readOnly bool - isOpen bool - - pwd []byte - - // Sync - m sync.Mutex -} - -// Init initializes this KeyStore with a password, a path to a folder -// where the keys are stored and a read only flag. -// Each key is stored in a separated file whose name contains the key's SKI -// and flags to identity the key's type. -// If the KeyStore is initialized with a password, this password -// is used to encrypt and decrypt the files storing the keys. -// The pwd can be nil for non-encrypted KeyStores. If an encrypted -// key-store is initialized without a password, then retrieving keys from the -// KeyStore will fail. -// A KeyStore can be read only to avoid the overwriting of keys. -func (ks *FileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error { - // Validate inputs - // pwd can be nil - - if len(path) == 0 { - return errors.New("An invalid KeyStore path provided. Path cannot be an empty string.") - } - - ks.m.Lock() - defer ks.m.Unlock() - - if ks.isOpen { - return errors.New("KeyStore already initilized.") - } - - ks.path = path - ks.pwd = utils.Clone(pwd) - - err := ks.createKeyStoreIfNotExists() - if err != nil { - return err - } - - err = ks.openKeyStore() - if err != nil { - return err - } - - ks.readOnly = readOnly - - return nil -} - -// ReadOnly returns true if this KeyStore is read only, false otherwise. -// If ReadOnly is true then StoreKey will fail. -func (ks *FileBasedKeyStore) ReadOnly() bool { - return ks.readOnly -} - -// GetKey returns a key object whose SKI is the one passed. -func (ks *FileBasedKeyStore) GetKey(ski []byte) (k bccsp.Key, err error) { - // Validate arguments - if len(ski) == 0 { - return nil, errors.New("Invalid SKI. Cannot be of zero length.") - } - - suffix := ks.getSuffix(hex.EncodeToString(ski)) - - switch suffix { - case "key": - // Load the key - key, err := ks.loadKey(hex.EncodeToString(ski)) - if err != nil { - return nil, fmt.Errorf("Failed loading key [%x] [%s]", ski, err) - } - - return &aesPrivateKey{key, false}, nil - case "sk": - // Load the private key - key, err := ks.loadPrivateKey(hex.EncodeToString(ski)) - if err != nil { - return nil, fmt.Errorf("Failed loading secret key [%x] [%s]", ski, err) - } - - switch key.(type) { - case *rsa.PrivateKey: - return &rsaPrivateKey{key.(*rsa.PrivateKey)}, nil - default: - return nil, errors.New("Secret key type not recognized") - } - case "pk": - // Load the public key - key, err := ks.loadPublicKey(hex.EncodeToString(ski)) - if err != nil { - return nil, fmt.Errorf("Failed loading public key [%x] [%s]", ski, err) - } - - switch key.(type) { - case *rsa.PublicKey: - return &rsaPublicKey{key.(*rsa.PublicKey)}, nil - default: - return nil, errors.New("Public key type not recognized") - } - default: - return ks.searchKeystoreForSKI(ski) - } -} - -// StoreKey stores the key k in this KeyStore. -// If this KeyStore is read only then the method will fail. -func (ks *FileBasedKeyStore) StoreKey(k bccsp.Key) (err error) { - if ks.readOnly { - return errors.New("Read only KeyStore.") - } - - if k == nil { - return errors.New("Invalid key. It must be different from nil.") - } - switch k.(type) { - case *rsaPrivateKey: - kk := k.(*rsaPrivateKey) - - err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) - if err != nil { - return fmt.Errorf("Failed storing RSA private key [%s]", err) - } - - case *rsaPublicKey: - kk := k.(*rsaPublicKey) - - err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey) - if err != nil { - return fmt.Errorf("Failed storing RSA public key [%s]", err) - } - - case *aesPrivateKey: - kk := k.(*aesPrivateKey) - - err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey) - if err != nil { - return fmt.Errorf("Failed storing AES key [%s]", err) - } - - default: - return fmt.Errorf("Key type not reconigned [%s]", k) - } - - return -} - -func (ks *FileBasedKeyStore) searchKeystoreForSKI(ski []byte) (k bccsp.Key, err error) { - - files, _ := ioutil.ReadDir(ks.path) - for _, f := range files { - if f.IsDir() { - continue - } - raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name())) - - key, err := utils.PEMtoPrivateKey(raw, ks.pwd) - if err != nil { - continue - } - - switch key.(type) { - case *rsa.PrivateKey: - k = &rsaPrivateKey{key.(*rsa.PrivateKey)} - default: - continue - } - - if !bytes.Equal(k.SKI(), ski) { - continue - } - - return k, nil - } - return nil, errors.New("Key type not recognized") -} - -func (ks *FileBasedKeyStore) getSuffix(alias string) string { - files, _ := ioutil.ReadDir(ks.path) - for _, f := range files { - if strings.HasPrefix(f.Name(), alias) { - if strings.HasSuffix(f.Name(), "sk") { - return "sk" - } - if strings.HasSuffix(f.Name(), "pk") { - return "pk" - } - if strings.HasSuffix(f.Name(), "key") { - return "key" - } - break - } - } - return "" -} - -func (ks *FileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error { - rawKey, err := utils.PrivateKeyToPEM(privateKey, ks.pwd) - if err != nil { - logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0700) - if err != nil { - logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *FileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error { - rawKey, err := utils.PublicKeyToPEM(publicKey, ks.pwd) - if err != nil { - logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0700) - if err != nil { - logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *FileBasedKeyStore) storeKey(alias string, key []byte) error { - pem, err := utils.AEStoEncryptedPEM(key, ks.pwd) - if err != nil { - logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0700) - if err != nil { - logger.Errorf("Failed storing key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *FileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) { - path := ks.getPathForAlias(alias, "sk") - logger.Debugf("Loading private key [%s] at [%s]...", alias, path) - - raw, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - privateKey, err := utils.PEMtoPrivateKey(raw, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - return privateKey, nil -} - -func (ks *FileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) { - path := ks.getPathForAlias(alias, "pk") - logger.Debugf("Loading public key [%s] at [%s]...", alias, path) - - raw, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - privateKey, err := utils.PEMtoPublicKey(raw, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - return privateKey, nil -} - -func (ks *FileBasedKeyStore) loadKey(alias string) ([]byte, error) { - path := ks.getPathForAlias(alias, "key") - logger.Debugf("Loading key [%s] at [%s]...", alias, path) - - pem, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - key, err := utils.PEMtoAES(pem, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing key [%s]: [%s]", alias, err) - - return nil, err - } - - return key, nil -} - -func (ks *FileBasedKeyStore) createKeyStoreIfNotExists() error { - // Check keystore directory - ksPath := ks.path - missing, err := utils.DirMissingOrEmpty(ksPath) - - if missing { - logger.Debugf("KeyStore path [%s] missing [%t]: [%s]", ksPath, missing, utils.ErrToString(err)) - - err := ks.createKeyStore() - if err != nil { - logger.Errorf("Failed creating KeyStore At [%s]: [%s]", ksPath, err.Error()) - return nil - } - } - - return nil -} - -func (ks *FileBasedKeyStore) createKeyStore() error { - // Create keystore directory root if it doesn't exist yet - ksPath := ks.path - logger.Debugf("Creating KeyStore at [%s]...", ksPath) - - os.MkdirAll(ksPath, 0755) - - logger.Debugf("KeyStore created at [%s].", ksPath) - return nil -} - -func (ks *FileBasedKeyStore) openKeyStore() error { - if ks.isOpen { - return nil - } - - logger.Debugf("KeyStore opened at [%s]...done", ks.path) - - return nil -} - -func (ks *FileBasedKeyStore) getPathForAlias(alias, suffix string) string { - return filepath.Join(ks.path, alias+"_"+suffix) -} diff --git a/bccsp/pkcs11/fileks_test.go b/bccsp/pkcs11/fileks_test.go deleted file mode 100644 index 2e1990852c8..00000000000 --- a/bccsp/pkcs11/fileks_test.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "fmt" - "os" - "path/filepath" - "testing" -) - -func TestInvalidStoreKey(t *testing.T) { - ks := &FileBasedKeyStore{} - if err := ks.Init(nil, filepath.Join(os.TempDir(), "bccspks"), false); err != nil { - fmt.Printf("Failed initiliazing KeyStore [%s]", err) - os.Exit(-1) - } - - err := ks.StoreKey(nil) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - - err = ks.StoreKey(&rsaPublicKey{nil}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - - err = ks.StoreKey(&rsaPrivateKey{nil}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - - err = ks.StoreKey(&aesPrivateKey{nil, false}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - - err = ks.StoreKey(&aesPrivateKey{nil, true}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } -} diff --git a/bccsp/pkcs11/impl.go b/bccsp/pkcs11/impl.go index 28ed635c991..ef76f533320 100644 --- a/bccsp/pkcs11/impl.go +++ b/bccsp/pkcs11/impl.go @@ -18,24 +18,19 @@ package pkcs11 import ( "crypto/ecdsa" "crypto/elliptic" - "crypto/hmac" - "crypto/rand" "crypto/rsa" "crypto/sha256" - "crypto/sha512" "crypto/x509" "errors" "fmt" - "hash" "math/big" "os" "github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric/bccsp/sw" "github.com/hyperledger/fabric/bccsp/utils" "github.com/hyperledger/fabric/common/flogging" "github.com/miekg/pkcs11" - - "golang.org/x/crypto/sha3" ) var ( @@ -53,6 +48,11 @@ func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { return nil, fmt.Errorf("Failed initializing configuration [%s]", err) } + swCSP, err := sw.New(opts.SecLevel, opts.HashFamily, keyStore) + if err != nil { + return nil, fmt.Errorf("Failed initializing fallback SW BCCSP [%s]", err) + } + // Check KeyStore if keyStore == nil { return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil.") @@ -68,12 +68,14 @@ func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { } sessions := make(chan pkcs11.SessionHandle, sessionCacheSize) - csp := &impl{conf, keyStore, ctx, sessions, slot, lib, opts.Sensitive, opts.SoftVerify} + csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, lib, opts.Sensitive, opts.SoftVerify} csp.returnSession(*session) return csp, nil } type impl struct { + bccsp.BCCSP + conf *config ks bccsp.KeyStore @@ -93,8 +95,6 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { return nil, errors.New("Invalid Opts parameter. It must not be nil.") } - pkcs11Stored := false - // Parse algorithm switch opts.(type) { case *bccsp.ECDSAKeyGenOpts: @@ -103,7 +103,6 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { return nil, fmt.Errorf("Failed generating ECDSA key [%s]", err) } k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} - pkcs11Stored = true case *bccsp.ECDSAP256KeyGenOpts: ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) @@ -112,7 +111,6 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { } k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} - pkcs11Stored = true case *bccsp.ECDSAP384KeyGenOpts: ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) @@ -121,100 +119,9 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { } k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} - pkcs11Stored = true - - case *bccsp.AESKeyGenOpts: - lowLevelKey, err := GetRandomBytes(csp.conf.aesBitLength) - - if err != nil { - return nil, fmt.Errorf("Failed generating AES key [%s]", err) - } - - k = &aesPrivateKey{lowLevelKey, false} - - case *bccsp.AES256KeyGenOpts: - lowLevelKey, err := GetRandomBytes(32) - - if err != nil { - return nil, fmt.Errorf("Failed generating AES 256 key [%s]", err) - } - - k = &aesPrivateKey{lowLevelKey, false} - - case *bccsp.AES192KeyGenOpts: - lowLevelKey, err := GetRandomBytes(24) - - if err != nil { - return nil, fmt.Errorf("Failed generating AES 192 key [%s]", err) - } - - k = &aesPrivateKey{lowLevelKey, false} - - case *bccsp.AES128KeyGenOpts: - lowLevelKey, err := GetRandomBytes(16) - - if err != nil { - return nil, fmt.Errorf("Failed generating AES 128 key [%s]", err) - } - - k = &aesPrivateKey{lowLevelKey, false} - - case *bccsp.RSAKeyGenOpts: - lowLevelKey, err := rsa.GenerateKey(rand.Reader, csp.conf.rsaBitLength) - - if err != nil { - return nil, fmt.Errorf("Failed generating RSA key [%s]", err) - } - - k = &rsaPrivateKey{lowLevelKey} - - case *bccsp.RSA1024KeyGenOpts: - lowLevelKey, err := rsa.GenerateKey(rand.Reader, 1024) - - if err != nil { - return nil, fmt.Errorf("Failed generating RSA 1024 key [%s]", err) - } - - k = &rsaPrivateKey{lowLevelKey} - - case *bccsp.RSA2048KeyGenOpts: - lowLevelKey, err := rsa.GenerateKey(rand.Reader, 2048) - - if err != nil { - return nil, fmt.Errorf("Failed generating RSA 2048 key [%s]", err) - } - - k = &rsaPrivateKey{lowLevelKey} - - case *bccsp.RSA3072KeyGenOpts: - lowLevelKey, err := rsa.GenerateKey(rand.Reader, 3072) - - if err != nil { - return nil, fmt.Errorf("Failed generating RSA 3072 key [%s]", err) - } - - k = &rsaPrivateKey{lowLevelKey} - - case *bccsp.RSA4096KeyGenOpts: - lowLevelKey, err := rsa.GenerateKey(rand.Reader, 4096) - - if err != nil { - return nil, fmt.Errorf("Failed generating RSA 4096 key [%s]", err) - } - - k = &rsaPrivateKey{lowLevelKey} default: - return nil, fmt.Errorf("Unrecognized KeyGenOpts provided [%s]", opts.Algorithm()) - } - - // If the key is not Ephemeral, store it. EC Keys now in HSM, no need to store - if !pkcs11Stored && !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing key [%s]. [%s]", opts.Algorithm(), err) - } + return csp.BCCSP.KeyGen(opts) } return k, nil @@ -352,59 +259,10 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e return nil, fmt.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) } - case *aesPrivateKey: - // Validate opts - if opts == nil { - return nil, errors.New("Invalid Opts parameter. It must not be nil.") - } - - aesK := k.(*aesPrivateKey) - - switch opts.(type) { - case *bccsp.HMACTruncated256AESDeriveKeyOpts: - hmacOpts := opts.(*bccsp.HMACTruncated256AESDeriveKeyOpts) - - mac := hmac.New(csp.conf.hashFunction, aesK.privKey) - mac.Write(hmacOpts.Argument()) - hmacedKey := &aesPrivateKey{mac.Sum(nil)[:csp.conf.aesBitLength], false} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(hmacedKey) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } - } - - return hmacedKey, nil - - case *bccsp.HMACDeriveKeyOpts: - - hmacOpts := opts.(*bccsp.HMACDeriveKeyOpts) - - mac := hmac.New(csp.conf.hashFunction, aesK.privKey) - mac.Write(hmacOpts.Argument()) - hmacedKey := &aesPrivateKey{mac.Sum(nil), true} - - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(hmacedKey) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } - } - - return hmacedKey, nil - - default: - return nil, fmt.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) - - } default: - return nil, fmt.Errorf("Key type not recognized [%s]", k) + return csp.BCCSP.KeyDeriv(k, opts) + } } @@ -422,52 +280,6 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K 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 { @@ -588,25 +400,6 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K k = &ecdsaPublicKey{ski, lowLevelKey} 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 { @@ -625,7 +418,8 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K } default: - return nil, errors.New("Import Key Options not recognized") + return csp.BCCSP.KeyImport(raw, opts) + } } @@ -640,56 +434,7 @@ func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { return &ecdsaPublicKey{ski, pubKey}, nil } } - return csp.ks.GetKey(ski) -} - -// Hash hashes messages msg using options opts. -func (csp *impl) Hash(msg []byte, opts bccsp.HashOpts) (digest []byte, err error) { - var h hash.Hash - if opts == nil { - h = csp.conf.hashFunction() - } else { - switch opts.(type) { - case *bccsp.SHAOpts: - h = csp.conf.hashFunction() - case *bccsp.SHA256Opts: - h = sha256.New() - case *bccsp.SHA384Opts: - h = sha512.New384() - case *bccsp.SHA3_256Opts: - h = sha3.New256() - case *bccsp.SHA3_384Opts: - h = sha3.New384() - default: - return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm()) - } - } - - h.Write(msg) - return h.Sum(nil), nil -} - -// GetHash returns and instance of hash.Hash using options opts. -// If opts is nil then the default hash function is returned. -func (csp *impl) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) { - if opts == nil { - return csp.conf.hashFunction(), nil - } - - switch opts.(type) { - case *bccsp.SHAOpts: - return csp.conf.hashFunction(), nil - case *bccsp.SHA256Opts: - return sha256.New(), nil - case *bccsp.SHA384Opts: - return sha512.New384(), nil - case *bccsp.SHA3_256Opts: - return sha3.New256(), nil - case *bccsp.SHA3_384Opts: - return sha3.New384(), nil - default: - return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm()) - } + return csp.BCCSP.GetKey(ski) } // Sign signs digest using key k. @@ -711,15 +456,8 @@ func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signat switch k.(type) { case *ecdsaPrivateKey: return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts) - case *rsaPrivateKey: - if opts == nil { - return nil, errors.New("Invalid options. Nil.") - } - - return k.(*rsaPrivateKey).privKey.Sign(rand.Reader, digest, opts) default: - //return nil, fmt.Errorf("Key type not recognized [%s]", k) - panic(fmt.Errorf("Key type not recognized - [%+v] [%#v] [%T] [%T]", k, k, k, k)) + return csp.BCCSP.Sign(k, digest, opts) } } @@ -742,85 +480,22 @@ func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Signer return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts) case *ecdsaPublicKey: return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts) - case *rsaPrivateKey: - if opts == nil { - return false, errors.New("Invalid options. It must not be nil.") - } - switch opts.(type) { - case *rsa.PSSOptions: - err := rsa.VerifyPSS(&(k.(*rsaPrivateKey).privKey.PublicKey), - (opts.(*rsa.PSSOptions)).Hash, - digest, signature, opts.(*rsa.PSSOptions)) - - return err == nil, err - default: - return false, fmt.Errorf("Opts type not recognized [%s]", opts) - } - case *rsaPublicKey: - if opts == nil { - return false, errors.New("Invalid options. It must not be nil.") - } - switch opts.(type) { - case *rsa.PSSOptions: - err := rsa.VerifyPSS(k.(*rsaPublicKey).pubKey, - (opts.(*rsa.PSSOptions)).Hash, - digest, signature, opts.(*rsa.PSSOptions)) - - return err == nil, err - default: - return false, fmt.Errorf("Opts type not recognized [%s]", opts) - } default: - return false, fmt.Errorf("Key type not recognized [%s]", k) + return csp.BCCSP.Verify(k, signature, digest, opts) } } // Encrypt encrypts plaintext using key k. // The opts argument should be appropriate for the primitive used. func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) { - // Validate arguments - if k == nil { - return nil, errors.New("Invalid Key. It must not be nil.") - } - - // Check key type - switch k.(type) { - case *aesPrivateKey: - // check for mode - switch opts.(type) { - case *bccsp.AESCBCPKCS7ModeOpts, bccsp.AESCBCPKCS7ModeOpts: - // AES in CBC mode with PKCS7 padding - return AESCBCPKCS7Encrypt(k.(*aesPrivateKey).privKey, plaintext) - default: - return nil, fmt.Errorf("Mode not recognized [%s]", opts) - } - default: - return nil, fmt.Errorf("Key type not recognized [%s]", k) - } + // TODO: Add PKCS11 support for encryption, when fabric starts requiring it + return csp.BCCSP.Encrypt(k, plaintext, opts) } // Decrypt decrypts ciphertext using key k. // The opts argument should be appropriate for the primitive used. func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) { - // Validate arguments - if k == nil { - return nil, errors.New("Invalid Key. It must not be nil.") - } - - // Check key type - switch k.(type) { - case *aesPrivateKey: - // check for mode - switch opts.(type) { - case *bccsp.AESCBCPKCS7ModeOpts, bccsp.AESCBCPKCS7ModeOpts: - // AES in CBC mode with PKCS7 padding - return AESCBCPKCS7Decrypt(k.(*aesPrivateKey).privKey, ciphertext) - default: - return nil, fmt.Errorf("Mode not recognized [%s]", opts) - } - default: - return nil, fmt.Errorf("Key type not recognized [%s]", k) - } + return csp.BCCSP.Decrypt(k, ciphertext, opts) } // THIS IS ONLY USED FOR TESTING diff --git a/bccsp/pkcs11/impl_test.go b/bccsp/pkcs11/impl_test.go index bd8bd95d7f1..fd186ee0481 100644 --- a/bccsp/pkcs11/impl_test.go +++ b/bccsp/pkcs11/impl_test.go @@ -38,6 +38,7 @@ import ( "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/signer" + "github.com/hyperledger/fabric/bccsp/sw" "github.com/hyperledger/fabric/bccsp/utils" "golang.org/x/crypto/sha3" ) @@ -56,8 +57,8 @@ type testConfig struct { } func TestMain(m *testing.M) { - ks := &FileBasedKeyStore{} - if err := ks.Init(nil, os.TempDir(), false); err != nil { + ks, err := sw.NewFileBasedKeyStore(nil, os.TempDir(), false) + if err != nil { fmt.Printf("Failed initiliazing KeyStore [%s]", err) os.Exit(-1) } @@ -233,17 +234,6 @@ func TestKeyGenRSAOpts(t *testing.T) { t.Fatal("Failed generating RSA 1024 key. Key should be asymmetric") } - rsaKey := k.(*rsaPrivateKey).privKey - if rsaKey.N.BitLen() != 1024 { - t.Fatal("1024 RSA generated key in invalid. Modulus be of length 1024.") - } - if rsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("1024 RSA generated key in invalid. Private key must be different from 0.") - } - if rsaKey.E < 3 { - t.Fatal("1024 RSA generated key in invalid. Private key must be different from 0.") - } - // 2048 k, err = currentBCCSP.KeyGen(&bccsp.RSA2048KeyGenOpts{Temporary: false}) if err != nil { @@ -258,72 +248,6 @@ func TestKeyGenRSAOpts(t *testing.T) { if k.Symmetric() { t.Fatal("Failed generating RSA 2048 key. Key should be asymmetric") } - - rsaKey = k.(*rsaPrivateKey).privKey - if rsaKey.N.BitLen() != 2048 { - t.Fatal("2048 RSA generated key in invalid. Modulus be of length 2048.") - } - if rsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("2048 RSA generated key in invalid. Private key must be different from 0.") - } - if rsaKey.E < 3 { - t.Fatal("2048 RSA generated key in invalid. Private key must be different from 0.") - } - - /* - // Skipping these tests because they take too much time to run. - // 3072 - k, err = currentBCCSP.KeyGen(&bccsp.RSA3072KeyGenOpts{Temporary: false}) - if err != nil { - t.Fatalf("Failed generating RSA 3072 key [%s]", err) - } - if k == nil { - t.Fatal("Failed generating RSA 3072 key. Key must be different from nil") - } - if !k.Private() { - t.Fatal("Failed generating RSA 3072 key. Key should be private") - } - if k.Symmetric() { - t.Fatal("Failed generating RSA 3072 key. Key should be asymmetric") - } - - rsaKey = k.(*rsaPrivateKey).privKey - if rsaKey.N.BitLen() != 3072 { - t.Fatal("3072 RSA generated key in invalid. Modulus be of length 3072.") - } - if rsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("3072 RSA generated key in invalid. Private key must be different from 0.") - } - if rsaKey.E < 3 { - t.Fatal("3072 RSA generated key in invalid. Private key must be different from 0.") - } - - // 4096 - k, err = currentBCCSP.KeyGen(&bccsp.RSA4096KeyGenOpts{Temporary: false}) - if err != nil { - t.Fatalf("Failed generating RSA 4096 key [%s]", err) - } - if k == nil { - t.Fatal("Failed generating RSA 4096 key. Key must be different from nil") - } - if !k.Private() { - t.Fatal("Failed generating RSA 4096 key. Key should be private") - } - if k.Symmetric() { - t.Fatal("Failed generating RSA 4096 key. Key should be asymmetric") - } - - rsaKey = k.(*rsaPrivateKey).privKey - if rsaKey.N.BitLen() != 4096 { - t.Fatal("4096 RSA generated key in invalid. Modulus be of length 4096.") - } - if rsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("4096 RSA generated key in invalid. Private key must be different from 0.") - } - if rsaKey.E < 3 { - t.Fatal("4096 RSA generated key in invalid. Private key must be different from 0.") - } - */ } func TestKeyGenAESOpts(t *testing.T) { @@ -342,11 +266,6 @@ func TestKeyGenAESOpts(t *testing.T) { t.Fatal("Failed generating AES 128 key. Key should be symmetric") } - aesKey := k.(*aesPrivateKey).privKey - if len(aesKey) != 16 { - t.Fatal("AES Key generated key in invalid. The key must have length 16.") - } - // AES 192 k, err = currentBCCSP.KeyGen(&bccsp.AES192KeyGenOpts{Temporary: false}) if err != nil { @@ -362,11 +281,6 @@ func TestKeyGenAESOpts(t *testing.T) { t.Fatal("Failed generating AES 192 key. Key should be symmetric") } - aesKey = k.(*aesPrivateKey).privKey - if len(aesKey) != 24 { - t.Fatal("AES Key generated key in invalid. The key must have length 16.") - } - // AES 256 k, err = currentBCCSP.KeyGen(&bccsp.AES256KeyGenOpts{Temporary: false}) if err != nil { @@ -381,11 +295,6 @@ func TestKeyGenAESOpts(t *testing.T) { if !k.Symmetric() { t.Fatal("Failed generating AES 256 key. Key should be symmetric") } - - aesKey = k.(*aesPrivateKey).privKey - if len(aesKey) != 32 { - t.Fatal("AES Key generated key in invalid. The key must have length 16.") - } } func TestHashOpts(t *testing.T) { @@ -1316,7 +1225,7 @@ func TestHMACKeyDerivOverAES256Key(t *testing.T) { func TestAES256KeyImport(t *testing.T) { - raw, err := GetRandomBytes(32) + raw, err := sw.GetRandomBytes(32) if err != nil { t.Fatalf("Failed generating AES key [%s]", err) } @@ -1406,7 +1315,7 @@ func TestAES256KeyGenSKI(t *testing.T) { func TestSHA(t *testing.T) { for i := 0; i < 100; i++ { - b, err := GetRandomBytes(i) + b, err := sw.GetRandomBytes(i) if err != nil { t.Fatalf("Failed getting random bytes [%s]", err) } @@ -1481,17 +1390,6 @@ func TestRSAKeyGenEphemeral(t *testing.T) { } -func TestRSAPublicKeyInvalidBytes(t *testing.T) { - rsaKey := &rsaPublicKey{nil} - b, err := rsaKey.Bytes() - if err == nil { - t.Fatal("It must fail in this case") - } - if len(b) != 0 { - t.Fatal("It must be nil") - } -} - func TestRSAPrivateKeySKI(t *testing.T) { k, err := currentBCCSP.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: false}) @@ -1877,51 +1775,6 @@ func TestKeyImportFromX509RSAPublicKey(t *testing.T) { } } -func TestGetHashAndHashCompatibility(t *testing.T) { - - msg1 := []byte("abcd") - msg2 := []byte("efgh") - msg := []byte("abcdefgh") - - digest1, err := currentBCCSP.Hash(msg, &bccsp.SHAOpts{}) - if err != nil { - t.Fatalf("Failed computing HASH [%s]", err) - } - - digest2, err := currentBCCSP.Hash(msg, nil) - if err != nil { - t.Fatalf("Failed computing HASH [%s]", err) - } - - if !bytes.Equal(digest1, digest2) { - t.Fatalf("Different hash computed. [%x][%x]", digest1, digest2) - } - - h, err := currentBCCSP.GetHash(nil) - if err != nil { - t.Fatalf("Failed getting hash.Hash instance [%s]", err) - } - h.Write(msg1) - h.Write(msg2) - digest3 := h.Sum(nil) - - h2, err := currentBCCSP.GetHash(&bccsp.SHAOpts{}) - if err != nil { - t.Fatalf("Failed getting SHA hash.Hash instance [%s]", err) - } - h2.Write(msg1) - h2.Write(msg2) - digest4 := h2.Sum(nil) - - if !bytes.Equal(digest3, digest4) { - t.Fatalf("Different hash computed. [%x][%x]", digest3, digest4) - } - - if !bytes.Equal(digest1, digest3) { - t.Fatalf("Different hash computed. [%x][%x]", digest1, digest3) - } -} - func getCryptoHashIndex(t *testing.T) crypto.Hash { switch currentTestConfig.hashFamily { case "SHA2": diff --git a/bccsp/pkcs11/rsakey.go b/bccsp/pkcs11/rsakey.go deleted file mode 100644 index c9c0e257059..00000000000 --- a/bccsp/pkcs11/rsakey.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright IBM Corp. 2016 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 pkcs11 - -import ( - "crypto/rsa" - "crypto/x509" - "fmt" - - "crypto/sha256" - - "errors" - - "encoding/asn1" - "math/big" - - "github.com/hyperledger/fabric/bccsp" -) - -// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key. -type rsaPublicKeyASN struct { - N *big.Int - E int -} - -type rsaPrivateKey struct { - privKey *rsa.PrivateKey -} - -// Bytes converts this key to its byte representation, -// if this operation is allowed. -func (k *rsaPrivateKey) Bytes() (raw []byte, err error) { - return nil, errors.New("Not supported.") -} - -// SKI returns the subject key identifier of this key. -func (k *rsaPrivateKey) SKI() (ski []byte) { - if k.privKey == nil { - return nil - } - - // Marshall the public key - raw, _ := asn1.Marshal(rsaPublicKeyASN{ - N: k.privKey.N, - E: k.privKey.E, - }) - - // Hash it - hash := sha256.New() - hash.Write(raw) - return hash.Sum(nil) -} - -// Symmetric returns true if this key is a symmetric key, -// false is this key is asymmetric -func (k *rsaPrivateKey) Symmetric() bool { - return false -} - -// Private returns true if this key is an asymmetric private key, -// false otherwise. -func (k *rsaPrivateKey) Private() bool { - return true -} - -// PublicKey returns the corresponding public key part of an asymmetric public/private key pair. -// This method returns an error in symmetric key schemes. -func (k *rsaPrivateKey) PublicKey() (bccsp.Key, error) { - return &rsaPublicKey{&k.privKey.PublicKey}, nil -} - -type rsaPublicKey struct { - pubKey *rsa.PublicKey -} - -// Bytes converts this key to its byte representation, -// if this operation is allowed. -func (k *rsaPublicKey) Bytes() (raw []byte, err error) { - if k.pubKey == nil { - return nil, errors.New("Failed marshalling key. Key is nil.") - } - raw, err = x509.MarshalPKIXPublicKey(k.pubKey) - if err != nil { - return nil, fmt.Errorf("Failed marshalling key [%s]", err) - } - return -} - -// SKI returns the subject key identifier of this key. -func (k *rsaPublicKey) SKI() (ski []byte) { - if k.pubKey == nil { - return nil - } - - // Marshall the public key - raw, _ := asn1.Marshal(rsaPublicKeyASN{ - N: k.pubKey.N, - E: k.pubKey.E, - }) - - // Hash it - hash := sha256.New() - hash.Write(raw) - return hash.Sum(nil) -} - -// Symmetric returns true if this key is a symmetric key, -// false is this key is asymmetric -func (k *rsaPublicKey) Symmetric() bool { - return false -} - -// Private returns true if this key is an asymmetric private key, -// false otherwise. -func (k *rsaPublicKey) Private() bool { - return false -} - -// PublicKey returns the corresponding public key part of an asymmetric public/private key pair. -// This method returns an error in symmetric key schemes. -func (k *rsaPublicKey) PublicKey() (bccsp.Key, error) { - return k, nil -}