diff options
author | tb <> | 2022-07-07 20:01:20 +0000 |
---|---|---|
committer | tb <> | 2022-07-07 20:01:20 +0000 |
commit | b836d66591e0c2a45519653d065d29807d70ac5d (patch) | |
tree | 676c18a467cb0fc9fdc91292b157f3fe2fe38905 /src | |
parent | dad327347e69c9005cad59140fe50274b5e469e6 (diff) | |
download | openbsd-b836d66591e0c2a45519653d065d29807d70ac5d.tar.gz openbsd-b836d66591e0c2a45519653d065d29807d70ac5d.tar.bz2 openbsd-b836d66591e0c2a45519653d065d29807d70ac5d.zip |
Add support for primality checking
Project Wycheproof's primality_tests.json contain a set of 280 numbers
that trigger edge cases in Miller-Rabin and related checks. libcrypto's
Miller-Rabin test is known to be rather poor, hopefully we will soon see
a diff on tech that improves on this.
This extends the Go test in the usual way and also adds a perl script
that allows testing on non-Go architectures.
Deliberately not yet linked to regress since the tests are flaky with
the current BN_is_prime_ex() implementatation.
Diffstat (limited to 'src')
4 files changed, 218 insertions, 10 deletions
diff --git a/src/regress/lib/libcrypto/wycheproof/Makefile b/src/regress/lib/libcrypto/wycheproof/Makefile index 0fcde086f7..2e1d16b165 100644 --- a/src/regress/lib/libcrypto/wycheproof/Makefile +++ b/src/regress/lib/libcrypto/wycheproof/Makefile | |||
@@ -1,17 +1,21 @@ | |||
1 | # $OpenBSD: Makefile,v 1.3 2019/04/24 20:25:19 bluhm Exp $ | 1 | # $OpenBSD: Makefile,v 1.4 2022/07/07 20:01:20 tb Exp $ |
2 | 2 | ||
3 | .if ! (make(clean) || make(cleandir) || make(obj)) | 3 | WYCHEPROOF_TESTVECTORS = /usr/local/share/wycheproof/testvectors/ |
4 | GO_VERSION != sh -c "(go version) 2>/dev/null || true" | ||
5 | .endif | ||
6 | 4 | ||
7 | .if empty(GO_VERSION) | 5 | .if !exists(${WYCHEPROOF_TESTVECTORS}) |
8 | regress: | 6 | regress: |
9 | @echo package go is required for this regress | 7 | @echo package wycheproof-testvectors is required for this regress |
8 | @echo package go should be installed if available | ||
10 | @echo SKIPPED | 9 | @echo SKIPPED |
11 | .endif | 10 | .else |
11 | |||
12 | # REGRESS_TARGETS += regress-wycheproof-primes | ||
13 | |||
14 | . if exists(/usr/local/bin/go) | ||
12 | 15 | ||
13 | CLEANFILES+=wycheproof | 16 | REGRESS_TARGETS += regress-wycheproof |
14 | REGRESS_TARGETS=regress-wycheproof | 17 | |
18 | CLEANFILES += wycheproof | ||
15 | 19 | ||
16 | audit: wycheproof | 20 | audit: wycheproof |
17 | ./wycheproof -v | 21 | ./wycheproof -v |
@@ -24,4 +28,25 @@ regress-wycheproof: wycheproof | |||
24 | 28 | ||
25 | .PHONY: audit | 29 | .PHONY: audit |
26 | 30 | ||
31 | . endif | ||
32 | |||
33 | PROGS += wycheproof-primes | ||
34 | |||
35 | LDADD = -lcrypto | ||
36 | DPADD = ${LIBCRYPTO} | ||
37 | CFLAGS = -I${.CURDIR} -I${.OBJDIR} | ||
38 | |||
39 | primality_testcases.h: wycheproof-json.pl ${WYCHEPROOF_TESTVECTORS}/primality_test.json | ||
40 | perl ${.CURDIR}/wycheproof-json.pl > $@.tmp | ||
41 | mv -f $@.tmp $@ | ||
42 | |||
43 | wycheproof-primes: wycheproof-primes.c primality_testcases.h | ||
44 | |||
45 | regress-wycheproof-primes: primality_testcases.h wycheproof-primes | ||
46 | ./wycheproof-primes | ||
47 | |||
48 | CLEANFILES += primality_testcases.h | ||
49 | |||
50 | .endif | ||
51 | |||
27 | .include <bsd.regress.mk> | 52 | .include <bsd.regress.mk> |
diff --git a/src/regress/lib/libcrypto/wycheproof/wycheproof-json.pl b/src/regress/lib/libcrypto/wycheproof/wycheproof-json.pl new file mode 100644 index 0000000000..01fa66f7f7 --- /dev/null +++ b/src/regress/lib/libcrypto/wycheproof/wycheproof-json.pl | |||
@@ -0,0 +1,71 @@ | |||
1 | # $OpenBSD: wycheproof-json.pl,v 1.1 2022/07/07 20:01:20 tb Exp $ | ||
2 | |||
3 | # Copyright (c) 2022 Joel Sing <jsing@openbsd.org> | ||
4 | # Copyright (c) 2022 Theo Buehler <tb@openbsd.org> | ||
5 | # | ||
6 | # Permission to use, copy, modify, and distribute this software for any | ||
7 | # purpose with or without fee is hereby granted, provided that the above | ||
8 | # copyright notice and this permission notice appear in all copies. | ||
9 | # | ||
10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | |||
18 | use JSON::PP; | ||
19 | |||
20 | $test_vector_path = "/usr/local/share/wycheproof/testvectors"; | ||
21 | |||
22 | open JSON, "$test_vector_path/primality_test.json" or die; | ||
23 | @json = <JSON>; | ||
24 | close JSON; | ||
25 | |||
26 | $tv = JSON::PP::decode_json(join "\n", @json); | ||
27 | $test_groups = %$tv{"testGroups"}; | ||
28 | |||
29 | my $wycheproof_struct = <<"EOL"; | ||
30 | struct wycheproof_testcase { | ||
31 | int id; | ||
32 | const char *value; | ||
33 | int acceptable; | ||
34 | int result; | ||
35 | }; | ||
36 | |||
37 | struct wycheproof_testcase testcases[] = { | ||
38 | EOL | ||
39 | |||
40 | print $wycheproof_struct; | ||
41 | |||
42 | foreach $test_group (@$test_groups) { | ||
43 | $test_group_type = %$test_group{"type"}; | ||
44 | $test_group_tests = %$test_group{"tests"}; | ||
45 | |||
46 | foreach $test_case (@$test_group_tests) { | ||
47 | %tc = %$test_case; | ||
48 | |||
49 | $tc_id = $tc{"tcId"}; | ||
50 | $tc_value = $tc{"value"}; | ||
51 | $tc_result = $tc{"result"}; | ||
52 | $tc_flags = @{$tc{"flags"}}; | ||
53 | |||
54 | my $result = $tc_result eq "valid" ? 1 : 0; | ||
55 | |||
56 | print "\t{\n"; | ||
57 | print "\t\t.id = $tc_id,\n"; | ||
58 | print "\t\t.value = \"$tc_value\",\n"; | ||
59 | print "\t\t.result = $result,\n"; | ||
60 | |||
61 | if ($tc_result eq "acceptable") { | ||
62 | print "\t\t.acceptable = 1,\n"; | ||
63 | } | ||
64 | |||
65 | print "\t},\n"; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | print "};\n\n"; | ||
70 | |||
71 | print "#define N_TESTS (sizeof(testcases) / sizeof(testcases[0]))\n" | ||
diff --git a/src/regress/lib/libcrypto/wycheproof/wycheproof-primes.c b/src/regress/lib/libcrypto/wycheproof/wycheproof-primes.c new file mode 100644 index 0000000000..669531d135 --- /dev/null +++ b/src/regress/lib/libcrypto/wycheproof/wycheproof-primes.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* $OpenBSD: wycheproof-primes.c,v 1.1 2022/07/07 20:01:20 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2022 Theo Buehler <tb@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 | #include <err.h> | ||
19 | #include <stdio.h> | ||
20 | |||
21 | #include <openssl/bn.h> | ||
22 | |||
23 | #include "primality_testcases.h" | ||
24 | |||
25 | int | ||
26 | primality_test(struct wycheproof_testcase *test) | ||
27 | { | ||
28 | BIGNUM *value = NULL; | ||
29 | int ret; | ||
30 | int failed = 1; | ||
31 | |||
32 | if (!BN_hex2bn(&value, test->value)) | ||
33 | errx(1, "%d: failed to set value \"%s\"", test->id, test->value); | ||
34 | |||
35 | if ((ret = BN_is_prime_ex(value, BN_prime_checks, NULL, NULL)) < 0) | ||
36 | errx(1, "%d: BN_is_prime_ex errored", test->id); | ||
37 | |||
38 | if (ret != test->result && !test->acceptable) { | ||
39 | fprintf(stderr, "%d failed, want %d, got %d\n", test->id, | ||
40 | test->result, ret); | ||
41 | goto err; | ||
42 | } | ||
43 | |||
44 | failed = 0; | ||
45 | err: | ||
46 | BN_free(value); | ||
47 | |||
48 | return failed; | ||
49 | } | ||
50 | |||
51 | int | ||
52 | main(void) | ||
53 | { | ||
54 | size_t i; | ||
55 | int failed = 0; | ||
56 | |||
57 | for (i = 0; i < N_TESTS; i++) | ||
58 | failed |= primality_test(&testcases[i]); | ||
59 | |||
60 | printf("%s\n", failed ? "FAILED" : "SUCCESS"); | ||
61 | |||
62 | return failed; | ||
63 | } | ||
diff --git a/src/regress/lib/libcrypto/wycheproof/wycheproof.go b/src/regress/lib/libcrypto/wycheproof/wycheproof.go index bd45a733b4..a638d0fdd9 100644 --- a/src/regress/lib/libcrypto/wycheproof/wycheproof.go +++ b/src/regress/lib/libcrypto/wycheproof/wycheproof.go | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: wycheproof.go,v 1.126 2022/05/05 18:34:27 tb Exp $ */ | 1 | /* $OpenBSD: wycheproof.go,v 1.127 2022/07/07 20:01:20 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2018 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2018 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2018,2019,2022 Theo Buehler <tb@openbsd.org> | 4 | * Copyright (c) 2018,2019,2022 Theo Buehler <tb@openbsd.org> |
@@ -349,6 +349,19 @@ type wycheproofTestGroupKW struct { | |||
349 | Tests []*wycheproofTestKW `json:"tests"` | 349 | Tests []*wycheproofTestKW `json:"tests"` |
350 | } | 350 | } |
351 | 351 | ||
352 | type wycheproofTestPrimality struct { | ||
353 | TCID int `json:"tcId"` | ||
354 | Comment string `json:"comment"` | ||
355 | Value string `json:"value"` | ||
356 | Result string `json:"result"` | ||
357 | Flags []string `json:"flags"` | ||
358 | } | ||
359 | |||
360 | type wycheproofTestGroupPrimality struct { | ||
361 | Type string `json:"type"` | ||
362 | Tests []*wycheproofTestPrimality `json:"tests"` | ||
363 | } | ||
364 | |||
352 | type wycheproofTestRSA struct { | 365 | type wycheproofTestRSA struct { |
353 | TCID int `json:"tcId"` | 366 | TCID int `json:"tcId"` |
354 | Comment string `json:"comment"` | 367 | Comment string `json:"comment"` |
@@ -2223,6 +2236,35 @@ func runKWTestGroup(algorithm string, wtg *wycheproofTestGroupKW) bool { | |||
2223 | return success | 2236 | return success |
2224 | } | 2237 | } |
2225 | 2238 | ||
2239 | func runPrimalityTest(wt *wycheproofTestPrimality) bool { | ||
2240 | var bnValue *C.BIGNUM | ||
2241 | value := C.CString(wt.Value) | ||
2242 | if C.BN_hex2bn(&bnValue, value) == 0 { | ||
2243 | log.Fatal("Failed to set bnValue") | ||
2244 | } | ||
2245 | C.free(unsafe.Pointer(value)) | ||
2246 | defer C.BN_free(bnValue) | ||
2247 | |||
2248 | ret := C.BN_is_prime_ex(bnValue, C.BN_prime_checks, (*C.BN_CTX)(unsafe.Pointer(nil)), (*C.BN_GENCB)(unsafe.Pointer(nil))) | ||
2249 | success := wt.Result == "acceptable" || (ret == 0 && wt.Result == "invalid") || (ret == 1 && wt.Result == "valid") | ||
2250 | if !success { | ||
2251 | fmt.Printf("FAIL: Test case %d (%q) %v failed - got %d, want %v\n", wt.TCID, wt.Comment, wt.Flags, ret, wt.Result) | ||
2252 | } | ||
2253 | return success | ||
2254 | } | ||
2255 | |||
2256 | func runPrimalityTestGroup(algorithm string, wtg *wycheproofTestGroupPrimality) bool { | ||
2257 | fmt.Printf("Running %v test group...\n", algorithm) | ||
2258 | |||
2259 | success := true | ||
2260 | for _, wt := range wtg.Tests { | ||
2261 | if !runPrimalityTest(wt) { | ||
2262 | success = false | ||
2263 | } | ||
2264 | } | ||
2265 | return success | ||
2266 | } | ||
2267 | |||
2226 | func runRsaesOaepTest(rsa *C.RSA, sha *C.EVP_MD, mgfSha *C.EVP_MD, wt *wycheproofTestRsaes) bool { | 2268 | func runRsaesOaepTest(rsa *C.RSA, sha *C.EVP_MD, mgfSha *C.EVP_MD, wt *wycheproofTestRsaes) bool { |
2227 | ct, err := hex.DecodeString(wt.CT) | 2269 | ct, err := hex.DecodeString(wt.CT) |
2228 | if err != nil { | 2270 | if err != nil { |
@@ -2733,6 +2775,8 @@ func runTestVectors(path string, variant testVariant) bool { | |||
2733 | wtg = &wycheproofTestGroupHmac{} | 2775 | wtg = &wycheproofTestGroupHmac{} |
2734 | case "KW": | 2776 | case "KW": |
2735 | wtg = &wycheproofTestGroupKW{} | 2777 | wtg = &wycheproofTestGroupKW{} |
2778 | case "PrimalityTest": | ||
2779 | wtg = &wycheproofTestGroupPrimality{} | ||
2736 | case "RSAES-OAEP": | 2780 | case "RSAES-OAEP": |
2737 | wtg = &wycheproofTestGroupRsaesOaep{} | 2781 | wtg = &wycheproofTestGroupRsaesOaep{} |
2738 | case "RSAES-PKCS1-v1_5": | 2782 | case "RSAES-PKCS1-v1_5": |
@@ -2812,6 +2856,10 @@ func runTestVectors(path string, variant testVariant) bool { | |||
2812 | if !runKWTestGroup(wtv.Algorithm, wtg.(*wycheproofTestGroupKW)) { | 2856 | if !runKWTestGroup(wtv.Algorithm, wtg.(*wycheproofTestGroupKW)) { |
2813 | success = false | 2857 | success = false |
2814 | } | 2858 | } |
2859 | case "PrimalityTest": | ||
2860 | if !runPrimalityTestGroup(wtv.Algorithm, wtg.(*wycheproofTestGroupPrimality)) { | ||
2861 | success = false | ||
2862 | } | ||
2815 | case "RSAES-OAEP": | 2863 | case "RSAES-OAEP": |
2816 | if !runRsaesOaepTestGroup(wtv.Algorithm, wtg.(*wycheproofTestGroupRsaesOaep)) { | 2864 | if !runRsaesOaepTestGroup(wtv.Algorithm, wtg.(*wycheproofTestGroupRsaesOaep)) { |
2817 | success = false | 2865 | success = false |
@@ -2875,6 +2923,7 @@ func main() { | |||
2875 | {"HKDF", "hkdf_sha*_test.json", Normal}, | 2923 | {"HKDF", "hkdf_sha*_test.json", Normal}, |
2876 | {"HMAC", "hmac_sha*_test.json", Normal}, | 2924 | {"HMAC", "hmac_sha*_test.json", Normal}, |
2877 | {"KW", "kw_test.json", Normal}, | 2925 | {"KW", "kw_test.json", Normal}, |
2926 | {"Primality test", "primality_test.json", Skip}, // XXX | ||
2878 | {"RSA", "rsa_*test.json", Normal}, | 2927 | {"RSA", "rsa_*test.json", Normal}, |
2879 | {"X25519", "x25519_test.json", Normal}, | 2928 | {"X25519", "x25519_test.json", Normal}, |
2880 | {"X25519 ASN", "x25519_asn_test.json", Skip}, | 2929 | {"X25519 ASN", "x25519_asn_test.json", Skip}, |