ECDSA Signature with crypto.Signer and PKCS#11

1,003 views
Skip to first unread message

Paul van Brouwershaven

unread,
Oct 9, 2014, 6:40:48 AM10/9/14
to golan...@googlegroups.com, Adam Langley
I'm working on a PKCS#11 (github.com/miekg/pkcs11) crypto.Signer and currently struggling to obtain 'r' and 's' in the right format as used by 'ecdsaSignature'. The same crypto.Signer is dealing with RSA signatures and is working fine.

When verifying the certificate that contains the embedded signature I get a "x509: ECDSA verification failure".

http://play.golang.org/p/KEDhy6akWQ

The issue is potentially caused by the way I'm splitting the signature as returned by the PKCS#11 interface (one array of 64 bytes for a P256 curve).

r := new(big.Int).SetBytes(sig[:len(sig)/2])
s := new(big.Int).SetBytes(sig[len(sig)/2:])

sig, err = asn1.Marshal(ecdsaSignature{r, s})

Which results in:

SEQUENCE(2 elem)
INTEGER(255 bit) 4926646066816546635773105742728194416509116305881183826812797818311257…
INTEGER(256 bit) 8001629261687403358200509917628748063517175240869055934673736255153843…

PKCS #11 Mechanisms v2.30 states:

"The signature octets correspond to the concatenation of the ECDSA values r and s, both represented as an octet string of equal length of at most nLen with the most significant byte first. If r and s have different octet length, the shorter of both must be padded with leading zero octets such that both have the same octet length. Loosely spoken, the first half of the signature is r and the second half is s."

I'm not padding the shorter of both (this could be the cause of the invalid siganture), but r and s they have the same length in bytes so there is nothing to add... is there?

Thanks,

Paul

Adam Langley

unread,
Oct 9, 2014, 8:19:16 AM10/9/14
to Paul van Brouwershaven, golang-nuts
On Thu, Oct 9, 2014 at 3:40 AM, Paul van Brouwershaven
<pa...@vanbrouwershaven.com> wrote:
> The issue is potentially caused by the way I'm splitting the signature as
> returned by the PKCS#11 interface (one array of 64 bytes for a P256 curve).
>
> r := new(big.Int).SetBytes(sig[:len(sig)/2])
> s := new(big.Int).SetBytes(sig[len(sig)/2:])

That seems fine. Why not verify the signature immediately after
signing to avoid having to worry about the ASN.1 for debugging? If
it's invalid then are you sure that the PKCS#11 interface isn't
hashing its input?


Cheers

AGL

Paul van Brouwershaven

unread,
Oct 9, 2014, 8:48:33 AM10/9/14
to Adam Langley, golang-nuts
That was a good and simple idea to eliminate some of the code.

The signature verification fails indeed, but the CKM_ECDSA mechanism is not hashing the input.

case *ecdsa.PublicKey:
// Marshal ECDSA signature
r := new(big.Int).SetBytes(sig[:len(sig)/2])
s := new(big.Int).SetBytes(sig[len(sig)/2:])
if !ecdsa.Verify(pub, msg, r, s) {
err = fmt.Errorf("Invalid ECDSA signature")
return
}

sig, err = asn1.Marshal(ecdsaSignature{r, s})


One other potential cause of the problem could be the marshaling of the the public key from the CKA_EC_POINT value of the PKCS#11 interface:

// ECDSA
if a.Type == pkcs11.CKA_EC_POINT {
ecdsaPub.Curve = elliptic.P256()
pointLenght := ecdsaPub.Curve.Params().BitSize/8*2+1
if len(a.Value) < pointLenght {
err = fmt.Errorf("CKA_EC_POINT to small for used curve")
return
}
ecdsaPub.X, ecdsaPub.Y = elliptic.Unmarshal(ecdsaPub.Curve, a.Value[:pointLenght])
if ecdsaPub.X == nil {
err = fmt.Errorf("Failed to decode CKA_EC_POINT")
return
}
}

Adam Langley

unread,
Oct 9, 2014, 9:39:50 AM10/9/14
to Paul van Brouwershaven, golang-nuts
On Thu, Oct 9, 2014 at 5:48 AM, Paul van Brouwershaven
<pa...@vanbrouwershaven.com> wrote:
> One other potential cause of the problem could be the marshaling of the the
> public key from the CKA_EC_POINT value of the PKCS#11 interface:

Check http://godoc.org/crypto/elliptic#CurveParams.IsOnCurve for
sanity on the public key? Also check that pointLength is exactly
len(a.Value)


Cheers

AGL

Paul van Brouwershaven

unread,
Oct 9, 2014, 10:42:58 AM10/9/14
to Adam Langley, golang-nuts
The public key was indeed not on the curve, the CKA_EC_POINT value as returned by PKCS#11 is a  DER-encoded (OCTET STRING) ECPoint 

Example for the record:

Thanks!

Adam Langley

unread,
Oct 9, 2014, 11:11:35 AM10/9/14
to Paul van Brouwershaven, golang-nuts
On Thu, Oct 9, 2014 at 7:42 AM, Paul van Brouwershaven
<pa...@vanbrouwershaven.com> wrote:
> The public key was indeed not on the curve, the CKA_EC_POINT value as
> returned by PKCS#11 is a DER-encoded (OCTET STRING) ECPoint

And the 0x04 for OCTET STRING nicely matches the 0x04 for
"uncompressed point", allowing the parser to succeed :)


Cheers

AGL
Reply all
Reply to author
Forward
0 new messages