Skip to content

Commit

Permalink
bug fix 4127. PKCS11 from Fabric 2.2.x don't support MSPs with CA cer…
Browse files Browse the repository at this point in the history
…tificates that included RSA public keys

Signed-off-by: Thiago Mariano <mariano.thiago@gmail.com>
  • Loading branch information
marianothiago authored and ale-linux committed Apr 17, 2023
1 parent 8612501 commit 394ef77
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 3 deletions.
2 changes: 1 addition & 1 deletion bccsp/pkcs11/ecdsakey_test.go
Expand Up @@ -32,5 +32,5 @@ func TestX509PublicKeyImportOptsKeyImporter(t *testing.T) {
cert.PublicKey = "Hello world"
_, err = ki.KeyImport(cert, &bccsp.X509PublicKeyImportOpts{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "Certificate's public key type not recognized. Supported keys: [ECDSA]")
assert.Contains(t, err.Error(), "Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]")
}
9 changes: 7 additions & 2 deletions bccsp/pkcs11/pkcs11.go
Expand Up @@ -9,6 +9,7 @@ package pkcs11
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
Expand Down Expand Up @@ -218,11 +219,15 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K

pk := x509Cert.PublicKey

switch pk.(type) {
switch pk := pk.(type) {
case *ecdsa.PublicKey:
return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
case *rsa.PublicKey:
// This path only exists to support environments that use RSA certificate
// authorities to issue ECDSA certificates.
return &rsaPublicKey{pubKey: pk}, nil
default:
return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA]")
return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]")
}

default:
Expand Down
11 changes: 11 additions & 0 deletions bccsp/pkcs11/pkcs11_test.go
Expand Up @@ -13,6 +13,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
Expand Down Expand Up @@ -847,6 +848,16 @@ func TestECDSAKeyImportFromECDSAPublicKey(t *testing.T) {
}
}

func TestX509RSAKeyImport(t *testing.T) {
pk, err := rsa.GenerateKey(rand.Reader, 2048)
assert.NoError(t, err, "key generation failed")
cert := &x509.Certificate{PublicKey: pk.Public()}
key, err := currentBCCSP.KeyImport(cert, &bccsp.X509PublicKeyImportOpts{Temporary: false})
assert.NoError(t, err, "key import failed")
assert.NotNil(t, key, "key must not be nil")
assert.Equal(t, &rsaPublicKey{pubKey: &pk.PublicKey}, key)
}

func TestKeyImportFromX509ECDSAPublicKey(t *testing.T) {
// Generate an ECDSA key
k, err := currentBCCSP.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: false})
Expand Down
52 changes: 52 additions & 0 deletions bccsp/pkcs11/rsa.go
@@ -0,0 +1,52 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package pkcs11

import (
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"errors"
"fmt"

"github.com/hyperledger/fabric/bccsp"
)

// An rsaPublicKey wraps the standard library implementation of an RSA public
// key with functions that satisfy the bccsp.Key interface.
//
// NOTE: Fabric does not support RSA signing or verification. This code simply
// allows MSPs to include RSA CAs in their certificate chains.
type rsaPublicKey struct{ pubKey *rsa.PublicKey }

func (k *rsaPublicKey) Symmetric() bool { return false }
func (k *rsaPublicKey) Private() bool { return false }
func (k *rsaPublicKey) PublicKey() (bccsp.Key, error) { return k, nil }

// Bytes converts this key to its serialized representation.
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() []byte {
if k.pubKey == nil {
return nil
}

// Marshal the public key and hash it
raw := x509.MarshalPKCS1PublicKey(k.pubKey)
hash := sha256.Sum256(raw)
return hash[:]
}
58 changes: 58 additions & 0 deletions bccsp/pkcs11/rsa_test.go
@@ -0,0 +1,58 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package pkcs11

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"math/big"
"testing"

"github.com/stretchr/testify/require"
)

type rsaPublicKeyASN struct {
N *big.Int
E int
}

func TestRSAPublicKey(t *testing.T) {
lowLevelKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
k := &rsaPublicKey{&lowLevelKey.PublicKey}

require.False(t, k.Symmetric())
require.False(t, k.Private())

k.pubKey = nil
ski := k.SKI()
require.Nil(t, ski)

k.pubKey = &lowLevelKey.PublicKey
ski = k.SKI()
raw, err := asn1.Marshal(rsaPublicKeyASN{N: k.pubKey.N, E: k.pubKey.E})
require.NoError(t, err, "asn1 marshal failed")
hash := sha256.New()
hash.Write(raw)
ski2 := hash.Sum(nil)
require.Equal(t, ski, ski2, "SKI is not computed in the right way.")

pk, err := k.PublicKey()
require.NoError(t, err)
require.Equal(t, k, pk)

bytes, err := k.Bytes()
require.NoError(t, err)
bytes2, err := x509.MarshalPKIXPublicKey(k.pubKey)
require.Equal(t, bytes2, bytes, "bytes are not computed in the right way.")

_, err = (&rsaPublicKey{}).Bytes()
require.EqualError(t, err, "Failed marshalling key. Key is nil.")
}

0 comments on commit 394ef77

Please sign in to comment.