From 141831ecbc8cf3fb5f2c20d87e94212f803ed69a Mon Sep 17 00:00:00 2001 From: Angelo De Caro Date: Mon, 7 Nov 2016 16:33:19 +0100 Subject: [PATCH] BCCSP-based crypto.Signer This change-set introduced a crypto.Signer implementation based on BCCSP. This is needed to be able to sign x509 certificates using the BCCSP. This change-set comes in the context of: https://jira.hyperledger.org/browse/FAB-354 Change-Id: I3adaf716bd513f6447f0d65c23ec71b06d5dcdda Signed-off-by: Angelo De Caro --- core/crypto/bccsp/signer/signer.go | 103 ++++++++++++++++++++++ core/crypto/bccsp/signer/signer_test.go | 110 ++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 core/crypto/bccsp/signer/signer.go create mode 100644 core/crypto/bccsp/signer/signer_test.go diff --git a/core/crypto/bccsp/signer/signer.go b/core/crypto/bccsp/signer/signer.go new file mode 100644 index 00000000000..ee252a36a6a --- /dev/null +++ b/core/crypto/bccsp/signer/signer.go @@ -0,0 +1,103 @@ +/* +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 signer + +import ( + "crypto" + "errors" + "fmt" + "io" + + "github.com/hyperledger/fabric/core/crypto/bccsp" + "github.com/hyperledger/fabric/core/crypto/primitives" +) + +// CryptoSigner is the BCCSP-based implementation of a crypto.Signer +type CryptoSigner struct { + csp bccsp.BCCSP + key bccsp.Key + pk interface{} +} + +// Init initializes this CryptoSigner. +func (s *CryptoSigner) Init(csp bccsp.BCCSP, key bccsp.Key) error { + // Validate arguments + if csp == nil { + return errors.New("Invalid BCCSP. Nil.") + } + if key == nil { + return errors.New("Invalid Key. Nil.") + } + if key.Symmetric() { + return errors.New("Invalid Key. Symmetric.") + } + + // Marshall the bccsp public key as a crypto.PublicKey + pub, err := key.PublicKey() + if err != nil { + return fmt.Errorf("Failed getting public key [%s]", err) + } + + raw, err := pub.Bytes() + if err != nil { + return fmt.Errorf("Failed marshalling public key [%s]", err) + } + + pk, err := primitives.DERToPublicKey(raw) + if err != nil { + return fmt.Errorf("Failed marshalling public key [%s]", err) + } + + // Init fields + s.csp = csp + s.key = key + s.pk = pk + + return nil + +} + +// Public returns the public key corresponding to the opaque, +// private key. +func (s *CryptoSigner) Public() crypto.PublicKey { + return s.pk +} + +// Sign signs digest with the private key, possibly using entropy from +// rand. For an RSA key, the resulting signature should be either a +// PKCS#1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA +// key, it should be a DER-serialised, ASN.1 signature structure. +// +// Hash implements the SignerOpts interface and, in most cases, one can +// simply pass in the hash function used as opts. Sign may also attempt +// to type assert opts to other types in order to obtain algorithm +// specific values. See the documentation in each package for details. +// +// Note that when a signature of a hash of a larger message is needed, +// the caller is responsible for hashing the larger message and passing +// the hash (as digest) and the hash function (as opts) to Sign. +func (s *CryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { + if opts == nil { + return s.csp.Sign(s.key, digest, nil) + } + + so, ok := opts.(bccsp.SignerOpts) + if !ok { + return nil, errors.New("Invalid opts type. Expecting bccsp.SignerOpts") + } + + return s.csp.Sign(s.key, digest, so) +} diff --git a/core/crypto/bccsp/signer/signer_test.go b/core/crypto/bccsp/signer/signer_test.go new file mode 100644 index 00000000000..8451171da4e --- /dev/null +++ b/core/crypto/bccsp/signer/signer_test.go @@ -0,0 +1,110 @@ +/* +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 signer + +import ( + "crypto/rand" + "os" + "testing" + + "github.com/hyperledger/fabric/core/crypto/bccsp" + "github.com/hyperledger/fabric/core/crypto/bccsp/sw" + "github.com/hyperledger/fabric/core/crypto/primitives" + "github.com/spf13/viper" +) + +var ( + swBCCSPInstance bccsp.BCCSP +) + +func getBCCSP(t *testing.T) bccsp.BCCSP { + if swBCCSPInstance == nil { + primitives.InitSecurityLevel("SHA2", 256) + viper.Set("security.bccsp.default.keyStorePath", os.TempDir()) + + var err error + swBCCSPInstance, err = sw.New() + if err != nil { + t.Fatalf("Failed initializing key store [%s]", err) + } + } + + return swBCCSPInstance +} + +func TestInit(t *testing.T) { + csp := getBCCSP(t) + + k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) + if err != nil { + t.Fatalf("Failed generating ECDSA key [%s]", err) + } + + signer := &CryptoSigner{} + err = signer.Init(csp, k) + if err != nil { + t.Fatalf("Failed initializing CryptoSigner [%s]", err) + } +} + +func TestPublic(t *testing.T) { + csp := getBCCSP(t) + + k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) + if err != nil { + t.Fatalf("Failed generating ECDSA key [%s]", err) + } + + signer := &CryptoSigner{} + err = signer.Init(csp, k) + if err != nil { + t.Fatalf("Failed initializing CryptoSigner [%s]", err) + } + + pk := signer.Public() + if pk == nil { + t.Fatal("Failed getting PublicKey. Nil.") + } +} + +func TestSign(t *testing.T) { + csp := getBCCSP(t) + + k, err := csp.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: true}) + if err != nil { + t.Fatalf("Failed generating ECDSA key [%s]", err) + } + + signer := &CryptoSigner{} + err = signer.Init(csp, k) + if err != nil { + t.Fatalf("Failed initializing CryptoSigner [%s]", err) + } + + msg := []byte("Hello World") + signature, err := signer.Sign(rand.Reader, primitives.Hash(msg), nil) + if err != nil { + t.Fatalf("Failed generating ECDSA signature [%s]", err) + } + + valid, err := csp.Verify(k, signature, primitives.Hash(msg)) + if err != nil { + t.Fatalf("Failed verifying ECDSA signature [%s]", err) + } + if !valid { + t.Fatal("Failed verifying ECDSA signature. Signature not valid.") + } +}