From 3d1af977314e4be8d35fa706b26e969e26d32756 Mon Sep 17 00:00:00 2001 From: jsing Date: Fri, 10 Aug 2018 16:22:58 +0000 Subject: [PATCH] Run the wycheproof ECDSA test vectors against libcrypto. Skip the ecdsa_webcrypto_test.json vectors for the time being, as these likely need some extra glue. --- .../lib/libcrypto/wycheproof/wycheproof.go | 154 +++++++++++++++++- 1 file changed, 147 insertions(+), 7 deletions(-) diff --git a/regress/lib/libcrypto/wycheproof/wycheproof.go b/regress/lib/libcrypto/wycheproof/wycheproof.go index 427dc47aec4..d1457238774 100644 --- a/regress/lib/libcrypto/wycheproof/wycheproof.go +++ b/regress/lib/libcrypto/wycheproof/wycheproof.go @@ -1,4 +1,4 @@ -/* $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 * @@ -23,6 +23,8 @@ package main #include #include +#include +#include #include #include */ @@ -46,6 +48,33 @@ import ( 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"` @@ -94,11 +123,25 @@ type wycheproofTestVectors struct { } 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) { @@ -126,6 +169,96 @@ func hashFromString(hs string) (hash.Hash, 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 { @@ -257,6 +390,8 @@ func runTestVectors(path string) bool { var wtg interface{} switch wtv.Algorithm { + case "ECDSA": + wtg = &wycheproofTestGroupECDSA{} case "RSASig": wtg = &wycheproofTestGroupRSA{} case "X25519": @@ -271,6 +406,10 @@ func runTestVectors(path string) bool { 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 @@ -293,11 +432,12 @@ func main() { 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"}, } -- 2.20.1