Skip to content

Commit 2f7153f

Browse files
committed
BCCSP ECDSA/RSA/X509 public/private key import
This change-set introduces support for importing ecdsa/rsa public keys in different formats, namely: ECDSA - PKIX format and as ecdsa.PublicKey instances. RSA - rsa.PublicKey instances. X509 - The public key in the X509 certificate (ECDSA or RSA). This change-set also adds support for importing ecdsa private keys using DER or PKCS#8 format. This change-set comes in the context of: https://jira.hyperledger.org/browse/FAB-354 Change-Id: I6a875f34f3cccf52755aa7617a29c16014e17028 Signed-off-by: Angelo De Caro <[email protected]>
1 parent 3508592 commit 2f7153f

File tree

5 files changed

+773
-8
lines changed

5 files changed

+773
-8
lines changed

core/crypto/bccsp/bccsp_opts.go

+113
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ limitations under the License.
1616

1717
package bccsp
1818

19+
import (
20+
"crypto/ecdsa"
21+
"crypto/rsa"
22+
"crypto/x509"
23+
)
24+
1925
const (
2026
// ECDSA Elliptic Curve Digital Signature Algorithm (key gen, import, sign, verify),
2127
// at default security level (see primitives package).
@@ -36,6 +42,9 @@ const (
3642

3743
// SHA Secure Hash Algorithm using default family (see primitives package)
3844
SHA = "SHA"
45+
46+
// X509Certificate Label for X509 certificate realted operation
47+
X509Certificate = "X509Certificate"
3948
)
4049

4150
// ECDSAKeyGenOpts contains options for ECDSA key generation.
@@ -55,6 +64,64 @@ func (opts *ECDSAKeyGenOpts) Ephemeral() bool {
5564
return opts.Temporary
5665
}
5766

67+
// ECDSAPKIXPublicKeyImportOpts contains options for ECDSA public key importation in PKIX format
68+
type ECDSAPKIXPublicKeyImportOpts struct {
69+
Temporary bool
70+
}
71+
72+
// Algorithm returns an identifier for the algorithm to be used
73+
// to generate a key.
74+
func (opts *ECDSAPKIXPublicKeyImportOpts) Algorithm() string {
75+
return ECDSA
76+
}
77+
78+
// Ephemeral returns true if the key to generate has to be ephemeral,
79+
// false otherwise.
80+
func (opts *ECDSAPKIXPublicKeyImportOpts) Ephemeral() bool {
81+
return opts.Temporary
82+
}
83+
84+
// ECDSAPrivateKeyImportOpts contains options for ECDSA secret key importation in DER format
85+
// or PKCS#8 format.
86+
type ECDSAPrivateKeyImportOpts struct {
87+
Temporary bool
88+
}
89+
90+
// Algorithm returns an identifier for the algorithm to be used
91+
// to generate a key.
92+
func (opts *ECDSAPrivateKeyImportOpts) Algorithm() string {
93+
return ECDSA
94+
}
95+
96+
// Ephemeral returns true if the key to generate has to be ephemeral,
97+
// false otherwise.
98+
func (opts *ECDSAPrivateKeyImportOpts) Ephemeral() bool {
99+
return opts.Temporary
100+
}
101+
102+
// ECDSAGoPublicKeyImportOpts contains options for ECDSA key importation from ecdsa.PublicKey
103+
type ECDSAGoPublicKeyImportOpts struct {
104+
Temporary bool
105+
PK *ecdsa.PublicKey
106+
}
107+
108+
// Algorithm returns an identifier for the algorithm to be used
109+
// to generate a key.
110+
func (opts *ECDSAGoPublicKeyImportOpts) Algorithm() string {
111+
return ECDSA
112+
}
113+
114+
// Ephemeral returns true if the key to generate has to be ephemeral,
115+
// false otherwise.
116+
func (opts *ECDSAGoPublicKeyImportOpts) Ephemeral() bool {
117+
return opts.Temporary
118+
}
119+
120+
// PublicKey returns the ecdsa.PublicKey to be imported.
121+
func (opts *ECDSAGoPublicKeyImportOpts) PublicKey() *ecdsa.PublicKey {
122+
return opts.PK
123+
}
124+
58125
// ECDSAReRandKeyOpts contains options for ECDSA key re-randomization.
59126
type ECDSAReRandKeyOpts struct {
60127
Temporary bool
@@ -206,3 +273,49 @@ func (opts *RSAKeyGenOpts) Algorithm() string {
206273
func (opts *RSAKeyGenOpts) Ephemeral() bool {
207274
return opts.Temporary
208275
}
276+
277+
// ECDSAGoPublicKeyImportOpts contains options for RSA key importation from rsa.PublicKey
278+
type RSAGoPublicKeyImportOpts struct {
279+
Temporary bool
280+
PK *rsa.PublicKey
281+
}
282+
283+
// Algorithm returns an identifier for the algorithm to be used
284+
// to generate a key.
285+
func (opts *RSAGoPublicKeyImportOpts) Algorithm() string {
286+
return RSA
287+
}
288+
289+
// Ephemeral returns true if the key to generate has to be ephemeral,
290+
// false otherwise.
291+
func (opts *RSAGoPublicKeyImportOpts) Ephemeral() bool {
292+
return opts.Temporary
293+
}
294+
295+
// PublicKey returns the ecdsa.PublicKey to be imported.
296+
func (opts *RSAGoPublicKeyImportOpts) PublicKey() *rsa.PublicKey {
297+
return opts.PK
298+
}
299+
300+
// X509PublicKeyImportOpts contains options for importing public keys from an x509 certificate
301+
type X509PublicKeyImportOpts struct {
302+
Temporary bool
303+
Cert *x509.Certificate
304+
}
305+
306+
// Algorithm returns an identifier for the algorithm to be used
307+
// to generate a key.
308+
func (opts *X509PublicKeyImportOpts) Algorithm() string {
309+
return X509Certificate
310+
}
311+
312+
// Ephemeral returns true if the key to generate has to be ephemeral,
313+
// false otherwise.
314+
func (opts *X509PublicKeyImportOpts) Ephemeral() bool {
315+
return opts.Temporary
316+
}
317+
318+
// PublicKey returns the ecdsa.PublicKey to be imported.
319+
func (opts *X509PublicKeyImportOpts) Certificate() *x509.Certificate {
320+
return opts.Cert
321+
}

core/crypto/bccsp/sw/ecdsakey.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type ecdsaPrivateKey struct {
2828
k *ecdsa.PrivateKey
2929
}
3030

31-
// ToByte converts this key to its byte representation,
31+
// Bytes converts this key to its byte representation,
3232
// if this operation is allowed.
3333
func (k *ecdsaPrivateKey) Bytes() (raw []byte, err error) {
3434
return
@@ -64,7 +64,7 @@ type ecdsaPublicKey struct {
6464
k *ecdsa.PublicKey
6565
}
6666

67-
// ToByte converts this key to its byte representation,
67+
// Bytes converts this key to its byte representation,
6868
// if this operation is allowed.
6969
func (k *ecdsaPublicKey) Bytes() (raw []byte, err error) {
7070
raw, err = x509.MarshalPKIXPublicKey(k.k)

core/crypto/bccsp/sw/impl.go

+147-5
Original file line numberDiff line numberDiff line change
@@ -256,18 +256,16 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e
256256
// The opts argument should be appropriate for the primitive used.
257257
func (csp *impl) KeyImport(raw []byte, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
258258
// Validate arguments
259-
if len(raw) == 0 {
260-
return nil, errors.New("Invalid raw. Zero length.")
261-
}
262259
if opts == nil {
263260
return nil, errors.New("Invalid Opts parameter. It must not be nil.")
264261
}
265262

266263
switch opts.(type) {
264+
267265
case *bccsp.AES256ImportKeyOpts:
268266

269267
if len(raw) != 32 {
270-
return nil, fmt.Errorf("Invalid Key Length [%d]. Must be 32 bytes", len(raw))
268+
return nil, fmt.Errorf("[AES256ImportKeyOpts] Invalid Key Length [%d]. Must be 32 bytes", len(raw))
271269
}
272270

273271
aesK := &aesPrivateKey{utils.Clone(raw), false}
@@ -282,8 +280,13 @@ func (csp *impl) KeyImport(raw []byte, opts bccsp.KeyImportOpts) (k bccsp.Key, e
282280
}
283281

284282
return aesK, nil
283+
285284
case *bccsp.HMACImportKeyOpts:
286285

286+
if len(raw) == 0 {
287+
return nil, errors.New("[HMACImportKeyOpts] Invalid raw. It must not be nil.")
288+
}
289+
287290
aesK := &aesPrivateKey{utils.Clone(raw), false}
288291

289292
// If the key is not Ephemeral, store it.
@@ -296,6 +299,123 @@ func (csp *impl) KeyImport(raw []byte, opts bccsp.KeyImportOpts) (k bccsp.Key, e
296299
}
297300

298301
return aesK, nil
302+
303+
case *bccsp.ECDSAPKIXPublicKeyImportOpts:
304+
305+
if len(raw) == 0 {
306+
return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw. It must not be nil.")
307+
}
308+
309+
lowLevelKey, err := primitives.DERToPublicKey(raw)
310+
if err != nil {
311+
return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err)
312+
}
313+
314+
ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey)
315+
if !ok {
316+
return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.")
317+
}
318+
319+
k = &ecdsaPublicKey{ecdsaPK}
320+
321+
// If the key is not Ephemeral, store it.
322+
if !opts.Ephemeral() {
323+
// Store the key
324+
err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey)
325+
if err != nil {
326+
return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err)
327+
}
328+
}
329+
330+
return k, nil
331+
332+
case *bccsp.ECDSAPrivateKeyImportOpts:
333+
334+
if len(raw) == 0 {
335+
return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.")
336+
}
337+
338+
lowLevelKey, err := primitives.DERToPrivateKey(raw)
339+
if err != nil {
340+
return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err)
341+
}
342+
343+
ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey)
344+
if !ok {
345+
return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.")
346+
}
347+
348+
k = &ecdsaPrivateKey{ecdsaSK}
349+
350+
// If the key is not Ephemeral, store it.
351+
if !opts.Ephemeral() {
352+
// Store the key
353+
err = csp.ks.storePrivateKey(hex.EncodeToString(k.SKI()), lowLevelKey)
354+
if err != nil {
355+
return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err)
356+
}
357+
}
358+
359+
return k, nil
360+
361+
case *bccsp.ECDSAGoPublicKeyImportOpts:
362+
363+
lowLevelKey := opts.(*bccsp.ECDSAGoPublicKeyImportOpts).PublicKey()
364+
if lowLevelKey == nil {
365+
return nil, errors.New("Invalid Opts. ECDSA Public key cannot be nil")
366+
}
367+
368+
k = &ecdsaPublicKey{lowLevelKey}
369+
370+
// If the key is not Ephemeral, store it.
371+
if !opts.Ephemeral() {
372+
// Store the key
373+
err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey)
374+
if err != nil {
375+
return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err)
376+
}
377+
}
378+
379+
return k, nil
380+
381+
case *bccsp.RSAGoPublicKeyImportOpts:
382+
383+
lowLevelKey := opts.(*bccsp.RSAGoPublicKeyImportOpts).PublicKey()
384+
if lowLevelKey == nil {
385+
return nil, errors.New("Invalid Opts. ECDSA Public key cannot be nil")
386+
}
387+
388+
k = &rsaPublicKey{lowLevelKey}
389+
390+
// If the key is not Ephemeral, store it.
391+
if !opts.Ephemeral() {
392+
// Store the key
393+
err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey)
394+
if err != nil {
395+
return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err)
396+
}
397+
}
398+
399+
return k, nil
400+
401+
case *bccsp.X509PublicKeyImportOpts:
402+
403+
x509Cert := opts.(*bccsp.X509PublicKeyImportOpts).Certificate()
404+
if x509Cert == nil {
405+
return nil, errors.New("Invalid Opts. X509 certificate cannot be nil")
406+
}
407+
408+
pk := x509Cert.PublicKey
409+
410+
switch pk.(type) {
411+
case *ecdsa.PublicKey:
412+
return csp.KeyImport(nil, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral(), PK: pk.(*ecdsa.PublicKey)})
413+
case *rsa.PublicKey:
414+
return csp.KeyImport(nil, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral(), PK: pk.(*rsa.PublicKey)})
415+
default:
416+
return nil, errors.New("Certificate public key type not recognized. Supported keys: [ECDSA, RSA]")
417+
}
418+
299419
default:
300420
return nil, errors.New("Import Key Options not recognized")
301421
}
@@ -407,16 +527,38 @@ func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Signer
407527
}
408528

409529
return ecdsa.Verify(&(k.(*ecdsaPrivateKey).k.PublicKey), digest, ecdsaSignature.R, ecdsaSignature.S), nil
530+
case *ecdsaPublicKey:
531+
ecdsaSignature := new(primitives.ECDSASignature)
532+
_, err := asn1.Unmarshal(signature, ecdsaSignature)
533+
if err != nil {
534+
return false, fmt.Errorf("Failed unmashalling signature [%s]", err)
535+
}
536+
537+
return ecdsa.Verify(k.(*ecdsaPublicKey).k, digest, ecdsaSignature.R, ecdsaSignature.S), nil
410538
case *rsaPrivateKey:
411539
if opts == nil {
412-
return false, errors.New("Invalid options. Nil.")
540+
return false, errors.New("Invalid options. It must not be nil.")
413541
}
414542
switch opts.(type) {
415543
case *rsa.PSSOptions:
416544
err := rsa.VerifyPSS(&(k.(*rsaPrivateKey).k.PublicKey),
417545
(opts.(*rsa.PSSOptions)).Hash,
418546
digest, signature, opts.(*rsa.PSSOptions))
419547

548+
return err == nil, err
549+
default:
550+
return false, fmt.Errorf("Opts type not recognized [%s]", opts)
551+
}
552+
case *rsaPublicKey:
553+
if opts == nil {
554+
return false, errors.New("Invalid options. It must not be nil.")
555+
}
556+
switch opts.(type) {
557+
case *rsa.PSSOptions:
558+
err := rsa.VerifyPSS(k.(*rsaPublicKey).k,
559+
(opts.(*rsa.PSSOptions)).Hash,
560+
digest, signature, opts.(*rsa.PSSOptions))
561+
420562
return err == nil, err
421563
default:
422564
return false, fmt.Errorf("Opts type not recognized [%s]", opts)

0 commit comments

Comments
 (0)