blob: 80125ada75f53a0c08599c8c6c3e321b51f2e959 [file] [log] [blame]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/ecdsa"
"math/big"
"testing"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
func TestECDSA(t *testing.T) {
type ASNSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment"`
// A list of flags
Flags []string `json:"flags"`
// The message to sign
Msg string `json:"msg"`
// Test result
Result string `json:"result"`
// An ASN.1 encoded signature for msg
Sig string `json:"sig"`
// Identifier of the test case
TcID int `json:"tcId"`
}
type ECPublicKey struct {
// The EC group used by this public key
Curve interface{} `json:"curve"`
}
type ECDSATestGroup struct {
// Unencoded EC public key
Key *ECPublicKey `json:"key"`
// DER encoded public key
KeyDER string `json:"keyDer"`
// the hash function used for ECDSA
SHA string `json:"sha"`
Tests []*ASNSignatureTestVector `json:"tests"`
}
type Root struct {
TestGroups []*ECDSATestGroup `json:"testGroups"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but
// accepted by some implementations.
"MissingZero": false,
// A signature using a weaker hash than the EC params is not a security
// risk, as long as the hash is secure.
// https://www.imperialviolet.org/2014/05/25/strengthmatching.html
"WeakHash": true,
}
// supportedCurves is a map of all elliptic curves supported
// by crypto/elliptic, which can subsequently be parsed and tested.
supportedCurves := map[string]bool{
"secp224r1": true,
"secp256r1": true,
"secp384r1": true,
"secp521r1": true,
}
var root Root
readTestVector(t, "ecdsa_test.json", &root)
for _, tg := range root.TestGroups {
curve := tg.Key.Curve.(string)
if !supportedCurves[curve] {
continue
}
pub := decodePublicKey(tg.KeyDER).(*ecdsa.PublicKey)
h := parseHash(tg.SHA).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
sigBytes := decodeHex(sig.Sig)
got := ecdsa.VerifyASN1(pub, hashed, sigBytes)
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, VerifyASN1 wanted success: %t", sig.TcID, sig.Result, sig.Comment, want)
}
var r, s big.Int
var inner cryptobyte.String
input := cryptobyte.String(sigBytes)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(&r) ||
!inner.ReadASN1Integer(&s) ||
!inner.Empty() {
continue
}
got = ecdsa.Verify(pub, hashed, &r, &s)
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, Verify wanted success: %t", sig.TcID, sig.Result, sig.Comment, want)
}
}
}
}