Skip to content

Commit

Permalink
[FAB-8212] Fixed GetSigningIdentity()
Browse files Browse the repository at this point in the history
Change-Id: I6e99f86962ad74fad34e1f6b707af98bd9d848b9
Signed-off-by: Aleksandar Likic <aleksandar.likic@securekey.com>
  • Loading branch information
Aleksandar Likic committed Feb 12, 2018
1 parent ac89b89 commit 34108c5
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 59 deletions.
57 changes: 29 additions & 28 deletions pkg/fabric-client/credentialmgr/credentialmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package credentialmgr
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

Expand Down Expand Up @@ -101,8 +102,7 @@ func (mgr *CredentialManager) GetSigningIdentity(userName string) (*apifabclient
}

if certBytes == nil {
certBytes, err = mgr.getStoredCertBytes(userName)

certBytes, err = mgr.getCertBytesFromCertStore(userName)
if err != nil {
return nil, errors.WithMessage(err, "fetching cert from store failed")
}
Expand All @@ -119,7 +119,7 @@ func (mgr *CredentialManager) GetSigningIdentity(userName string) (*apifabclient
}

if privateKey == nil {
privateKey, err = mgr.getPivateKeyFromCert(userName, certBytes)
privateKey, err = mgr.getPrivateKeyFromCert(userName, certBytes)
if err != nil {
return nil, errors.Wrapf(err, "getting private key from cert failed")
}
Expand Down Expand Up @@ -172,9 +172,18 @@ func (mgr *CredentialManager) getEmbeddedPrivateKey(userName string) (apicryptos
pemBytes = []byte(keyPem)
} else if keyPath != "" {
// Try importing from the Embedded Path
pemBytes, err = ioutil.ReadFile(keyPath)
_, err := os.Stat(keyPath)
if err != nil {
return nil, errors.Wrapf(err, "reading private key from embedded path failed")
if !os.IsNotExist(err) {
return nil, errors.Wrapf(err, "OS stat embedded path failed")
}
// file doesn't exist, continue
} else {
// file exists, try to read it
pemBytes, err = ioutil.ReadFile(keyPath)
if err != nil {
return nil, errors.Wrapf(err, "reading private key from embedded path failed")
}
}
}

Expand All @@ -193,7 +202,7 @@ func (mgr *CredentialManager) getEmbeddedPrivateKey(userName string) (apicryptos
return privateKey, nil
}

func (mgr *CredentialManager) getStoredPrivateKeyPem(userName string, ski []byte) ([]byte, error) {
func (mgr *CredentialManager) getPrivateKeyPemFromKeyStore(userName string, ski []byte) ([]byte, error) {
if mgr.privKeyStore == nil {
return nil, nil
}
Expand All @@ -204,9 +213,6 @@ func (mgr *CredentialManager) getStoredPrivateKeyPem(userName string, ski []byte
SKI: ski,
})
if err != nil {
if err == kvstore.ErrNotFound {
return nil, nil
}
return nil, err
}
keyBytes, ok := key.([]byte)
Expand All @@ -216,7 +222,7 @@ func (mgr *CredentialManager) getStoredPrivateKeyPem(userName string, ski []byte
return keyBytes, nil
}

func (mgr *CredentialManager) getStoredCertBytes(userName string) ([]byte, error) {
func (mgr *CredentialManager) getCertBytesFromCertStore(userName string) ([]byte, error) {
if mgr.certStore == nil {
return nil, nil
}
Expand All @@ -237,36 +243,31 @@ func (mgr *CredentialManager) getStoredCertBytes(userName string) ([]byte, error
return certBytes, nil
}

func (mgr *CredentialManager) getPivateKeyFromCert(userName string, cert []byte) (apicryptosuite.Key, error) {
func (mgr *CredentialManager) getPrivateKeyFromCert(userName string, cert []byte) (apicryptosuite.Key, error) {
if cert == nil {
return nil, errors.New("cert is nil")
}
pubKey, err := cryptoutil.GetPublicKeyFromCert(cert, mgr.cryptoProvider)
if err != nil {
return nil, errors.WithMessage(err, "fetching public key from cert failed")
}
secProvider := mgr.config.SecurityProvider()
if secProvider == "SW" {
return mgr.getPivateKeyForSKIFromStore(userName, pubKey.SKI())
privKey, err := mgr.getPrivateKeyFromKeyStore(userName, pubKey.SKI())
if err == nil {
return privKey, nil
}
return mgr.getPivateKeyForSKIFromHSM(pubKey.SKI())
if err != kvstore.ErrNotFound {
return nil, errors.WithMessage(err, "fetching private key from key store failed")
}
return mgr.cryptoProvider.GetKey(pubKey.SKI())
}

func (mgr *CredentialManager) getPivateKeyForSKIFromStore(userName string, ski []byte) (apicryptosuite.Key, error) {
pemBytes, err := mgr.getStoredPrivateKeyPem(userName, ski)
func (mgr *CredentialManager) getPrivateKeyFromKeyStore(userName string, ski []byte) (apicryptosuite.Key, error) {
pemBytes, err := mgr.getPrivateKeyPemFromKeyStore(userName, ski)
if err != nil {
return nil, err
}
if pemBytes == nil {
return nil, fmt.Errorf("private key not found in key store for user [%s]", userName)
}
privateKey, err := fabricCaUtil.ImportBCCSPKeyFromPEMBytes(pemBytes, mgr.cryptoProvider, true)
if err != nil {
return nil, errors.Wrapf(err, "import private key failed %v", pemBytes)
if pemBytes != nil {
return fabricCaUtil.ImportBCCSPKeyFromPEMBytes(pemBytes, mgr.cryptoProvider, true)
}
return privateKey, nil
}

func (mgr *CredentialManager) getPivateKeyForSKIFromHSM(ski []byte) (apicryptosuite.Key, error) {
return mgr.cryptoProvider.GetKey(ski)
return nil, kvstore.ErrNotFound
}
37 changes: 11 additions & 26 deletions pkg/fabric-client/credentialmgr/credentialmgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,17 @@ func TestCredentialManager(t *testing.T) {
t.Fatalf("Should have failed to retrieve signing identity for non-existent user")
}

id, err := credentialMgr.GetSigningIdentity("User1")
if err != nil {
t.Fatalf("Failed to retrieve signing identity: %s", err)
}
if err := checkSigningIdentity(id); err != nil {
if err := checkSigningIdentity(credentialMgr, "User1"); err != nil {
t.Fatalf("checkSigningIdentity failes: %s", err)
}
}

func checkSigningIdentity(id *apifabclient.SigningIdentity) error {
func checkSigningIdentity(credentialMgr apifabclient.CredentialManager, user string) error {
id, err := credentialMgr.GetSigningIdentity(user)
if err != nil {
return errors.Wrapf(err, "Failed to retrieve signing identity: %s", err)
}

if id == nil {
return errors.New("SigningIdentity is nil")
}
Expand Down Expand Up @@ -100,35 +101,19 @@ func TestCredentialManagerFromEmbeddedCryptoConfig(t *testing.T) {
t.Fatalf("Should have failed to retrieve signing identity for non-existent user")
}

id, err := credentialMgr.GetSigningIdentity("EmbeddedUser")
if err != nil {
t.Fatalf("Failed to retrieve signing identity: %+v", err)
}
if err := checkSigningIdentity(id); err != nil {
if err := checkSigningIdentity(credentialMgr, "EmbeddedUser"); err != nil {
t.Fatalf("checkSigningIdentity failes: %s", err)
}

id, err = credentialMgr.GetSigningIdentity("EmbeddedUserWithPaths")
if err != nil {
t.Fatalf("Failed to retrieve signing identity: %+v", err)
}
if err := checkSigningIdentity(id); err != nil {
if err := checkSigningIdentity(credentialMgr, "EmbeddedUserWithPaths"); err != nil {
t.Fatalf("checkSigningIdentity failes: %s", err)
}

id, err = credentialMgr.GetSigningIdentity("EmbeddedUserMixed")
if err != nil {
t.Fatalf("Failed to retrieve signing identity: %+v", err)
}
if err := checkSigningIdentity(id); err != nil {
if err := checkSigningIdentity(credentialMgr, "EmbeddedUserMixed"); err != nil {
t.Fatalf("checkSigningIdentity failes: %s", err)
}

id, err = credentialMgr.GetSigningIdentity("EmbeddedUserMixed2")
if err != nil {
t.Fatalf("Failed to retrieve signing identity: %+v", err)
}
if err := checkSigningIdentity(id); err != nil {
if err := checkSigningIdentity(credentialMgr, "EmbeddedUserMixed2"); err != nil {
t.Fatalf("checkSigningIdentity failes: %s", err)
}
}
183 changes: 183 additions & 0 deletions pkg/fabric-client/credentialmgr/enrollment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package credentialmgr

import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"

"github.com/golang/mock/gomock"
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
"github.com/hyperledger/fabric-sdk-go/api/apicryptosuite"
camocks "github.com/hyperledger/fabric-sdk-go/api/apifabca/mocks"
"github.com/hyperledger/fabric-sdk-go/api/kvstore"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric-ca/util"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/credentialmgr/persistence"
"github.com/pkg/errors"

"github.com/hyperledger/fabric-sdk-go/pkg/config"
"github.com/hyperledger/fabric-sdk-go/pkg/cryptosuite/bccsp/sw"
)

func TestCredentialManagerWithEnrollment(t *testing.T) {
config, err := config.FromFile("../../../test/fixtures/config/config_test.yaml")()
if err != nil {
t.Fatalf(err.Error())
}
netConfig, err := config.NetworkConfig()
if err != nil {
t.Fatalf("NetworkConfig failed: %s", err)
}
orgName := "Org1"
orgConfig, ok := netConfig.Organizations[strings.ToLower(orgName)]
if !ok {
t.Fatalf("org config not found: %s", orgName)
}

cs, err := sw.GetSuiteByConfig(config)

credentialMgr, err := NewCredentialManager(orgName, config, cs)
if err != nil {
t.Fatalf("Failed to setup credential manager: %s", err)
}

if err := checkSigningIdentity(credentialMgr, "User1"); err != nil {
t.Fatalf("checkSigningIdentity failed: %s", err)
}

userToEnroll := "enrollmentID"
certLookupKey := &persistence.CertKey{
MspID: orgConfig.MspID,
UserName: userToEnroll,
}

// Refers to the same location used by the CredentialManager for looking up certs
certStore, err := getCertStore(config, orgName)
if err != nil {
t.Fatalf("NewFileCertStore failed: %v", err)
}

// // Delete all private keys from the crypto suite store
keyStorePath := config.KeyStorePath()
err = cleanup(keyStorePath)
if err != nil {
t.Fatalf("cleanup keyStorePath failed: %v", err)
}

// Delete userToEnroll from cert store in case it's there
err = certStore.Delete(certLookupKey)
if err != nil {
t.Fatalf("certStore.Delete failed: %v", err)
}

if err := checkSigningIdentity(credentialMgr, userToEnroll); err == nil {
t.Fatalf("checkSigningIdentity should fail for user who hasn't been enrolled")
}

ctrl := gomock.NewController(t)
defer ctrl.Finish()
caClient := camocks.NewMockFabricCAClient(ctrl)
prepareForEnroll(t, caClient, cs)

_, certBytes, err := caClient.Enroll(userToEnroll, "enrollmentSecret")
if err != nil {
t.Fatalf("fabricCAClient Enroll failed: %v", err)
}
if certBytes == nil || len(certBytes) == 0 {
t.Fatalf("Got an empty cert from Enrill()")
}

err = certStore.Store(certLookupKey, certBytes)
if err != nil {
t.Fatalf("certStore.Store: %v", err)
}

if err := checkSigningIdentity(credentialMgr, userToEnroll); err != nil {
t.Fatalf("checkSigningIdentity shouldn't fail for user who hasn been just enrolled: %s", err)
}
}

// Simulate caClient.Enroll()
func prepareForEnroll(t *testing.T, mc *camocks.MockFabricCAClient, cs apicryptosuite.CryptoSuite) {
// A real caClient.Enroll() generates a CSR. In the process, a crypto suite generates
// a new key pair, and the private key is stored into crypto suite private key storage.

// "Generated" private key
keyBytes := []byte(`-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5Ahcehypz6IpAYy6
DtIf5zZsRjP4PtsmDhLbBJsXmD6hRANCAAR+YRAn8dFpDQDyvDA7JKPl5PoZenj3
m1KOnMry/mOZcnXnTIh2ASV4ss8VluzBcyHGAv7BCmxXxDkjcV9eybv8
-----END PRIVATE KEY-----`)

// "Generated" cert, the "result" of a CA CSR processing
certBytes := []byte(`-----BEGIN CERTIFICATE-----
MIICGjCCAcCgAwIBAgIRAIQkbh9nsGnLmDalAVlj8sUwCgYIKoZIzj0EAwIwczEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh
Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNzI4MTQyNzIwWhcNMjcwNzI2MTQyNzIw
WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWQWRtaW5Ab3JnMS5leGFtcGxlLmNvbTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABH5hECfx0WkNAPK8MDsko+Xk+hl6ePeb
Uo6cyvL+Y5lydedMiHYBJXiyzxWW7MFzIcYC/sEKbFfEOSNxX17Ju/yjTTBLMA4G
A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIIeR0TY+iVFf
mvoEKwaToscEu43ZXSj5fTVJornjxDUtMAoGCCqGSM49BAMCA0gAMEUCIQDVf8cL
NrfToiPzJpEFPGF+/8CpzOkl91oz+XJsvdgf5wIgI/e8mpvpplUQbU52+LejA36D
CsbWERvZPjR/GFEDEvc=
-----END CERTIFICATE-----`)

var privateKey apicryptosuite.Key
var err error

mc.EXPECT().Enroll(gomock.Any(), gomock.Any()).Do(func(enrollmentID string, enrollmentSecret string) {
// Import the key into the crypto suite's private key storage.
// This is normally done by a crypto suite when a new key is generated
privateKey, err = util.ImportBCCSPKeyFromPEMBytes(keyBytes, cs, false)
}).Return(privateKey, certBytes, err)
}

func getCertStore(config apiconfig.Config, orgName string) (kvstore.KVStore, error) {
netConfig, err := config.NetworkConfig()
if err != nil {
return nil, err
}
orgConfig, ok := netConfig.Organizations[strings.ToLower(orgName)]
if !ok {
return nil, errors.New("org config retrieval failed")
}
orgCryptoPathTemplate := orgConfig.CryptoPath
if !filepath.IsAbs(orgCryptoPathTemplate) {
orgCryptoPathTemplate = filepath.Join(config.CryptoConfigPath(), orgCryptoPathTemplate)
}
fmt.Printf("orgCryptoPathTemplate: %s\n", orgCryptoPathTemplate)
certStore, err := persistence.NewFileCertStore(orgCryptoPathTemplate)
if err != nil {
return nil, errors.Wrapf(err, "creating a cert store failed")
}
return certStore, nil
}

func cleanup(storePath string) error {
d, err := os.Open(storePath)
if err != nil {
return err
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
return err
}
for _, name := range names {
err = os.RemoveAll(filepath.Join(storePath, name))
if err != nil {
return err
}
}
return nil
}
Loading

0 comments on commit 34108c5

Please sign in to comment.