Skip to content

Commit 35af475

Browse files
committed
BCCSP support for RSA signing
This change-set introduces the BCCSP support for the RSA signing algorithm with verification supporting PSS signatures only. New tests have been added. This change-set comes in the context of: https://jira.hyperledger.org/browse/FAB-354 Change-Id: I54e21fe15561a9a024dfee8b12595dc36f828123 Signed-off-by: Angelo De Caro <[email protected]>
1 parent 216ae65 commit 35af475

File tree

9 files changed

+418
-8
lines changed

9 files changed

+418
-8
lines changed

core/crypto/bccsp/bccsp.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ type BCCSP interface {
126126

127127
// Verify verifies signature against key k and digest
128128
// The opts argument should be appropriate for the algorithm used.
129-
Verify(k Key, signature, digest []byte) (valid bool, err error)
129+
Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error)
130130

131131
// Encrypt encrypts plaintext using key k.
132132
// The opts argument should be appropriate for the algorithm used.

core/crypto/bccsp/bccsp_opts.go

+24-3
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,24 @@ limitations under the License.
1717
package bccsp
1818

1919
const (
20-
// ECDSA Elliptic Curve Digital Signature Algorithm (key gen, import, sign, veirfy).
20+
// ECDSA Elliptic Curve Digital Signature Algorithm (key gen, import, sign, verify),
21+
// at default security level (see primitives package).
2122
ECDSA = "ECDSA"
2223
// ECDSAReRand ECDSA key re-randomization
2324
ECDSAReRand = "ECDSA_RERAND"
2425

25-
// AES Advanced Encryption Standard
26+
// RSA at default security level (see primitives package)
27+
RSA = "RSA"
28+
29+
// AES Advanced Encryption Standard at default security level (see primitives package)
2630
AES = "AES"
2731

2832
// HMAC keyed-hash message authentication code
2933
HMAC = "HMAC"
3034
// HMACTruncated256 HMAC truncated at 256 bits.
3135
HMACTruncated256 = "HMAC_TRUNCATED_256"
3236

33-
// SHA Secure Hash Algorithm
37+
// SHA Secure Hash Algorithm using default family (see primitives package)
3438
SHA = "SHA"
3539
)
3640

@@ -185,3 +189,20 @@ type SHAOpts struct {
185189
func (opts *SHAOpts) Algorithm() string {
186190
return SHA
187191
}
192+
193+
// RSAKeyGenOpts contains options for RSA key generation.
194+
type RSAKeyGenOpts struct {
195+
Temporary bool
196+
}
197+
198+
// Algorithm returns an identifier for the algorithm to be used
199+
// to generate a key.
200+
func (opts *RSAKeyGenOpts) Algorithm() string {
201+
return RSA
202+
}
203+
204+
// Ephemeral returns true if the key to generate has to be ephemeral,
205+
// false otherwise.
206+
func (opts *RSAKeyGenOpts) Ephemeral() bool {
207+
return opts.Temporary
208+
}

core/crypto/bccsp/signer/signer_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func TestSign(t *testing.T) {
100100
t.Fatalf("Failed generating ECDSA signature [%s]", err)
101101
}
102102

103-
valid, err := csp.Verify(k, signature, primitives.Hash(msg))
103+
valid, err := csp.Verify(k, signature, primitives.Hash(msg), nil)
104104
if err != nil {
105105
t.Fatalf("Failed verifying ECDSA signature [%s]", err)
106106
}

core/crypto/bccsp/sw/impl.go

+44-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"fmt"
2525
"math/big"
2626

27+
"crypto/rsa"
28+
2729
"github.com/hyperledger/fabric/core/crypto/bccsp"
2830
"github.com/hyperledger/fabric/core/crypto/primitives"
2931
"github.com/hyperledger/fabric/core/crypto/utils"
@@ -101,6 +103,25 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
101103
}
102104
}
103105

106+
return k, nil
107+
case bccsp.RSA:
108+
lowLevelKey, err := primitives.NewRSAKey()
109+
110+
if err != nil {
111+
return nil, fmt.Errorf("Failed generating RSA (2048) key [%s]", err)
112+
}
113+
114+
k = &rsaPrivateKey{lowLevelKey}
115+
116+
// If the key is not Ephemeral, store it.
117+
if !opts.Ephemeral() {
118+
// Store the key
119+
err = csp.ks.storePrivateKey(hex.EncodeToString(k.SKI()), lowLevelKey)
120+
if err != nil {
121+
return nil, fmt.Errorf("Failed storing AES key [%s]", err)
122+
}
123+
}
124+
104125
return k, nil
105126
default:
106127
return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm())
@@ -309,6 +330,8 @@ func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) {
309330
switch key.(type) {
310331
case *ecdsa.PrivateKey:
311332
return &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)}, nil
333+
case *rsa.PrivateKey:
334+
return &rsaPrivateKey{key.(*rsa.PrivateKey)}, nil
312335
default:
313336
return nil, errors.New("Key type not recognized")
314337
}
@@ -350,13 +373,19 @@ func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signat
350373
switch k.(type) {
351374
case *ecdsaPrivateKey:
352375
return k.(*ecdsaPrivateKey).k.Sign(rand.Reader, digest, nil)
376+
case *rsaPrivateKey:
377+
if opts == nil {
378+
return nil, errors.New("Invalid options. Nil.")
379+
}
380+
381+
return k.(*rsaPrivateKey).k.Sign(rand.Reader, digest, opts)
353382
default:
354383
return nil, fmt.Errorf("Key type not recognized [%s]", k)
355384
}
356385
}
357386

358387
// Verify verifies signature against key k and digest
359-
func (csp *impl) Verify(k bccsp.Key, signature, digest []byte) (valid bool, err error) {
388+
func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) {
360389
// Validate arguments
361390
if k == nil {
362391
return false, errors.New("Invalid Key. It must not be nil.")
@@ -378,6 +407,20 @@ func (csp *impl) Verify(k bccsp.Key, signature, digest []byte) (valid bool, err
378407
}
379408

380409
return ecdsa.Verify(&(k.(*ecdsaPrivateKey).k.PublicKey), digest, ecdsaSignature.R, ecdsaSignature.S), nil
410+
case *rsaPrivateKey:
411+
if opts == nil {
412+
return false, errors.New("Invalid options. Nil.")
413+
}
414+
switch opts.(type) {
415+
case *rsa.PSSOptions:
416+
err := rsa.VerifyPSS(&(k.(*rsaPrivateKey).k.PublicKey),
417+
(opts.(*rsa.PSSOptions)).Hash,
418+
digest, signature, opts.(*rsa.PSSOptions))
419+
420+
return err == nil, err
421+
default:
422+
return false, fmt.Errorf("Opts type not recognized [%s]", opts)
423+
}
381424
default:
382425
return false, fmt.Errorf("Key type not recognized [%s]", k)
383426
}

core/crypto/bccsp/sw/impl_test.go

+200-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"os"
2121
"testing"
2222

23+
"crypto"
24+
"crypto/rsa"
25+
2326
"github.com/hyperledger/fabric/core/crypto/bccsp"
2427
"github.com/hyperledger/fabric/core/crypto/primitives"
2528
"github.com/spf13/viper"
@@ -253,7 +256,7 @@ func TestECDSAVerify(t *testing.T) {
253256
t.Fatalf("Failed generating ECDSA signature [%s]", err)
254257
}
255258

256-
valid, err := csp.Verify(k, signature, digest)
259+
valid, err := csp.Verify(k, signature, digest, nil)
257260
if err != nil {
258261
t.Fatalf("Failed verifying ECDSA signature [%s]", err)
259262
}
@@ -287,7 +290,7 @@ func TestECDSAKeyDeriv(t *testing.T) {
287290
t.Fatalf("Failed generating ECDSA signature [%s]", err)
288291
}
289292

290-
valid, err := csp.Verify(reRandomizedKey, signature, digest)
293+
valid, err := csp.Verify(reRandomizedKey, signature, digest, nil)
291294
if err != nil {
292295
t.Fatalf("Failed verifying ECDSA signature [%s]", err)
293296
}
@@ -553,3 +556,198 @@ func TestSHA(t *testing.T) {
553556
}
554557
}
555558
}
559+
560+
func TestRSAKeyGenEphemeral(t *testing.T) {
561+
csp := getBCCSP(t)
562+
563+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
564+
if err != nil {
565+
t.Fatalf("Failed generating RSA key [%s]", err)
566+
}
567+
if k == nil {
568+
t.Fatal("Failed generating RSA key. Key must be different from nil")
569+
}
570+
if !k.Private() {
571+
t.Fatal("Failed generating RSA key. Key should be private")
572+
}
573+
if k.Symmetric() {
574+
t.Fatal("Failed generating RSA key. Key should be asymmetric")
575+
}
576+
}
577+
578+
func TestRSAPrivateKeySKI(t *testing.T) {
579+
csp := getBCCSP(t)
580+
581+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
582+
if err != nil {
583+
t.Fatalf("Failed generating RSA key [%s]", err)
584+
}
585+
586+
ski := k.SKI()
587+
if len(ski) == 0 {
588+
t.Fatal("SKI not valid. Zero length.")
589+
}
590+
}
591+
592+
func TestRSAKeyGenNonEphemeral(t *testing.T) {
593+
csp := getBCCSP(t)
594+
595+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: false})
596+
if err != nil {
597+
t.Fatalf("Failed generating RSA key [%s]", err)
598+
}
599+
if k == nil {
600+
t.Fatal("Failed generating RSA key. Key must be different from nil")
601+
}
602+
if !k.Private() {
603+
t.Fatal("Failed generating RSA key. Key should be private")
604+
}
605+
if k.Symmetric() {
606+
t.Fatal("Failed generating RSA key. Key should be asymmetric")
607+
}
608+
}
609+
610+
func TestRSAGetKeyBySKI(t *testing.T) {
611+
csp := getBCCSP(t)
612+
613+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: false})
614+
if err != nil {
615+
t.Fatalf("Failed generating RSA key [%s]", err)
616+
}
617+
618+
k2, err := csp.GetKey(k.SKI())
619+
if err != nil {
620+
t.Fatalf("Failed getting RSA key [%s]", err)
621+
}
622+
if k2 == nil {
623+
t.Fatal("Failed getting RSA key. Key must be different from nil")
624+
}
625+
if !k2.Private() {
626+
t.Fatal("Failed getting RSA key. Key should be private")
627+
}
628+
if k2.Symmetric() {
629+
t.Fatal("Failed getting RSA key. Key should be asymmetric")
630+
}
631+
632+
// Check that the SKIs are the same
633+
if !bytes.Equal(k.SKI(), k2.SKI()) {
634+
t.Fatalf("SKIs are different [%x]!=[%x]", k.SKI(), k2.SKI())
635+
}
636+
}
637+
638+
func TestRSAPublicKeyFromPrivateKey(t *testing.T) {
639+
csp := getBCCSP(t)
640+
641+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
642+
if err != nil {
643+
t.Fatalf("Failed generating RSA key [%s]", err)
644+
}
645+
646+
pk, err := k.PublicKey()
647+
if err != nil {
648+
t.Fatalf("Failed getting public key from private RSA key [%s]", err)
649+
}
650+
if pk == nil {
651+
t.Fatal("Failed getting public key from private RSA key. Key must be different from nil")
652+
}
653+
if pk.Private() {
654+
t.Fatal("Failed generating RSA key. Key should be public")
655+
}
656+
if pk.Symmetric() {
657+
t.Fatal("Failed generating RSA key. Key should be asymmetric")
658+
}
659+
}
660+
661+
func TestRSAPublicKeyBytes(t *testing.T) {
662+
csp := getBCCSP(t)
663+
664+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
665+
if err != nil {
666+
t.Fatalf("Failed generating RSA key [%s]", err)
667+
}
668+
669+
pk, err := k.PublicKey()
670+
if err != nil {
671+
t.Fatalf("Failed getting public key from private RSA key [%s]", err)
672+
}
673+
674+
raw, err := pk.Bytes()
675+
if err != nil {
676+
t.Fatalf("Failed marshalling RSA public key [%s]", err)
677+
}
678+
if len(raw) == 0 {
679+
t.Fatal("Failed marshalling RSA public key. Zero length")
680+
}
681+
}
682+
683+
func TestRSAPublicKeySKI(t *testing.T) {
684+
csp := getBCCSP(t)
685+
686+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
687+
if err != nil {
688+
t.Fatalf("Failed generating RSA key [%s]", err)
689+
}
690+
691+
pk, err := k.PublicKey()
692+
if err != nil {
693+
t.Fatalf("Failed getting public key from private RSA key [%s]", err)
694+
}
695+
696+
ski := pk.SKI()
697+
if len(ski) == 0 {
698+
t.Fatal("SKI not valid. Zero length.")
699+
}
700+
}
701+
702+
func TestRSASign(t *testing.T) {
703+
csp := getBCCSP(t)
704+
705+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
706+
if err != nil {
707+
t.Fatalf("Failed generating RSA key [%s]", err)
708+
}
709+
710+
msg := []byte("Hello World")
711+
712+
digest, err := csp.Hash(msg, &bccsp.SHAOpts{})
713+
if err != nil {
714+
t.Fatalf("Failed computing HASH [%s]", err)
715+
}
716+
717+
signature, err := csp.Sign(k, digest, &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256})
718+
if err != nil {
719+
t.Fatalf("Failed generating RSA signature [%s]", err)
720+
}
721+
if len(signature) == 0 {
722+
t.Fatal("Failed generating RSA key. Signature must be different from nil")
723+
}
724+
}
725+
726+
func TestRSAVerify(t *testing.T) {
727+
csp := getBCCSP(t)
728+
729+
k, err := csp.KeyGen(&bccsp.RSAKeyGenOpts{Temporary: true})
730+
if err != nil {
731+
t.Fatalf("Failed generating RSA key [%s]", err)
732+
}
733+
734+
msg := []byte("Hello World")
735+
736+
digest, err := csp.Hash(msg, &bccsp.SHAOpts{})
737+
if err != nil {
738+
t.Fatalf("Failed computing HASH [%s]", err)
739+
}
740+
741+
signature, err := csp.Sign(k, digest, &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256})
742+
if err != nil {
743+
t.Fatalf("Failed generating RSA signature [%s]", err)
744+
}
745+
746+
valid, err := csp.Verify(k, signature, digest, &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256})
747+
if err != nil {
748+
t.Fatalf("Failed verifying RSA signature [%s]", err)
749+
}
750+
if !valid {
751+
t.Fatal("Failed verifying RSA signature. Signature not valid.")
752+
}
753+
}

0 commit comments

Comments
 (0)