From 860a3b5d8959606b2e68aba6fbb36e559f54488b Mon Sep 17 00:00:00 2001 From: Troy Ronda Date: Tue, 19 Sep 2017 12:17:04 -0400 Subject: [PATCH] [FAB-6221] Import BCCSP as third_party Change-Id: I1cdbbb37af1917bd0e6e0cded80caa6ba6c2c777 Signed-off-by: Troy Ronda --- Gopkg.lock | 2 +- .../hyperledger/fabric/bccsp/aesopts.go | 82 +++ .../hyperledger/fabric/bccsp/bccsp.go | 144 ++++ .../hyperledger/fabric/bccsp/ecdsaopts.go | 49 ++ .../fabric/bccsp/factory/factory.go | 93 +++ .../fabric/bccsp/factory/nopkcs11.go | 86 +++ .../hyperledger/fabric/bccsp/factory/opts.go | 35 + .../fabric/bccsp/factory/pkcs11.go | 105 +++ .../fabric/bccsp/factory/pkcs11factory.go | 64 ++ .../fabric/bccsp/factory/swfactory.go | 80 +++ .../hyperledger/fabric/bccsp/hashopts.go | 70 ++ .../hyperledger/fabric/bccsp/keystore.go | 34 + .../hyperledger/fabric/bccsp/opts.go | 322 +++++++++ .../hyperledger/fabric/bccsp/pkcs11/conf.go | 108 +++ .../hyperledger/fabric/bccsp/pkcs11/ecdsa.go | 120 ++++ .../fabric/bccsp/pkcs11/ecdsakey.go | 97 +++ .../hyperledger/fabric/bccsp/pkcs11/impl.go | 534 +++++++++++++++ .../hyperledger/fabric/bccsp/pkcs11/pkcs11.go | 626 ++++++++++++++++++ .../hyperledger/fabric/bccsp/rsaopts.go | 81 +++ .../hyperledger/fabric/bccsp/signer/signer.go | 88 +++ .../hyperledger/fabric/bccsp/sw/aes.go | 221 +++++++ .../hyperledger/fabric/bccsp/sw/aeskey.go | 65 ++ .../hyperledger/fabric/bccsp/sw/conf.go | 81 +++ .../hyperledger/fabric/bccsp/sw/dummyks.go | 49 ++ .../hyperledger/fabric/bccsp/sw/ecdsa.go | 171 +++++ .../hyperledger/fabric/bccsp/sw/ecdsakey.go | 120 ++++ .../hyperledger/fabric/bccsp/sw/fileks.go | 431 ++++++++++++ .../hyperledger/fabric/bccsp/sw/hash.go | 37 ++ .../hyperledger/fabric/bccsp/sw/impl.go | 393 +++++++++++ .../hyperledger/fabric/bccsp/sw/internals.go | 94 +++ .../hyperledger/fabric/bccsp/sw/keyderiv.go | 157 +++++ .../hyperledger/fabric/bccsp/sw/keygen.go | 67 ++ .../hyperledger/fabric/bccsp/sw/keyimport.go | 162 +++++ .../hyperledger/fabric/bccsp/sw/rsa.go | 72 ++ .../hyperledger/fabric/bccsp/sw/rsakey.go | 136 ++++ .../hyperledger/fabric/bccsp/utils/errs.go | 26 + .../hyperledger/fabric/bccsp/utils/io.go | 69 ++ .../hyperledger/fabric/bccsp/utils/keys.go | 459 +++++++++++++ .../hyperledger/fabric/bccsp/utils/slice.go | 25 + .../hyperledger/fabric/bccsp/utils/x509.go | 26 + 40 files changed, 5680 insertions(+), 1 deletion(-) create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/aesopts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/bccsp.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/ecdsaopts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/factory.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/opts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/factory/swfactory.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/hashopts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/keystore.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/opts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsakey.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/rsaopts.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/signer/signer.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/aes.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/aeskey.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/conf.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/dummyks.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsa.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsakey.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/fileks.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/hash.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/impl.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/internals.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/keyderiv.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/keygen.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/keyimport.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/rsa.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/sw/rsakey.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/utils/errs.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/utils/io.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/utils/keys.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/utils/slice.go create mode 100644 third_party/github.com/hyperledger/fabric/bccsp/utils/x509.go diff --git a/Gopkg.lock b/Gopkg.lock index 808b146874..92009a312d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -348,6 +348,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "fe7a9899d1cbbb9cbd256ee66db7421b5207e34241681202cc78e740ff33547a" + inputs-digest = "b5e20422756040455e2f65e3612fb5ce7669bbebc4d746d165e827c0aca28559" solver-name = "gps-cdcl" solver-version = 1 diff --git a/third_party/github.com/hyperledger/fabric/bccsp/aesopts.go b/third_party/github.com/hyperledger/fabric/bccsp/aesopts.go new file mode 100644 index 0000000000..93a2e95692 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/aesopts.go @@ -0,0 +1,82 @@ +/* +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 bccsp + +import "io" + +// AES128KeyGenOpts contains options for AES key generation at 128 security level +type AES128KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *AES128KeyGenOpts) Algorithm() string { + return AES128 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *AES128KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// AES192KeyGenOpts contains options for AES key generation at 192 security level +type AES192KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *AES192KeyGenOpts) Algorithm() string { + return AES192 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *AES192KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// AES256KeyGenOpts contains options for AES key generation at 256 security level +type AES256KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *AES256KeyGenOpts) Algorithm() string { + return AES256 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *AES256KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// AESCBCPKCS7ModeOpts contains options for AES encryption in CBC mode +// with PKCS7 padding. +// Notice that both IV and PRNG can be nil. In that case, the BCCSP implementation +// is supposed to sample the IV using a cryptographic secure PRNG. +// Notice also that either IV or PRNG can be different from nil. +type AESCBCPKCS7ModeOpts struct { + // IV is the initialization vector to be used by the underlying cipher. + // The length of IV must be the same as the Block's block size. + // It is used only if different from nil. + IV []byte + // PRNG is an instance of a PRNG to be used by the underlying cipher. + // It is used only if different from nil. + PRNG io.Reader +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/bccsp.go b/third_party/github.com/hyperledger/fabric/bccsp/bccsp.go new file mode 100644 index 0000000000..5664a20498 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/bccsp.go @@ -0,0 +1,144 @@ +/* +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 bccsp + +import ( + "crypto" + "hash" +) + +// Key represents a cryptographic key +type Key interface { + + // Bytes converts this key to its byte representation, + // if this operation is allowed. + Bytes() ([]byte, error) + + // SKI returns the subject key identifier of this key. + SKI() []byte + + // Symmetric returns true if this key is a symmetric key, + // false is this key is asymmetric + Symmetric() bool + + // Private returns true if this key is a private key, + // false otherwise. + Private() bool + + // PublicKey returns the corresponding public key part of an asymmetric public/private key pair. + // This method returns an error in symmetric key schemes. + PublicKey() (Key, error) +} + +// KeyGenOpts contains options for key-generation with a CSP. +type KeyGenOpts interface { + + // Algorithm returns the key generation algorithm identifier (to be used). + Algorithm() string + + // Ephemeral returns true if the key to generate has to be ephemeral, + // false otherwise. + Ephemeral() bool +} + +// KeyDerivOpts contains options for key-derivation with a CSP. +type KeyDerivOpts interface { + + // Algorithm returns the key derivation algorithm identifier (to be used). + Algorithm() string + + // Ephemeral returns true if the key to derived has to be ephemeral, + // false otherwise. + Ephemeral() bool +} + +// KeyImportOpts contains options for importing the raw material of a key with a CSP. +type KeyImportOpts interface { + + // Algorithm returns the key importation algorithm identifier (to be used). + Algorithm() string + + // Ephemeral returns true if the key generated has to be ephemeral, + // false otherwise. + Ephemeral() bool +} + +// HashOpts contains options for hashing with a CSP. +type HashOpts interface { + + // Algorithm returns the hash algorithm identifier (to be used). + Algorithm() string +} + +// SignerOpts contains options for signing with a CSP. +type SignerOpts interface { + crypto.SignerOpts +} + +// EncrypterOpts contains options for encrypting with a CSP. +type EncrypterOpts interface{} + +// DecrypterOpts contains options for decrypting with a CSP. +type DecrypterOpts interface{} + +// BCCSP is the blockchain cryptographic service provider that offers +// the implementation of cryptographic standards and algorithms. +type BCCSP interface { + + // KeyGen generates a key using opts. + KeyGen(opts KeyGenOpts) (k Key, err error) + + // KeyDeriv derives a key from k using opts. + // The opts argument should be appropriate for the primitive used. + KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error) + + // KeyImport imports a key from its raw representation using opts. + // The opts argument should be appropriate for the primitive used. + KeyImport(raw interface{}, opts KeyImportOpts) (k Key, err error) + + // GetKey returns the key this CSP associates to + // the Subject Key Identifier ski. + GetKey(ski []byte) (k Key, err error) + + // Hash hashes messages msg using options opts. + // If opts is nil, the default hash function will be used. + Hash(msg []byte, opts HashOpts) (hash []byte, err error) + + // GetHash returns and instance of hash.Hash using options opts. + // If opts is nil, the default hash function will be returned. + GetHash(opts HashOpts) (h hash.Hash, err error) + + // Sign signs digest using key k. + // The opts argument should be appropriate for the algorithm used. + // + // 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). + Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error) + + // Verify verifies signature against key k and digest + // The opts argument should be appropriate for the algorithm used. + Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error) + + // Encrypt encrypts plaintext using key k. + // The opts argument should be appropriate for the algorithm used. + Encrypt(k Key, plaintext []byte, opts EncrypterOpts) (ciphertext []byte, err error) + + // Decrypt decrypts ciphertext using key k. + // The opts argument should be appropriate for the algorithm used. + Decrypt(k Key, ciphertext []byte, opts DecrypterOpts) (plaintext []byte, err error) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/ecdsaopts.go b/third_party/github.com/hyperledger/fabric/bccsp/ecdsaopts.go new file mode 100644 index 0000000000..40d5c7cc0d --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/ecdsaopts.go @@ -0,0 +1,49 @@ +/* +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 bccsp + +// ECDSAP256KeyGenOpts contains options for ECDSA key generation with curve P-256. +type ECDSAP256KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *ECDSAP256KeyGenOpts) Algorithm() string { + return ECDSAP256 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAP256KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAP384KeyGenOpts contains options for ECDSA key generation with curve P-384. +type ECDSAP384KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *ECDSAP384KeyGenOpts) Algorithm() string { + return ECDSAP384 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAP384KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/factory.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/factory.go new file mode 100644 index 0000000000..8e6cbaf8d9 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/factory.go @@ -0,0 +1,93 @@ +/* +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 factory + +import ( + "sync" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/flogging" + "github.com/pkg/errors" +) + +var ( + // Default BCCSP + defaultBCCSP bccsp.BCCSP + + // when InitFactories has not been called yet (should only happen + // in test cases), use this BCCSP temporarily + bootBCCSP bccsp.BCCSP + + // BCCSP Factories + bccspMap map[string]bccsp.BCCSP + + // factories' Sync on Initialization + factoriesInitOnce sync.Once + bootBCCSPInitOnce sync.Once + + // Factories' Initialization Error + factoriesInitError error + + logger = flogging.MustGetLogger("bccsp") +) + +// BCCSPFactory is used to get instances of the BCCSP interface. +// A Factory has name used to address it. +type BCCSPFactory interface { + + // Name returns the name of this factory + Name() string + + // Get returns an instance of BCCSP using opts. + Get(opts *FactoryOpts) (bccsp.BCCSP, error) +} + +// GetDefault returns a non-ephemeral (long-term) BCCSP +func GetDefault() bccsp.BCCSP { + if defaultBCCSP == nil { + logger.Warning("Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.") + bootBCCSPInitOnce.Do(func() { + var err error + f := &SWFactory{} + bootBCCSP, err = f.Get(GetDefaultOpts()) + if err != nil { + panic("BCCSP Internal error, failed initialization with GetDefaultOpts!") + } + }) + return bootBCCSP + } + return defaultBCCSP +} + +// GetBCCSP returns a BCCSP created according to the options passed in input. +func GetBCCSP(name string) (bccsp.BCCSP, error) { + csp, ok := bccspMap[name] + if !ok { + return nil, errors.Errorf("Could not find BCCSP, no '%s' provider", name) + } + return csp, nil +} + +func initBCCSP(f BCCSPFactory, config *FactoryOpts) error { + csp, err := f.Get(config) + if err != nil { + return errors.Errorf("Could not initialize BCCSP %s [%s]", f.Name(), err) + } + + logger.Debugf("Initialize BCCSP [%s]", f.Name()) + bccspMap[f.Name()] = csp + return nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go new file mode 100644 index 0000000000..af8099389b --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go @@ -0,0 +1,86 @@ +// +build nopkcs11 + +/* +Copyright IBM Corp. 2017 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 factory + +import ( + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/pkg/errors" +) + +type FactoryOpts struct { + ProviderName string `mapstructure:"default" json:"default" yaml:"Default"` + SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SwOpts"` +} + +// InitFactories must be called before using factory interfaces +// It is acceptable to call with config = nil, in which case +// some defaults will get used +// Error is returned only if defaultBCCSP cannot be found +func InitFactories(config *FactoryOpts) error { + factoriesInitOnce.Do(func() { + // Take some precautions on default opts + if config == nil { + config = GetDefaultOpts() + } + + if config.ProviderName == "" { + config.ProviderName = "SW" + } + + if config.SwOpts == nil { + config.SwOpts = GetDefaultOpts().SwOpts + } + + // Initialize factories map + bccspMap = make(map[string]bccsp.BCCSP) + + // Software-Based BCCSP + if config.SwOpts != nil { + f := &SWFactory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = errors.Wrapf(err, "Failed initializing BCCSP.") + } + } + + var ok bool + defaultBCCSP, ok = bccspMap[config.ProviderName] + if !ok { + factoriesInitError = errors.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName) + } + }) + + return factoriesInitError +} + +// GetBCCSPFromOpts returns a BCCSP created according to the options passed in input. +func GetBCCSPFromOpts(config *FactoryOpts) (bccsp.BCCSP, error) { + var f BCCSPFactory + switch config.ProviderName { + case "SW": + f = &SWFactory{} + default: + return nil, errors.Errorf("Could not find BCCSP, no '%s' provider", config.ProviderName) + } + + csp, err := f.Get(config) + if err != nil { + return nil, errors.Wrapf(err, "Could not initialize BCCSP %s", f.Name()) + } + return csp, nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/opts.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/opts.go new file mode 100644 index 0000000000..927ee79346 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/opts.go @@ -0,0 +1,35 @@ +/* +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 factory + +// GetDefaultOpts offers a default implementation for Opts +// returns a new instance every time +func GetDefaultOpts() *FactoryOpts { + return &FactoryOpts{ + ProviderName: "SW", + SwOpts: &SwOpts{ + HashFamily: "SHA2", + SecLevel: 256, + + Ephemeral: true, + }, + } +} + +// FactoryName returns the name of the provider +func (o *FactoryOpts) FactoryName() string { + return o.ProviderName +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go new file mode 100644 index 0000000000..13896b4bd0 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go @@ -0,0 +1,105 @@ +// +build !nopkcs11 + +/* +Copyright IBM Corp. 2017 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 factory + +import ( + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/pkcs11" + "github.com/pkg/errors" +) + +type FactoryOpts struct { + ProviderName string `mapstructure:"default" json:"default" yaml:"Default"` + SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SwOpts"` + Pkcs11Opts *pkcs11.PKCS11Opts `mapstructure:"PKCS11,omitempty" json:"PKCS11,omitempty" yaml:"PKCS11"` +} + +// InitFactories must be called before using factory interfaces +// It is acceptable to call with config = nil, in which case +// some defaults will get used +// Error is returned only if defaultBCCSP cannot be found +func InitFactories(config *FactoryOpts) error { + factoriesInitOnce.Do(func() { + setFactories(config) + }) + + return factoriesInitError +} + +func setFactories(config *FactoryOpts) error { + // Take some precautions on default opts + if config == nil { + config = GetDefaultOpts() + } + + if config.ProviderName == "" { + config.ProviderName = "SW" + } + + if config.SwOpts == nil { + config.SwOpts = GetDefaultOpts().SwOpts + } + + // Initialize factories map + bccspMap = make(map[string]bccsp.BCCSP) + + // Software-Based BCCSP + if config.SwOpts != nil { + f := &SWFactory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = errors.Wrap(err, "Failed initializing SW.BCCSP") + } + } + + // PKCS11-Based BCCSP + if config.Pkcs11Opts != nil { + f := &PKCS11Factory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = errors.Wrapf(err, "Failed initializing PKCS11.BCCSP %s", factoriesInitError) + } + } + + var ok bool + defaultBCCSP, ok = bccspMap[config.ProviderName] + if !ok { + factoriesInitError = errors.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName) + } + + return factoriesInitError +} + +// GetBCCSPFromOpts returns a BCCSP created according to the options passed in input. +func GetBCCSPFromOpts(config *FactoryOpts) (bccsp.BCCSP, error) { + var f BCCSPFactory + switch config.ProviderName { + case "SW": + f = &SWFactory{} + case "PKCS11": + f = &PKCS11Factory{} + default: + return nil, errors.Errorf("Could not find BCCSP, no '%s' provider", config.ProviderName) + } + + csp, err := f.Get(config) + if err != nil { + return nil, errors.Wrapf(err, "Could not initialize BCCSP %s", f.Name()) + } + return csp, nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go new file mode 100644 index 0000000000..c574bc3838 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go @@ -0,0 +1,64 @@ +// +build !nopkcs11 + +/* +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 factory + +import ( + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/pkcs11" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/sw" + "github.com/pkg/errors" +) + +const ( + // PKCS11BasedFactoryName is the name of the factory of the hsm-based BCCSP implementation + PKCS11BasedFactoryName = "PKCS11" +) + +// PKCS11Factory is the factory of the HSM-based BCCSP. +type PKCS11Factory struct{} + +// Name returns the name of this factory +func (f *PKCS11Factory) Name() string { + return PKCS11BasedFactoryName +} + +// Get returns an instance of BCCSP using Opts. +func (f *PKCS11Factory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { + // Validate arguments + if config == nil || config.Pkcs11Opts == nil { + return nil, errors.New("Invalid config. It must not be nil.") + } + + p11Opts := config.Pkcs11Opts + + //TODO: PKCS11 does not need a keystore, but we have not migrated all of PKCS11 BCCSP to PKCS11 yet + var ks bccsp.KeyStore + if p11Opts.Ephemeral == true { + ks = sw.NewDummyKeyStore() + } else if p11Opts.FileKeystore != nil { + fks, err := sw.NewFileBasedKeyStore(nil, p11Opts.FileKeystore.KeyStorePath, false) + if err != nil { + return nil, errors.Wrapf(err, "Failed to initialize software key store") + } + ks = fks + } else { + // Default to DummyKeystore + ks = sw.NewDummyKeyStore() + } + return pkcs11.New(*p11Opts, ks) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/factory/swfactory.go b/third_party/github.com/hyperledger/fabric/bccsp/factory/swfactory.go new file mode 100644 index 0000000000..9a68df2b23 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/factory/swfactory.go @@ -0,0 +1,80 @@ +/* +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 factory + +import ( + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/sw" + "github.com/pkg/errors" +) + +const ( + // SoftwareBasedFactoryName is the name of the factory of the software-based BCCSP implementation + SoftwareBasedFactoryName = "SW" +) + +// SWFactory is the factory of the software-based BCCSP. +type SWFactory struct{} + +// Name returns the name of this factory +func (f *SWFactory) Name() string { + return SoftwareBasedFactoryName +} + +// Get returns an instance of BCCSP using Opts. +func (f *SWFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { + // Validate arguments + if config == nil || config.SwOpts == nil { + return nil, errors.New("Invalid config. It must not be nil.") + } + + swOpts := config.SwOpts + + var ks bccsp.KeyStore + if swOpts.Ephemeral == true { + ks = sw.NewDummyKeyStore() + } else if swOpts.FileKeystore != nil { + fks, err := sw.NewFileBasedKeyStore(nil, swOpts.FileKeystore.KeyStorePath, false) + if err != nil { + return nil, errors.Wrapf(err, "Failed to initialize software key store") + } + ks = fks + } else { + // Default to DummyKeystore + ks = sw.NewDummyKeyStore() + } + + return sw.New(swOpts.SecLevel, swOpts.HashFamily, ks) +} + +// SwOpts contains options for the SWFactory +type SwOpts struct { + // Default algorithms when not specified (Deprecated?) + SecLevel int `mapstructure:"security" json:"security" yaml:"Security"` + HashFamily string `mapstructure:"hash" json:"hash" yaml:"Hash"` + + // Keystore Options + Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"` + FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty" yaml:"FileKeyStore"` + DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"` +} + +// Pluggable Keystores, could add JKS, P12, etc.. +type FileKeystoreOpts struct { + KeyStorePath string `mapstructure:"keystore" yaml:"KeyStore"` +} + +type DummyKeystoreOpts struct{} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/hashopts.go b/third_party/github.com/hyperledger/fabric/bccsp/hashopts.go new file mode 100644 index 0000000000..a405f762e6 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/hashopts.go @@ -0,0 +1,70 @@ +/* +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 bccsp + +import "fmt" + +// SHA256Opts contains options relating to SHA-256. +type SHA256Opts struct { +} + +// Algorithm returns the hash algorithm identifier (to be used). +func (opts *SHA256Opts) Algorithm() string { + return SHA256 +} + +// SHA384Opts contains options relating to SHA-384. +type SHA384Opts struct { +} + +// Algorithm returns the hash algorithm identifier (to be used). +func (opts *SHA384Opts) Algorithm() string { + return SHA384 +} + +// SHA3_256Opts contains options relating to SHA3-256. +type SHA3_256Opts struct { +} + +// Algorithm returns the hash algorithm identifier (to be used). +func (opts *SHA3_256Opts) Algorithm() string { + return SHA3_256 +} + +// SHA3_384Opts contains options relating to SHA3-384. +type SHA3_384Opts struct { +} + +// Algorithm returns the hash algorithm identifier (to be used). +func (opts *SHA3_384Opts) Algorithm() string { + return SHA3_384 +} + +// GetHashOpt returns the HashOpts corresponding to the passed hash function +func GetHashOpt(hashFunction string) (HashOpts, error) { + switch hashFunction { + case SHA256: + return &SHA256Opts{}, nil + case SHA384: + return &SHA384Opts{}, nil + case SHA3_256: + return &SHA3_256Opts{}, nil + case SHA3_384: + return &SHA3_384Opts{}, nil + } + return nil, fmt.Errorf("hash function not recognized [%s]", hashFunction) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/keystore.go b/third_party/github.com/hyperledger/fabric/bccsp/keystore.go new file mode 100644 index 0000000000..bb1ca6c8c2 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/keystore.go @@ -0,0 +1,34 @@ +/* +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 bccsp + +// KeyStore represents a storage system for cryptographic keys. +// It allows to store and retrieve bccsp.Key objects. +// The KeyStore can be read only, in that case StoreKey will return +// an error. +type KeyStore interface { + + // ReadOnly returns true if this KeyStore is read only, false otherwise. + // If ReadOnly is true then StoreKey will fail. + ReadOnly() bool + + // GetKey returns a key object whose SKI is the one passed. + GetKey(ski []byte) (k Key, err error) + + // StoreKey stores the key k in this KeyStore. + // If this KeyStore is read only then the method will fail. + StoreKey(k Key) (err error) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/opts.go b/third_party/github.com/hyperledger/fabric/bccsp/opts.go new file mode 100644 index 0000000000..e81e50cb85 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/opts.go @@ -0,0 +1,322 @@ +/* +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 bccsp + +const ( + // ECDSA Elliptic Curve Digital Signature Algorithm (key gen, import, sign, verify), + // at default security level. + // Each BCCSP may or may not support default security level. If not supported than + // an error will be returned. + ECDSA = "ECDSA" + + // ECDSA Elliptic Curve Digital Signature Algorithm over P-256 curve + ECDSAP256 = "ECDSAP256" + + // ECDSA Elliptic Curve Digital Signature Algorithm over P-384 curve + ECDSAP384 = "ECDSAP384" + + // ECDSAReRand ECDSA key re-randomization + ECDSAReRand = "ECDSA_RERAND" + + // RSA at the default security level. + // Each BCCSP may or may not support default security level. If not supported than + // an error will be returned. + RSA = "RSA" + // RSA at 1024 bit security level. + RSA1024 = "RSA1024" + // RSA at 2048 bit security level. + RSA2048 = "RSA2048" + // RSA at 3072 bit security level. + RSA3072 = "RSA3072" + // RSA at 4096 bit security level. + RSA4096 = "RSA4096" + + // AES Advanced Encryption Standard at the default security level. + // Each BCCSP may or may not support default security level. If not supported than + // an error will be returned. + AES = "AES" + // AES Advanced Encryption Standard at 128 bit security level + AES128 = "AES128" + // AES Advanced Encryption Standard at 192 bit security level + AES192 = "AES192" + // AES Advanced Encryption Standard at 256 bit security level + AES256 = "AES256" + + // HMAC keyed-hash message authentication code + HMAC = "HMAC" + // HMACTruncated256 HMAC truncated at 256 bits. + HMACTruncated256 = "HMAC_TRUNCATED_256" + + // SHA Secure Hash Algorithm using default family. + // Each BCCSP may or may not support default security level. If not supported than + // an error will be returned. + SHA = "SHA" + + // SHA2 is an identifier for SHA2 hash family + SHA2 = "SHA2" + // SHA3 is an identifier for SHA3 hash family + SHA3 = "SHA3" + + // SHA256 + SHA256 = "SHA256" + // SHA384 + SHA384 = "SHA384" + // SHA3_256 + SHA3_256 = "SHA3_256" + // SHA3_384 + SHA3_384 = "SHA3_384" + + // X509Certificate Label for X509 certificate related operation + X509Certificate = "X509Certificate" +) + +// ECDSAKeyGenOpts contains options for ECDSA key generation. +type ECDSAKeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *ECDSAKeyGenOpts) Algorithm() string { + return ECDSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAKeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAPKIXPublicKeyImportOpts contains options for ECDSA public key importation in PKIX format +type ECDSAPKIXPublicKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *ECDSAPKIXPublicKeyImportOpts) Algorithm() string { + return ECDSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAPKIXPublicKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAPrivateKeyImportOpts contains options for ECDSA secret key importation in DER format +// or PKCS#8 format. +type ECDSAPrivateKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *ECDSAPrivateKeyImportOpts) Algorithm() string { + return ECDSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAPrivateKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAGoPublicKeyImportOpts contains options for ECDSA key importation from ecdsa.PublicKey +type ECDSAGoPublicKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *ECDSAGoPublicKeyImportOpts) Algorithm() string { + return ECDSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAGoPublicKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAReRandKeyOpts contains options for ECDSA key re-randomization. +type ECDSAReRandKeyOpts struct { + Temporary bool + Expansion []byte +} + +// Algorithm returns the key derivation algorithm identifier (to be used). +func (opts *ECDSAReRandKeyOpts) Algorithm() string { + return ECDSAReRand +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *ECDSAReRandKeyOpts) Ephemeral() bool { + return opts.Temporary +} + +// ExpansionValue returns the re-randomization factor +func (opts *ECDSAReRandKeyOpts) ExpansionValue() []byte { + return opts.Expansion +} + +// AESKeyGenOpts contains options for AES key generation at default security level +type AESKeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *AESKeyGenOpts) Algorithm() string { + return AES +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *AESKeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// HMACTruncated256AESDeriveKeyOpts contains options for HMAC truncated +// at 256 bits key derivation. +type HMACTruncated256AESDeriveKeyOpts struct { + Temporary bool + Arg []byte +} + +// Algorithm returns the key derivation algorithm identifier (to be used). +func (opts *HMACTruncated256AESDeriveKeyOpts) Algorithm() string { + return HMACTruncated256 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *HMACTruncated256AESDeriveKeyOpts) Ephemeral() bool { + return opts.Temporary +} + +// Argument returns the argument to be passed to the HMAC +func (opts *HMACTruncated256AESDeriveKeyOpts) Argument() []byte { + return opts.Arg +} + +// HMACDeriveKeyOpts contains options for HMAC key derivation. +type HMACDeriveKeyOpts struct { + Temporary bool + Arg []byte +} + +// Algorithm returns the key derivation algorithm identifier (to be used). +func (opts *HMACDeriveKeyOpts) Algorithm() string { + return HMAC +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *HMACDeriveKeyOpts) Ephemeral() bool { + return opts.Temporary +} + +// Argument returns the argument to be passed to the HMAC +func (opts *HMACDeriveKeyOpts) Argument() []byte { + return opts.Arg +} + +// AES256ImportKeyOpts contains options for importing AES 256 keys. +type AES256ImportKeyOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *AES256ImportKeyOpts) Algorithm() string { + return AES +} + +// Ephemeral returns true if the key generated has to be ephemeral, +// false otherwise. +func (opts *AES256ImportKeyOpts) Ephemeral() bool { + return opts.Temporary +} + +// HMACImportKeyOpts contains options for importing HMAC keys. +type HMACImportKeyOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *HMACImportKeyOpts) Algorithm() string { + return HMAC +} + +// Ephemeral returns true if the key generated has to be ephemeral, +// false otherwise. +func (opts *HMACImportKeyOpts) Ephemeral() bool { + return opts.Temporary +} + +// SHAOpts contains options for computing SHA. +type SHAOpts struct { +} + +// Algorithm returns the hash algorithm identifier (to be used). +func (opts *SHAOpts) Algorithm() string { + return SHA +} + +// RSAKeyGenOpts contains options for RSA key generation. +type RSAKeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *RSAKeyGenOpts) Algorithm() string { + return RSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSAKeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// ECDSAGoPublicKeyImportOpts contains options for RSA key importation from rsa.PublicKey +type RSAGoPublicKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *RSAGoPublicKeyImportOpts) Algorithm() string { + return RSA +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSAGoPublicKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} + +// X509PublicKeyImportOpts contains options for importing public keys from an x509 certificate +type X509PublicKeyImportOpts struct { + Temporary bool +} + +// Algorithm returns the key importation algorithm identifier (to be used). +func (opts *X509PublicKeyImportOpts) Algorithm() string { + return X509Certificate +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *X509PublicKeyImportOpts) Ephemeral() bool { + return opts.Temporary +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go new file mode 100644 index 0000000000..8a13169ca7 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go @@ -0,0 +1,108 @@ +/* +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/sha256" + "crypto/sha512" + "encoding/asn1" + "fmt" + "hash" + + "golang.org/x/crypto/sha3" +) + +type config struct { + ellipticCurve asn1.ObjectIdentifier + hashFunction func() hash.Hash + aesBitLength int + rsaBitLength int +} + +func (conf *config) setSecurityLevel(securityLevel int, hashFamily string) (err error) { + switch hashFamily { + case "SHA2": + err = conf.setSecurityLevelSHA2(securityLevel) + case "SHA3": + err = conf.setSecurityLevelSHA3(securityLevel) + default: + err = fmt.Errorf("Hash Family not supported [%s]", hashFamily) + } + return +} + +func (conf *config) setSecurityLevelSHA2(level int) (err error) { + switch level { + case 256: + conf.ellipticCurve = oidNamedCurveP256 + conf.hashFunction = sha256.New + conf.rsaBitLength = 2048 + conf.aesBitLength = 32 + case 384: + conf.ellipticCurve = oidNamedCurveP384 + conf.hashFunction = sha512.New384 + conf.rsaBitLength = 3072 + conf.aesBitLength = 32 + default: + err = fmt.Errorf("Security level not supported [%d]", level) + } + return +} + +func (conf *config) setSecurityLevelSHA3(level int) (err error) { + switch level { + case 256: + conf.ellipticCurve = oidNamedCurveP256 + conf.hashFunction = sha3.New256 + conf.rsaBitLength = 2048 + conf.aesBitLength = 32 + case 384: + conf.ellipticCurve = oidNamedCurveP384 + conf.hashFunction = sha3.New384 + conf.rsaBitLength = 3072 + conf.aesBitLength = 32 + default: + err = fmt.Errorf("Security level not supported [%d]", level) + } + return +} + +// PKCS11Opts contains options for the P11Factory +type PKCS11Opts struct { + // Default algorithms when not specified (Deprecated?) + SecLevel int `mapstructure:"security" json:"security"` + HashFamily string `mapstructure:"hash" json:"hash"` + + // Keystore options + Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"` + FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty"` + DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"` + + // PKCS11 options + Library string `mapstructure:"library" json:"library"` + Label string `mapstructure:"label" json:"label"` + Pin string `mapstructure:"pin" json:"pin"` + Sensitive bool `mapstructure:"sensitivekeys,omitempty" json:"sensitivekeys,omitempty"` + SoftVerify bool `mapstructure:"softwareverify,omitempty" json:"softwareverify,omitempty"` +} + +// Since currently only ECDSA operations go to PKCS11, need a keystore still +// Pluggable Keystores, could add JKS, P12, etc.. +type FileKeystoreOpts struct { + KeyStorePath string `mapstructure:"keystore" json:"keystore" yaml:"KeyStore"` +} + +type DummyKeystoreOpts struct{} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go new file mode 100644 index 0000000000..bfa8bf438d --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go @@ -0,0 +1,120 @@ +/* +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/ecdsa" + "crypto/elliptic" + "encoding/asn1" + "errors" + "fmt" + "math/big" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ecdsaSignature struct { + R, S *big.Int +} + +var ( + // curveHalfOrders contains the precomputed curve group orders halved. + // It is used to ensure that signature' S value is lower or equal to the + // curve group order halved. We accept only low-S signatures. + // They are precomputed for efficiency reasons. + curveHalfOrders map[elliptic.Curve]*big.Int = map[elliptic.Curve]*big.Int{ + elliptic.P224(): new(big.Int).Rsh(elliptic.P224().Params().N, 1), + elliptic.P256(): new(big.Int).Rsh(elliptic.P256().Params().N, 1), + elliptic.P384(): new(big.Int).Rsh(elliptic.P384().Params().N, 1), + elliptic.P521(): new(big.Int).Rsh(elliptic.P521().Params().N, 1), + } +) + +func marshalECDSASignature(r, s *big.Int) ([]byte, error) { + return asn1.Marshal(ecdsaSignature{r, s}) +} + +func unmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) { + // Unmarshal + sig := new(ecdsaSignature) + _, err := asn1.Unmarshal(raw, sig) + if err != nil { + return nil, nil, fmt.Errorf("Failed unmashalling signature [%s]", err) + } + + // Validate sig + if sig.R == nil { + return nil, nil, errors.New("Invalid signature. R must be different from nil.") + } + if sig.S == nil { + return nil, nil, errors.New("Invalid signature. S must be different from nil.") + } + + if sig.R.Sign() != 1 { + return nil, nil, errors.New("Invalid signature. R must be larger than zero") + } + if sig.S.Sign() != 1 { + return nil, nil, errors.New("Invalid signature. S must be larger than zero") + } + + return sig.R, sig.S, nil +} + +func (csp *impl) signECDSA(k ecdsaPrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + r, s, err := csp.signP11ECDSA(k.ski, digest) + if err != nil { + return nil, err + } + + // check for low-S + halfOrder, ok := curveHalfOrders[k.pub.pub.Curve] + if !ok { + return nil, fmt.Errorf("Curve not recognized [%s]", k.pub.pub.Curve) + } + + // is s > halfOrder Then + if s.Cmp(halfOrder) == 1 { + // Set s to N - s that will be then in the lower part of signature space + // less or equal to half order + s.Sub(k.pub.pub.Params().N, s) + } + + return marshalECDSASignature(r, s) +} + +func (csp *impl) verifyECDSA(k ecdsaPublicKey, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + r, s, err := unmarshalECDSASignature(signature) + if err != nil { + return false, fmt.Errorf("Failed unmashalling signature [%s]", err) + } + + // check for low-S + halfOrder, ok := curveHalfOrders[k.pub.Curve] + if !ok { + return false, fmt.Errorf("Curve not recognized [%s]", k.pub.Curve) + } + + // If s > halfOrder Then + if s.Cmp(halfOrder) == 1 { + return false, fmt.Errorf("Invalid S. Must be smaller than half the order [%s][%s].", s, halfOrder) + } + + if csp.softVerify { + return ecdsa.Verify(k.pub, digest, r, s), nil + } else { + return csp.verifyP11ECDSA(k.ski, digest, r, s, k.pub.Curve.Params().BitSize/8) + } +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsakey.go b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsakey.go new file mode 100644 index 0000000000..c90dfb17fe --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsakey.go @@ -0,0 +1,97 @@ +/* +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/ecdsa" + "crypto/x509" + "errors" + "fmt" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ecdsaPrivateKey struct { + ski []byte + pub ecdsaPublicKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ecdsaPrivateKey) Bytes() (raw []byte, err error) { + return nil, errors.New("Not supported.") +} + +// SKI returns the subject key identifier of this key. +func (k *ecdsaPrivateKey) SKI() (ski []byte) { + return k.ski +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ecdsaPrivateKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ecdsaPrivateKey) 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 *ecdsaPrivateKey) PublicKey() (bccsp.Key, error) { + return &k.pub, nil +} + +type ecdsaPublicKey struct { + ski []byte + pub *ecdsa.PublicKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ecdsaPublicKey) Bytes() (raw []byte, err error) { + raw, err = x509.MarshalPKIXPublicKey(k.pub) + if err != nil { + return nil, fmt.Errorf("Failed marshalling key [%s]", err) + } + return +} + +// SKI returns the subject key identifier of this key. +func (k *ecdsaPublicKey) SKI() (ski []byte) { + return k.ski +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ecdsaPublicKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ecdsaPublicKey) 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 *ecdsaPublicKey) PublicKey() (bccsp.Key, error) { + return k, nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go new file mode 100644 index 0000000000..047e0ec328 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go @@ -0,0 +1,534 @@ +/* +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/ecdsa" + "crypto/elliptic" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "math/big" + "os" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/sw" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/utils" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/flogging" + "github.com/miekg/pkcs11" + "github.com/pkg/errors" +) + +var ( + logger = flogging.MustGetLogger("bccsp_p11") + sessionCacheSize = 10 +) + +// New returns a new instance of the software-based BCCSP +// set at the passed security level, hash family and KeyStore. +func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { + // Init config + conf := &config{} + err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily) + if err != nil { + return nil, errors.Wrapf(err, "Failed initializing configuration") + } + + swCSP, err := sw.New(opts.SecLevel, opts.HashFamily, keyStore) + if err != nil { + return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP") + } + + // Check KeyStore + if keyStore == nil { + return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil.") + } + + lib := opts.Library + pin := opts.Pin + label := opts.Label + ctx, slot, session, err := loadLib(lib, pin, label) + if err != nil { + return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s", + lib, label) + } + + sessions := make(chan pkcs11.SessionHandle, sessionCacheSize) + 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 + + ctx *pkcs11.Ctx + sessions chan pkcs11.SessionHandle + slot uint + + lib string + noPrivImport bool + softVerify bool +} + +// KeyGen generates a key using opts. +func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { + // Validate arguments + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + // Parse algorithm + switch opts.(type) { + case *bccsp.ECDSAKeyGenOpts: + ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) + if err != nil { + return nil, errors.Wrapf(err, "Failed generating ECDSA key") + } + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + + case *bccsp.ECDSAP256KeyGenOpts: + ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) + if err != nil { + return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key") + } + + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + + case *bccsp.ECDSAP384KeyGenOpts: + ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) + if err != nil { + return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key [%s]") + } + + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + + default: + return csp.BCCSP.KeyGen(opts) + } + + return k, nil +} + +// KeyDeriv derives a key from k using opts. +// The opts argument should be appropriate for the primitive used. +func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { + // Validate arguments + if k == nil { + return nil, errors.New("Invalid Key. It must not be nil.") + } + + // Derive key + switch k.(type) { + case *ecdsaPublicKey: + // Validate opts + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + ecdsaK := k.(*ecdsaPublicKey) + + switch opts.(type) { + + // Re-randomized an ECDSA public key + case *bccsp.ECDSAReRandKeyOpts: + pubKey := ecdsaK.pub + if pubKey == nil { + return nil, errors.New("Public base key cannot be nil.") + } + reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + tempSK := &ecdsa.PublicKey{ + Curve: pubKey.Curve, + X: new(big.Int), + Y: new(big.Int), + } + + var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) + var one = new(big.Int).SetInt64(1) + n := new(big.Int).Sub(pubKey.Params().N, one) + k.Mod(k, n) + k.Add(k, one) + + // Compute temporary public key + tempX, tempY := pubKey.ScalarBaseMult(k.Bytes()) + tempSK.X, tempSK.Y = tempSK.Add( + pubKey.X, pubKey.Y, + tempX, tempY, + ) + + // Verify temporary public key is a valid point on the reference curve + isOn := tempSK.Curve.IsOnCurve(tempSK.X, tempSK.Y) + if !isOn { + return nil, errors.New("Failed temporary public key IsOnCurve check.") + } + + ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) + oid, ok := oidFromNamedCurve(tempSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + ski, err := csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting importing EC Public Key") + } + reRandomizedKey := &ecdsaPublicKey{ski, tempSK} + + return reRandomizedKey, nil + + default: + return nil, errors.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) + + } + case *ecdsaPrivateKey: + // Validate opts + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + ecdsaK := k.(*ecdsaPrivateKey) + + switch opts.(type) { + + // Re-randomized an ECDSA private key + case *bccsp.ECDSAReRandKeyOpts: + reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + pubKey := ecdsaK.pub.pub + if pubKey == nil { + return nil, errors.New("Public base key cannot be nil.") + } + + secret := csp.getSecretValue(ecdsaK.ski) + if secret == nil { + return nil, errors.New("Could not obtain EC Private Key") + } + bigSecret := new(big.Int).SetBytes(secret) + + tempSK := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: pubKey.Curve, + X: new(big.Int), + Y: new(big.Int), + }, + D: new(big.Int), + } + + var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) + var one = new(big.Int).SetInt64(1) + n := new(big.Int).Sub(pubKey.Params().N, one) + k.Mod(k, n) + k.Add(k, one) + + tempSK.D.Add(bigSecret, k) + tempSK.D.Mod(tempSK.D, pubKey.Params().N) + + // Compute temporary public key + tempSK.PublicKey.X, tempSK.PublicKey.Y = pubKey.ScalarBaseMult(tempSK.D.Bytes()) + + // Verify temporary public key is a valid point on the reference curve + isOn := tempSK.Curve.IsOnCurve(tempSK.PublicKey.X, tempSK.PublicKey.Y) + if !isOn { + return nil, errors.New("Failed temporary public key IsOnCurve check.") + } + + ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) + oid, ok := oidFromNamedCurve(tempSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + ski, err := csp.importECKey(oid, tempSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting importing EC Public Key") + } + reRandomizedKey := &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &tempSK.PublicKey}} + + return reRandomizedKey, nil + + default: + return nil, errors.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) + + } + + default: + return csp.BCCSP.KeyDeriv(k, opts) + + } +} + +// KeyImport imports a key from its raw representation using opts. +// The opts argument should be appropriate for the primitive used. +func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + // Validate arguments + if raw == nil { + return nil, errors.New("Invalid raw. Cannot be nil.") + } + + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + switch opts.(type) { + + case *bccsp.ECDSAPKIXPublicKeyImportOpts: + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPublicKey(der) + if err != nil { + return nil, errors.Wrapf(err, "Failed converting PKIX to ECDSA public key") + } + + ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") + } + + ecPt := elliptic.Marshal(ecdsaPK.Curve, ecdsaPK.X, ecdsaPK.Y) + oid, ok := oidFromNamedCurve(ecdsaPK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + var ski []byte + if csp.noPrivImport { + // opencryptoki does not support public ec key imports. This is a sufficient + // workaround for now to use soft verify + hash := sha256.Sum256(ecPt) + ski = hash[:] + } else { + // Warn about potential future problems + if !csp.softVerify { + logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + + "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + + "in pkcs11 options, if suspect this issue.") + } + ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting importing EC Public Key") + } + } + + k = &ecdsaPublicKey{ski, ecdsaPK} + return k, nil + + case *bccsp.ECDSAPrivateKeyImportOpts: + if csp.noPrivImport { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] PKCS11 options 'sensitivekeys' is set to true. Cannot import.") + } + + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPrivateKey(der) + if err != nil { + return nil, errors.Wrapf(err, "Failed converting PKIX to ECDSA public key [%s]") + } + + ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") + } + + ecPt := elliptic.Marshal(ecdsaSK.Curve, ecdsaSK.X, ecdsaSK.Y) + oid, ok := oidFromNamedCurve(ecdsaSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + ski, err := csp.importECKey(oid, ecdsaSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting importing EC Private Key") + } + + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &ecdsaSK.PublicKey}} + return k, nil + + case *bccsp.ECDSAGoPublicKeyImportOpts: + lowLevelKey, ok := raw.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("[ECDSAGoPublicKeyImportOpts] Invalid raw material. Expected *ecdsa.PublicKey.") + } + + ecPt := elliptic.Marshal(lowLevelKey.Curve, lowLevelKey.X, lowLevelKey.Y) + oid, ok := oidFromNamedCurve(lowLevelKey.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + var ski []byte + if csp.noPrivImport { + // opencryptoki does not support public ec key imports. This is a sufficient + // workaround for now to use soft verify + hash := sha256.Sum256(ecPt) + ski = hash[:] + } else { + // Warn about potential future problems + if !csp.softVerify { + logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + + "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + + "in pkcs11 options, if suspect this issue.") + } + ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting importing EC Public Key") + } + } + + k = &ecdsaPublicKey{ski, lowLevelKey} + return k, nil + + case *bccsp.X509PublicKeyImportOpts: + x509Cert, ok := raw.(*x509.Certificate) + if !ok { + return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate.") + } + + pk := x509Cert.PublicKey + + switch pk.(type) { + case *ecdsa.PublicKey: + return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + case *rsa.PublicKey: + return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + default: + return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") + } + + default: + return csp.BCCSP.KeyImport(raw, opts) + + } +} + +// GetKey returns the key this CSP associates to +// the Subject Key Identifier ski. +func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { + pubKey, isPriv, err := csp.getECKey(ski) + if err == nil { + if isPriv { + return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil + } else { + return &ecdsaPublicKey{ski, pubKey}, nil + } + } + return csp.BCCSP.GetKey(ski) +} + +// Sign signs digest using key k. +// The opts argument should be appropriate for the primitive used. +// +// 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). +func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + // Validate arguments + if k == nil { + return nil, errors.New("Invalid Key. It must not be nil.") + } + if len(digest) == 0 { + return nil, errors.New("Invalid digest. Cannot be empty.") + } + + // Check key type + switch k.(type) { + case *ecdsaPrivateKey: + return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts) + default: + return csp.BCCSP.Sign(k, digest, opts) + } +} + +// Verify verifies signature against key k and digest +func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + // Validate arguments + if k == nil { + return false, errors.New("Invalid Key. It must not be nil.") + } + if len(signature) == 0 { + return false, errors.New("Invalid signature. Cannot be empty.") + } + if len(digest) == 0 { + return false, errors.New("Invalid digest. Cannot be empty.") + } + + // Check key type + switch k.(type) { + case *ecdsaPrivateKey: + return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts) + case *ecdsaPublicKey: + return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts) + default: + 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) { + // 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) { + return csp.BCCSP.Decrypt(k, ciphertext, opts) +} + +// THIS IS ONLY USED FOR TESTING +// This is a convenience function. Useful to self-configure, for tests where usual configuration is not +// available +func FindPKCS11Lib() (lib, pin, label string) { + //FIXME: Till we workout the configuration piece, look for the libraries in the familiar places + lib = os.Getenv("PKCS11_LIB") + if lib == "" { + pin = "98765432" + label = "ForFabric" + possibilities := []string{ + "/usr/lib/softhsm/libsofthsm2.so", //Debian + "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu + "/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu + "/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so", //Power + "/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS + } + for _, path := range possibilities { + if _, err := os.Stat(path); !os.IsNotExist(err) { + lib = path + break + } + } + } else { + pin = os.Getenv("PKCS11_PIN") + label = os.Getenv("PKCS11_LABEL") + } + return lib, pin, label +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go new file mode 100644 index 0000000000..f35b35698c --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go @@ -0,0 +1,626 @@ +/* +Copyright IBM Corp. 2017 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/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "encoding/asn1" + "encoding/hex" + "fmt" + "math/big" + "sync" + + "github.com/miekg/pkcs11" + "github.com/op/go-logging" +) + +func loadLib(lib, pin, label string) (*pkcs11.Ctx, uint, *pkcs11.SessionHandle, error) { + var slot uint = 0 + logger.Debugf("Loading pkcs11 library [%s]\n", lib) + if lib == "" { + return nil, slot, nil, fmt.Errorf("No PKCS11 library default") + } + + ctx := pkcs11.New(lib) + if ctx == nil { + return nil, slot, nil, fmt.Errorf("Instantiate failed [%s]", lib) + } + + ctx.Initialize() + slots, err := ctx.GetSlotList(true) + if err != nil { + return nil, slot, nil, fmt.Errorf("Could not get Slot List [%s]", err) + } + found := false + for _, s := range slots { + info, err := ctx.GetTokenInfo(s) + if err != nil { + continue + } + logger.Debugf("Looking for %s, found label %s\n", label, info.Label) + if label == info.Label { + found = true + slot = s + break + } + } + if !found { + return nil, slot, nil, fmt.Errorf("Could not find token with label %s", label) + } + + var session pkcs11.SessionHandle + for i := 0; i < 10; i++ { + session, err = ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) + if err != nil { + logger.Warningf("OpenSession failed, retrying [%s]\n", err) + } else { + break + } + } + if err != nil { + logger.Fatalf("OpenSession [%s]\n", err) + } + logger.Debugf("Created new pkcs11 session %+v on slot %d\n", session, slot) + + if pin == "" { + return nil, slot, nil, fmt.Errorf("No PIN set\n") + } + err = ctx.Login(session, pkcs11.CKU_USER, pin) + if err != nil { + if err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) { + return nil, slot, nil, fmt.Errorf("Login failed [%s]\n", err) + } + } + + return ctx, slot, &session, nil +} + +func (csp *impl) getSession() (session pkcs11.SessionHandle) { + select { + case session = <-csp.sessions: + logger.Debugf("Reusing existing pkcs11 session %+v on slot %d\n", session, csp.slot) + + default: + // cache is empty (or completely in use), create a new session + var s pkcs11.SessionHandle + var err error = nil + for i := 0; i < 10; i++ { + s, err = csp.ctx.OpenSession(csp.slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) + if err != nil { + logger.Warningf("OpenSession failed, retrying [%s]\n", err) + } else { + break + } + } + if err != nil { + panic(fmt.Errorf("OpenSession failed [%s]\n", err)) + } + logger.Debugf("Created new pkcs11 session %+v on slot %d\n", s, csp.slot) + session = s + } + return session +} + +func (csp *impl) returnSession(session pkcs11.SessionHandle) { + select { + case csp.sessions <- session: + // returned session back to session cache + default: + // have plenty of sessions in cache, dropping + csp.ctx.CloseSession(session) + } +} + +// Look for an EC key by SKI, stored in CKA_ID +// This function can probably be adapted for both EC and RSA keys. +func (csp *impl) getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + isPriv = true + _, err = findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) + if err != nil { + isPriv = false + logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski)) + } + + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag) + if err != nil { + return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) + } + + ecpt, marshaledOid, err := ecPoint(p11lib, session, *publicKey) + if err != nil { + return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) + } + + curveOid := new(asn1.ObjectIdentifier) + _, err = asn1.Unmarshal(marshaledOid, curveOid) + if err != nil { + return nil, false, fmt.Errorf("Failed Unmarshaling Curve OID [%s]\n%s", err.Error(), hex.EncodeToString(marshaledOid)) + } + + curve := namedCurveFromOID(*curveOid) + if curve == nil { + return nil, false, fmt.Errorf("Cound not recognize Curve from OID") + } + x, y := elliptic.Unmarshal(curve, ecpt) + if x == nil { + return nil, false, fmt.Errorf("Failed Unmarshaling Public Key") + } + + pubKey = &ecdsa.PublicKey{Curve: curve, X: x, Y: y} + return pubKey, isPriv, nil +} + +// RFC 5480, 2.1.1.1. Named Curve +// +// secp224r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 33 } +// +// secp256r1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) +// prime(1) 7 } +// +// secp384r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 34 } +// +// secp521r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 35 } +// +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { + switch { + case oid.Equal(oidNamedCurveP224): + return elliptic.P224() + case oid.Equal(oidNamedCurveP256): + return elliptic.P256() + case oid.Equal(oidNamedCurveP384): + return elliptic.P384() + case oid.Equal(oidNamedCurveP521): + return elliptic.P521() + } + return nil +} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + + return nil, false +} + +func (csp *impl) generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + + id := nextIDCtr() + publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) + prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16)) + + marshaledOID, err := asn1.Marshal(curve) + if err != nil { + return nil, nil, fmt.Errorf("Could not marshal OID [%s]", err.Error()) + } + + pubkey_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + + pkcs11.NewAttribute(pkcs11.CKA_ID, publabel), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), + } + + prvkey_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), + pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), + + pkcs11.NewAttribute(pkcs11.CKA_ID, prvlabel), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), + + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, !csp.noPrivImport), + } + + pub, prv, err := p11lib.GenerateKeyPair(session, + []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil)}, + pubkey_t, prvkey_t) + + if err != nil { + return nil, nil, fmt.Errorf("P11: keypair generate failed [%s]\n", err) + } + + ecpt, _, _ := ecPoint(p11lib, session, pub) + hash := sha256.Sum256(ecpt) + ski = hash[:] + + // set CKA_ID of the both keys to SKI(public key) + setski_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + } + + logger.Infof("Generated new P11 key, SKI %x\n", ski) + err = p11lib.SetAttributeValue(session, pub, setski_t) + if err != nil { + return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[public] failed [%s]\n", err) + } + + err = p11lib.SetAttributeValue(session, prv, setski_t) + if err != nil { + return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[private] failed [%s]\n", err) + } + + nistCurve := namedCurveFromOID(curve) + if curve == nil { + return nil, nil, fmt.Errorf("Cound not recognize Curve from OID") + } + x, y := elliptic.Unmarshal(nistCurve, ecpt) + if x == nil { + return nil, nil, fmt.Errorf("Failed Unmarshaling Public Key") + } + + pubGoKey := &ecdsa.PublicKey{Curve: nistCurve, X: x, Y: y} + + if logger.IsEnabledFor(logging.DEBUG) { + listAttrs(p11lib, session, prv) + listAttrs(p11lib, session, pub) + } + + return ski, pubGoKey, nil +} + +func (csp *impl) signP11ECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + + privateKey, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) + if err != nil { + return nil, nil, fmt.Errorf("Private key not found [%s]\n", err) + } + + err = p11lib.SignInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, *privateKey) + if err != nil { + return nil, nil, fmt.Errorf("Sign-initialize failed [%s]\n", err) + } + + var sig []byte + + sig, err = p11lib.Sign(session, msg) + if err != nil { + return nil, nil, fmt.Errorf("P11: sign failed [%s]\n", err) + } + + R = new(big.Int) + S = new(big.Int) + R.SetBytes(sig[0 : len(sig)/2]) + S.SetBytes(sig[len(sig)/2:]) + + return R, S, nil +} + +func (csp *impl) verifyP11ECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (valid bool, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + + logger.Debugf("Verify ECDSA\n") + + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag) + if err != nil { + return false, fmt.Errorf("Public key not found [%s]\n", err) + } + + r := R.Bytes() + s := S.Bytes() + + // Pad front of R and S with Zeroes if needed + sig := make([]byte, 2*byteSize) + copy(sig[byteSize-len(r):byteSize], r) + copy(sig[2*byteSize-len(s):], s) + + err = p11lib.VerifyInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, + *publicKey) + if err != nil { + return false, fmt.Errorf("PKCS11: Verify-initialize [%s]\n", err) + } + err = p11lib.Verify(session, msg, sig) + if err == pkcs11.Error(pkcs11.CKR_SIGNATURE_INVALID) { + return false, nil + } + if err != nil { + return false, fmt.Errorf("PKCS11: Verify failed [%s]\n", err) + } + + return true, nil +} + +func (csp *impl) importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bool, keyType bool) (ski []byte, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + + id := nextIDCtr() + + marshaledOID, err := asn1.Marshal(curve) + if err != nil { + return nil, fmt.Errorf("Could not marshal OID [%s]", err.Error()) + } + + var keyTemplate []*pkcs11.Attribute + if keyType == publicKeyFlag { + logger.Debug("Importing Public EC Key") + publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) + + hash := sha256.Sum256(ecPt) + ski = hash[:] + + // Add DER encoding for the CKA_EC_POINT + ecPt = append([]byte{0x04, byte(len(ecPt))}, ecPt...) + + keyTemplate = []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), + pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, ecPt), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + } + } else { // isPrivateKey + ski, err = csp.importECKey(curve, nil, ecPt, ephemeral, publicKeyFlag) + if err != nil { + return nil, fmt.Errorf("Failed importing private EC Key [%s]\n", err) + } + + logger.Debugf("Importing Private EC Key [%d]\n%s\n", len(privKey)*8, hex.Dump(privKey)) + prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16)) + keyTemplate = []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), + pkcs11.NewAttribute(pkcs11.CKR_ATTRIBUTE_SENSITIVE, false), + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true), + pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), + } + } + + keyHandle, err := p11lib.CreateObject(session, keyTemplate) + if err != nil { + return nil, fmt.Errorf("P11: keypair generate failed [%s]\n", err) + } + + if logger.IsEnabledFor(logging.DEBUG) { + listAttrs(p11lib, session, keyHandle) + } + + return ski, nil +} + +const ( + privateKeyFlag = true + publicKeyFlag = false +) + +func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, keyType bool) (*pkcs11.ObjectHandle, error) { + ktype := pkcs11.CKO_PUBLIC_KEY + if keyType == privateKeyFlag { + ktype = pkcs11.CKO_PRIVATE_KEY + } + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype), + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + } + if err := mod.FindObjectsInit(session, template); err != nil { + return nil, err + } + + // single session instance, assume one hit only + objs, _, err := mod.FindObjects(session, 1) + if err != nil { + return nil, err + } + if err = mod.FindObjectsFinal(session); err != nil { + return nil, err + } + + if len(objs) == 0 { + return nil, fmt.Errorf("Key not found [%s]", hex.Dump(ski)) + } + + return &objs[0], nil +} + +// Fairly straightforward EC-point query, other than opencryptoki +// mis-reporting length, including the 04 Tag of the field following +// the SPKI in EP11-returned MACed publickeys: +// +// attr type 385/x181, length 66 b -- SHOULD be 1+64 +// EC point: +// 00000000 04 ce 30 31 6d 5a fd d3 53 2d 54 9a 27 54 d8 7c +// 00000010 d9 80 35 91 09 2d 6f 06 5a 8e e3 cb c0 01 b7 c9 +// 00000020 13 5d 70 d4 e5 62 f2 1b 10 93 f7 d5 77 41 ba 9d +// 00000030 93 3e 18 3e 00 c6 0a 0e d2 36 cc 7f be 50 16 ef +// 00000040 06 04 +// +// cf. correct field: +// 0 89: SEQUENCE { +// 2 19: SEQUENCE { +// 4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) +// 13 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) +// : } +// 23 66: BIT STRING +// : 04 CE 30 31 6D 5A FD D3 53 2D 54 9A 27 54 D8 7C +// : D9 80 35 91 09 2D 6F 06 5A 8E E3 CB C0 01 B7 C9 +// : 13 5D 70 D4 E5 62 F2 1B 10 93 F7 D5 77 41 BA 9D +// : 93 3E 18 3E 00 C6 0A 0E D2 36 CC 7F BE 50 16 EF +// : 06 +// : } +// +// as a short-term workaround, remove the trailing byte if: +// - receiving an even number of bytes == 2*prime-coordinate +2 bytes +// - starting byte is 04: uncompressed EC point +// - trailing byte is 04: assume it belongs to the next OCTET STRING +// +// [mis-parsing encountered with v3.5.1, 2016-10-22] +// +// SoftHSM reports extra two bytes before the uncompressed point +// 0x04 || +// VV< Actual start of point +// 00000000 04 41 04 6c c8 57 32 13 02 12 6a 19 23 1d 5a 64 |.A.l.W2...j.#.Zd| +// 00000010 33 0c eb 75 4d e8 99 22 92 35 96 b2 39 58 14 1e |3..uM..".5..9X..| +// 00000020 19 de ef 32 46 50 68 02 24 62 36 db ed b1 84 7b |...2FPh.$b6....{| +// 00000030 93 d8 40 c3 d5 a6 b7 38 16 d2 35 0a 53 11 f9 51 |..@....8..5.S..Q| +// 00000040 fc a7 16 |...| +func ecPoint(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, key pkcs11.ObjectHandle) (ecpt, oid []byte, err error) { + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), + } + + attr, err := p11lib.GetAttributeValue(session, key, template) + if err != nil { + return nil, nil, fmt.Errorf("PKCS11: get(EC point) [%s]\n", err) + } + + for _, a := range attr { + if a.Type == pkcs11.CKA_EC_POINT { + logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + + // workarounds, see above + if (0 == (len(a.Value) % 2)) && + (byte(0x04) == a.Value[0]) && + (byte(0x04) == a.Value[len(a.Value)-1]) { + logger.Debugf("Detected opencryptoki bug, trimming trailing 0x04") + ecpt = a.Value[0 : len(a.Value)-1] // Trim trailing 0x04 + } else if byte(0x04) == a.Value[0] && byte(0x04) == a.Value[2] { + logger.Debugf("Detected SoftHSM bug, trimming leading 0x04 0xXX") + ecpt = a.Value[2:len(a.Value)] + } else { + ecpt = a.Value + } + } else if a.Type == pkcs11.CKA_EC_PARAMS { + logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + + oid = a.Value + } + } + if oid == nil || ecpt == nil { + return nil, nil, fmt.Errorf("CKA_EC_POINT not found, perhaps not an EC Key?") + } + + return ecpt, oid, nil +} + +func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.ObjectHandle) { + var cktype, ckclass uint + var ckaid, cklabel []byte + + if p11lib == nil { + return + } + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, ckclass), + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, cktype), + pkcs11.NewAttribute(pkcs11.CKA_ID, ckaid), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, cklabel), + } + + // certain errors are tolerated, if value is missing + attr, err := p11lib.GetAttributeValue(session, obj, template) + if err != nil { + logger.Debugf("P11: get(attrlist) [%s]\n", err) + } + + for _, a := range attr { + // Would be friendlier if the bindings provided a way convert Attribute hex to string + logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + } +} + +func (csp *impl) getSecretValue(ski []byte) []byte { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) + + keyHandle, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) + + var privKey []byte + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), + } + + // certain errors are tolerated, if value is missing + attr, err := p11lib.GetAttributeValue(session, *keyHandle, template) + if err != nil { + logger.Warningf("P11: get(attrlist) [%s]\n", err) + } + + for _, a := range attr { + // Would be friendlier if the bindings provided a way convert Attribute hex to string + logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + return a.Value + } + logger.Warningf("No Key Value found!", err) + return nil +} + +var ( + bigone = new(big.Int).SetInt64(1) + id_ctr = new(big.Int) + id_mutex sync.Mutex +) + +func nextIDCtr() *big.Int { + id_mutex.Lock() + id_ctr = new(big.Int).Add(id_ctr, bigone) + id_mutex.Unlock() + return id_ctr +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/rsaopts.go b/third_party/github.com/hyperledger/fabric/bccsp/rsaopts.go new file mode 100644 index 0000000000..13accfba89 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/rsaopts.go @@ -0,0 +1,81 @@ +/* +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 bccsp + +// RSA1024KeyGenOpts contains options for RSA key generation at 1024 security. +type RSA1024KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *RSA1024KeyGenOpts) Algorithm() string { + return RSA1024 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSA1024KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// RSA2048KeyGenOpts contains options for RSA key generation at 2048 security. +type RSA2048KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *RSA2048KeyGenOpts) Algorithm() string { + return RSA2048 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSA2048KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// RSA3072KeyGenOpts contains options for RSA key generation at 3072 security. +type RSA3072KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *RSA3072KeyGenOpts) Algorithm() string { + return RSA3072 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSA3072KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} + +// RSA4096KeyGenOpts contains options for RSA key generation at 4096 security. +type RSA4096KeyGenOpts struct { + Temporary bool +} + +// Algorithm returns the key generation algorithm identifier (to be used). +func (opts *RSA4096KeyGenOpts) Algorithm() string { + return RSA4096 +} + +// Ephemeral returns true if the key to generate has to be ephemeral, +// false otherwise. +func (opts *RSA4096KeyGenOpts) Ephemeral() bool { + return opts.Temporary +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/signer/signer.go b/third_party/github.com/hyperledger/fabric/bccsp/signer/signer.go new file mode 100644 index 0000000000..b82b60f4f9 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/signer/signer.go @@ -0,0 +1,88 @@ +/* +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" + "io" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/utils" + "github.com/pkg/errors" +) + +// bccspCryptoSigner is the BCCSP-based implementation of a crypto.Signer +type bccspCryptoSigner struct { + csp bccsp.BCCSP + key bccsp.Key + pk interface{} +} + +// New returns a new BCCSP-based crypto.Signer +// for the given BCCSP instance and key. +func New(csp bccsp.BCCSP, key bccsp.Key) (crypto.Signer, error) { + // Validate arguments + if csp == nil { + return nil, errors.New("bccsp instance must be different from nil.") + } + if key == nil { + return nil, errors.New("key must be different from nil.") + } + if key.Symmetric() { + return nil, errors.New("key must be asymmetric.") + } + + // Marshall the bccsp public key as a crypto.PublicKey + pub, err := key.PublicKey() + if err != nil { + return nil, errors.Wrap(err, "failed getting public key") + } + + raw, err := pub.Bytes() + if err != nil { + return nil, errors.Wrap(err, "failed marshalling public key") + } + + pk, err := utils.DERToPublicKey(raw) + if err != nil { + return nil, errors.Wrap(err, "failed marshalling der to public key") + } + + return &bccspCryptoSigner{csp, key, pk}, nil +} + +// Public returns the public key corresponding to the opaque, +// private key. +func (s *bccspCryptoSigner) 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 *bccspCryptoSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { + return s.csp.Sign(s.key, digest, opts) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/aes.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/aes.go new file mode 100644 index 0000000000..469df40a25 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/aes.go @@ -0,0 +1,221 @@ +/* +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 sw + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "errors" + "fmt" + "io" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +// GetRandomBytes returns len random looking bytes +func GetRandomBytes(len int) ([]byte, error) { + if len < 0 { + return nil, errors.New("Len must be larger than 0") + } + + 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) { + return aesCBCEncryptWithRand(rand.Reader, key, s) +} + +func aesCBCEncryptWithRand(prng io.Reader, 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(prng, iv); err != nil { + return nil, err + } + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], s) + + return ciphertext, nil +} + +func aesCBCEncryptWithIV(IV []byte, 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") + } + + if len(IV) != aes.BlockSize { + return nil, errors.New("Invalid IV. It must have length the block size") + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + ciphertext := make([]byte, aes.BlockSize+len(s)) + copy(ciphertext[:aes.BlockSize], IV) + + 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) +} + +// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding using as prng the passed to the function +func AESCBCPKCS7EncryptWithRand(prng io.Reader, key, src []byte) ([]byte, error) { + // First pad + tmp := pkcs7Padding(src) + + // Then encrypt + return aesCBCEncryptWithRand(prng, key, tmp) +} + +// AESCBCPKCS7Encrypt combines CBC encryption and PKCS7 padding, the IV used is the one passed to the function +func AESCBCPKCS7EncryptWithIV(IV []byte, key, src []byte) ([]byte, error) { + // First pad + tmp := pkcs7Padding(src) + + // Then encrypt + return aesCBCEncryptWithIV(IV, 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 pkcs7UnPadding(pt) + } + return nil, err +} + +type aescbcpkcs7Encryptor struct{} + +func (e *aescbcpkcs7Encryptor) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) { + switch o := opts.(type) { + case *bccsp.AESCBCPKCS7ModeOpts: + // AES in CBC mode with PKCS7 padding + + if len(o.IV) != 0 && o.PRNG != nil { + return nil, errors.New("Invalid options. Either IV or PRNG should be different from nil, or both nil.") + } + + if len(o.IV) != 0 { + // Encrypt with the passed IV + return AESCBCPKCS7EncryptWithIV(o.IV, k.(*aesPrivateKey).privKey, plaintext) + } else if o.PRNG != nil { + // Encrypt with PRNG + return AESCBCPKCS7EncryptWithRand(o.PRNG, k.(*aesPrivateKey).privKey, plaintext) + } + // AES in CBC mode with PKCS7 padding + return AESCBCPKCS7Encrypt(k.(*aesPrivateKey).privKey, plaintext) + case bccsp.AESCBCPKCS7ModeOpts: + return e.Encrypt(k, plaintext, &o) + default: + return nil, fmt.Errorf("Mode not recognized [%s]", opts) + } +} + +type aescbcpkcs7Decryptor struct{} + +func (*aescbcpkcs7Decryptor) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) { + // 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) + } +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/aeskey.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/aeskey.go new file mode 100644 index 0000000000..32537c273c --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/aeskey.go @@ -0,0 +1,65 @@ +/* +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 sw + +import ( + "errors" + + "crypto/sha256" + + "github.com/hyperledger/fabric-sdk-go/third_party/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/third_party/github.com/hyperledger/fabric/bccsp/sw/conf.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/conf.go new file mode 100644 index 0000000000..ee73e85324 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/conf.go @@ -0,0 +1,81 @@ +/* +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 sw + +import ( + "crypto/elliptic" + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + + "golang.org/x/crypto/sha3" +) + +type config struct { + ellipticCurve elliptic.Curve + hashFunction func() hash.Hash + aesBitLength int + rsaBitLength int +} + +func (conf *config) setSecurityLevel(securityLevel int, hashFamily string) (err error) { + switch hashFamily { + case "SHA2": + err = conf.setSecurityLevelSHA2(securityLevel) + case "SHA3": + err = conf.setSecurityLevelSHA3(securityLevel) + default: + err = fmt.Errorf("Hash Family not supported [%s]", hashFamily) + } + return +} + +func (conf *config) setSecurityLevelSHA2(level int) (err error) { + switch level { + case 256: + conf.ellipticCurve = elliptic.P256() + conf.hashFunction = sha256.New + conf.rsaBitLength = 2048 + conf.aesBitLength = 32 + case 384: + conf.ellipticCurve = elliptic.P384() + conf.hashFunction = sha512.New384 + conf.rsaBitLength = 3072 + conf.aesBitLength = 32 + default: + err = fmt.Errorf("Security level not supported [%d]", level) + } + return +} + +func (conf *config) setSecurityLevelSHA3(level int) (err error) { + switch level { + case 256: + conf.ellipticCurve = elliptic.P256() + conf.hashFunction = sha3.New256 + conf.rsaBitLength = 2048 + conf.aesBitLength = 32 + case 384: + conf.ellipticCurve = elliptic.P384() + conf.hashFunction = sha3.New384 + conf.rsaBitLength = 3072 + conf.aesBitLength = 32 + default: + err = fmt.Errorf("Security level not supported [%d]", level) + } + return +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/dummyks.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/dummyks.go new file mode 100644 index 0000000000..247dba6122 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/dummyks.go @@ -0,0 +1,49 @@ +/* +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 sw + +import ( + "errors" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +// NewDummyKeyStore instantiate a dummy key store +// that neither loads nor stores keys +func NewDummyKeyStore() bccsp.KeyStore { + return &dummyKeyStore{} +} + +// 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/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsa.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsa.go new file mode 100644 index 0000000000..af87fbe33b --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsa.go @@ -0,0 +1,171 @@ +/* +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 sw + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/asn1" + "errors" + "fmt" + "math/big" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ECDSASignature struct { + R, S *big.Int +} + +var ( + // curveHalfOrders contains the precomputed curve group orders halved. + // It is used to ensure that signature' S value is lower or equal to the + // curve group order halved. We accept only low-S signatures. + // They are precomputed for efficiency reasons. + curveHalfOrders map[elliptic.Curve]*big.Int = map[elliptic.Curve]*big.Int{ + elliptic.P224(): new(big.Int).Rsh(elliptic.P224().Params().N, 1), + elliptic.P256(): new(big.Int).Rsh(elliptic.P256().Params().N, 1), + elliptic.P384(): new(big.Int).Rsh(elliptic.P384().Params().N, 1), + elliptic.P521(): new(big.Int).Rsh(elliptic.P521().Params().N, 1), + } +) + +func MarshalECDSASignature(r, s *big.Int) ([]byte, error) { + return asn1.Marshal(ECDSASignature{r, s}) +} + +func UnmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) { + // Unmarshal + sig := new(ECDSASignature) + _, err := asn1.Unmarshal(raw, sig) + if err != nil { + return nil, nil, fmt.Errorf("Failed unmashalling signature [%s]", err) + } + + // Validate sig + if sig.R == nil { + return nil, nil, errors.New("Invalid signature. R must be different from nil.") + } + if sig.S == nil { + return nil, nil, errors.New("Invalid signature. S must be different from nil.") + } + + if sig.R.Sign() != 1 { + return nil, nil, errors.New("Invalid signature. R must be larger than zero") + } + if sig.S.Sign() != 1 { + return nil, nil, errors.New("Invalid signature. S must be larger than zero") + } + + return sig.R, sig.S, nil +} + +func signECDSA(k *ecdsa.PrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + r, s, err := ecdsa.Sign(rand.Reader, k, digest) + if err != nil { + return nil, err + } + + s, _, err = ToLowS(&k.PublicKey, s) + if err != nil { + return nil, err + } + + return MarshalECDSASignature(r, s) +} + +func verifyECDSA(k *ecdsa.PublicKey, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + r, s, err := UnmarshalECDSASignature(signature) + if err != nil { + return false, fmt.Errorf("Failed unmashalling signature [%s]", err) + } + + lowS, err := IsLowS(k, s) + if err != nil { + return false, err + } + + if !lowS { + return false, fmt.Errorf("Invalid S. Must be smaller than half the order [%s][%s].", s, curveHalfOrders[k.Curve]) + } + + return ecdsa.Verify(k, digest, r, s), nil +} + +func SignatureToLowS(k *ecdsa.PublicKey, signature []byte) ([]byte, error) { + r, s, err := UnmarshalECDSASignature(signature) + if err != nil { + return nil, err + } + + s, modified, err := ToLowS(k, s) + if err != nil { + return nil, err + } + + if modified { + return MarshalECDSASignature(r, s) + } + + return signature, nil +} + +// IsLow checks that s is a low-S +func IsLowS(k *ecdsa.PublicKey, s *big.Int) (bool, error) { + halfOrder, ok := curveHalfOrders[k.Curve] + if !ok { + return false, fmt.Errorf("Curve not recognized [%s]", k.Curve) + } + + return s.Cmp(halfOrder) != 1, nil + +} + +func ToLowS(k *ecdsa.PublicKey, s *big.Int) (*big.Int, bool, error) { + lowS, err := IsLowS(k, s) + if err != nil { + return nil, false, err + } + + if !lowS { + // Set s to N - s that will be then in the lower part of signature space + // less or equal to half order + s.Sub(k.Params().N, s) + + return s, true, nil + } + + return s, false, nil +} + +type ecdsaSigner struct{} + +func (s *ecdsaSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + return signECDSA(k.(*ecdsaPrivateKey).privKey, digest, opts) +} + +type ecdsaPrivateKeyVerifier struct{} + +func (v *ecdsaPrivateKeyVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + return verifyECDSA(&(k.(*ecdsaPrivateKey).privKey.PublicKey), signature, digest, opts) +} + +type ecdsaPublicKeyKeyVerifier struct{} + +func (v *ecdsaPublicKeyKeyVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + return verifyECDSA(k.(*ecdsaPublicKey).pubKey, signature, digest, opts) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsakey.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsakey.go new file mode 100644 index 0000000000..1b47644cb1 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/ecdsakey.go @@ -0,0 +1,120 @@ +/* +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 sw + +import ( + "crypto/ecdsa" + "crypto/x509" + "fmt" + + "crypto/sha256" + + "errors" + + "crypto/elliptic" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ecdsaPrivateKey struct { + privKey *ecdsa.PrivateKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ecdsaPrivateKey) Bytes() (raw []byte, err error) { + return nil, errors.New("Not supported.") +} + +// SKI returns the subject key identifier of this key. +func (k *ecdsaPrivateKey) SKI() (ski []byte) { + if k.privKey == nil { + return nil + } + + // Marshall the public key + raw := elliptic.Marshal(k.privKey.Curve, k.privKey.PublicKey.X, k.privKey.PublicKey.Y) + + // Hash it + hash := sha256.New() + hash.Write(raw) + return hash.Sum(nil) +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ecdsaPrivateKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ecdsaPrivateKey) 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 *ecdsaPrivateKey) PublicKey() (bccsp.Key, error) { + return &ecdsaPublicKey{&k.privKey.PublicKey}, nil +} + +type ecdsaPublicKey struct { + pubKey *ecdsa.PublicKey +} + +// Bytes converts this key to its byte representation, +// if this operation is allowed. +func (k *ecdsaPublicKey) Bytes() (raw []byte, err error) { + 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 *ecdsaPublicKey) SKI() (ski []byte) { + if k.pubKey == nil { + return nil + } + + // Marshall the public key + raw := elliptic.Marshal(k.pubKey.Curve, k.pubKey.X, k.pubKey.Y) + + // Hash it + hash := sha256.New() + hash.Write(raw) + return hash.Sum(nil) +} + +// Symmetric returns true if this key is a symmetric key, +// false if this key is asymmetric +func (k *ecdsaPublicKey) Symmetric() bool { + return false +} + +// Private returns true if this key is a private key, +// false otherwise. +func (k *ecdsaPublicKey) 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 *ecdsaPublicKey) PublicKey() (bccsp.Key, error) { + return k, nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/fileks.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/fileks.go new file mode 100644 index 0000000000..b702faf583 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/fileks.go @@ -0,0 +1,431 @@ +/* +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 sw + +import ( + "bytes" + "io/ioutil" + "os" + "sync" + + "errors" + "strings" + + "crypto/ecdsa" + "crypto/rsa" + "encoding/hex" + "fmt" + "path/filepath" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/utils" +) + +// NewFileBasedKeyStore instantiated a file-based key store at a given position. +// The key store can be encrypted if a non-empty password is specifiec. +// It can be also be set as read only. In this case, any store operation +// will be forbidden +func NewFileBasedKeyStore(pwd []byte, path string, readOnly bool) (bccsp.KeyStore, error) { + ks := &fileBasedKeyStore{} + return ks, ks.Init(pwd, path, readOnly) +} + +// 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 *ecdsa.PrivateKey: + return &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)}, nil + 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 *ecdsa.PublicKey: + return &ecdsaPublicKey{key.(*ecdsa.PublicKey)}, nil + 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 *ecdsaPrivateKey: + kk := k.(*ecdsaPrivateKey) + + err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) + if err != nil { + return fmt.Errorf("Failed storing ECDSA private key [%s]", err) + } + + case *ecdsaPublicKey: + kk := k.(*ecdsaPublicKey) + + err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey) + if err != nil { + return fmt.Errorf("Failed storing ECDSA public key [%s]", err) + } + + 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())) + if err != nil { + continue + } + + key, err := utils.PEMtoPrivateKey(raw, ks.pwd) + if err != nil { + continue + } + + switch key.(type) { + case *ecdsa.PrivateKey: + k = &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)} + 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/third_party/github.com/hyperledger/fabric/bccsp/sw/hash.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/hash.go new file mode 100644 index 0000000000..61f1f1dd37 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/hash.go @@ -0,0 +1,37 @@ +/* +Copyright IBM Corp. 2017 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 sw + +import ( + "hash" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type hasher struct { + hash func() hash.Hash +} + +func (c *hasher) Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) { + h := c.hash() + h.Write(msg) + return h.Sum(nil), nil +} + +func (c *hasher) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) { + return c.hash(), nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/impl.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/impl.go new file mode 100644 index 0000000000..13764c1fdd --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/impl.go @@ -0,0 +1,393 @@ +/* +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 sw + +import ( + "crypto/elliptic" + "crypto/sha256" + "crypto/sha512" + "hash" + "reflect" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/flogging" + "github.com/pkg/errors" + "golang.org/x/crypto/sha3" +) + +var ( + logger = flogging.MustGetLogger("bccsp_sw") +) + +// NewDefaultSecurityLevel returns a new instance of the software-based BCCSP +// at security level 256, hash family SHA2 and using FolderBasedKeyStore as KeyStore. +func NewDefaultSecurityLevel(keyStorePath string) (bccsp.BCCSP, error) { + ks := &fileBasedKeyStore{} + if err := ks.Init(nil, keyStorePath, false); err != nil { + return nil, errors.Wrapf(err, "Failed initializing key store at [%v]", keyStorePath) + } + + return New(256, "SHA2", ks) +} + +// NewDefaultSecurityLevel returns a new instance of the software-based BCCSP +// at security level 256, hash family SHA2 and using the passed KeyStore. +func NewDefaultSecurityLevelWithKeystore(keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { + return New(256, "SHA2", keyStore) +} + +// New returns a new instance of the software-based BCCSP +// set at the passed security level, hash family and KeyStore. +func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { + // Init config + conf := &config{} + err := conf.setSecurityLevel(securityLevel, hashFamily) + if err != nil { + return nil, errors.Wrapf(err, "Failed initializing configuration at [%v,%v]", securityLevel, hashFamily) + } + + // Check KeyStore + if keyStore == nil { + return nil, errors.Errorf("Invalid bccsp.KeyStore instance. It must be different from nil.") + } + + // Set the encryptors + encryptors := make(map[reflect.Type]Encryptor) + encryptors[reflect.TypeOf(&aesPrivateKey{})] = &aescbcpkcs7Encryptor{} + + // Set the decryptors + decryptors := make(map[reflect.Type]Decryptor) + decryptors[reflect.TypeOf(&aesPrivateKey{})] = &aescbcpkcs7Decryptor{} + + // Set the signers + signers := make(map[reflect.Type]Signer) + signers[reflect.TypeOf(&ecdsaPrivateKey{})] = &ecdsaSigner{} + signers[reflect.TypeOf(&rsaPrivateKey{})] = &rsaSigner{} + + // Set the verifiers + verifiers := make(map[reflect.Type]Verifier) + verifiers[reflect.TypeOf(&ecdsaPrivateKey{})] = &ecdsaPrivateKeyVerifier{} + verifiers[reflect.TypeOf(&ecdsaPublicKey{})] = &ecdsaPublicKeyKeyVerifier{} + verifiers[reflect.TypeOf(&rsaPrivateKey{})] = &rsaPrivateKeyVerifier{} + verifiers[reflect.TypeOf(&rsaPublicKey{})] = &rsaPublicKeyKeyVerifier{} + + // Set the hashers + hashers := make(map[reflect.Type]Hasher) + hashers[reflect.TypeOf(&bccsp.SHAOpts{})] = &hasher{hash: conf.hashFunction} + hashers[reflect.TypeOf(&bccsp.SHA256Opts{})] = &hasher{hash: sha256.New} + hashers[reflect.TypeOf(&bccsp.SHA384Opts{})] = &hasher{hash: sha512.New384} + hashers[reflect.TypeOf(&bccsp.SHA3_256Opts{})] = &hasher{hash: sha3.New256} + hashers[reflect.TypeOf(&bccsp.SHA3_384Opts{})] = &hasher{hash: sha3.New384} + + impl := &impl{ + conf: conf, + ks: keyStore, + encryptors: encryptors, + decryptors: decryptors, + signers: signers, + verifiers: verifiers, + hashers: hashers} + + // Set the key generators + keyGenerators := make(map[reflect.Type]KeyGenerator) + keyGenerators[reflect.TypeOf(&bccsp.ECDSAKeyGenOpts{})] = &ecdsaKeyGenerator{curve: conf.ellipticCurve} + keyGenerators[reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P256()} + keyGenerators[reflect.TypeOf(&bccsp.ECDSAP384KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P384()} + keyGenerators[reflect.TypeOf(&bccsp.AESKeyGenOpts{})] = &aesKeyGenerator{length: conf.aesBitLength} + keyGenerators[reflect.TypeOf(&bccsp.AES256KeyGenOpts{})] = &aesKeyGenerator{length: 32} + keyGenerators[reflect.TypeOf(&bccsp.AES192KeyGenOpts{})] = &aesKeyGenerator{length: 24} + keyGenerators[reflect.TypeOf(&bccsp.AES128KeyGenOpts{})] = &aesKeyGenerator{length: 16} + keyGenerators[reflect.TypeOf(&bccsp.RSAKeyGenOpts{})] = &rsaKeyGenerator{length: conf.rsaBitLength} + keyGenerators[reflect.TypeOf(&bccsp.RSA1024KeyGenOpts{})] = &rsaKeyGenerator{length: 1024} + keyGenerators[reflect.TypeOf(&bccsp.RSA2048KeyGenOpts{})] = &rsaKeyGenerator{length: 2048} + keyGenerators[reflect.TypeOf(&bccsp.RSA3072KeyGenOpts{})] = &rsaKeyGenerator{length: 3072} + keyGenerators[reflect.TypeOf(&bccsp.RSA4096KeyGenOpts{})] = &rsaKeyGenerator{length: 4096} + impl.keyGenerators = keyGenerators + + // Set the key generators + keyDerivers := make(map[reflect.Type]KeyDeriver) + keyDerivers[reflect.TypeOf(&ecdsaPrivateKey{})] = &ecdsaPrivateKeyKeyDeriver{} + keyDerivers[reflect.TypeOf(&ecdsaPublicKey{})] = &ecdsaPublicKeyKeyDeriver{} + keyDerivers[reflect.TypeOf(&aesPrivateKey{})] = &aesPrivateKeyKeyDeriver{bccsp: impl} + impl.keyDerivers = keyDerivers + + // Set the key importers + keyImporters := make(map[reflect.Type]KeyImporter) + keyImporters[reflect.TypeOf(&bccsp.AES256ImportKeyOpts{})] = &aes256ImportKeyOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.HMACImportKeyOpts{})] = &hmacImportKeyOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAPKIXPublicKeyImportOpts{})] = &ecdsaPKIXPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAPrivateKeyImportOpts{})] = &ecdsaPrivateKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{})] = &ecdsaGoPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.RSAGoPublicKeyImportOpts{})] = &rsaGoPublicKeyImportOptsKeyImporter{} + keyImporters[reflect.TypeOf(&bccsp.X509PublicKeyImportOpts{})] = &x509PublicKeyImportOptsKeyImporter{bccsp: impl} + + impl.keyImporters = keyImporters + + return impl, nil +} + +// SoftwareBasedBCCSP is the software-based implementation of the BCCSP. +type impl struct { + conf *config + ks bccsp.KeyStore + + keyGenerators map[reflect.Type]KeyGenerator + keyDerivers map[reflect.Type]KeyDeriver + keyImporters map[reflect.Type]KeyImporter + encryptors map[reflect.Type]Encryptor + decryptors map[reflect.Type]Decryptor + signers map[reflect.Type]Signer + verifiers map[reflect.Type]Verifier + hashers map[reflect.Type]Hasher +} + +// KeyGen generates a key using opts. +func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { + // Validate arguments + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + keyGenerator, found := csp.keyGenerators[reflect.TypeOf(opts)] + if !found { + return nil, errors.Errorf("Unsupported 'KeyGenOpts' provided [%v]", opts) + } + + k, err = keyGenerator.KeyGen(opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed generating key with opts [%v]", opts) + } + + // If the key is not Ephemeral, store it. + if !opts.Ephemeral() { + // Store the key + err = csp.ks.StoreKey(k) + if err != nil { + return nil, errors.Wrapf(err, "Failed storing key [%s]", opts.Algorithm()) + } + } + + return k, nil +} + +// KeyDeriv derives a key from k using opts. +// The opts argument should be appropriate for the primitive used. +func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { + // Validate arguments + if k == nil { + return nil, errors.New("Invalid Key. It must not be nil.") + } + if opts == nil { + return nil, errors.New("Invalid opts. It must not be nil.") + } + + keyDeriver, found := csp.keyDerivers[reflect.TypeOf(k)] + if !found { + return nil, errors.Errorf("Unsupported 'Key' provided [%v]", k) + } + + k, err = keyDeriver.KeyDeriv(k, opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed deriving key with opts [%v]", opts) + } + + // If the key is not Ephemeral, store it. + if !opts.Ephemeral() { + // Store the key + err = csp.ks.StoreKey(k) + if err != nil { + return nil, errors.Wrapf(err, "Failed storing key [%s]", opts.Algorithm()) + } + } + + return k, nil +} + +// KeyImport imports a key from its raw representation using opts. +// The opts argument should be appropriate for the primitive used. +func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + // Validate arguments + if raw == nil { + return nil, errors.New("Invalid raw. It must not be nil.") + } + if opts == nil { + return nil, errors.New("Invalid opts. It must not be nil.") + } + + keyImporter, found := csp.keyImporters[reflect.TypeOf(opts)] + if !found { + return nil, errors.Errorf("Unsupported 'KeyImportOpts' provided [%v]", opts) + } + + k, err = keyImporter.KeyImport(raw, opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed importing key with opts [%v]", opts) + } + + // If the key is not Ephemeral, store it. + if !opts.Ephemeral() { + // Store the key + err = csp.ks.StoreKey(k) + if err != nil { + return nil, errors.Wrapf(err, "Failed storing imported key with opts [%v]", opts) + } + } + + return +} + +// GetKey returns the key this CSP associates to +// the Subject Key Identifier ski. +func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { + k, err = csp.ks.GetKey(ski) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting key for SKI [%v]", ski) + } + + return +} + +// Hash hashes messages msg using options opts. +func (csp *impl) Hash(msg []byte, opts bccsp.HashOpts) (digest []byte, err error) { + // Validate arguments + if opts == nil { + return nil, errors.New("Invalid opts. It must not be nil.") + } + + hasher, found := csp.hashers[reflect.TypeOf(opts)] + if !found { + return nil, errors.Errorf("Unsupported 'HashOpt' provided [%v]", opts) + } + + digest, err = hasher.Hash(msg, opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed hashing with opts [%v]", opts) + } + + return +} + +// 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) { + // Validate arguments + if opts == nil { + return nil, errors.New("Invalid opts. It must not be nil.") + } + + hasher, found := csp.hashers[reflect.TypeOf(opts)] + if !found { + return nil, errors.Errorf("Unsupported 'HashOpt' provided [%v]", opts) + } + + h, err = hasher.GetHash(opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed getting hash function with opts [%v]", opts) + } + + return +} + +// Sign signs digest using key k. +// The opts argument should be appropriate for the primitive used. +// +// 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). +func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + // Validate arguments + if k == nil { + return nil, errors.New("Invalid Key. It must not be nil.") + } + if len(digest) == 0 { + return nil, errors.New("Invalid digest. Cannot be empty.") + } + + signer, found := csp.signers[reflect.TypeOf(k)] + if !found { + return nil, errors.Errorf("Unsupported 'SignKey' provided [%v]", k) + } + + signature, err = signer.Sign(k, digest, opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed signing with opts [%v]", opts) + } + + return +} + +// Verify verifies signature against key k and digest +func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + // Validate arguments + if k == nil { + return false, errors.New("Invalid Key. It must not be nil.") + } + if len(signature) == 0 { + return false, errors.New("Invalid signature. Cannot be empty.") + } + if len(digest) == 0 { + return false, errors.New("Invalid digest. Cannot be empty.") + } + + verifier, found := csp.verifiers[reflect.TypeOf(k)] + if !found { + return false, errors.Errorf("Unsupported 'VerifyKey' provided [%v]", k) + } + + valid, err = verifier.Verify(k, signature, digest, opts) + if err != nil { + return false, errors.Wrapf(err, "Failed verifing with opts [%v]", opts) + } + + return +} + +// 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.") + } + + encryptor, found := csp.encryptors[reflect.TypeOf(k)] + if !found { + return nil, errors.Errorf("Unsupported 'EncryptKey' provided [%v]", k) + } + + return encryptor.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.") + } + + decryptor, found := csp.decryptors[reflect.TypeOf(k)] + if !found { + return nil, errors.Errorf("Unsupported 'DecryptKey' provided [%v]", k) + } + + plaintext, err = decryptor.Decrypt(k, ciphertext, opts) + if err != nil { + return nil, errors.Wrapf(err, "Failed decrypting with opts [%v]", opts) + } + + return +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/internals.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/internals.go new file mode 100644 index 0000000000..323797c6ee --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/internals.go @@ -0,0 +1,94 @@ +/* +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 sw + +import ( + "hash" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +// KeyGenerator is a BCCSP-like interface that provides key generation algorithms +type KeyGenerator interface { + + // KeyGen generates a key using opts. + KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) +} + +// KeyDeriver is a BCCSP-like interface that provides key derivation algorithms +type KeyDeriver interface { + + // KeyDeriv derives a key from k using opts. + // The opts argument should be appropriate for the primitive used. + KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) +} + +// KeyImporter is a BCCSP-like interface that provides key import algorithms +type KeyImporter interface { + + // KeyImport imports a key from its raw representation using opts. + // The opts argument should be appropriate for the primitive used. + KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) +} + +// Encryptor is a BCCSP-like interface that provides encryption algorithms +type Encryptor interface { + + // Encrypt encrypts plaintext using key k. + // The opts argument should be appropriate for the algorithm used. + Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) +} + +// Decryptor is a BCCSP-like interface that provides decryption algorithms +type Decryptor interface { + + // Decrypt decrypts ciphertext using key k. + // The opts argument should be appropriate for the algorithm used. + Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) +} + +// Signer is a BCCSP-like interface that provides signing algorithms +type Signer interface { + + // Sign signs digest using key k. + // The opts argument should be appropriate for the algorithm used. + // + // 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). + Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) +} + +// Verifier is a BCCSP-like interface that provides verifying algorithms +type Verifier interface { + + // Verify verifies signature against key k and digest + // The opts argument should be appropriate for the algorithm used. + Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) +} + +// Hasher is a BCCSP-like interface that provides hash algorithms +type Hasher interface { + + // Hash hashes messages msg using options opts. + // If opts is nil, the default hash function will be used. + Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) + + // GetHash returns and instance of hash.Hash using options opts. + // If opts is nil, the default hash function will be returned. + GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/keyderiv.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/keyderiv.go new file mode 100644 index 0000000000..9ea8046195 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/keyderiv.go @@ -0,0 +1,157 @@ +/* +Copyright IBM Corp. 2017 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 sw + +import ( + "crypto/ecdsa" + "fmt" + + "errors" + "math/big" + + "crypto/hmac" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ecdsaPublicKeyKeyDeriver struct{} + +func (kd *ecdsaPublicKeyKeyDeriver) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { + // Validate opts + if opts == nil { + return nil, errors.New("Invalid opts parameter. It must not be nil.") + } + + ecdsaK := k.(*ecdsaPublicKey) + + switch opts.(type) { + // Re-randomized an ECDSA private key + case *bccsp.ECDSAReRandKeyOpts: + reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + tempSK := &ecdsa.PublicKey{ + Curve: ecdsaK.pubKey.Curve, + X: new(big.Int), + Y: new(big.Int), + } + + var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) + var one = new(big.Int).SetInt64(1) + n := new(big.Int).Sub(ecdsaK.pubKey.Params().N, one) + k.Mod(k, n) + k.Add(k, one) + + // Compute temporary public key + tempX, tempY := ecdsaK.pubKey.ScalarBaseMult(k.Bytes()) + tempSK.X, tempSK.Y = tempSK.Add( + ecdsaK.pubKey.X, ecdsaK.pubKey.Y, + tempX, tempY, + ) + + // Verify temporary public key is a valid point on the reference curve + isOn := tempSK.Curve.IsOnCurve(tempSK.X, tempSK.Y) + if !isOn { + return nil, errors.New("Failed temporary public key IsOnCurve check.") + } + + return &ecdsaPublicKey{tempSK}, nil + default: + return nil, fmt.Errorf("Unsupported 'KeyDerivOpts' provided [%v]", opts) + } +} + +type ecdsaPrivateKeyKeyDeriver struct{} + +func (kd *ecdsaPrivateKeyKeyDeriver) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { + // Validate opts + if opts == nil { + return nil, errors.New("Invalid opts parameter. It must not be nil.") + } + + ecdsaK := k.(*ecdsaPrivateKey) + + switch opts.(type) { + // Re-randomized an ECDSA private key + case *bccsp.ECDSAReRandKeyOpts: + reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + tempSK := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: ecdsaK.privKey.Curve, + X: new(big.Int), + Y: new(big.Int), + }, + D: new(big.Int), + } + + var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) + var one = new(big.Int).SetInt64(1) + n := new(big.Int).Sub(ecdsaK.privKey.Params().N, one) + k.Mod(k, n) + k.Add(k, one) + + tempSK.D.Add(ecdsaK.privKey.D, k) + tempSK.D.Mod(tempSK.D, ecdsaK.privKey.PublicKey.Params().N) + + // Compute temporary public key + tempX, tempY := ecdsaK.privKey.PublicKey.ScalarBaseMult(k.Bytes()) + tempSK.PublicKey.X, tempSK.PublicKey.Y = + tempSK.PublicKey.Add( + ecdsaK.privKey.PublicKey.X, ecdsaK.privKey.PublicKey.Y, + tempX, tempY, + ) + + // Verify temporary public key is a valid point on the reference curve + isOn := tempSK.Curve.IsOnCurve(tempSK.PublicKey.X, tempSK.PublicKey.Y) + if !isOn { + return nil, errors.New("Failed temporary public key IsOnCurve check.") + } + + return &ecdsaPrivateKey{tempSK}, nil + default: + return nil, fmt.Errorf("Unsupported 'KeyDerivOpts' provided [%v]", opts) + } +} + +type aesPrivateKeyKeyDeriver struct { + bccsp *impl +} + +func (kd *aesPrivateKeyKeyDeriver) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { + // 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(kd.bccsp.conf.hashFunction, aesK.privKey) + mac.Write(hmacOpts.Argument()) + return &aesPrivateKey{mac.Sum(nil)[:kd.bccsp.conf.aesBitLength], false}, nil + + case *bccsp.HMACDeriveKeyOpts: + hmacOpts := opts.(*bccsp.HMACDeriveKeyOpts) + + mac := hmac.New(kd.bccsp.conf.hashFunction, aesK.privKey) + mac.Write(hmacOpts.Argument()) + return &aesPrivateKey{mac.Sum(nil), true}, nil + default: + return nil, fmt.Errorf("Unsupported 'KeyDerivOpts' provided [%v]", opts) + } +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/keygen.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/keygen.go new file mode 100644 index 0000000000..dd1540d797 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/keygen.go @@ -0,0 +1,67 @@ +/* +Copyright IBM Corp. 2017 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 sw + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "fmt" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type ecdsaKeyGenerator struct { + curve elliptic.Curve +} + +func (kg *ecdsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { + privKey, err := ecdsa.GenerateKey(kg.curve, rand.Reader) + if err != nil { + return nil, fmt.Errorf("Failed generating ECDSA key for [%v]: [%s]", kg.curve, err) + } + + return &ecdsaPrivateKey{privKey}, nil +} + +type aesKeyGenerator struct { + length int +} + +func (kg *aesKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { + lowLevelKey, err := GetRandomBytes(int(kg.length)) + if err != nil { + return nil, fmt.Errorf("Failed generating AES %d key [%s]", kg.length, err) + } + + return &aesPrivateKey{lowLevelKey, false}, nil +} + +type rsaKeyGenerator struct { + length int +} + +func (kg *rsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { + lowLevelKey, err := rsa.GenerateKey(rand.Reader, int(kg.length)) + + if err != nil { + return nil, fmt.Errorf("Failed generating RSA %d key [%s]", kg.length, err) + } + + return &rsaPrivateKey{lowLevelKey}, nil +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/keyimport.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/keyimport.go new file mode 100644 index 0000000000..63261a80c2 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/keyimport.go @@ -0,0 +1,162 @@ +/* +Copyright IBM Corp. 2017 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 sw + +import ( + "errors" + "fmt" + + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "reflect" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp/utils" +) + +type aes256ImportKeyOptsKeyImporter struct{} + +func (*aes256ImportKeyOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + aesRaw, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if aesRaw == nil { + return nil, errors.New("Invalid raw material. It must not be nil.") + } + + if len(aesRaw) != 32 { + return nil, fmt.Errorf("Invalid Key Length [%d]. Must be 32 bytes", len(aesRaw)) + } + + return &aesPrivateKey{utils.Clone(aesRaw), false}, nil +} + +type hmacImportKeyOptsKeyImporter struct{} + +func (*hmacImportKeyOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + aesRaw, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if len(aesRaw) == 0 { + return nil, errors.New("Invalid raw material. It must not be nil.") + } + + return &aesPrivateKey{utils.Clone(aesRaw), false}, nil +} + +type ecdsaPKIXPublicKeyImportOptsKeyImporter struct{} + +func (*ecdsaPKIXPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPublicKey(der) + if err != nil { + return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) + } + + ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") + } + + return &ecdsaPublicKey{ecdsaPK}, nil +} + +type ecdsaPrivateKeyImportOptsKeyImporter struct{} + +func (*ecdsaPrivateKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + der, ok := raw.([]byte) + if !ok { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") + } + + if len(der) == 0 { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.") + } + + lowLevelKey, err := utils.DERToPrivateKey(der) + if err != nil { + return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) + } + + ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("Failed casting to ECDSA private key. Invalid raw material.") + } + + return &ecdsaPrivateKey{ecdsaSK}, nil +} + +type ecdsaGoPublicKeyImportOptsKeyImporter struct{} + +func (*ecdsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + lowLevelKey, ok := raw.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("Invalid raw material. Expected *ecdsa.PublicKey.") + } + + return &ecdsaPublicKey{lowLevelKey}, nil +} + +type rsaGoPublicKeyImportOptsKeyImporter struct{} + +func (*rsaGoPublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + lowLevelKey, ok := raw.(*rsa.PublicKey) + if !ok { + return nil, errors.New("Invalid raw material. Expected *rsa.PublicKey.") + } + + return &rsaPublicKey{lowLevelKey}, nil +} + +type x509PublicKeyImportOptsKeyImporter struct { + bccsp *impl +} + +func (ki *x509PublicKeyImportOptsKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { + x509Cert, ok := raw.(*x509.Certificate) + if !ok { + return nil, errors.New("Invalid raw material. Expected *x509.Certificate.") + } + + pk := x509Cert.PublicKey + + switch pk.(type) { + case *ecdsa.PublicKey: + return ki.bccsp.keyImporters[reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{})].KeyImport( + pk, + &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + case *rsa.PublicKey: + return ki.bccsp.keyImporters[reflect.TypeOf(&bccsp.RSAGoPublicKeyImportOpts{})].KeyImport( + pk, + &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) + default: + return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") + } +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/rsa.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/rsa.go new file mode 100644 index 0000000000..2b9839b054 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/rsa.go @@ -0,0 +1,72 @@ +/* +Copyright IBM Corp. 2017 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 sw + +import ( + "crypto/rand" + "crypto/rsa" + "errors" + "fmt" + + "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/bccsp" +) + +type rsaSigner struct{} + +func (s *rsaSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + if opts == nil { + return nil, errors.New("Invalid options. Must be different from nil.") + } + + return k.(*rsaPrivateKey).privKey.Sign(rand.Reader, digest, opts) +} + +type rsaPrivateKeyVerifier struct{} + +func (v *rsaPrivateKeyVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + 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) + } +} + +type rsaPublicKeyKeyVerifier struct{} + +func (v *rsaPublicKeyKeyVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { + 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) + } +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/sw/rsakey.go b/third_party/github.com/hyperledger/fabric/bccsp/sw/rsakey.go new file mode 100644 index 0000000000..759a5764bd --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/sw/rsakey.go @@ -0,0 +1,136 @@ +/* +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 sw + +import ( + "crypto/rsa" + "crypto/x509" + "fmt" + + "crypto/sha256" + + "errors" + + "encoding/asn1" + "math/big" + + "github.com/hyperledger/fabric-sdk-go/third_party/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 +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/utils/errs.go b/third_party/github.com/hyperledger/fabric/bccsp/utils/errs.go new file mode 100644 index 0000000000..3164d8759f --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/utils/errs.go @@ -0,0 +1,26 @@ +/* +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 utils + +// ErrToString converts and error to a string. If the error is nil, it returns the string "" +func ErrToString(err error) string { + if err != nil { + return err.Error() + } + + return "" +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/utils/io.go b/third_party/github.com/hyperledger/fabric/bccsp/utils/io.go new file mode 100644 index 0000000000..90a065a20a --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/utils/io.go @@ -0,0 +1,69 @@ +/* +Copyright IBM Corp. 2017 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 utils + +import ( + "io" + "os" +) + +// DirMissingOrEmpty checks is a directory is missing or empty +func DirMissingOrEmpty(path string) (bool, error) { + dirExists, err := DirExists(path) + if err != nil { + return false, err + } + if !dirExists { + return true, nil + } + + dirEmpty, err := DirEmpty(path) + if err != nil { + return false, err + } + if dirEmpty { + return true, nil + } + return false, nil +} + +// DirExists checks if a directory exists +func DirExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +// DirEmpty checks if a directory is empty +func DirEmpty(path string) (bool, error) { + f, err := os.Open(path) + if err != nil { + return false, err + } + defer f.Close() + + _, err = f.Readdir(1) + if err == io.EOF { + return true, nil + } + return false, err +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/utils/keys.go b/third_party/github.com/hyperledger/fabric/bccsp/utils/keys.go new file mode 100644 index 0000000000..ee2d928135 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/utils/keys.go @@ -0,0 +1,459 @@ +/* +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 utils + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" +) + +// struct to hold info required for PKCS#8 +type pkcs8Info struct { + Version int + PrivateKeyAlgorithm []asn1.ObjectIdentifier + PrivateKey []byte +} + +type ecPrivateKey struct { + Version int + PrivateKey []byte + NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` + PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` +} + +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +var oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + return nil, false +} + +// PrivateKeyToDER marshals a private key to der +func PrivateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) { + if privateKey == nil { + return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") + } + + return x509.MarshalECPrivateKey(privateKey) +} + +// PrivateKeyToPEM converts the private key to PEM format. +// EC private keys are converted to PKCS#8 format. +// RSA private keys are converted to PKCS#1 format. +func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { + // Validate inputs + if len(pwd) != 0 { + return PrivateKeyToEncryptedPEM(privateKey, pwd) + } + if privateKey == nil { + return nil, errors.New("Invalid key. It must be different from nil.") + } + + switch k := privateKey.(type) { + case *ecdsa.PrivateKey: + if k == nil { + return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") + } + + // get the oid for the curve + oidNamedCurve, ok := oidFromNamedCurve(k.Curve) + if !ok { + return nil, errors.New("unknown elliptic curve") + } + + // based on https://golang.org/src/crypto/x509/sec1.go + privateKeyBytes := k.D.Bytes() + paddedPrivateKey := make([]byte, (k.Curve.Params().N.BitLen()+7)/8) + copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) + // omit NamedCurveOID for compatibility as it's optional + asn1Bytes, err := asn1.Marshal(ecPrivateKey{ + Version: 1, + PrivateKey: paddedPrivateKey, + PublicKey: asn1.BitString{Bytes: elliptic.Marshal(k.Curve, k.X, k.Y)}, + }) + + if err != nil { + return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) + } + + var pkcs8Key pkcs8Info + pkcs8Key.Version = 0 + pkcs8Key.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2) + pkcs8Key.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA + pkcs8Key.PrivateKeyAlgorithm[1] = oidNamedCurve + pkcs8Key.PrivateKey = asn1Bytes + + pkcs8Bytes, err := asn1.Marshal(pkcs8Key) + if err != nil { + return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) + } + return pem.EncodeToMemory( + &pem.Block{ + Type: "PRIVATE KEY", + Bytes: pkcs8Bytes, + }, + ), nil + case *rsa.PrivateKey: + if k == nil { + return nil, errors.New("Invalid rsa private key. It must be different from nil.") + } + raw := x509.MarshalPKCS1PrivateKey(k) + + return pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: raw, + }, + ), nil + default: + return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey or *rsa.PrivateKey") + } +} + +// PrivateKeyToEncryptedPEM converts a private key to an encrypted PEM +func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) { + if privateKey == nil { + return nil, errors.New("Invalid private key. It must be different from nil.") + } + + switch k := privateKey.(type) { + case *ecdsa.PrivateKey: + if k == nil { + return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") + } + raw, err := x509.MarshalECPrivateKey(k) + + if err != nil { + return nil, err + } + + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PRIVATE KEY", + raw, + pwd, + x509.PEMCipherAES256) + + if err != nil { + return nil, err + } + + return pem.EncodeToMemory(block), nil + + default: + return nil, errors.New("Invalid key type. It must be *ecdsa.PrivateKey") + } +} + +// DERToPrivateKey unmarshals a der to private key +func DERToPrivateKey(der []byte) (key interface{}, err error) { + + if key, err = x509.ParsePKCS1PrivateKey(der); err == nil { + return key, nil + } + + if key, err = x509.ParsePKCS8PrivateKey(der); err == nil { + switch key.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey: + return + default: + return nil, errors.New("Found unknown private key type in PKCS#8 wrapping") + } + } + + if key, err = x509.ParseECPrivateKey(der); err == nil { + return + } + + return nil, errors.New("Invalid key type. The DER must contain an rsa.PrivateKey or ecdsa.PrivateKey") +} + +// PEMtoPrivateKey unmarshals a pem to private key +func PEMtoPrivateKey(raw []byte, pwd []byte) (interface{}, error) { + if len(raw) == 0 { + return nil, errors.New("Invalid PEM. It must be different from nil.") + } + block, _ := pem.Decode(raw) + if block == nil { + return nil, fmt.Errorf("Failed decoding PEM. Block must be different from nil. [% x]", raw) + } + + // TODO: derive from header the type of the key + + if x509.IsEncryptedPEMBlock(block) { + if len(pwd) == 0 { + return nil, errors.New("Encrypted Key. Need a password") + } + + decrypted, err := x509.DecryptPEMBlock(block, pwd) + if err != nil { + return nil, fmt.Errorf("Failed PEM decryption [%s]", err) + } + + key, err := DERToPrivateKey(decrypted) + if err != nil { + return nil, err + } + return key, err + } + + cert, err := DERToPrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return cert, err +} + +// PEMtoAES extracts from the PEM an AES key +func PEMtoAES(raw []byte, pwd []byte) ([]byte, error) { + if len(raw) == 0 { + return nil, errors.New("Invalid PEM. It must be different from nil.") + } + block, _ := pem.Decode(raw) + if block == nil { + return nil, fmt.Errorf("Failed decoding PEM. Block must be different from nil. [% x]", raw) + } + + if x509.IsEncryptedPEMBlock(block) { + if len(pwd) == 0 { + return nil, errors.New("Encrypted Key. Password must be different fom nil") + } + + decrypted, err := x509.DecryptPEMBlock(block, pwd) + if err != nil { + return nil, fmt.Errorf("Failed PEM decryption. [%s]", err) + } + return decrypted, nil + } + + return block.Bytes, nil +} + +// AEStoPEM encapsulates an AES key in the PEM format +func AEStoPEM(raw []byte) []byte { + return pem.EncodeToMemory(&pem.Block{Type: "AES PRIVATE KEY", Bytes: raw}) +} + +// AEStoEncryptedPEM encapsulates an AES key in the encrypted PEM format +func AEStoEncryptedPEM(raw []byte, pwd []byte) ([]byte, error) { + if len(raw) == 0 { + return nil, errors.New("Invalid aes key. It must be different from nil") + } + if len(pwd) == 0 { + return AEStoPEM(raw), nil + } + + block, err := x509.EncryptPEMBlock( + rand.Reader, + "AES PRIVATE KEY", + raw, + pwd, + x509.PEMCipherAES256) + + if err != nil { + return nil, err + } + + return pem.EncodeToMemory(block), nil +} + +// PublicKeyToPEM marshals a public key to the pem format +func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { + if len(pwd) != 0 { + return PublicKeyToEncryptedPEM(publicKey, pwd) + } + + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + + switch k := publicKey.(type) { + case *ecdsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") + } + PubASN1, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + return pem.EncodeToMemory( + &pem.Block{ + Type: "PUBLIC KEY", + Bytes: PubASN1, + }, + ), nil + case *rsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid rsa public key. It must be different from nil.") + } + PubASN1, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + return pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: PubASN1, + }, + ), nil + + default: + return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") + } +} + +// PublicKeyToDER marshals a public key to the der format +func PublicKeyToDER(publicKey interface{}) ([]byte, error) { + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + + switch k := publicKey.(type) { + case *ecdsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") + } + PubASN1, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + return PubASN1, nil + + case *rsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid rsa public key. It must be different from nil.") + } + PubASN1, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + return PubASN1, nil + + default: + return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey or *rsa.PublicKey") + } +} + +// PublicKeyToEncryptedPEM converts a public key to encrypted pem +func PublicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) { + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + if len(pwd) == 0 { + return nil, errors.New("Invalid password. It must be different from nil.") + } + + switch k := publicKey.(type) { + case *ecdsa.PublicKey: + if k == nil { + return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") + } + raw, err := x509.MarshalPKIXPublicKey(k) + if err != nil { + return nil, err + } + + block, err := x509.EncryptPEMBlock( + rand.Reader, + "PUBLIC KEY", + raw, + pwd, + x509.PEMCipherAES256) + + if err != nil { + return nil, err + } + + return pem.EncodeToMemory(block), nil + + default: + return nil, errors.New("Invalid key type. It must be *ecdsa.PublicKey") + } +} + +// PEMtoPublicKey unmarshals a pem to public key +func PEMtoPublicKey(raw []byte, pwd []byte) (interface{}, error) { + if len(raw) == 0 { + return nil, errors.New("Invalid PEM. It must be different from nil.") + } + block, _ := pem.Decode(raw) + if block == nil { + return nil, fmt.Errorf("Failed decoding. Block must be different from nil. [% x]", raw) + } + + // TODO: derive from header the type of the key + if x509.IsEncryptedPEMBlock(block) { + if len(pwd) == 0 { + return nil, errors.New("Encrypted Key. Password must be different from nil") + } + + decrypted, err := x509.DecryptPEMBlock(block, pwd) + if err != nil { + return nil, fmt.Errorf("Failed PEM decryption. [%s]", err) + } + + key, err := DERToPublicKey(decrypted) + if err != nil { + return nil, err + } + return key, err + } + + cert, err := DERToPublicKey(block.Bytes) + if err != nil { + return nil, err + } + return cert, err +} + +// DERToPublicKey unmarshals a der to public key +func DERToPublicKey(raw []byte) (pub interface{}, err error) { + if len(raw) == 0 { + return nil, errors.New("Invalid DER. It must be different from nil.") + } + + key, err := x509.ParsePKIXPublicKey(raw) + + return key, err +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/utils/slice.go b/third_party/github.com/hyperledger/fabric/bccsp/utils/slice.go new file mode 100644 index 0000000000..59e5374c38 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/utils/slice.go @@ -0,0 +1,25 @@ +/* +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 utils + +// Clone clones the passed slice +func Clone(src []byte) []byte { + clone := make([]byte, len(src)) + copy(clone, src) + + return clone +} diff --git a/third_party/github.com/hyperledger/fabric/bccsp/utils/x509.go b/third_party/github.com/hyperledger/fabric/bccsp/utils/x509.go new file mode 100644 index 0000000000..43b51ce867 --- /dev/null +++ b/third_party/github.com/hyperledger/fabric/bccsp/utils/x509.go @@ -0,0 +1,26 @@ +/* +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 utils + +import ( + "crypto/x509" +) + +// DERToX509Certificate converts der to x509 +func DERToX509Certificate(asn1Data []byte) (*x509.Certificate, error) { + return x509.ParseCertificate(asn1Data) +}