Skip to content

Commit

Permalink
BCCSP-based crypto.Signer
Browse files Browse the repository at this point in the history
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 <adc@zurich.ibm.com>
  • Loading branch information
adecaro committed Nov 7, 2016
1 parent 6ac4ed5 commit 141831e
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 0 deletions.
103 changes: 103 additions & 0 deletions core/crypto/bccsp/signer/signer.go
Original file line number Diff line number Diff line change
@@ -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)
}
110 changes: 110 additions & 0 deletions core/crypto/bccsp/signer/signer_test.go
Original file line number Diff line number Diff line change
@@ -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.")
}
}

0 comments on commit 141831e

Please sign in to comment.