-/* $OpenBSD: wycheproof.go,v 1.4 2018/08/10 16:18:55 jsing Exp $ */
+/* $OpenBSD: wycheproof.go,v 1.5 2018/08/10 16:22:58 jsing Exp $ */
/*
* Copyright (c) 2018 Joel Sing <jsing@openbsd.org>
*
#include <openssl/bn.h>
#include <openssl/curve25519.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
#include <openssl/objects.h>
#include <openssl/rsa.h>
*/
const testVectorPath = "/usr/local/share/wycheproof/testvectors"
+type wycheproofECDSAKey struct {
+ Curve string `json:"curve"`
+ KeySize int `json:"keySize"`
+ Type string `json:"type"`
+ Uncompressed string `json:"uncompressed"`
+ WX string `json:"wx"`
+ WY string `json:"wy"`
+}
+
+type wycheproofTestECDSA struct {
+ TCID int `json:"tcId"`
+ Comment string `json:"comment"`
+ Msg string `json:"msg"`
+ Sig string `json:"sig"`
+ Result string `json:"result"`
+ Flags []string `json:"flags"`
+}
+
+type wycheproofTestGroupECDSA struct {
+ Key *wycheproofECDSAKey `json:"key"`
+ KeyDER string `json:"keyDer"`
+ KeyPEM string `json:"keyPem"`
+ SHA string `json:"sha"`
+ Type string `json:"type"`
+ Tests []*wycheproofTestECDSA `json:"tests"`
+}
+
type wycheproofTestRSA struct {
TCID int `json:"tcId"`
Comment string `json:"comment"`
}
var nids = map[string]int{
- "SHA-1": C.NID_sha1,
- "SHA-224": C.NID_sha224,
- "SHA-256": C.NID_sha256,
- "SHA-384": C.NID_sha384,
- "SHA-512": C.NID_sha512,
+ "brainpoolP224r1": C.NID_brainpoolP224r1,
+ "brainpoolP256r1": C.NID_brainpoolP256r1,
+ "brainpoolP320r1": C.NID_brainpoolP320r1,
+ "brainpoolP384r1": C.NID_brainpoolP384r1,
+ "brainpoolP512r1": C.NID_brainpoolP512r1,
+ "brainpoolP224t1": C.NID_brainpoolP224t1,
+ "brainpoolP256t1": C.NID_brainpoolP256t1,
+ "brainpoolP320t1": C.NID_brainpoolP320t1,
+ "brainpoolP384t1": C.NID_brainpoolP384t1,
+ "brainpoolP512t1": C.NID_brainpoolP512t1,
+ "secp224r1": C.NID_secp224r1,
+ "secp256k1": C.NID_secp256k1,
+ "secp384r1": C.NID_secp384r1,
+ "secp521r1": C.NID_secp521r1,
+ "SHA-1": C.NID_sha1,
+ "SHA-224": C.NID_sha224,
+ "SHA-256": C.NID_sha256,
+ "SHA-384": C.NID_sha384,
+ "SHA-512": C.NID_sha512,
}
func nidFromString(ns string) (int, error) {
}
}
+func runECDSATest(ecKey *C.EC_KEY, nid int, h hash.Hash, wt *wycheproofTestECDSA) bool {
+ msg, err := hex.DecodeString(wt.Msg)
+ if err != nil {
+ log.Fatalf("Failed to decode message %q: %v", wt.Msg, err)
+ }
+
+ h.Reset()
+ h.Write(msg)
+ msg = h.Sum(nil)
+
+ sig, err := hex.DecodeString(wt.Sig)
+ if err != nil {
+ log.Fatalf("Failed to decode signature %q: %v", wt.Sig, err)
+ }
+
+ msgLen, sigLen := len(msg), len(sig)
+ if msgLen == 0 {
+ msg = append(msg, 0)
+ }
+ if sigLen == 0 {
+ sig = append(sig, 0)
+ }
+ ret := C.ECDSA_verify(0, (*C.uchar)(unsafe.Pointer(&msg[0])), C.int(msgLen),
+ (*C.uchar)(unsafe.Pointer(&sig[0])), C.int(sigLen), ecKey)
+
+ // XXX audit acceptable cases...
+ success := true
+ if (ret == 1) != (wt.Result == "valid") && wt.Result != "acceptable" {
+ fmt.Printf("FAIL: Test case %d (%q) - ECDSA_verify() = %d, want %v\n", wt.TCID, wt.Comment, int(ret), wt.Result)
+ success = false
+ }
+ return success
+}
+
+func runECDSATestGroup(wtg *wycheproofTestGroupECDSA) bool {
+ // No secp256r1 support.
+ if wtg.Key.Curve == "secp256r1" {
+ return true
+ }
+
+ fmt.Printf("Running ECDSA test group %v with curve %v, key size %d and %v...\n", wtg.Type, wtg.Key.Curve, wtg.Key.KeySize, wtg.SHA)
+
+ nid, err := nidFromString(wtg.Key.Curve)
+ if err != nil {
+ log.Fatalf("Failed to get nid for curve: %v", err)
+ }
+ ecKey := C.EC_KEY_new_by_curve_name(C.int(nid))
+ if ecKey == nil {
+ log.Fatal("EC_KEY_new_by_curve_name failed")
+ }
+ defer C.EC_KEY_free(ecKey)
+
+ var bnX *C.BIGNUM
+ wx := C.CString(wtg.Key.WX)
+ if C.BN_hex2bn(&bnX, wx) == 0 {
+ log.Fatal("Failed to decode WX")
+ }
+ C.free(unsafe.Pointer(wx))
+ defer C.BN_free(bnX)
+
+ var bnY *C.BIGNUM
+ wy := C.CString(wtg.Key.WY)
+ if C.BN_hex2bn(&bnY, wy) == 0 {
+ log.Fatal("Failed to decode WY")
+ }
+ C.free(unsafe.Pointer(wy))
+ defer C.BN_free(bnY)
+
+ if C.EC_KEY_set_public_key_affine_coordinates(ecKey, bnX, bnY) != 1 {
+ log.Fatal("Failed to set EC public key")
+ }
+
+ nid, err = nidFromString(wtg.SHA)
+ if err != nil {
+ log.Fatalf("Failed to get MD NID: %v", err)
+ }
+ h, err := hashFromString(wtg.SHA)
+ if err != nil {
+ log.Fatalf("Failed to get hash: %v", err)
+ }
+
+ success := true
+ for _, wt := range wtg.Tests {
+ if !runECDSATest(ecKey, nid, h, wt) {
+ success = false
+ }
+ }
+ return success
+}
+
func runRSATest(rsa *C.RSA, nid int, h hash.Hash, wt *wycheproofTestRSA) bool {
msg, err := hex.DecodeString(wt.Msg)
if err != nil {
var wtg interface{}
switch wtv.Algorithm {
+ case "ECDSA":
+ wtg = &wycheproofTestGroupECDSA{}
case "RSASig":
wtg = &wycheproofTestGroupRSA{}
case "X25519":
log.Fatalf("Failed to unmarshal test groups JSON: %v", err)
}
switch wtv.Algorithm {
+ case "ECDSA":
+ if !runECDSATestGroup(wtg.(*wycheproofTestGroupECDSA)) {
+ success = false
+ }
case "RSASig":
if !runRSATestGroup(wtg.(*wycheproofTestGroupRSA)) {
success = false
os.Exit(0)
}
- // TODO: AES, Chacha20Poly1305, DSA, ECDH, ECDSA, RSA-PSS.
+ // AES, Chacha20Poly1305, DSA, ECDH
tests := []struct {
name string
pattern string
}{
+ {"ECDSA", "ecdsa_[^w]*test.json"}, // Skip ecdsa_webcrypto_test.json for now.
{"RSA signature", "rsa_signature_*test.json"},
{"X25519", "x25519_*test.json"},
}