Skip to content

Commit a3665e3

Browse files
committed
[FAB-3441] bccsp/sw KeyGen test coverage
Using the approach discussed in FAB-3465, this change-sets refactors the way key generatiion 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 85%y Change-Id: I6447cb6774a6dfcbd3139b22a7cc62666f39382d Signed-off-by: Angelo De Caro <[email protected]>
1 parent 1b7b163 commit a3665e3

File tree

8 files changed

+237
-118
lines changed

8 files changed

+237
-118
lines changed

bccsp/mocks/mocks.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,16 @@ func (o *SignerOpts) HashFunc() crypto.Hash {
123123
return o.HashFuncValue
124124
}
125125

126-
type KeyGenOpts struct{}
126+
type KeyGenOpts struct {
127+
EphemeralValue bool
128+
}
127129

128130
func (*KeyGenOpts) Algorithm() string {
129131
return "Mock KeyGenOpts"
130132
}
131133

132-
func (*KeyGenOpts) Ephemeral() bool {
133-
panic("Not yet implemented")
134+
func (o *KeyGenOpts) Ephemeral() bool {
135+
return o.EphemeralValue
134136
}
135137

136138
type KeyStore struct {

bccsp/sw/aes.go

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ import (
3030

3131
// GetRandomBytes returns len random looking bytes
3232
func GetRandomBytes(len int) ([]byte, error) {
33+
if len < 0 {
34+
return nil, errors.New("Len must be larger than 0")
35+
}
36+
3337
buffer := make([]byte, len)
3438

3539
n, err := rand.Read(buffer)

bccsp/sw/impl.go

+29-114
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"crypto/ecdsa"
2020
"crypto/elliptic"
2121
"crypto/hmac"
22-
"crypto/rand"
2322
"crypto/rsa"
2423
"crypto/x509"
2524
"errors"
@@ -110,6 +109,22 @@ func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.B
110109
verifiers: verifiers,
111110
hashers: hashers}
112111

112+
// Set the key generators
113+
keyGenerators := make(map[reflect.Type]KeyGenerator)
114+
keyGenerators[reflect.TypeOf(&bccsp.ECDSAKeyGenOpts{})] = &ecdsaKeyGenerator{curve: conf.ellipticCurve}
115+
keyGenerators[reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P256()}
116+
keyGenerators[reflect.TypeOf(&bccsp.ECDSAP384KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P384()}
117+
keyGenerators[reflect.TypeOf(&bccsp.AESKeyGenOpts{})] = &aesKeyGenerator{length: conf.aesBitLength}
118+
keyGenerators[reflect.TypeOf(&bccsp.AES256KeyGenOpts{})] = &aesKeyGenerator{length: 32}
119+
keyGenerators[reflect.TypeOf(&bccsp.AES192KeyGenOpts{})] = &aesKeyGenerator{length: 24}
120+
keyGenerators[reflect.TypeOf(&bccsp.AES128KeyGenOpts{})] = &aesKeyGenerator{length: 16}
121+
keyGenerators[reflect.TypeOf(&bccsp.RSAKeyGenOpts{})] = &rsaKeyGenerator{length: conf.rsaBitLength}
122+
keyGenerators[reflect.TypeOf(&bccsp.RSA1024KeyGenOpts{})] = &rsaKeyGenerator{length: 1024}
123+
keyGenerators[reflect.TypeOf(&bccsp.RSA2048KeyGenOpts{})] = &rsaKeyGenerator{length: 2048}
124+
keyGenerators[reflect.TypeOf(&bccsp.RSA3072KeyGenOpts{})] = &rsaKeyGenerator{length: 3072}
125+
keyGenerators[reflect.TypeOf(&bccsp.RSA4096KeyGenOpts{})] = &rsaKeyGenerator{length: 4096}
126+
impl.keyGenerators = keyGenerators
127+
113128
return impl, nil
114129
}
115130

@@ -118,11 +133,12 @@ type impl struct {
118133
conf *config
119134
ks bccsp.KeyStore
120135

121-
encryptors map[reflect.Type]Encryptor
122-
decryptors map[reflect.Type]Decryptor
123-
signers map[reflect.Type]Signer
124-
verifiers map[reflect.Type]Verifier
125-
hashers map[reflect.Type]Hasher
136+
keyGenerators map[reflect.Type]KeyGenerator
137+
encryptors map[reflect.Type]Encryptor
138+
decryptors map[reflect.Type]Decryptor
139+
signers map[reflect.Type]Signer
140+
verifiers map[reflect.Type]Verifier
141+
hashers map[reflect.Type]Hasher
126142
}
127143

128144
// KeyGen generates a key using opts.
@@ -132,115 +148,14 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
132148
return nil, errors.New("Invalid Opts parameter. It must not be nil.")
133149
}
134150

135-
// Parse algorithm
136-
switch opts.(type) {
137-
case *bccsp.ECDSAKeyGenOpts:
138-
lowLevelKey, err := ecdsa.GenerateKey(csp.conf.ellipticCurve, rand.Reader)
139-
if err != nil {
140-
return nil, fmt.Errorf("Failed generating ECDSA key [%s]", err)
141-
}
142-
143-
k = &ecdsaPrivateKey{lowLevelKey}
144-
145-
case *bccsp.ECDSAP256KeyGenOpts:
146-
lowLevelKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
147-
if err != nil {
148-
return nil, fmt.Errorf("Failed generating ECDSA P256 key [%s]", err)
149-
}
150-
151-
k = &ecdsaPrivateKey{lowLevelKey}
152-
153-
case *bccsp.ECDSAP384KeyGenOpts:
154-
lowLevelKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
155-
if err != nil {
156-
return nil, fmt.Errorf("Failed generating ECDSA P384 key [%s]", err)
157-
}
158-
159-
k = &ecdsaPrivateKey{lowLevelKey}
160-
161-
case *bccsp.AESKeyGenOpts:
162-
lowLevelKey, err := GetRandomBytes(csp.conf.aesBitLength)
163-
164-
if err != nil {
165-
return nil, fmt.Errorf("Failed generating AES key [%s]", err)
166-
}
167-
168-
k = &aesPrivateKey{lowLevelKey, false}
169-
170-
case *bccsp.AES256KeyGenOpts:
171-
lowLevelKey, err := GetRandomBytes(32)
172-
173-
if err != nil {
174-
return nil, fmt.Errorf("Failed generating AES 256 key [%s]", err)
175-
}
176-
177-
k = &aesPrivateKey{lowLevelKey, false}
178-
179-
case *bccsp.AES192KeyGenOpts:
180-
lowLevelKey, err := GetRandomBytes(24)
181-
182-
if err != nil {
183-
return nil, fmt.Errorf("Failed generating AES 192 key [%s]", err)
184-
}
185-
186-
k = &aesPrivateKey{lowLevelKey, false}
187-
188-
case *bccsp.AES128KeyGenOpts:
189-
lowLevelKey, err := GetRandomBytes(16)
190-
191-
if err != nil {
192-
return nil, fmt.Errorf("Failed generating AES 128 key [%s]", err)
193-
}
194-
195-
k = &aesPrivateKey{lowLevelKey, false}
196-
197-
case *bccsp.RSAKeyGenOpts:
198-
lowLevelKey, err := rsa.GenerateKey(rand.Reader, csp.conf.rsaBitLength)
199-
200-
if err != nil {
201-
return nil, fmt.Errorf("Failed generating RSA key [%s]", err)
202-
}
203-
204-
k = &rsaPrivateKey{lowLevelKey}
205-
206-
case *bccsp.RSA1024KeyGenOpts:
207-
lowLevelKey, err := rsa.GenerateKey(rand.Reader, 1024)
208-
209-
if err != nil {
210-
return nil, fmt.Errorf("Failed generating RSA 1024 key [%s]", err)
211-
}
212-
213-
k = &rsaPrivateKey{lowLevelKey}
214-
215-
case *bccsp.RSA2048KeyGenOpts:
216-
lowLevelKey, err := rsa.GenerateKey(rand.Reader, 2048)
217-
218-
if err != nil {
219-
return nil, fmt.Errorf("Failed generating RSA 2048 key [%s]", err)
220-
}
221-
222-
k = &rsaPrivateKey{lowLevelKey}
223-
224-
case *bccsp.RSA3072KeyGenOpts:
225-
lowLevelKey, err := rsa.GenerateKey(rand.Reader, 3072)
226-
227-
if err != nil {
228-
return nil, fmt.Errorf("Failed generating RSA 3072 key [%s]", err)
229-
}
230-
231-
k = &rsaPrivateKey{lowLevelKey}
232-
233-
case *bccsp.RSA4096KeyGenOpts:
234-
lowLevelKey, err := rsa.GenerateKey(rand.Reader, 4096)
235-
236-
if err != nil {
237-
return nil, fmt.Errorf("Failed generating RSA 4096 key [%s]", err)
238-
}
239-
240-
k = &rsaPrivateKey{lowLevelKey}
151+
keyGenerator, found := csp.keyGenerators[reflect.TypeOf(opts)]
152+
if !found {
153+
return nil, fmt.Errorf("Unsupported 'KeyGenOpts' provided [%v]", opts)
154+
}
241155

242-
default:
243-
return nil, fmt.Errorf("Unrecognized KeyGenOpts provided [%s]", opts.Algorithm())
156+
k, err = keyGenerator.KeyGen(opts)
157+
if err != nil {
158+
return nil, err
244159
}
245160

246161
// If the key is not Ephemeral, store it.

bccsp/sw/internals.go

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ import (
2222
"github.com/hyperledger/fabric/bccsp"
2323
)
2424

25+
// KeyGenerator is a BCCSP-like interface that provides key generation algorithms
26+
type KeyGenerator interface {
27+
28+
// KeyGen generates a key using opts.
29+
KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error)
30+
}
31+
2532
// Encryptor is a BCCSP-like interface that provides encryption algorithms
2633
type Encryptor interface {
2734

bccsp/sw/keygen.go

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sw
18+
19+
import (
20+
"crypto/ecdsa"
21+
"crypto/elliptic"
22+
"crypto/rand"
23+
"crypto/rsa"
24+
"fmt"
25+
26+
"github.com/hyperledger/fabric/bccsp"
27+
)
28+
29+
type ecdsaKeyGenerator struct {
30+
curve elliptic.Curve
31+
}
32+
33+
func (kg *ecdsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
34+
privKey, err := ecdsa.GenerateKey(kg.curve, rand.Reader)
35+
if err != nil {
36+
return nil, fmt.Errorf("Failed generating ECDSA key for [%v]: [%s]", kg.curve, err)
37+
}
38+
39+
return &ecdsaPrivateKey{privKey}, nil
40+
}
41+
42+
type aesKeyGenerator struct {
43+
length int
44+
}
45+
46+
func (kg *aesKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
47+
lowLevelKey, err := GetRandomBytes(int(kg.length))
48+
if err != nil {
49+
return nil, fmt.Errorf("Failed generating AES %d key [%s]", kg.length, err)
50+
}
51+
52+
return &aesPrivateKey{lowLevelKey, false}, nil
53+
}
54+
55+
type rsaKeyGenerator struct {
56+
length int
57+
}
58+
59+
func (kg *rsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
60+
lowLevelKey, err := rsa.GenerateKey(rand.Reader, int(kg.length))
61+
62+
if err != nil {
63+
return nil, fmt.Errorf("Failed generating RSA %d key [%s]", kg.length, err)
64+
}
65+
66+
return &rsaPrivateKey{lowLevelKey}, nil
67+
}

bccsp/sw/keygen_test.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sw
18+
19+
import (
20+
"crypto/elliptic"
21+
"errors"
22+
"reflect"
23+
"testing"
24+
25+
mocks2 "github.com/hyperledger/fabric/bccsp/mocks"
26+
"github.com/hyperledger/fabric/bccsp/sw/mocks"
27+
"github.com/stretchr/testify/assert"
28+
)
29+
30+
func TestKeyGen(t *testing.T) {
31+
expectedOpts := &mocks2.KeyGenOpts{EphemeralValue: true}
32+
expectetValue := &mocks2.MockKey{}
33+
expectedErr := errors.New("no error")
34+
35+
keyGenerators := make(map[reflect.Type]KeyGenerator)
36+
keyGenerators[reflect.TypeOf(&mocks2.KeyGenOpts{})] = &mocks.KeyGenerator{
37+
OptsArg: expectedOpts,
38+
Value: expectetValue,
39+
Err: expectedErr,
40+
}
41+
csp := impl{keyGenerators: keyGenerators}
42+
value, err := csp.KeyGen(expectedOpts)
43+
assert.Equal(t, nil, value)
44+
assert.Equal(t, expectedErr, err)
45+
46+
keyGenerators = make(map[reflect.Type]KeyGenerator)
47+
keyGenerators[reflect.TypeOf(&mocks2.KeyGenOpts{})] = &mocks.KeyGenerator{
48+
OptsArg: expectedOpts,
49+
Value: expectetValue,
50+
Err: nil,
51+
}
52+
csp = impl{keyGenerators: keyGenerators}
53+
value, err = csp.KeyGen(expectedOpts)
54+
assert.Equal(t, expectetValue, value)
55+
assert.Equal(t, nil, err)
56+
57+
}
58+
59+
func TestECDSAKeyGenerator(t *testing.T) {
60+
kg := &ecdsaKeyGenerator{curve: elliptic.P256()}
61+
62+
k, err := kg.KeyGen(nil)
63+
assert.NoError(t, err)
64+
65+
ecdsaK, ok := k.(*ecdsaPrivateKey)
66+
assert.True(t, ok)
67+
assert.NotNil(t, ecdsaK.privKey)
68+
assert.Equal(t, ecdsaK.privKey.Curve, elliptic.P256())
69+
}
70+
71+
func TestRSAKeyGenerator(t *testing.T) {
72+
kg := &rsaKeyGenerator{length: 512}
73+
74+
k, err := kg.KeyGen(nil)
75+
assert.NoError(t, err)
76+
77+
rsaK, ok := k.(*rsaPrivateKey)
78+
assert.True(t, ok)
79+
assert.NotNil(t, rsaK.privKey)
80+
assert.Equal(t, rsaK.privKey.N.BitLen(), 512)
81+
}
82+
83+
func TestAESKeyGenerator(t *testing.T) {
84+
kg := &aesKeyGenerator{length: 32}
85+
86+
k, err := kg.KeyGen(nil)
87+
assert.NoError(t, err)
88+
89+
aesK, ok := k.(*aesPrivateKey)
90+
assert.True(t, ok)
91+
assert.NotNil(t, aesK.privKey)
92+
assert.Equal(t, len(aesK.privKey), 32)
93+
}
94+
95+
func TestAESKeyGeneratorInvalidInputs(t *testing.T) {
96+
kg := &aesKeyGenerator{length: -1}
97+
98+
_, err := kg.KeyGen(nil)
99+
assert.Error(t, err)
100+
assert.Contains(t, err.Error(), "Len must be larger than 0")
101+
}
102+
103+
func TestRSAKeyGeneratorInvalidInputs(t *testing.T) {
104+
kg := &rsaKeyGenerator{length: -1}
105+
106+
_, err := kg.KeyGen(nil)
107+
assert.Error(t, err)
108+
assert.Contains(t, err.Error(), "Failed generating RSA -1 key")
109+
}

0 commit comments

Comments
 (0)