internal/wycheproof: add Wycheproof tests for verifying signatures

https://github.com/google/wycheproof provides test vectors exposing
vulnerabilities in crypto packages. This change creates a new package
called internal/wycheproof that runs these Wycheproof tests against
a number of pacakages in the standard library (and in the future,
x/crypto).

Directory structure:
 - interal/wycheproof/internal/ecdsa: internal version of ecdsa package which
includes a new function that verifies ASN encoded signatures directly
 - interal/wycheproof/internal/dsa: internal version of dsa package which
includes a new function that verifies ASN encoded signatures directly
 - internal/wycheproof: all tests

internal/wycheproof/wycheproof_test.go provides utility functions that are
common to many tests in the package, and contains the TestMain which
fetches github.com/google/wycheproof from the source.

This change includes tests for signature verification with dsa, ecdsa,
eddsa, and rsa (both PKCS#1 v1.5 and PSS signatures).

Note that these tests download testdata from github.com/google/wycheproof
by running `go mod download` in the TestMain. This means that internet
access will be necessary in order to run these tests if the testdata is
not already in your module cache.

More tests will be added incrementally.

Change-Id: I0378d4be24b5679fdc186e9fc94c1cc0068e81f7
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/209221
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
Katie Hockman
2019-12-06 17:25:30 +00:00
parent e7c4368fe9
commit e9b2fee464
9 changed files with 892 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
This package runs a set of the Wycheproof tests provided by
https://github.com/google/wycheproof.
The JSON test files live in
https://github.com/google/wycheproof/tree/master/testvectors
and are being fetched and cached at a pinned version every time
these tests are run. To change the version of the wycheproof
repository that is being used for testing, update wycheproofModVer.
The structs for these tests are generated from the
schemas provided in https://github.com/google/wycheproof/tree/master/schemas
using https://github.com/a-h/generate.
+123
View File
@@ -0,0 +1,123 @@
// 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/dsa"
"testing"
wdsa "golang.org/x/crypto/internal/wycheproof/internal/dsa"
)
func TestDsa(t *testing.T) {
// AsnSignatureTestVector
type AsnSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// An ASN encoded signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// DsaPublicKey
type DsaPublicKey struct {
// the generator of the multiplicative subgroup
G string `json:"g,omitempty"`
// the key size in bits
KeySize int `json:"keySize,omitempty"`
// the modulus p
P string `json:"p,omitempty"`
// the order of the generator g
Q string `json:"q,omitempty"`
// the key type
Type string `json:"type,omitempty"`
// the public key value
Y string `json:"y,omitempty"`
}
// DsaTestGroup
type DsaTestGroup struct {
// unenocded DSA public key
Key *DsaPublicKey `json:"key,omitempty"`
// DER encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the hash function used for DSA
Sha string `json:"sha,omitempty"`
Tests []*AsnSignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*DsaTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but accepted by some implementations.
"NoLeadingZero": false,
}
var root Root
readTestVector(t, "dsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*dsa.PublicKey)
h := parseHash(tg.Sha).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
hashed = hashed[:pub.Q.BitLen()/8] // Truncate to the byte-length of the subgroup (Q)
got := wdsa.VerifyASN1(pub, hashed, decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
+166
View File
@@ -0,0 +1,166 @@
// 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"
"testing"
wecdsa "golang.org/x/crypto/internal/wycheproof/internal/ecdsa"
)
func TestEcdsa(t *testing.T) {
// AsnSignatureTestVector
type AsnSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// An ASN encoded signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// EcPublicKey
type EcPublicKey struct {
// the EC group used by this public key
Curve interface{} `json:"curve,omitempty"`
// the key size in bits
KeySize int `json:"keySize,omitempty"`
// the key type
Type string `json:"type,omitempty"`
// encoded public key point
Uncompressed string `json:"uncompressed,omitempty"`
// the x-coordinate of the public key point
Wx string `json:"wx,omitempty"`
// the y-coordinate of the public key point
Wy string `json:"wy,omitempty"`
}
// EcUnnamedGroup
type EcUnnamedGroup struct {
// coefficient a of the elliptic curve equation
A string `json:"a,omitempty"`
// coefficient b of the elliptic curve equation
B string `json:"b,omitempty"`
// the x-coordinate of the generator
Gx string `json:"gx,omitempty"`
// the y-coordinate of the generator
Gy string `json:"gy,omitempty"`
// the cofactor
H int `json:"h,omitempty"`
// the order of the generator
N string `json:"n,omitempty"`
// the order of the underlying field
P string `json:"p,omitempty"`
// an unnamed EC group over a prime field in Weierstrass form
Type string `json:"type,omitempty"`
}
// EcdsaTestGroup
type EcdsaTestGroup struct {
// unenocded EC public key
Key *EcPublicKey `json:"key,omitempty"`
// DER encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the hash function used for ECDSA
Sha string `json:"sha,omitempty"`
Tests []*AsnSignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*EcdsaTestGroup `json:"testGroups,omitempty"`
}
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)
got := wecdsa.VerifyASN1(pub, hashed, decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
+100
View File
@@ -0,0 +1,100 @@
// 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.
// +build go1.13
package wycheproof
import (
"testing"
"golang.org/x/crypto/ed25519"
)
func TestEddsa(t *testing.T) {
// Jwk the private key in webcrypto format
type Jwk struct {
}
// Key unencoded key pair
type Key struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// EddsaTestGroup
type EddsaTestGroup struct {
// the private key in webcrypto format
Jwk *Jwk `json:"jwk,omitempty"`
// unencoded key pair
Key *Key `json:"key,omitempty"`
// Asn encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*EddsaTestGroup `json:"testGroups,omitempty"`
}
var root Root
readTestVector(t, "eddsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(ed25519.PublicKey)
for _, sig := range tg.Tests {
got := ed25519.Verify(pub, decodeHex(sig.Msg), decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, nil); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
+33
View File
@@ -0,0 +1,33 @@
// 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 dsa provides an internal version of dsa.Verify
// that is used for the Wycheproof tests.
package dsa
import (
"crypto/dsa"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
// VerifyASN1 verifies the ASN1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *dsa.PublicKey, hash, sig []byte) bool {
var (
r, s = &big.Int{}, &big.Int{}
inner cryptobyte.String
)
input := cryptobyte.String(sig)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(r) ||
!inner.ReadASN1Integer(s) ||
!inner.Empty() {
return false
}
return dsa.Verify(pub, hash, r, s)
}
@@ -0,0 +1,33 @@
// 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 ecdsa provides an internal version of ecdsa.Verify
// that is used for the Wycheproof tests.
package ecdsa
import (
"crypto/ecdsa"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
// VerifyASN1 verifies the ASN1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *ecdsa.PublicKey, hash, sig []byte) bool {
var (
r, s = &big.Int{}, &big.Int{}
inner cryptobyte.String
)
input := cryptobyte.String(sig)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(r) ||
!inner.ReadASN1Integer(s) ||
!inner.Empty() {
return false
}
return ecdsa.Verify(pub, hash, r, s)
}
+164
View File
@@ -0,0 +1,164 @@
// 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/rsa"
"testing"
)
func TestRsaPss(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// The salt length
SLen int `json:"sLen,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// 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,
}
// filesOverrideToPassZeroSLen is a map of all test files
// and which TcIds that should be overriden to pass if the
// rsa.PSSOptions.SaltLength is zero.
// These tests expect a failure with a PSSOptions.SaltLength: 0
// and a signature that uses a different salt length. However,
// a salt length of 0 is defined as rsa.PSSSaltLengthAuto which
// works deterministically to auto-detect the length when
// verifying, so these tests actually pass as they should.
filesOverrideToPassZeroSLen := map[string][]int{
"rsa_pss_2048_sha1_mgf1_20_test.json": []int{46, 47},
"rsa_pss_2048_sha256_mgf1_0_test.json": []int{67, 68},
"rsa_pss_2048_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_2048_sha512_256_mgf1_28_test.json": []int{13, 14, 15},
"rsa_pss_2048_sha512_256_mgf1_32_test.json": []int{13, 14},
"rsa_pss_3072_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha512_mgf1_32_test.json": []int{136, 137},
// "rsa_pss_misc_test.json": nil, // TODO: This ones seems to be broken right now, but can enable later on.
}
for f := range filesOverrideToPassZeroSLen {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
opts := &rsa.PSSOptions{
Hash: ch,
SaltLength: rsa.PSSSaltLengthAuto,
}
// Run all the tests twice: the first time with the salt length
// as PSSSaltLengthAuto, and the second time with the salt length
// explictily set to tg.SLen.
for i := 0; i < 2; i++ {
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPSS(pub, ch, hashed, decodeHex(sig.Sig), opts)
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if opts.SaltLength == 0 {
for _, id := range filesOverrideToPassZeroSLen[f] {
if sig.TcId == id {
want = true
break
}
}
}
if (err == nil) != want {
t.Errorf("file: %v, tcid: %d, type: %s, opts.SaltLength: %v, comment: %q, wanted success: %t", f, sig.TcId, sig.Result, opts.SaltLength, sig.Comment, want)
}
}
// Update opts.SaltLength for the second run of the tests.
opts.SaltLength = tg.SLen
}
}
}
}
+123
View File
@@ -0,0 +1,123 @@
// 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/rsa"
"testing"
)
func TestRsa(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// Omitting the parameter field in an ASN encoded integer is a legacy behavior.
"MissingNull": false,
// Keys with a modulus less than 2048 bits are supported by crypto/rsa.
"SmallModulus": true,
// Small public keys are supported by crypto/rsa.
"SmallPublicKey": true,
}
var root Root
readTestVector(t, "rsa_signature_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPKCS1v15(pub, ch, hashed, decodeHex(sig.Sig))
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if (err == nil) != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
+138
View File
@@ -0,0 +1,138 @@
// 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 runs a set of the Wycheproof tests
// provided by https://github.com/google/wycheproof.
package wycheproof
import (
"crypto"
"crypto/x509"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
)
const wycheproofModVer = "v0.0.0-20191126014559-06e5e105eeb9"
var wycheproofTestVectorsDir string
func TestMain(m *testing.M) {
if _, err := exec.LookPath("go"); err != nil {
log.Printf("skipping test because 'go' command is unavailable: %v", err)
os.Exit(0)
}
if runtime.GOARCH == "386" {
os.Exit(0) // skip tests
}
// Download the JSON test files from github.com/google/wycheproof
// using `go mod download -json` so the cached source of the testdata
// can be used in the following tests.
path := "github.com/google/wycheproof@" + wycheproofModVer
cmd := exec.Command("go", "mod", "download", "-json", path)
// TODO: enable the sumdb once the Trybots proxy supports it.
cmd.Env = append(os.Environ(), "GONOSUMDB=*")
output, err := cmd.Output()
if err != nil {
log.Fatalf("failed to run `go mod download -json %s`, output: %s", path, output)
}
var dm struct {
Dir string // absolute path to cached source root directory
}
if err := json.Unmarshal(output, &dm); err != nil {
log.Fatal(err)
}
// Now that the module has been downloaded, use the absolute path of the
// cached source as the root directory for all tests going forward.
wycheproofTestVectorsDir = filepath.Join(dm.Dir, "testvectors")
os.Exit(m.Run())
}
func readTestVector(t *testing.T, f string, dest interface{}) {
b, err := ioutil.ReadFile(filepath.Join(wycheproofTestVectorsDir, f))
if err != nil {
t.Fatalf("failed to read json file: %v", err)
}
if err := json.Unmarshal(b, &dest); err != nil {
t.Fatalf("failed to unmarshal json file: %v", err)
}
}
func decodeHex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
func decodePublicKey(der string) interface{} {
d := decodeHex(der)
pub, err := x509.ParsePKIXPublicKey(d)
if err != nil {
panic(fmt.Sprintf("failed to parse DER encoded public key: %v", err))
}
return pub
}
func parseHash(h string) crypto.Hash {
switch h {
case "SHA-1":
return crypto.SHA1
case "SHA-256":
return crypto.SHA256
case "SHA-224":
return crypto.SHA224
case "SHA-384":
return crypto.SHA384
case "SHA-512":
return crypto.SHA512
case "SHA-512/224":
return crypto.SHA512_224
case "SHA-512/256":
return crypto.SHA512_256
default:
panic(fmt.Sprintf("could not identify SHA hash algorithm: %q", h))
}
}
// shouldPass returns whether or not the test should pass.
// flagsShouldPass is a map associated with whether or not
// a flag for an "acceptable" result should pass.
// Every possible flag value that's associated with an
// "acceptable" result should be explicitly specified,
// otherwise the test will panic.
func shouldPass(result string, flags []string, flagsShouldPass map[string]bool) bool {
switch result {
case "valid":
return true
case "invalid":
return false
case "acceptable":
for _, flag := range flags {
pass, ok := flagsShouldPass[flag]
if !ok {
panic(fmt.Sprintf("unspecified flag: %q", flag))
}
if !pass {
return false
}
}
return true // There are no flags, or all are meant to pass.
default:
panic(fmt.Sprintf("unexpected result: %v", result))
}
}