The testdata for this package is around 8 MB and downloaded dynamically via 'go mod download' from its canonical source rather than being copied to this repository. We're moving towards disallowing all network use in short test mode, including proxy.golang.org, so add a corresponding test skip. Needing to lookup a go test flag is unfortunate, but I don't know of a less bad available option while the test does the download in TestMain. On balance, it becomes viable to no longer disable the checksum database since the test will only run on builders that permit internet use and so sum.golang.org should just work. Change-Id: Iaffe3899351da375928aaba114c4875f5438336b Reviewed-on: https://go-review.googlesource.com/c/crypto/+/510695 Run-TryBot: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
// 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"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
_ "crypto/sha1"
|
|
_ "crypto/sha256"
|
|
_ "crypto/sha512"
|
|
)
|
|
|
|
const wycheproofModVer = "v0.0.0-20191219022705-2196000605e4"
|
|
|
|
var wycheproofTestVectorsDir string
|
|
|
|
func TestMain(m *testing.M) {
|
|
flag.Parse()
|
|
if flag.Lookup("test.short").Value.(flag.Getter).Get().(bool) {
|
|
log.Println("skipping test that downloads testdata via 'go mod download' in short mode")
|
|
os.Exit(0)
|
|
}
|
|
if _, err := exec.LookPath("go"); err != nil {
|
|
log.Printf("skipping test because 'go' command is unavailable: %v", err)
|
|
os.Exit(0)
|
|
}
|
|
if os.Getenv("GO_BUILDER_FLAKY_NET") != "" {
|
|
log.Printf("skipping test because GO_BUILDER_FLAKY_NET is set")
|
|
os.Exit(0)
|
|
}
|
|
|
|
// 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)
|
|
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 := os.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))
|
|
}
|
|
}
|