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

Commit a03806b

Browse files
committed
[FAB-7765] Use CryptoSuite to load private key/signer
Change-Id: I16a3a4fc0275c38d86a85ede90899f0a623151e8 Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
1 parent c06069c commit a03806b

File tree

10 files changed

+544
-33
lines changed

10 files changed

+544
-33
lines changed

pkg/config/config.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ import (
2323
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
2424

2525
"github.com/hyperledger/fabric-sdk-go/api/apilogging"
26+
"github.com/hyperledger/fabric-sdk-go/pkg/config/cryptoutil"
2627
"github.com/hyperledger/fabric-sdk-go/pkg/config/urlutil"
2728
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
2829
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
2930
lu "github.com/hyperledger/fabric-sdk-go/pkg/logging/utils"
31+
32+
cs "github.com/hyperledger/fabric-sdk-go/pkg/cryptosuite"
3033
)
3134

3235
var logger = logging.NewLogger(logModule)
@@ -828,24 +831,41 @@ func (c *Config) TLSClientCerts() ([]tls.Certificate, error) {
828831
}
829832
}
830833

831-
if clientConfig.TLSCerts.Client.KeyPem != "" {
832-
kb = []byte(clientConfig.TLSCerts.Client.KeyPem)
833-
} else if clientConfig.TLSCerts.Client.Keyfile != "" {
834-
kb, err = loadByteKeyOrCertFromFile(&clientConfig, true)
834+
if len(cb) == 0 {
835+
// if no cert found in the config, return empty cert chain
836+
return []tls.Certificate{clientCerts}, nil
837+
}
838+
839+
// Load private key from cert using default crypto suite
840+
cs := cs.GetDefault()
841+
pk, err := cryptoutil.GetPrivateKeyFromCert(cb, cs)
842+
843+
// If CryptoSuite fails to load private key from cert then load private key from config
844+
if err != nil || pk == nil {
845+
logger.Debugf("Reading pk from config, unable to retrieve from cert: %s", err)
846+
if clientConfig.TLSCerts.Client.KeyPem != "" {
847+
kb = []byte(clientConfig.TLSCerts.Client.KeyPem)
848+
} else if clientConfig.TLSCerts.Client.Keyfile != "" {
849+
kb, err = loadByteKeyOrCertFromFile(&clientConfig, true)
850+
if err != nil {
851+
return nil, errors.Wrapf(err, "Failed to load key from file path '%s'", clientConfig.TLSCerts.Client.Keyfile)
852+
}
853+
}
854+
855+
// load the key/cert pair from []byte
856+
clientCerts, err = tls.X509KeyPair(cb, kb)
835857
if err != nil {
836-
return nil, errors.Wrapf(err, "Failed to load key from file path '%s'", clientConfig.TLSCerts.Client.Keyfile)
858+
return nil, errors.Errorf("Error loading cert/key pair as TLS client credentials: %v", err)
837859
}
838-
}
839860

840-
if len(cb) == 0 && len(kb) == 0 {
841-
// if no cert found in the config, return empty cert chain
842861
return []tls.Certificate{clientCerts}, nil
862+
843863
}
844864

845-
// load the key/cert pair from []byte
846-
clientCerts, err = tls.X509KeyPair(cb, kb)
865+
// private key was retrieved from cert
866+
clientCerts, err = cryptoutil.X509KeyPair(cb, pk, cs)
847867
if err != nil {
848-
return nil, errors.Errorf("Error loading cert/key pair as TLS client credentials: %v", err)
868+
return nil, err
849869
}
850870

851871
return []tls.Certificate{clientCerts}, nil
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package cryptoutil
8+
9+
import (
10+
"crypto"
11+
"crypto/ecdsa"
12+
"crypto/rsa"
13+
"crypto/tls"
14+
"crypto/x509"
15+
"encoding/pem"
16+
"io"
17+
18+
"github.com/hyperledger/fabric-sdk-go/api/apicryptosuite"
19+
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
20+
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
21+
22+
factory "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric-ca/sdkpatch/cryptosuitebridge"
23+
)
24+
25+
var logger = logging.NewLogger("fabric_sdk_go")
26+
27+
// GetPrivateKeyFromCert will return private key represented by SKI in cert's public key
28+
func GetPrivateKeyFromCert(cert []byte, cs apicryptosuite.CryptoSuite) (apicryptosuite.Key, error) {
29+
30+
dcert, _ := pem.Decode(cert)
31+
if dcert == nil {
32+
return nil, errors.Errorf("Unable to decode cert bytes [%v]", cert)
33+
}
34+
35+
x509Cert, err := x509.ParseCertificate(dcert.Bytes)
36+
if err != nil {
37+
return nil, errors.Errorf("Unable to parse cert from decoded bytes: %s", err)
38+
}
39+
40+
// get the public key in the right format
41+
certPubK, err := cs.KeyImport(x509Cert, factory.GetX509PublicKeyImportOpts(true))
42+
if err != nil {
43+
return nil, errors.WithMessage(err, "Failed to import certificate's public key")
44+
}
45+
46+
if certPubK == nil || certPubK.SKI() == nil {
47+
return nil, errors.New("Failed to get SKI")
48+
}
49+
50+
// Get the key given the SKI value
51+
key, err := cs.GetKey(certPubK.SKI())
52+
if err != nil {
53+
return nil, errors.WithMessage(err, "Could not find matching key for SKI")
54+
}
55+
56+
if key != nil && key.Private() == false {
57+
return nil, errors.Errorf("Found key is not private, SKI: %s", certPubK.SKI())
58+
}
59+
60+
return key, nil
61+
}
62+
63+
// X509KeyPair will return cer/key pair used for mutual TLS
64+
func X509KeyPair(certPEMBlock []byte, pk apicryptosuite.Key, cs apicryptosuite.CryptoSuite) (tls.Certificate, error) {
65+
66+
fail := func(err error) (tls.Certificate, error) { return tls.Certificate{}, err }
67+
68+
var cert tls.Certificate
69+
for {
70+
var certDERBlock *pem.Block
71+
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
72+
if certDERBlock == nil {
73+
break
74+
}
75+
if certDERBlock.Type == "CERTIFICATE" {
76+
cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
77+
} else {
78+
logger.Debugf("Skipping block type: %s", certDERBlock.Type)
79+
}
80+
}
81+
82+
if len(cert.Certificate) == 0 {
83+
return fail(errors.New("No certs available from bytes"))
84+
}
85+
86+
// We are parsing public key for TLS to find its type
87+
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
88+
if err != nil {
89+
return fail(err)
90+
}
91+
92+
switch x509Cert.PublicKey.(type) {
93+
case *rsa.PublicKey:
94+
cert.PrivateKey = &PrivateKey{cs, pk, &rsa.PublicKey{}}
95+
case *ecdsa.PublicKey:
96+
cert.PrivateKey = &PrivateKey{cs, pk, &ecdsa.PublicKey{}}
97+
default:
98+
return fail(errors.New("tls: unknown public key algorithm"))
99+
}
100+
101+
return cert, nil
102+
}
103+
104+
//PrivateKey is signer implementation for golang client TLS
105+
type PrivateKey struct {
106+
cryptoSuite apicryptosuite.CryptoSuite
107+
key apicryptosuite.Key
108+
publicKey crypto.PublicKey
109+
}
110+
111+
// Public returns the public key corresponding to private key
112+
func (priv *PrivateKey) Public() crypto.PublicKey {
113+
return priv.publicKey
114+
}
115+
116+
// Sign signs msg with priv, reading randomness from rand. If opts is a
117+
// *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will
118+
// be used. This method is intended to support keys where the private part is
119+
// kept in, for example, a hardware module.
120+
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
121+
if priv.cryptoSuite == nil {
122+
return nil, errors.New("Crypto suite not set")
123+
}
124+
125+
if priv.key == nil {
126+
return nil, errors.New("Private key not set")
127+
}
128+
129+
return priv.cryptoSuite.Sign(priv.key, msg, opts)
130+
}

0 commit comments

Comments
 (0)