File: wycheproof_test.go

package info (click to toggle)
golang-go.crypto 1%3A0.36.0-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 7,352 kB
  • sloc: asm: 27,990; ansic: 258; sh: 25; makefile: 6
file content (141 lines) | stat: -rw-r--r-- 3,751 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 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))
	}
}