summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libcrypto/Makefile3
-rw-r--r--src/regress/lib/libcrypto/wycheproof/Makefile18
-rw-r--r--src/regress/lib/libcrypto/wycheproof/wycheproof.go233
3 files changed, 253 insertions, 1 deletions
diff --git a/src/regress/lib/libcrypto/Makefile b/src/regress/lib/libcrypto/Makefile
index b357b3be88..38e3304eb4 100644
--- a/src/regress/lib/libcrypto/Makefile
+++ b/src/regress/lib/libcrypto/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.31 2018/05/15 15:11:15 tb Exp $ 1# $OpenBSD: Makefile,v 1.32 2018/07/25 18:04:09 jsing Exp $
2 2
3SUBDIR= \ 3SUBDIR= \
4 aead \ 4 aead \
@@ -44,6 +44,7 @@ SUBDIR= \
44 sha256 \ 44 sha256 \
45 sha512 \ 45 sha512 \
46 utf8 \ 46 utf8 \
47 wycheproof \
47 x509 48 x509
48 49
49install: 50install:
diff --git a/src/regress/lib/libcrypto/wycheproof/Makefile b/src/regress/lib/libcrypto/wycheproof/Makefile
new file mode 100644
index 0000000000..e7338cb1f0
--- /dev/null
+++ b/src/regress/lib/libcrypto/wycheproof/Makefile
@@ -0,0 +1,18 @@
1# $OpenBSD: Makefile,v 1.1 2018/07/25 18:04:09 jsing Exp $
2
3GO_VERSION != sh -c "(go version) 2>/dev/null || true"
4
5.if empty(GO_VERSION)
6regress:
7 @echo package go is required for this regress
8 @echo SKIPPED
9.endif
10
11CLEANFILES+=wycheproof
12REGRESS_TARGETS=regress-wycheproof
13
14regress-wycheproof:
15 go build -o wycheproof ${.CURDIR}/wycheproof.go
16 ./wycheproof
17
18.include <bsd.regress.mk>
diff --git a/src/regress/lib/libcrypto/wycheproof/wycheproof.go b/src/regress/lib/libcrypto/wycheproof/wycheproof.go
new file mode 100644
index 0000000000..ee53195f02
--- /dev/null
+++ b/src/regress/lib/libcrypto/wycheproof/wycheproof.go
@@ -0,0 +1,233 @@
1/* $OpenBSD: wycheproof.go,v 1.1 2018/07/25 18:04:09 jsing Exp $ */
2/*
3 * Copyright (c) 2018 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18// Wycheproof runs test vectors from Project Wycheproof against libcrypto.
19package main
20
21/*
22#cgo LDFLAGS: -lcrypto
23
24#include <openssl/bn.h>
25#include <openssl/objects.h>
26#include <openssl/rsa.h>
27*/
28import "C"
29
30import (
31 "crypto/sha1"
32 "crypto/sha256"
33 "crypto/sha512"
34 "encoding/hex"
35 "encoding/json"
36 "fmt"
37 "hash"
38 "io/ioutil"
39 "log"
40 "os"
41 "path/filepath"
42 "unsafe"
43)
44
45const testVectorPath = "/usr/local/share/wycheproof/testvectors"
46
47type wycheproofTest struct {
48 TCID int `json:"tcId"`
49 Comment string `json:"comment"`
50 Msg string `json:"msg"`
51 Sig string `json:"sig"`
52 Padding string `json:"padding"`
53 Result string `json:"result"`
54 Flags []string `json:"flags"`
55}
56
57type wycheproofTestGroup struct {
58 E string `json:"e"`
59 KeyASN string `json:"keyAsn"`
60 KeyDER string `json:"keyDer"`
61 KeyPEM string `json:"keyPem"`
62 KeySize int `json:"keysize"`
63 N string `json:"n"`
64 SHA string `json:"sha"`
65 Type string `json:"type"`
66 Tests []*wycheproofTest `json:"tests"`
67}
68
69type wycheproofTestVectors struct {
70 Algorithm string `json:"algorithm"`
71 GeneratorVersion string `json:"generatorVersion"`
72 Notes map[string]string `json:"notes"`
73 NumberOfTests int `json:"numberOfTests"`
74 // Header
75 TestGroups []*wycheproofTestGroup `json:"testGroups"`
76}
77
78func nidFromString(ns string) (int, error) {
79 switch ns {
80 case "SHA-1":
81 return C.NID_sha1, nil
82 case "SHA-224":
83 return C.NID_sha224, nil
84 case "SHA-256":
85 return C.NID_sha256, nil
86 case "SHA-384":
87 return C.NID_sha384, nil
88 case "SHA-512":
89 return C.NID_sha512, nil
90 default:
91 return -1, fmt.Errorf("unknown NID %q", ns)
92 }
93}
94
95func hashFromString(hs string) (hash.Hash, error) {
96 switch hs {
97 case "SHA-1":
98 return sha1.New(), nil
99 case "SHA-224":
100 return sha256.New224(), nil
101 case "SHA-256":
102 return sha256.New(), nil
103 case "SHA-384":
104 return sha512.New384(), nil
105 case "SHA-512":
106 return sha512.New(), nil
107 default:
108 return nil, fmt.Errorf("unknown hash %q", hs)
109 }
110}
111
112func runRSATest(rsa *C.RSA, nid int, h hash.Hash, wt *wycheproofTest) bool {
113 msg, err := hex.DecodeString(wt.Msg)
114 if err != nil {
115 log.Fatalf("Failed to decode message %q: %v", wt.Msg, err)
116 }
117
118 h.Reset()
119 h.Write(msg)
120 msg = h.Sum(nil)
121
122 sig, err := hex.DecodeString(wt.Sig)
123 if err != nil {
124 log.Fatalf("Failed to decode signature %q: %v", wt.Sig, err)
125 }
126
127 msgLen, sigLen := len(msg), len(sig)
128 if msgLen == 0 {
129 msg = append(msg, 0)
130 }
131 if sigLen == 0 {
132 sig = append(sig, 0)
133 }
134
135 ret := C.RSA_verify(C.int(nid), (*C.uchar)(unsafe.Pointer(&msg[0])), C.uint(msgLen),
136 (*C.uchar)(unsafe.Pointer(&sig[0])), C.uint(sigLen), rsa)
137
138 // XXX audit acceptable cases...
139 succeeded := true
140 if (ret == 1) != (wt.Result == "valid") && wt.Result != "acceptable" {
141 fmt.Printf("FAIL: Test case %d - RSA_verify() = %d, want %v\n", wt.TCID, int(ret), wt.Result)
142 succeeded = false
143 }
144 return succeeded
145}
146
147func runRSATestGroup(wtg *wycheproofTestGroup) bool {
148 fmt.Printf("Running RSA test group %v with key size %d and %v...\n", wtg.Type, wtg.KeySize, wtg.SHA)
149
150 rsa := C.RSA_new()
151 if rsa == nil {
152 log.Fatal("RSA_new failed")
153 }
154 defer C.RSA_free(rsa)
155
156 e := C.CString(wtg.E)
157 if C.BN_hex2bn(&rsa.e, e) == 0 {
158 log.Fatalf("Failed to set RSA e")
159 }
160 C.free(unsafe.Pointer(e))
161
162 n := C.CString(wtg.N)
163 if C.BN_hex2bn(&rsa.n, n) == 0 {
164 log.Fatalf("Failed to set RSA n")
165 }
166 C.free(unsafe.Pointer(n))
167
168 nid, err := nidFromString(wtg.SHA)
169 if err != nil {
170 log.Fatalf("Failed to get MD NID: %v", err)
171 }
172 h, err := hashFromString(wtg.SHA)
173 if err != nil {
174 log.Fatalf("Failed to get hash: %v", err)
175 }
176
177 succeeded := true
178 for _, wt := range wtg.Tests {
179 if !runRSATest(rsa, nid, h, wt) {
180 succeeded = false
181 }
182 }
183 return succeeded
184}
185
186func runRSATestVectors(path string) bool {
187 b, err := ioutil.ReadFile(path)
188 if err != nil {
189 log.Fatalf("Failed to read test vectors: %v", err)
190 }
191 wtv := &wycheproofTestVectors{}
192 if err := json.Unmarshal(b, wtv); err != nil {
193 log.Fatalf("Failed to unmarshal JSON: %v", err)
194 }
195 fmt.Printf("Loaded Wycheproof test vectors for %v with %d tests\n", wtv.Algorithm, wtv.NumberOfTests)
196
197 succeeded := true
198 for _, wtg := range wtv.TestGroups {
199 if !runRSATestGroup(wtg) {
200 succeeded = false
201 }
202 }
203 return succeeded
204}
205
206func main() {
207 if _, err := os.Stat(testVectorPath); os.IsNotExist(err) {
208 fmt.Printf("package wycheproof-testvectors is required for this regress\n")
209 fmt.Printf("SKIPPING\n")
210 os.Exit(0)
211 }
212
213 tvs, err := filepath.Glob(filepath.Join(testVectorPath, "*.json"))
214 if err != nil || len(tvs) == 0 {
215 log.Fatalf("Failed to find test vectors at %q\n", testVectorPath)
216 }
217
218 succeeded := true
219
220 tvs, err = filepath.Glob(filepath.Join(testVectorPath, "rsa_signature_*test.json"))
221 if err != nil {
222 log.Fatalf("Failed to find RSA test vectors: %v", err)
223 }
224 for _, tv := range tvs {
225 if !runRSATestVectors(tv) {
226 succeeded = false
227 }
228 }
229
230 if !succeeded {
231 os.Exit(1)
232 }
233}