Skip to content

Commit eca98bc

Browse files
author
Volodymyr Paprotski
committedJan 24, 2017
Maleability resistance for PKCS11 BCCSP
Before pkcs11 modifications, sync up the two directories. This applies the change from Angelo: https://jira.hyperledger.org/browse/FAB-1276 https://gerrit.hyperledger.org/r/#/c/2983/ Change-Id: Ifbecd32567658d13ceaa250c702dba69f87ca655 Signed-off-by: Volodymyr Paprotski <vpaprots@ca.ibm.com>
1 parent 8f5dfca commit eca98bc

File tree

3 files changed

+199
-18
lines changed

3 files changed

+199
-18
lines changed
 

‎bccsp/pkcs11/ecdsa.go

+96-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,103 @@ limitations under the License.
1515
*/
1616
package pkcs11
1717

18-
import "math/big"
18+
import (
19+
"crypto/ecdsa"
20+
"crypto/elliptic"
21+
"crypto/rand"
22+
"encoding/asn1"
23+
"errors"
24+
"fmt"
25+
"math/big"
26+
27+
"github.com/hyperledger/fabric/bccsp"
28+
)
1929

20-
// ECDSASignature represents an ECDSA signature
2130
type ecdsaSignature struct {
2231
R, S *big.Int
2332
}
33+
34+
var (
35+
// curveHalfOrders contains the precomputed curve group orders halved.
36+
// It is used to ensure that signature' S value is lower or equal to the
37+
// curve group order halved. We accept only low-S signatures.
38+
// They are precomputed for efficiency reasons.
39+
curveHalfOrders map[elliptic.Curve]*big.Int = map[elliptic.Curve]*big.Int{
40+
elliptic.P224(): new(big.Int).Rsh(elliptic.P224().Params().N, 1),
41+
elliptic.P256(): new(big.Int).Rsh(elliptic.P256().Params().N, 1),
42+
elliptic.P384(): new(big.Int).Rsh(elliptic.P384().Params().N, 1),
43+
elliptic.P521(): new(big.Int).Rsh(elliptic.P521().Params().N, 1),
44+
}
45+
)
46+
47+
func marshalECDSASignature(r, s *big.Int) ([]byte, error) {
48+
return asn1.Marshal(ecdsaSignature{r, s})
49+
}
50+
51+
func unmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) {
52+
// Unmarshal
53+
sig := new(ecdsaSignature)
54+
_, err := asn1.Unmarshal(raw, sig)
55+
if err != nil {
56+
return nil, nil, fmt.Errorf("Failed unmashalling signature [%s]", err)
57+
}
58+
59+
// Validate sig
60+
if sig.R == nil {
61+
return nil, nil, errors.New("Invalid signature. R must be different from nil.")
62+
}
63+
if sig.S == nil {
64+
return nil, nil, errors.New("Invalid signature. S must be different from nil.")
65+
}
66+
67+
if sig.R.Sign() != 1 {
68+
return nil, nil, errors.New("Invalid signature. R must be larger than zero")
69+
}
70+
if sig.S.Sign() != 1 {
71+
return nil, nil, errors.New("Invalid signature. S must be larger than zero")
72+
}
73+
74+
return sig.R, sig.S, nil
75+
}
76+
77+
func (csp *impl) signECDSA(k *ecdsa.PrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) {
78+
r, s, err := ecdsa.Sign(rand.Reader, k, digest)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
// check for low-S
84+
halfOrder, ok := curveHalfOrders[k.Curve]
85+
if !ok {
86+
return nil, fmt.Errorf("Curve not recognized [%s]", k.Curve)
87+
}
88+
89+
// is s > halfOrder Then
90+
if s.Cmp(halfOrder) == 1 {
91+
// Set s to N - s that will be then in the lower part of signature space
92+
// less or equal to half order
93+
s.Sub(k.Params().N, s)
94+
}
95+
96+
return marshalECDSASignature(r, s)
97+
}
98+
99+
func (csp *impl) verifyECDSA(k *ecdsa.PublicKey, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) {
100+
r, s, err := unmarshalECDSASignature(signature)
101+
if err != nil {
102+
return false, fmt.Errorf("Failed unmashalling signature [%s]", err)
103+
}
104+
105+
// check for low-S
106+
halfOrder, ok := curveHalfOrders[k.Curve]
107+
if !ok {
108+
return false, fmt.Errorf("Curve not recognized [%s]", k.Curve)
109+
}
110+
111+
// If s > halfOrder Then
112+
if s.Cmp(halfOrder) == 1 {
113+
return false, fmt.Errorf("Invalid S. Must be smaller than half the order [%s][%s].", s, halfOrder)
114+
}
115+
116+
return ecdsa.Verify(k, digest, r, s), nil
117+
}

‎bccsp/pkcs11/impl.go

+3-16
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package pkcs11
1818
import (
1919
"crypto/ecdsa"
2020
"crypto/rand"
21-
"encoding/asn1"
2221
"errors"
2322
"fmt"
2423
"math/big"
@@ -603,7 +602,7 @@ func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signat
603602
// Check key type
604603
switch k.(type) {
605604
case *ecdsaPrivateKey:
606-
return k.(*ecdsaPrivateKey).privKey.Sign(rand.Reader, digest, nil)
605+
return csp.signECDSA(k.(*ecdsaPrivateKey).privKey, digest, opts)
607606
case *rsaPrivateKey:
608607
if opts == nil {
609608
return nil, errors.New("Invalid options. Nil.")
@@ -631,21 +630,9 @@ func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Signer
631630
// Check key type
632631
switch k.(type) {
633632
case *ecdsaPrivateKey:
634-
ecdsaSignature := new(ecdsaSignature)
635-
_, err := asn1.Unmarshal(signature, ecdsaSignature)
636-
if err != nil {
637-
return false, fmt.Errorf("Failed unmashalling signature [%s]", err)
638-
}
639-
640-
return ecdsa.Verify(&(k.(*ecdsaPrivateKey).privKey.PublicKey), digest, ecdsaSignature.R, ecdsaSignature.S), nil
633+
return csp.verifyECDSA(&(k.(*ecdsaPrivateKey).privKey.PublicKey), signature, digest, opts)
641634
case *ecdsaPublicKey:
642-
ecdsaSignature := new(ecdsaSignature)
643-
_, err := asn1.Unmarshal(signature, ecdsaSignature)
644-
if err != nil {
645-
return false, fmt.Errorf("Failed unmashalling signature [%s]", err)
646-
}
647-
648-
return ecdsa.Verify(k.(*ecdsaPublicKey).pubKey, digest, ecdsaSignature.R, ecdsaSignature.S), nil
635+
return csp.verifyECDSA(k.(*ecdsaPublicKey).pubKey, signature, digest, opts)
649636
case *rsaPrivateKey:
650637
if opts == nil {
651638
return false, errors.New("Invalid options. It must not be nil.")

‎bccsp/pkcs11/impl_test.go

+100
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,106 @@ func TestKeyImportFromX509ECDSAPublicKey(t *testing.T) {
10141014
}
10151015
}
10161016

1017+
func TestECDSASignatureEncoding(t *testing.T) {
1018+
v := []byte{0x30, 0x07, 0x02, 0x01, 0x8F, 0x02, 0x02, 0xff, 0xf1}
1019+
_, err := asn1.Unmarshal(v, &ecdsaSignature{})
1020+
if err == nil {
1021+
t.Fatalf("Unmarshalling should fail for [% x]", v)
1022+
}
1023+
t.Logf("Unmarshalling correctly failed for [% x] [%s]", v, err)
1024+
1025+
v = []byte{0x30, 0x07, 0x02, 0x01, 0x8F, 0x02, 0x02, 0x00, 0x01}
1026+
_, err = asn1.Unmarshal(v, &ecdsaSignature{})
1027+
if err == nil {
1028+
t.Fatalf("Unmarshalling should fail for [% x]", v)
1029+
}
1030+
t.Logf("Unmarshalling correctly failed for [% x] [%s]", v, err)
1031+
1032+
v = []byte{0x30, 0x07, 0x02, 0x01, 0x8F, 0x02, 0x81, 0x01, 0x01}
1033+
_, err = asn1.Unmarshal(v, &ecdsaSignature{})
1034+
if err == nil {
1035+
t.Fatalf("Unmarshalling should fail for [% x]", v)
1036+
}
1037+
t.Logf("Unmarshalling correctly failed for [% x] [%s]", v, err)
1038+
1039+
v = []byte{0x30, 0x07, 0x02, 0x01, 0x8F, 0x02, 0x81, 0x01, 0x8F}
1040+
_, err = asn1.Unmarshal(v, &ecdsaSignature{})
1041+
if err == nil {
1042+
t.Fatalf("Unmarshalling should fail for [% x]", v)
1043+
}
1044+
t.Logf("Unmarshalling correctly failed for [% x] [%s]", v, err)
1045+
1046+
v = []byte{0x30, 0x0A, 0x02, 0x01, 0x8F, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x8F}
1047+
_, err = asn1.Unmarshal(v, &ecdsaSignature{})
1048+
if err == nil {
1049+
t.Fatalf("Unmarshalling should fail for [% x]", v)
1050+
}
1051+
t.Logf("Unmarshalling correctly failed for [% x] [%s]", v, err)
1052+
1053+
}
1054+
1055+
func TestECDSALowS(t *testing.T) {
1056+
// Ensure that signature with low-S are generated
1057+
k, err := currentBCCSP.KeyGen(&bccsp.ECDSAKeyGenOpts{Temporary: false})
1058+
if err != nil {
1059+
t.Fatalf("Failed generating ECDSA key [%s]", err)
1060+
}
1061+
1062+
msg := []byte("Hello World")
1063+
1064+
digest, err := currentBCCSP.Hash(msg, &bccsp.SHAOpts{})
1065+
if err != nil {
1066+
t.Fatalf("Failed computing HASH [%s]", err)
1067+
}
1068+
1069+
signature, err := currentBCCSP.Sign(k, digest, nil)
1070+
if err != nil {
1071+
t.Fatalf("Failed generating ECDSA signature [%s]", err)
1072+
}
1073+
1074+
R, S, err := unmarshalECDSASignature(signature)
1075+
if err != nil {
1076+
t.Fatalf("Failed unmarshalling signature [%s]", err)
1077+
}
1078+
1079+
if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).privKey.Curve]) >= 0 {
1080+
t.Fatal("Invalid signature. It must have low-S")
1081+
}
1082+
1083+
valid, err := currentBCCSP.Verify(k, signature, digest, nil)
1084+
if err != nil {
1085+
t.Fatalf("Failed verifying ECDSA signature [%s]", err)
1086+
}
1087+
if !valid {
1088+
t.Fatal("Failed verifying ECDSA signature. Signature not valid.")
1089+
}
1090+
1091+
// Ensure that signature with high-S are rejected.
1092+
for {
1093+
R, S, err = ecdsa.Sign(rand.Reader, k.(*ecdsaPrivateKey).privKey, digest)
1094+
if err != nil {
1095+
t.Fatalf("Failed generating signature [%s]", err)
1096+
}
1097+
1098+
if S.Cmp(curveHalfOrders[k.(*ecdsaPrivateKey).privKey.Curve]) > 0 {
1099+
break
1100+
}
1101+
}
1102+
1103+
sig, err := marshalECDSASignature(R, S)
1104+
if err != nil {
1105+
t.Fatalf("Failing unmarshalling signature [%s]", err)
1106+
}
1107+
1108+
valid, err = currentBCCSP.Verify(k, sig, digest, nil)
1109+
if err == nil {
1110+
t.Fatal("Failed verifying ECDSA signature. It must fail for a signature with high-S")
1111+
}
1112+
if valid {
1113+
t.Fatal("Failed verifying ECDSA signature. It must fail for a signature with high-S")
1114+
}
1115+
}
1116+
10171117
func TestAESKeyGen(t *testing.T) {
10181118

10191119
k, err := currentBCCSP.KeyGen(&bccsp.AESKeyGenOpts{Temporary: false})

0 commit comments

Comments
 (0)