From cafeaf1c9077076816cd9be55f08df4ca0a30ee1 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Sun, 22 Jan 2017 16:54:31 -0500 Subject: [PATCH 1/2] [FAB-1648] Add (unreachable) PKCS11 BCCSP ECDSA op Added: - EC Key Generation - EC Public Key extraction (both opencryptoki and softhsm have bugs) - ECDSA Sign/Verify operations - EC Key Private Key extraction/import (this might not work on real HSM that disallows key import) Tested on SoftHSM (Mac, s390) and ACSP (s390) Signed-off-by: Volodymyr Paprotski Change-Id: I2d9ed4ba21fafedd9de24947b4a4a55b4db3b601 --- bccsp/pkcs11/pkcs11.go | 515 +++++++++++++++++++++++++++++++++++- bccsp/pkcs11/pkcs11_test.go | 206 +++++++++++++++ 2 files changed, 718 insertions(+), 3 deletions(-) diff --git a/bccsp/pkcs11/pkcs11.go b/bccsp/pkcs11/pkcs11.go index 507896b0af6..0efd7ba8451 100644 --- a/bccsp/pkcs11/pkcs11.go +++ b/bccsp/pkcs11/pkcs11.go @@ -16,17 +16,31 @@ limitations under the License. package pkcs11 import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "encoding/asn1" + "encoding/hex" "fmt" + "math/big" + "strings" + "sync" + "github.com/miekg/pkcs11" + "github.com/op/go-logging" ) var ( - ctx *pkcs11.Ctx - sessions = make(chan pkcs11.SessionHandle, 2000) - slot uint + ctx *pkcs11.Ctx + sessions = make(chan pkcs11.SessionHandle, 2000) + slot uint + probablySoftHSM = false //Only needed for KeyImport ) func initPKCS11(lib, pin, label string) error { + if strings.Contains(lib, "softhsm") { + probablySoftHSM = true + } return loadLib(lib, pin, label) } @@ -104,3 +118,498 @@ func getSession() (session pkcs11.SessionHandle) { func returnSession(session pkcs11.SessionHandle) { sessions <- session } + +// Look for an EC key by SKI, stored in CKA_ID +// This function can probably be addapted for both EC and RSA keys. +func getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) { + p11lib := ctx + session := getSession() + defer returnSession(session) + isPriv = true + _, err = findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + if err != nil { + isPriv = false + logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski)) + } + + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, isPublicKey) + if err != nil { + return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) + } + + ecpt, marshaledOid, err := ecPoint(p11lib, session, *publicKey) + if err != nil { + return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) + } + + curveOid := new(asn1.ObjectIdentifier) + _, err = asn1.Unmarshal(marshaledOid, curveOid) + if err != nil { + return nil, false, fmt.Errorf("Failed Unmarshaling Curve OID [%s]\n%s", err.Error(), hex.EncodeToString(marshaledOid)) + } + + curve := namedCurveFromOID(*curveOid) + if curve == nil { + return nil, false, fmt.Errorf("Cound not recognize Curve from OID") + } + x, y := elliptic.Unmarshal(curve, ecpt) + if x == nil { + return nil, false, fmt.Errorf("Failed Unmarshaling Public Key") + } + + pubKey = &ecdsa.PublicKey{curve, x, y} + return pubKey, isPriv, nil +} + +// RFC 5480, 2.1.1.1. Named Curve +// +// secp224r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 33 } +// +// secp256r1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) +// prime(1) 7 } +// +// secp384r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 34 } +// +// secp521r1 OBJECT IDENTIFIER ::= { +// iso(1) identified-organization(3) certicom(132) curve(0) 35 } +// +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { + switch { + case oid.Equal(oidNamedCurveP224): + return elliptic.P224() + case oid.Equal(oidNamedCurveP256): + return elliptic.P256() + case oid.Equal(oidNamedCurveP384): + return elliptic.P384() + case oid.Equal(oidNamedCurveP521): + return elliptic.P521() + } + return nil +} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + + return nil, false +} + +func generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) { + p11lib := ctx + session := getSession() + defer returnSession(session) + + id := nextIDCtr() + publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) + prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16)) + + marshaledOID, err := asn1.Marshal(curve) + if err != nil { + return nil, nil, fmt.Errorf("Could not marshal OID [%s]", err.Error()) + } + + pubkey_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + + pkcs11.NewAttribute(pkcs11.CKA_ID, publabel), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), + } + + prvkey_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), + + pkcs11.NewAttribute(pkcs11.CKA_ID, prvlabel), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), + + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true), + } + + pub, prv, err := p11lib.GenerateKeyPair(session, + []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil)}, + pubkey_t, prvkey_t) + + if err != nil { + return nil, nil, fmt.Errorf("P11: keypair generate failed [%s]\n", err) + } + + ecpt, _, _ := ecPoint(p11lib, session, pub) + hash := sha256.Sum256(ecpt) + ski = hash[:] + + // set CKA_ID of the both keys to SKI(public key) + setski_t := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + } + + logger.Infof("Generated new P11 key, SKI %x\n", ski) + err = p11lib.SetAttributeValue(session, pub, setski_t) + if err != nil { + return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[public] failed [%s]\n", err) + } + + err = p11lib.SetAttributeValue(session, prv, setski_t) + if err != nil { + return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[private] failed [%s]\n", err) + } + + nistCurve := namedCurveFromOID(curve) + if curve == nil { + return nil, nil, fmt.Errorf("Cound not recognize Curve from OID") + } + x, y := elliptic.Unmarshal(nistCurve, ecpt) + if x == nil { + return nil, nil, fmt.Errorf("Failed Unmarshaling Public Key") + } + + pubGoKey := &ecdsa.PublicKey{nistCurve, x, y} + + if logger.IsEnabledFor(logging.DEBUG) { + listAttrs(p11lib, session, prv) + listAttrs(p11lib, session, pub) + } + + return ski, pubGoKey, nil +} + +func signECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { + p11lib := ctx + session := getSession() + defer returnSession(session) + + privateKey, err := findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + if err != nil { + return nil, nil, fmt.Errorf("Private key not found [%s]\n", err) + } + + err = p11lib.SignInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, *privateKey) + if err != nil { + return nil, nil, fmt.Errorf("Sign-initialize failed [%s]\n", err) + } + + var sig []byte + + sig, err = p11lib.Sign(session, msg) + if err != nil { + return nil, nil, fmt.Errorf("P11: sign failed [%s]\n", err) + } + + R = new(big.Int) + S = new(big.Int) + R.SetBytes(sig[0 : len(sig)/2]) + S.SetBytes(sig[len(sig)/2:]) + + return R, S, nil +} + +func verifyECDSA(ski []byte, msg []byte, R, S *big.Int) (valid bool, err error) { + p11lib := ctx + session := getSession() + defer returnSession(session) + + logger.Debugf("Verify ECDSA\n") + + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, isPublicKey) + if err != nil { + return false, fmt.Errorf("Public key not found [%s]\n", err) + } + + sig := append(R.Bytes(), S.Bytes()...) + err = p11lib.VerifyInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, + *publicKey) + if err != nil { + return false, fmt.Errorf("PKCS11: Verify-initialize [%s]\n", err) + } + err = p11lib.Verify(session, msg, sig) + if err == pkcs11.Error(pkcs11.CKR_SIGNATURE_INVALID) { + return false, nil + } + if err != nil { + return false, fmt.Errorf("PKCS11: Verify failed [%s]\n", err) + } + + return true, nil +} + +func importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bool, isPrivate bool) (ski []byte, err error) { + p11lib := ctx + session := getSession() + defer returnSession(session) + + id := nextIDCtr() + + marshaledOID, err := asn1.Marshal(curve) + if err != nil { + return nil, fmt.Errorf("Could not marshal OID [%s]", err.Error()) + } + + var keyTemplate []*pkcs11.Attribute + if isPrivate == isPublicKey { + logger.Debug("Importing Public EC Key") + publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) + + hash := sha256.Sum256(ecPt) + ski = hash[:] + ski[0] = 1 + + if probablySoftHSM { + ecPt = append([]byte{0x04, byte(len(ecPt))}, ecPt...) + } + + keyTemplate = []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), + pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, ecPt), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + } + } else { // isPrivateKey + ski, err = importECKey(curve, nil, ecPt, ephemeral, isPublicKey) + if err != nil { + return nil, fmt.Errorf("Failed importing private EC Key [%s]\n", err) + } + + logger.Debugf("Importing Private EC Key [%d]\n%s\n", len(privKey)*8, hex.Dump(privKey)) + prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16)) + keyTemplate = []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), + + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), + pkcs11.NewAttribute(pkcs11.CKR_ATTRIBUTE_SENSITIVE, false), + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true), + pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), + } + } + + keyHandle, err := p11lib.CreateObject(session, keyTemplate) + if err != nil { + return nil, fmt.Errorf("P11: keypair generate failed [%s]\n", err) + } + + if logger.IsEnabledFor(logging.DEBUG) { + listAttrs(p11lib, session, keyHandle) + } + + return ski, nil +} + +const ( + isPrivateKey = true + isPublicKey = false +) + +func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, isPrivate bool) (*pkcs11.ObjectHandle, error) { + ktype := pkcs11.CKO_PUBLIC_KEY + if isPrivate == isPrivateKey { + ktype = pkcs11.CKO_PRIVATE_KEY + } + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype), + pkcs11.NewAttribute(pkcs11.CKA_ID, ski), + } + if err := mod.FindObjectsInit(session, template); err != nil { + return nil, err + } + + // single session instance, assume one hit only + objs, _, err := mod.FindObjects(session, 1) + if err != nil { + return nil, err + } + if err = mod.FindObjectsFinal(session); err != nil { + return nil, err + } + + if len(objs) == 0 { + return nil, fmt.Errorf("Key not found [%s]", hex.Dump(ski)) + } + + return &objs[0], nil +} + +// Fairly straightforward EC-point query, other than opencryptoki +// mis-reporting length, including the 04 Tag of the field following +// the SPKI in EP11-returned MACed publickeys: +// +// attr type 385/x181, length 66 b -- SHOULD be 1+64 +// EC point: +// 00000000 04 ce 30 31 6d 5a fd d3 53 2d 54 9a 27 54 d8 7c +// 00000010 d9 80 35 91 09 2d 6f 06 5a 8e e3 cb c0 01 b7 c9 +// 00000020 13 5d 70 d4 e5 62 f2 1b 10 93 f7 d5 77 41 ba 9d +// 00000030 93 3e 18 3e 00 c6 0a 0e d2 36 cc 7f be 50 16 ef +// 00000040 06 04 +// +// cf. correct field: +// 0 89: SEQUENCE { +// 2 19: SEQUENCE { +// 4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) +// 13 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) +// : } +// 23 66: BIT STRING +// : 04 CE 30 31 6D 5A FD D3 53 2D 54 9A 27 54 D8 7C +// : D9 80 35 91 09 2D 6F 06 5A 8E E3 CB C0 01 B7 C9 +// : 13 5D 70 D4 E5 62 F2 1B 10 93 F7 D5 77 41 BA 9D +// : 93 3E 18 3E 00 C6 0A 0E D2 36 CC 7F BE 50 16 EF +// : 06 +// : } +// +// as a short-term workaround, remove the trailing byte if: +// - receiving an even number of bytes == 2*prime-coordinate +2 bytes +// - starting byte is 04: uncompressed EC point +// - trailing byte is 04: assume it belongs to the next OCTET STRING +// +// [mis-parsing encountered with v3.5.1, 2016-10-22] +// +// SoftHSM reports extra two bytes before the uncrompressed point +// 0x04 || +// VV< Actual start of point +// 00000000 04 41 04 6c c8 57 32 13 02 12 6a 19 23 1d 5a 64 |.A.l.W2...j.#.Zd| +// 00000010 33 0c eb 75 4d e8 99 22 92 35 96 b2 39 58 14 1e |3..uM..".5..9X..| +// 00000020 19 de ef 32 46 50 68 02 24 62 36 db ed b1 84 7b |...2FPh.$b6....{| +// 00000030 93 d8 40 c3 d5 a6 b7 38 16 d2 35 0a 53 11 f9 51 |..@....8..5.S..Q| +// 00000040 fc a7 16 |...| +func ecPoint(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, key pkcs11.ObjectHandle) (ecpt, oid []byte, err error) { + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), + pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), + } + + attr, err := p11lib.GetAttributeValue(session, key, template) + if err != nil { + return nil, nil, fmt.Errorf("PKCS11: get(EC point) [%s]\n", err) + } + + for _, a := range attr { + if a.Type == pkcs11.CKA_EC_POINT { + logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + + // workarounds, see above + if (0 == (len(a.Value) % 2)) && + (byte(0x04) == a.Value[0]) && + (byte(0x04) == a.Value[len(a.Value)-1]) { + logger.Debugf("Detected opencryptoki bug, trimming trailing 0x04") + ecpt = a.Value[0 : len(a.Value)-1] // Trim trailing 0x04 + } else if byte(0x04) == a.Value[0] && byte(0x04) == a.Value[2] { + logger.Debugf("Detected SoftHSM bug, trimming leading 0x04 0xXX") + ecpt = a.Value[2:len(a.Value)] + } else { + ecpt = a.Value + } + } else if a.Type == pkcs11.CKA_EC_PARAMS { + logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + + oid = a.Value + } + } + if oid == nil || ecpt == nil { + return nil, nil, fmt.Errorf("CKA_EC_POINT not found, perhaps not an EC Key?") + } + + return ecpt, oid, nil +} + +func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.ObjectHandle) { + var cktype, ckclass uint + var ckaid, cklabel, privKey []byte + + if p11lib == nil { + return + } + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, ckclass), + pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, cktype), + pkcs11.NewAttribute(pkcs11.CKA_ID, ckaid), + pkcs11.NewAttribute(pkcs11.CKA_LABEL, cklabel), + pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), + } + + // certain errors are tolerated, if value is missing + attr, err := p11lib.GetAttributeValue(session, obj, template) + if err != nil { + logger.Warningf("P11: get(attrlist) [%s]\n", err) + } + + for _, a := range attr { + // Would be friendlier if the bindings provided a way convert Attribute hex to string + logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + } +} + +func getSecretValue(ski []byte) []byte { + p11lib := ctx + session := getSession() + defer returnSession(session) + + keyHandle, err := findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + + var privKey []byte + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), + } + + // certain errors are tolerated, if value is missing + attr, err := p11lib.GetAttributeValue(session, *keyHandle, template) + if err != nil { + logger.Warningf("P11: get(attrlist) [%s]\n", err) + } + + for _, a := range attr { + // Would be friendlier if the bindings provided a way convert Attribute hex to string + logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) + return a.Value + } + logger.Warningf("No Key Value found!", err) + return nil +} + +var ( + bigone = new(big.Int).SetInt64(1) + id_ctr = new(big.Int) + id_mutex sync.Mutex +) + +func nextIDCtr() *big.Int { + id_mutex.Lock() + id_ctr = new(big.Int).Add(id_ctr, bigone) + id_mutex.Unlock() + return id_ctr +} diff --git a/bccsp/pkcs11/pkcs11_test.go b/bccsp/pkcs11/pkcs11_test.go index 8631efead82..deff6289f8f 100644 --- a/bccsp/pkcs11/pkcs11_test.go +++ b/bccsp/pkcs11/pkcs11_test.go @@ -16,7 +16,14 @@ limitations under the License. package pkcs11 import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/asn1" + "encoding/hex" "testing" + + "github.com/hyperledger/fabric/bccsp" ) func TestPKCS11GetSession(t *testing.T) { @@ -27,3 +34,202 @@ func TestPKCS11GetSession(t *testing.T) { session := getSession() defer returnSession(session) } + +func TestPKCS11ECKeySignVerify(t *testing.T) { + if !enablePKCS11tests { + t.SkipNow() + } + + msg1 := []byte("This is my very authentic message") + msg2 := []byte("This is my very unauthentic message") + hash1, _ := currentBCCSP.Hash(msg1, &bccsp.SHAOpts{}) + hash2, _ := currentBCCSP.Hash(msg2, &bccsp.SHAOpts{}) + + var oid asn1.ObjectIdentifier + if currentTestConfig.securityLevel == 256 { + oid = oidNamedCurveP256 + } else if currentTestConfig.securityLevel == 384 { + oid = oidNamedCurveP384 + } + + key, pubKey, err := generateECKey(oid, true) + if err != nil { + t.Fatal("Failed generating Key [%s]", err) + } + + R, S, err := signECDSA(key, hash1) + + if err != nil { + t.Fatal("Failed signing message [%s]", err) + } + + pass, err := verifyECDSA(key, hash1, R, S) + if err != nil { + t.Fatal("Error verifying message 1 [%s]", err) + } + if pass == false { + t.Fatal("Signature should match!") + } + + pass = ecdsa.Verify(pubKey, hash1, R, S) + if pass == false { + t.Fatal("Signature should match with software verification!") + } + + pass, err = verifyECDSA(key, hash2, R, S) + if err != nil { + t.Fatal("Error verifying message 2 [%s]", err) + } + + if pass != false { + t.Fatal("Signature should not match!") + } + + pass = ecdsa.Verify(pubKey, hash2, R, S) + if pass != false { + t.Fatal("Signature should not match with software verification!") + } +} + +func TestPKCS11ECKeyImportSignVerify(t *testing.T) { + if !enablePKCS11tests { + t.SkipNow() + } + + msg1 := []byte("This is my very authentic message") + msg2 := []byte("This is my very unauthentic message") + hash1, _ := currentBCCSP.Hash(msg1, &bccsp.SHAOpts{}) + hash2, err := currentBCCSP.Hash(msg2, &bccsp.SHAOpts{}) + + var oid asn1.ObjectIdentifier + var key *ecdsa.PrivateKey + if currentTestConfig.securityLevel == 256 { + oid = oidNamedCurveP256 + key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("Failed generating ECDSA key [%s]", err) + } + } else if currentTestConfig.securityLevel == 384 { + oid = oidNamedCurveP384 + key, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + if err != nil { + t.Fatalf("Failed generating ECDSA key [%s]", err) + } + } + + ecPt := elliptic.Marshal(key.Curve, key.X, key.Y) + ski, err := importECKey(oid, key.D.Bytes(), ecPt, false, isPrivateKey) + if err != nil { + t.Fatalf("Failed getting importing EC Public Key [%s]", err) + } + + R, S, err := signECDSA(ski, hash1) + + if err != nil { + t.Fatal("Failed signing message [%s]", err) + } + + pass, err := verifyECDSA(ski, hash1, R, S) + if err != nil { + t.Fatalf("Error verifying message 1 [%s]\n%s\n\n%s", err, hex.Dump(R.Bytes()), hex.Dump(S.Bytes())) + } + if pass == false { + t.Fatalf("Signature should match!\n%s\n\n%s", hex.Dump(R.Bytes()), hex.Dump(S.Bytes())) + } + + pass = ecdsa.Verify(&key.PublicKey, hash1, R, S) + if pass == false { + t.Fatal("Signature should match with software verification!") + } + + pass, err = verifyECDSA(ski, hash2, R, S) + if err != nil { + t.Fatal("Error verifying message 2 [%s]", err) + } + + if pass != false { + t.Fatal("Signature should not match!") + } + + pass = ecdsa.Verify(&key.PublicKey, hash2, R, S) + if pass != false { + t.Fatal("Signature should not match with software verification!") + } +} + +func TestPKCS11ECKeyExport(t *testing.T) { + if !enablePKCS11tests { + t.SkipNow() + } + + msg1 := []byte("This is my very authentic message") + msg2 := []byte("This is my very unauthentic message") + hash1, _ := currentBCCSP.Hash(msg1, &bccsp.SHAOpts{}) + hash2, err := currentBCCSP.Hash(msg2, &bccsp.SHAOpts{}) + + var oid asn1.ObjectIdentifier + if currentTestConfig.securityLevel == 256 { + oid = oidNamedCurveP256 + } else if currentTestConfig.securityLevel == 384 { + oid = oidNamedCurveP384 + } + + key, pubKey, err := generateECKey(oid, false) + if err != nil { + t.Fatal("Failed generating Key [%s]", err) + } + + secret := getSecretValue(key) + x, y := pubKey.ScalarBaseMult(secret) + + if 0 != x.Cmp(pubKey.X) { + t.Fatal("X does not match") + } + + if 0 != y.Cmp(pubKey.Y) { + t.Fatal("Y does not match") + } + + ecPt := elliptic.Marshal(pubKey.Curve, x, y) + key2, err := importECKey(oid, secret, ecPt, false, isPrivateKey) + + R, S, err := signECDSA(key2, hash1) + if err != nil { + t.Fatalf("Failed signing message [%s]", err) + } + + pass, err := verifyECDSA(key2, hash1, R, S) + if err != nil { + t.Fatalf("Error verifying message 1 [%s]", err) + } + if pass == false { + t.Fatal("Signature should match! [1]") + } + + pass, err = verifyECDSA(key, hash1, R, S) + if err != nil { + t.Fatalf("Error verifying message 2 [%s]", err) + } + if pass == false { + t.Fatal("Signature should match! [2]") + } + + pass = ecdsa.Verify(pubKey, hash1, R, S) + if pass == false { + t.Fatal("Signature should match with software verification!") + } + + pass, err = verifyECDSA(key, hash2, R, S) + if err != nil { + t.Fatal("Error verifying message 3 [%s]", err) + } + + if pass != false { + t.Fatal("Signature should not match! [3]") + } + + pass = ecdsa.Verify(pubKey, hash2, R, S) + if pass != false { + t.Fatal("Signature should not match with software verification!") + } +} From fd0c5c481aad942e2a37836a6f30e7601444c7b6 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Tue, 24 Jan 2017 19:44:09 -0500 Subject: [PATCH 2/2] [FAB-1648] PKCS11 BCCSP now calls PKCS11 functions For all ECDSA operations, replace current PKCS11 CSP software calls with PKCS11 operations Note: KeyImport and KeyDerivation should not be allowed by a properly configured crypto card, but it does work with SoftHSM and is legal PKCS11 Change-Id: I0087c86cda048bf5f8df965580bef8896984e897 Signed-off-by: Volodymyr Paprotski --- bccsp/pkcs11/conf.go | 12 +-- bccsp/pkcs11/ecdsa.go | 20 ++-- bccsp/pkcs11/ecdsakey.go | 41 ++----- bccsp/pkcs11/fileks.go | 33 +----- bccsp/pkcs11/fileks_test.go | 10 -- bccsp/pkcs11/impl.go | 206 ++++++++++++++++++++++++------------ bccsp/pkcs11/impl_test.go | 77 +++++++++----- 7 files changed, 218 insertions(+), 181 deletions(-) diff --git a/bccsp/pkcs11/conf.go b/bccsp/pkcs11/conf.go index d11230de865..556a97e8cb0 100644 --- a/bccsp/pkcs11/conf.go +++ b/bccsp/pkcs11/conf.go @@ -16,9 +16,9 @@ limitations under the License. package pkcs11 import ( - "crypto/elliptic" "crypto/sha256" "crypto/sha512" + "encoding/asn1" "fmt" "hash" @@ -30,7 +30,7 @@ type config struct { securityLevel int hashFamily string - ellipticCurve elliptic.Curve + ellipticCurve asn1.ObjectIdentifier hashFunction func() hash.Hash aesBitLength int rsaBitLength int @@ -51,12 +51,12 @@ func (conf *config) setSecurityLevel(securityLevel int, hashFamily string) (err func (conf *config) setSecurityLevelSHA2(level int) (err error) { switch level { case 256: - conf.ellipticCurve = elliptic.P256() + conf.ellipticCurve = oidNamedCurveP256 conf.hashFunction = sha256.New conf.rsaBitLength = 2048 conf.aesBitLength = 32 case 384: - conf.ellipticCurve = elliptic.P384() + conf.ellipticCurve = oidNamedCurveP384 conf.hashFunction = sha512.New384 conf.rsaBitLength = 3072 conf.aesBitLength = 32 @@ -69,12 +69,12 @@ func (conf *config) setSecurityLevelSHA2(level int) (err error) { func (conf *config) setSecurityLevelSHA3(level int) (err error) { switch level { case 256: - conf.ellipticCurve = elliptic.P256() + conf.ellipticCurve = oidNamedCurveP256 conf.hashFunction = sha3.New256 conf.rsaBitLength = 2048 conf.aesBitLength = 32 case 384: - conf.ellipticCurve = elliptic.P384() + conf.ellipticCurve = oidNamedCurveP384 conf.hashFunction = sha3.New384 conf.rsaBitLength = 3072 conf.aesBitLength = 32 diff --git a/bccsp/pkcs11/ecdsa.go b/bccsp/pkcs11/ecdsa.go index e185aee1e47..fe0c7038466 100644 --- a/bccsp/pkcs11/ecdsa.go +++ b/bccsp/pkcs11/ecdsa.go @@ -16,9 +16,7 @@ limitations under the License. package pkcs11 import ( - "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" "encoding/asn1" "errors" "fmt" @@ -74,38 +72,38 @@ func unmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) { return sig.R, sig.S, nil } -func (csp *impl) signECDSA(k *ecdsa.PrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { - r, s, err := ecdsa.Sign(rand.Reader, k, digest) +func (csp *impl) signECDSA(k ecdsaPrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { + r, s, err := signECDSA(k.ski, digest) if err != nil { return nil, err } // check for low-S - halfOrder, ok := curveHalfOrders[k.Curve] + halfOrder, ok := curveHalfOrders[k.pub.pub.Curve] if !ok { - return nil, fmt.Errorf("Curve not recognized [%s]", k.Curve) + return nil, fmt.Errorf("Curve not recognized [%s]", k.pub.pub.Curve) } // is s > halfOrder Then if s.Cmp(halfOrder) == 1 { // Set s to N - s that will be then in the lower part of signature space // less or equal to half order - s.Sub(k.Params().N, s) + s.Sub(k.pub.pub.Params().N, s) } return marshalECDSASignature(r, s) } -func (csp *impl) verifyECDSA(k *ecdsa.PublicKey, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { +func (csp *impl) verifyECDSA(k ecdsaPublicKey, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { r, s, err := unmarshalECDSASignature(signature) if err != nil { return false, fmt.Errorf("Failed unmashalling signature [%s]", err) } // check for low-S - halfOrder, ok := curveHalfOrders[k.Curve] + halfOrder, ok := curveHalfOrders[k.pub.Curve] if !ok { - return false, fmt.Errorf("Curve not recognized [%s]", k.Curve) + return false, fmt.Errorf("Curve not recognized [%s]", k.pub.Curve) } // If s > halfOrder Then @@ -113,5 +111,5 @@ func (csp *impl) verifyECDSA(k *ecdsa.PublicKey, signature, digest []byte, opts return false, fmt.Errorf("Invalid S. Must be smaller than half the order [%s][%s].", s, halfOrder) } - return ecdsa.Verify(k, digest, r, s), nil + return verifyECDSA(k.ski, digest, r, s) } diff --git a/bccsp/pkcs11/ecdsakey.go b/bccsp/pkcs11/ecdsakey.go index 3a05fb8ee5f..8eb098d04a9 100644 --- a/bccsp/pkcs11/ecdsakey.go +++ b/bccsp/pkcs11/ecdsakey.go @@ -18,19 +18,15 @@ package pkcs11 import ( "crypto/ecdsa" "crypto/x509" - "fmt" - - "crypto/sha256" - "errors" - - "crypto/elliptic" + "fmt" "github.com/hyperledger/fabric/bccsp" ) type ecdsaPrivateKey struct { - privKey *ecdsa.PrivateKey + ski []byte + pub ecdsaPublicKey } // Bytes converts this key to its byte representation, @@ -41,17 +37,7 @@ func (k *ecdsaPrivateKey) Bytes() (raw []byte, err error) { // SKI returns the subject key identifier of this key. func (k *ecdsaPrivateKey) SKI() (ski []byte) { - if k.privKey == nil { - return nil - } - - // Marshall the public key - raw := elliptic.Marshal(k.privKey.Curve, k.privKey.PublicKey.X, k.privKey.PublicKey.Y) - - // Hash it - hash := sha256.New() - hash.Write(raw) - return hash.Sum(nil) + return k.ski } // Symmetric returns true if this key is a symmetric key, @@ -69,17 +55,18 @@ func (k *ecdsaPrivateKey) Private() bool { // PublicKey returns the corresponding public key part of an asymmetric public/private key pair. // This method returns an error in symmetric key schemes. func (k *ecdsaPrivateKey) PublicKey() (bccsp.Key, error) { - return &ecdsaPublicKey{&k.privKey.PublicKey}, nil + return &k.pub, nil } type ecdsaPublicKey struct { - pubKey *ecdsa.PublicKey + ski []byte + pub *ecdsa.PublicKey } // Bytes converts this key to its byte representation, // if this operation is allowed. func (k *ecdsaPublicKey) Bytes() (raw []byte, err error) { - raw, err = x509.MarshalPKIXPublicKey(k.pubKey) + raw, err = x509.MarshalPKIXPublicKey(k.pub) if err != nil { return nil, fmt.Errorf("Failed marshalling key [%s]", err) } @@ -88,17 +75,7 @@ func (k *ecdsaPublicKey) Bytes() (raw []byte, err error) { // SKI returns the subject key identifier of this key. func (k *ecdsaPublicKey) SKI() (ski []byte) { - if k.pubKey == nil { - return nil - } - - // Marshall the public key - raw := elliptic.Marshal(k.pubKey.Curve, k.pubKey.X, k.pubKey.Y) - - // Hash it - hash := sha256.New() - hash.Write(raw) - return hash.Sum(nil) + return k.ski } // Symmetric returns true if this key is a symmetric key, diff --git a/bccsp/pkcs11/fileks.go b/bccsp/pkcs11/fileks.go index 142d18468f0..ff7f98b4d55 100644 --- a/bccsp/pkcs11/fileks.go +++ b/bccsp/pkcs11/fileks.go @@ -16,18 +16,15 @@ limitations under the License. package pkcs11 import ( - "io/ioutil" - "os" - "sync" - - "errors" - "strings" - - "crypto/ecdsa" "crypto/rsa" "encoding/hex" + "errors" "fmt" + "io/ioutil" + "os" "path/filepath" + "strings" + "sync" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/utils" @@ -127,8 +124,6 @@ func (ks *FileBasedKeyStore) GetKey(ski []byte) (k bccsp.Key, err error) { } switch key.(type) { - case *ecdsa.PrivateKey: - return &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)}, nil case *rsa.PrivateKey: return &rsaPrivateKey{key.(*rsa.PrivateKey)}, nil default: @@ -142,8 +137,6 @@ func (ks *FileBasedKeyStore) GetKey(ski []byte) (k bccsp.Key, err error) { } switch key.(type) { - case *ecdsa.PublicKey: - return &ecdsaPublicKey{key.(*ecdsa.PublicKey)}, nil case *rsa.PublicKey: return &rsaPublicKey{key.(*rsa.PublicKey)}, nil default: @@ -165,22 +158,6 @@ func (ks *FileBasedKeyStore) StoreKey(k bccsp.Key) (err error) { return errors.New("Invalid key. It must be different from nil.") } switch k.(type) { - case *ecdsaPrivateKey: - kk := k.(*ecdsaPrivateKey) - - err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey) - if err != nil { - return fmt.Errorf("Failed storing ECDSA private key [%s]", err) - } - - case *ecdsaPublicKey: - kk := k.(*ecdsaPublicKey) - - err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey) - if err != nil { - return fmt.Errorf("Failed storing ECDSA public key [%s]", err) - } - case *rsaPrivateKey: kk := k.(*rsaPrivateKey) diff --git a/bccsp/pkcs11/fileks_test.go b/bccsp/pkcs11/fileks_test.go index 59ec0098f8f..2e1990852c8 100644 --- a/bccsp/pkcs11/fileks_test.go +++ b/bccsp/pkcs11/fileks_test.go @@ -34,16 +34,6 @@ func TestInvalidStoreKey(t *testing.T) { t.Fatal("Error should be different from nil in this case") } - err = ks.StoreKey(&ecdsaPrivateKey{nil}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - - err = ks.StoreKey(&ecdsaPublicKey{nil}) - if err == nil { - t.Fatal("Error should be different from nil in this case") - } - err = ks.StoreKey(&rsaPublicKey{nil}) if err == nil { t.Fatal("Error should be different from nil in this case") diff --git a/bccsp/pkcs11/impl.go b/bccsp/pkcs11/impl.go index bbd4415bb58..0f29c8f58e8 100644 --- a/bccsp/pkcs11/impl.go +++ b/bccsp/pkcs11/impl.go @@ -17,22 +17,17 @@ package pkcs11 import ( "crypto/ecdsa" + "crypto/elliptic" + "crypto/hmac" "crypto/rand" - "errors" - "fmt" - "math/big" - "crypto/rsa" - - "hash" - - "crypto/x509" - - "crypto/hmac" - - "crypto/elliptic" "crypto/sha256" "crypto/sha512" + "crypto/x509" + "errors" + "fmt" + "hash" + "math/big" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/utils" @@ -41,7 +36,7 @@ import ( ) var ( - logger = logging.MustGetLogger("SW_BCCSP") + logger = logging.MustGetLogger("PKCS11_BCCSP") ) // NewDefaultSecurityLevel returns a new instance of the software-based BCCSP @@ -92,31 +87,35 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { return nil, errors.New("Invalid Opts parameter. It must not be nil.") } + pkcs11Stored := false + // Parse algorithm switch opts.(type) { case *bccsp.ECDSAKeyGenOpts: - lowLevelKey, err := ecdsa.GenerateKey(csp.conf.ellipticCurve, rand.Reader) + ski, pub, err := generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA key [%s]", err) } - - k = &ecdsaPrivateKey{lowLevelKey} + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + pkcs11Stored = true case *bccsp.ECDSAP256KeyGenOpts: - lowLevelKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + ski, pub, err := generateECKey(oidNamedCurveP256, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA P256 key [%s]", err) } - k = &ecdsaPrivateKey{lowLevelKey} + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + pkcs11Stored = true case *bccsp.ECDSAP384KeyGenOpts: - lowLevelKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + ski, pub, err := generateECKey(oidNamedCurveP384, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA P384 key [%s]", err) } - k = &ecdsaPrivateKey{lowLevelKey} + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} + pkcs11Stored = true case *bccsp.AESKeyGenOpts: lowLevelKey, err := GetRandomBytes(csp.conf.aesBitLength) @@ -203,8 +202,8 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { return nil, fmt.Errorf("Unrecognized KeyGenOpts provided [%s]", opts.Algorithm()) } - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { + // If the key is not Ephemeral, store it. EC Keys now in HSM, no need to store + if !pkcs11Stored && !opts.Ephemeral() { // Store the key err = csp.ks.StoreKey(k) if err != nil { @@ -225,6 +224,63 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e // Derive key switch k.(type) { + case *ecdsaPublicKey: + // Validate opts + if opts == nil { + return nil, errors.New("Invalid Opts parameter. It must not be nil.") + } + + ecdsaK := k.(*ecdsaPublicKey) + + switch opts.(type) { + + // Re-randomized an ECDSA public key + case *bccsp.ECDSAReRandKeyOpts: + pubKey := ecdsaK.pub + reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + tempSK := &ecdsa.PublicKey{ + Curve: pubKey.Curve, + X: new(big.Int), + Y: new(big.Int), + } + + var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) + var one = new(big.Int).SetInt64(1) + n := new(big.Int).Sub(pubKey.Params().N, one) + k.Mod(k, n) + k.Add(k, one) + + // Compute temporary public key + tempX, tempY := pubKey.ScalarBaseMult(k.Bytes()) + tempSK.X, tempSK.Y = tempSK.Add( + pubKey.X, pubKey.Y, + tempX, tempY, + ) + + // Verify temporary public key is a valid point on the reference curve + isOn := tempSK.Curve.IsOnCurve(tempSK.X, tempSK.Y) + if !isOn { + return nil, errors.New("Failed temporary public key IsOnCurve check.") + } + + ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) + oid, ok := oidFromNamedCurve(tempSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } + + ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) + } + reRandomizedKey := &ecdsaPublicKey{ski, tempSK} + + return reRandomizedKey, nil + + default: + return nil, fmt.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) + + } case *ecdsaPrivateKey: // Validate opts if opts == nil { @@ -238,9 +294,16 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e // Re-randomized an ECDSA private key case *bccsp.ECDSAReRandKeyOpts: reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) + pubKey := ecdsaK.pub.pub + secret := getSecretValue(ecdsaK.ski) + if secret == nil { + return nil, errors.New("Could not obtain EC Private Key") + } + bigSecret := new(big.Int).SetBytes(secret) + tempSK := &ecdsa.PrivateKey{ PublicKey: ecdsa.PublicKey{ - Curve: ecdsaK.privKey.Curve, + Curve: pubKey.Curve, X: new(big.Int), Y: new(big.Int), }, @@ -249,37 +312,33 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) var one = new(big.Int).SetInt64(1) - n := new(big.Int).Sub(ecdsaK.privKey.Params().N, one) + n := new(big.Int).Sub(pubKey.Params().N, one) k.Mod(k, n) k.Add(k, one) - tempSK.D.Add(ecdsaK.privKey.D, k) - tempSK.D.Mod(tempSK.D, ecdsaK.privKey.PublicKey.Params().N) + tempSK.D.Add(bigSecret, k) + tempSK.D.Mod(tempSK.D, pubKey.Params().N) // Compute temporary public key - tempX, tempY := ecdsaK.privKey.PublicKey.ScalarBaseMult(k.Bytes()) - tempSK.PublicKey.X, tempSK.PublicKey.Y = - tempSK.PublicKey.Add( - ecdsaK.privKey.PublicKey.X, ecdsaK.privKey.PublicKey.Y, - tempX, tempY, - ) + tempSK.PublicKey.X, tempSK.PublicKey.Y = pubKey.ScalarBaseMult(tempSK.D.Bytes()) // Verify temporary public key is a valid point on the reference curve isOn := tempSK.Curve.IsOnCurve(tempSK.PublicKey.X, tempSK.PublicKey.Y) if !isOn { - return nil, errors.New("Failed temporary public key IsOnCurve check. This is an foreign key.") + return nil, errors.New("Failed temporary public key IsOnCurve check.") } - reRandomizedKey := &ecdsaPrivateKey{tempSK} + ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) + oid, ok := oidFromNamedCurve(tempSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(reRandomizedKey) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } + ski, err := importECKey(oid, tempSK.D.Bytes(), ecPt, opts.Ephemeral(), isPrivateKey) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) } + reRandomizedKey := &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &tempSK.PublicKey}} return reRandomizedKey, nil @@ -423,17 +482,18 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") } - k = &ecdsaPublicKey{ecdsaPK} + ecPt := elliptic.Marshal(ecdsaPK.Curve, ecdsaPK.X, ecdsaPK.Y) + oid, ok := oidFromNamedCurve(ecdsaPK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } + ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) } + k = &ecdsaPublicKey{ski, ecdsaPK} return k, nil case *bccsp.ECDSAPrivateKeyImportOpts: @@ -456,17 +516,18 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") } - k = &ecdsaPrivateKey{ecdsaSK} + ecPt := elliptic.Marshal(ecdsaSK.Curve, ecdsaSK.X, ecdsaSK.Y) + oid, ok := oidFromNamedCurve(ecdsaSK.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } + ski, err := importECKey(oid, ecdsaSK.D.Bytes(), ecPt, opts.Ephemeral(), isPrivateKey) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Private Key [%s]", err) } + k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &ecdsaSK.PublicKey}} return k, nil case *bccsp.ECDSAGoPublicKeyImportOpts: @@ -475,17 +536,18 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("[ECDSAGoPublicKeyImportOpts] Invalid raw material. Expected *ecdsa.PublicKey.") } - k = &ecdsaPublicKey{lowLevelKey} + ecPt := elliptic.Marshal(lowLevelKey.Curve, lowLevelKey.X, lowLevelKey.Y) + oid, ok := oidFromNamedCurve(lowLevelKey.Curve) + if !ok { + return nil, errors.New("Do not know OID for this Curve.") + } - // If the key is not Ephemeral, store it. - if !opts.Ephemeral() { - // Store the key - err = csp.ks.StoreKey(k) - if err != nil { - return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) - } + ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) } + k = &ecdsaPublicKey{ski, lowLevelKey} return k, nil case *bccsp.RSAGoPublicKeyImportOpts: @@ -532,6 +594,14 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // GetKey returns the key this CSP associates to // the Subject Key Identifier ski. func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { + pubKey, isPriv, err := getECKey(ski) + if err == nil { + if isPriv { + return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil + } else { + return &ecdsaPublicKey{ski, pubKey}, nil + } + } return csp.ks.GetKey(ski) } @@ -602,7 +672,7 @@ func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signat // Check key type switch k.(type) { case *ecdsaPrivateKey: - return csp.signECDSA(k.(*ecdsaPrivateKey).privKey, digest, opts) + return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts) case *rsaPrivateKey: if opts == nil { return nil, errors.New("Invalid options. Nil.") @@ -630,9 +700,9 @@ func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Signer // Check key type switch k.(type) { case *ecdsaPrivateKey: - return csp.verifyECDSA(&(k.(*ecdsaPrivateKey).privKey.PublicKey), signature, digest, opts) + return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts) case *ecdsaPublicKey: - return csp.verifyECDSA(k.(*ecdsaPublicKey).pubKey, signature, digest, opts) + return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts) case *rsaPrivateKey: if opts == nil { return false, errors.New("Invalid options. It must not be nil.") diff --git a/bccsp/pkcs11/impl_test.go b/bccsp/pkcs11/impl_test.go index a07b8518b28..133def6a4f1 100644 --- a/bccsp/pkcs11/impl_test.go +++ b/bccsp/pkcs11/impl_test.go @@ -37,6 +37,7 @@ import ( "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/signer" + "github.com/hyperledger/fabric/bccsp/sw" "github.com/hyperledger/fabric/bccsp/utils" "golang.org/x/crypto/sha3" ) @@ -44,6 +45,7 @@ import ( var ( currentKS bccsp.KeyStore currentBCCSP bccsp.BCCSP + currentSWBCCSP bccsp.BCCSP currentTestConfig testConfig ) @@ -86,6 +88,12 @@ func TestMain(m *testing.M) { fmt.Printf("Failed initiliazing BCCSP at [%d, %s]: [%s]", config.securityLevel, config.hashFamily, err) os.Exit(-1) } + + currentSWBCCSP, err = sw.New(config.securityLevel, config.hashFamily, &sw.DummyKeyStore{}) + if err != nil { + fmt.Printf("Failed initiliazing BCCSP at [%d, %s]: [%s]", config.securityLevel, config.hashFamily, err) + os.Exit(-1) + } ret := m.Run() if ret != 0 { fmt.Printf("Failed testing at [%d, %s]", config.securityLevel, config.hashFamily) @@ -171,16 +179,10 @@ func TestKeyGenECDSAOpts(t *testing.T) { t.Fatal("Failed generating ECDSA P256 key. Key should be asymmetric") } - ecdsaKey := k.(*ecdsaPrivateKey).privKey - if !elliptic.P256().IsOnCurve(ecdsaKey.X, ecdsaKey.Y) { - t.Fatal("P256 generated key in invalid. The public key must be on the P256 curve.") - } - if elliptic.P256() != ecdsaKey.Curve { + ecdsaKey := k.(*ecdsaPrivateKey).pub + if elliptic.P256() != ecdsaKey.pub.Curve { t.Fatal("P256 generated key in invalid. The curve must be P256.") } - if ecdsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("P256 generated key in invalid. Private key must be different from 0.") - } // Curve P384 k, err = currentBCCSP.KeyGen(&bccsp.ECDSAP384KeyGenOpts{Temporary: false}) @@ -197,17 +199,10 @@ func TestKeyGenECDSAOpts(t *testing.T) { t.Fatal("Failed generating ECDSA P384 key. Key should be asymmetric") } - ecdsaKey = k.(*ecdsaPrivateKey).privKey - if !elliptic.P384().IsOnCurve(ecdsaKey.X, ecdsaKey.Y) { - t.Fatal("P256 generated key in invalid. The public key must be on the P384 curve.") - } - if elliptic.P384() != ecdsaKey.Curve { + ecdsaKey = k.(*ecdsaPrivateKey).pub + if elliptic.P384() != ecdsaKey.pub.Curve { t.Fatal("P256 generated key in invalid. The curve must be P384.") } - if ecdsaKey.D.Cmp(big.NewInt(0)) == 0 { - t.Fatal("P256 generated key in invalid. Private key must be different from 0.") - } - } func TestKeyGenRSAOpts(t *testing.T) { @@ -595,20 +590,44 @@ func TestECDSAKeyReRand(t *testing.T) { if err != nil { t.Fatalf("Failed generating ECDSA key [%s]", err) } + if k == nil { + t.Fatal("Failed re-randomizing ECDSA key. Re-randomized Key must be different from nil") + } reRandomizedKey, err := currentBCCSP.KeyDeriv(k, &bccsp.ECDSAReRandKeyOpts{Temporary: false, Expansion: []byte{1}}) if err != nil { t.Fatalf("Failed re-randomizing ECDSA key [%s]", err) } - if k == nil { - t.Fatal("Failed re-randomizing ECDSA key. Re-randomized Key must be different from nil") - } if !reRandomizedKey.Private() { t.Fatal("Failed re-randomizing ECDSA key. Re-randomized Key should be private") } if reRandomizedKey.Symmetric() { t.Fatal("Failed re-randomizing ECDSA key. Re-randomized Key should be asymmetric") } + + k2, err := k.PublicKey() + if err != nil { + t.Fatalf("Failed getting public ECDSA key from private [%s]", err) + } + if k2 == nil { + t.Fatal("Failed re-randomizing ECDSA key. Re-randomized Key must be different from nil") + } + + reRandomizedKey2, err := currentBCCSP.KeyDeriv(k2, &bccsp.ECDSAReRandKeyOpts{Temporary: false, Expansion: []byte{1}}) + if err != nil { + t.Fatalf("Failed re-randomizing ECDSA key [%s]", err) + } + + if reRandomizedKey2.Private() { + t.Fatal("Re-randomized public Key must remain public") + } + if reRandomizedKey2.Symmetric() { + t.Fatal("Re-randomized ECDSA asymmetric key must remain asymmetric") + } + + if false == bytes.Equal(reRandomizedKey.SKI(), reRandomizedKey2.SKI()) { + t.Fatal("Re-randomized ECDSA Private- or Public-Keys must end up having the same SKI") + } } func TestECDSASign(t *testing.T) { @@ -650,7 +669,7 @@ func TestECDSAVerify(t *testing.T) { signature, err := currentBCCSP.Sign(k, digest, nil) if err != nil { - t.Fatalf("Failed generating ECDSA signature [%s]", err) + t.Fatalf("Failed generating ECDSA signature [%s]", err) } valid, err := currentBCCSP.Verify(k, signature, digest, nil) @@ -674,13 +693,19 @@ func TestECDSAVerify(t *testing.T) { t.Fatal("Failed verifying ECDSA signature. Signature not valid.") } + // Import the exported public key + pkRaw, err := pk.Bytes() + if err != nil { + t.Fatalf("Failed getting ECDSA raw public key [%s]", err) + } + // Store public key - err = currentKS.StoreKey(pk) + _, err = currentBCCSP.KeyImport(pkRaw, &bccsp.ECDSAPKIXPublicKeyImportOpts{Temporary: false}) if err != nil { t.Fatalf("Failed storing corresponding public key [%s]", err) } - pk2, err := currentKS.GetKey(pk.SKI()) + pk2, err := currentBCCSP.GetKey(pk.SKI()) if err != nil { t.Fatalf("Failed retrieving corresponding public key [%s]", err) } @@ -1082,7 +1107,7 @@ func TestECDSALowS(t *testing.T) { t.Fatalf("Failed unmarshalling signature [%s]", err) } - if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).privKey.Curve]) >= 0 { + if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).pub.pub.Curve]) >= 0 { t.Fatal("Invalid signature. It must have low-S") } @@ -1096,12 +1121,12 @@ func TestECDSALowS(t *testing.T) { // Ensure that signature with high-S are rejected. for { - R, S, err = ecdsa.Sign(rand.Reader, k.(*ecdsaPrivateKey).privKey, digest) + R, S, err = signECDSA(k.SKI(), digest) if err != nil { t.Fatalf("Failed generating signature [%s]", err) } - if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).privKey.Curve]) > 0 { + if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).pub.pub.Curve]) > 0 { break } }