Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 24f9ecc

Browse files
committed
[FAB-7452] Allow embedding cryptoconfig in the Config
This change makes it possible to embed the crypto material from the cryptoconfig and cryptoPaths for the users of an organization into the SDK's config.yaml. The apiconfig.OrganizationConfig was updated with a the new field `Users map[string]UserConfig`, which contains a map of the embedded users, where `UserConfig` is: type UserConfig struct { Key string Cert string } Additionally, the default CredentialManager's constructor and its method `GetSigningIdentity` were updated to make use of the embedded users. `GetSigningIdentity` first checks if an embedded user exists and if not, looks in the supplied cryptoPath. Lastly, some logic was extracted from the `util.ImportBCCSPKeyFromPEM` method into the `util.ImportBCCSPKeyFromPEMBytes` method in order to allow importing of keys directly from a byte array rather than a file path. Change-Id: I0333637ca03be5243d298158d128eb1fa8e399e0 Signed-off-by: Emil Nikolov <emil.e.nikolov@gmail.com>
1 parent dafcfbc commit 24f9ecc

File tree

7 files changed

+642
-29
lines changed

7 files changed

+642
-29
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ vendor/
1313

1414
# Files auto-generated by docker-compose
1515
test/fixtures/fabricca/tls/certs/server/ca.org*.example.com-cert.pem
16+
.idea/

api/apiconfig/network.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,18 @@ type NetworkPeer struct {
9191
type OrganizationConfig struct {
9292
MspID string
9393
CryptoPath string
94+
Users map[string]UserConfig
9495
Peers []string
9596
CertificateAuthorities []string
9697
AdminPrivateKey TLSConfig
9798
SignedCert TLSConfig
9899
}
99100

101+
type UserConfig struct {
102+
Key string
103+
Cert string
104+
}
105+
100106
// OrdererConfig defines an orderer configuration
101107
type OrdererConfig struct {
102108
URL string

internal/github.com/hyperledger/fabric-ca/util/csp.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,28 +126,39 @@ func ImportBCCSPKeyFromPEM(keyFile string, myCSP apicryptosuite.CryptoSuite, tem
126126
if err != nil {
127127
return nil, err
128128
}
129-
key, err := factory.PEMtoPrivateKey(keyBuff, nil)
129+
130+
key, err := ImportBCCSPKeyFromPEMBytes(keyBuff, myCSP, temporary)
131+
130132
if err != nil {
131133
return nil, errors.WithMessage(err, fmt.Sprintf("Failed parsing private key from %s", keyFile))
132134
}
135+
136+
return key, nil
137+
}
138+
139+
// ImportBCCSPKeyFromPEMBytes attempts to create a private BCCSP key from a pem byte slice
140+
func ImportBCCSPKeyFromPEMBytes(keyBuff []byte, myCSP apicryptosuite.CryptoSuite, temporary bool) (apicryptosuite.Key, error) {
141+
key, err := factory.PEMtoPrivateKey(keyBuff, nil)
142+
if err != nil {
143+
return nil, err
144+
}
133145
switch key.(type) {
134146
case *ecdsa.PrivateKey:
135147
priv, err := factory.PrivateKeyToDER(key.(*ecdsa.PrivateKey))
136148
if err != nil {
137-
return nil, errors.WithMessage(err, fmt.Sprintf("Failed to convert ECDSA private key for '%s'", keyFile))
149+
return nil, errors.WithMessage(err, fmt.Sprintf("Failed to convert ECDSA private key"))
138150
}
139151
sk, err := myCSP.KeyImport(priv, factory.GetECDSAPrivateKeyImportOpts(temporary))
140152
if err != nil {
141-
return nil, errors.WithMessage(err, fmt.Sprintf("Failed to import ECDSA private key for '%s'", keyFile))
153+
return nil, errors.WithMessage(err, fmt.Sprintf("Failed to import ECDSA private key"))
142154
}
143155
return sk, nil
144156
case *rsa.PrivateKey:
145-
return nil, errors.Errorf("Failed to import RSA key from %s; RSA private key import is not supported", keyFile)
157+
return nil, errors.Errorf("Failed to import RSA key: RSA private key import is not supported")
146158
default:
147-
return nil, errors.Errorf("Failed to import key from %s: invalid secret key type", keyFile)
159+
return nil, errors.Errorf("Failed to import key: invalid secret key type")
148160
}
149161
}
150-
151162
// LoadX509KeyPair reads and parses a public/private key pair from a pair
152163
// of files. The files must contain PEM encoded data. The certificate file
153164
// may contain intermediate certificates following the leaf certificate to

pkg/config/config_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var org0 = "org0"
2828
var org1 = "Org1"
2929
var configTestFilePath = "../../test/fixtures/config/config_test.yaml"
3030
var configPemTestFilePath = "testdata/config_test_pem.yaml"
31+
var configEmbeddedUsersTestFilePath = "../../test/fixtures/config/config_test_embedded_pems.yaml"
3132
var configType = "yaml"
3233

3334
func TestDefaultConfig(t *testing.T) {
@@ -837,6 +838,36 @@ O94CDp7l2k7hMQI0zQ==
837838
}
838839
}
839840

841+
func TestLoadConfigWithEmbeddedUsers(t *testing.T) {
842+
// get a config file with embedded users
843+
c, err := InitConfig(configEmbeddedUsersTestFilePath)
844+
if err != nil {
845+
t.Fatal(err)
846+
}
847+
848+
conf, err := c.NetworkConfig()
849+
850+
if err != nil {
851+
t.Fatal(err)
852+
}
853+
854+
if conf.Organizations[strings.ToLower(org1)].Users[strings.ToLower("EmbeddedUser")].Cert == "" {
855+
t.Fatal("Failed to parse the embedded cert for user EmbeddedUser")
856+
}
857+
858+
if conf.Organizations[strings.ToLower(org1)].Users[strings.ToLower("EmbeddedUser")].Key == "" {
859+
t.Fatal("Failed to parse the embedded key for user EmbeddedUser")
860+
}
861+
862+
if conf.Organizations[strings.ToLower(org1)].Users[strings.ToLower("NonExistentEmbeddedUser")].Key != "" {
863+
t.Fatal("Mistakenly found an embedded key for user NonExistentEmbeddedUser")
864+
}
865+
866+
if conf.Organizations[strings.ToLower(org1)].Users[strings.ToLower("NonExistentEmbeddedUser")].Cert != "" {
867+
t.Fatal("Mistakenly found an embedded cert for user NonExistentEmbeddedUser")
868+
}
869+
}
870+
840871
func TestInitConfigFromBytesWrongType(t *testing.T) {
841872
// get a config byte for testing
842873
cBytes, err := loadConfigBytesFromFile(t, configPemTestFilePath)

pkg/fabric-client/credentialmgr/credentialmgr.go

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var logger = logging.NewLogger("fabric_sdk_go")
2525
// CredentialManager is used for retriving user's signing identity (ecert + private key)
2626
type CredentialManager struct {
2727
orgName string
28+
embeddedUsers map[string]apiconfig.UserConfig
2829
keyDir string
2930
certDir string
3031
config apiconfig.Config
@@ -47,16 +48,16 @@ func NewCredentialManager(orgName string, config apiconfig.Config, cryptoProvide
4748
return nil, errors.New("org config retrieval failed")
4849
}
4950

50-
if orgConfig.CryptoPath == "" {
51-
return nil, errors.New("CryptoPath is required")
51+
if orgConfig.CryptoPath == "" && len(orgConfig.Users) == 0 {
52+
return nil, errors.New("Either a cryptopath or an embedded list of users is required")
5253
}
5354

5455
orgCryptoPath := orgConfig.CryptoPath
5556
if !filepath.IsAbs(orgCryptoPath) {
5657
orgCryptoPath = filepath.Join(config.CryptoConfigPath(), orgCryptoPath)
5758
}
5859

59-
return &CredentialManager{orgName: orgName, config: config, keyDir: orgCryptoPath + "/keystore", certDir: orgCryptoPath + "/signcerts", cryptoProvider: cryptoProvider}, nil
60+
return &CredentialManager{orgName: orgName, config: config, embeddedUsers: orgConfig.Users, keyDir: orgCryptoPath + "/keystore", certDir: orgCryptoPath + "/signcerts", cryptoProvider: cryptoProvider}, nil
6061
}
6162

6263
// GetSigningIdentity will sign the given object with provided key,
@@ -66,31 +67,47 @@ func (mgr *CredentialManager) GetSigningIdentity(userName string) (*apifabclient
6667
return nil, errors.New("username is required")
6768
}
6869

69-
privateKeyDir := strings.Replace(mgr.keyDir, "{userName}", userName, -1)
70-
enrollmentCertDir := strings.Replace(mgr.certDir, "{userName}", userName, -1)
71-
72-
privateKeyPath, err := getFirstPathFromDir(privateKeyDir)
73-
if err != nil {
74-
return nil, errors.WithMessage(err, "find private key path failed")
75-
}
76-
77-
enrollmentCertPath, err := getFirstPathFromDir(enrollmentCertDir)
78-
if err != nil {
79-
return nil, errors.WithMessage(err, "find enrollment cert path failed")
80-
}
81-
8270
mspID, err := mgr.config.MspID(mgr.orgName)
8371
if err != nil {
8472
return nil, errors.WithMessage(err, "MSP ID config read failed")
8573
}
8674

87-
privateKey, err := fabricCaUtil.ImportBCCSPKeyFromPEM(privateKeyPath, mgr.cryptoProvider, true)
88-
if err != nil {
89-
return nil, errors.Wrap(err, "import private key failed")
90-
}
91-
enrollmentCert, err := ioutil.ReadFile(enrollmentCertPath)
92-
if err != nil {
93-
return nil, errors.Wrap(err, "reading enrollment cert path failed")
75+
var privateKey apicryptosuite.Key
76+
var enrollmentCert []byte
77+
78+
embeddedCertBytes := []byte(mgr.embeddedUsers[strings.ToLower(userName)].Cert)
79+
embeddedKeyBytes := []byte(mgr.embeddedUsers[strings.ToLower(userName)].Key)
80+
81+
// First check the embedded users and then the paths
82+
if len(embeddedCertBytes) != 0 && len(embeddedKeyBytes) != 0 {
83+
privateKey, err = fabricCaUtil.ImportBCCSPKeyFromPEMBytes(embeddedKeyBytes, mgr.cryptoProvider, true)
84+
if err != nil {
85+
return nil, errors.Wrapf(err, "import private key failed %v", embeddedKeyBytes)
86+
}
87+
88+
enrollmentCert = embeddedCertBytes
89+
} else {
90+
privateKeyDir := strings.Replace(mgr.keyDir, "{userName}", userName, -1)
91+
enrollmentCertDir := strings.Replace(mgr.certDir, "{userName}", userName, -1)
92+
93+
privateKeyPath, err := getFirstPathFromDir(privateKeyDir)
94+
if err != nil {
95+
return nil, errors.WithMessage(err, "find private key path failed")
96+
}
97+
98+
enrollmentCertPath, err := getFirstPathFromDir(enrollmentCertDir)
99+
if err != nil {
100+
return nil, errors.WithMessage(err, "find enrollment cert path failed")
101+
}
102+
103+
privateKey, err = fabricCaUtil.ImportBCCSPKeyFromPEM(privateKeyPath, mgr.cryptoProvider, true)
104+
if err != nil {
105+
return nil, errors.Wrap(err, "import private key failed")
106+
}
107+
enrollmentCert, err = ioutil.ReadFile(enrollmentCertPath)
108+
if err != nil {
109+
return nil, errors.Wrap(err, "reading enrollment cert path failed")
110+
}
94111
}
95112

96113
signingIdentity := &apifabclient.SigningIdentity{MspID: mspID, PrivateKey: privateKey, EnrollmentCert: enrollmentCert}

pkg/fabric-client/credentialmgr/credentialmgr_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,31 @@ func TestInvalidOrgCredentialManager(t *testing.T) {
6666
}
6767

6868
}
69+
70+
func TestCredentialManagerFromEmbeddedCryptoConfig(t *testing.T) {
71+
config, err := config.InitConfig("../../../test/fixtures/config/config_test_embedded_pems.yaml")
72+
73+
if err != nil {
74+
t.Fatalf(err.Error())
75+
}
76+
77+
credentialMgr, err := NewCredentialManager("Org1", config, &fcmocks.MockCryptoSuite{})
78+
if err != nil {
79+
t.Fatalf("Failed to setup credential manager: %s", err)
80+
}
81+
82+
_, err = credentialMgr.GetSigningIdentity("")
83+
if err == nil {
84+
t.Fatalf("Should have failed to retrieve signing identity for empty user name")
85+
}
86+
87+
_, err = credentialMgr.GetSigningIdentity("Non-Existent")
88+
if err == nil {
89+
t.Fatalf("Should have failed to retrieve signing identity for non-existent user")
90+
}
91+
92+
_, err = credentialMgr.GetSigningIdentity("EmbeddedUser")
93+
if err != nil {
94+
t.Fatalf("Failed to retrieve signing identity: %+v", err)
95+
}
96+
}

0 commit comments

Comments
 (0)