diff options
author | tb <> | 2024-12-20 00:07:12 +0000 |
---|---|---|
committer | tb <> | 2024-12-20 00:07:12 +0000 |
commit | b1838090ad769162b2ea08f33254c67d084bb22f (patch) | |
tree | f04653a882e3c8a90b00b8e6f900e4a225736db9 /src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c | |
parent | 86a35b733e7f43fa01b1c83b3c582855e18ef432 (diff) | |
download | openbsd-b1838090ad769162b2ea08f33254c67d084bb22f.tar.gz openbsd-b1838090ad769162b2ea08f33254c67d084bb22f.tar.bz2 openbsd-b1838090ad769162b2ea08f33254c67d084bb22f.zip |
Rework and fix the mlkem tests
Make proper use of CBB and CBS. If a CBS ever owns data, you're holding
it wrong. Ditch gross macros, sscanf, and globals. The use of fgets is
annoying here, so replace it with getline, which be provided by portable
if needed.
Most importantly, make the tests actually signal failure rather than
only printing an error. Fix the state machines in a few of them. Some
tests didn't parse the .txt file at all. Others mostly did but didn't
actually test what they were supposed to be testing. Such failures
were hidden by the way the tests were written.
This basically needed a complete revamp. It still isn't pretty and much
of it could be deduplicated, but I only have so much time alotted on this
blue planet.
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c')
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c | 201 |
1 files changed, 134 insertions, 67 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c index 96dc435c4d..a88e487494 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* $OpenBSD: mlkem768_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ | 1 | /* $OpenBSD: mlkem768_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024 Google Inc. |
4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> |
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
5 | * | 6 | * |
6 | * Permission to use, copy, modify, and/or distribute this software for any | 7 | * Permission to use, copy, modify, and/or distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above |
@@ -16,113 +17,179 @@ | |||
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ | 18 | */ |
18 | 19 | ||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
19 | #include <stdint.h> | 22 | #include <stdint.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
22 | #include <string.h> | ||
23 | 25 | ||
24 | #include <openssl/bytestring.h> | 26 | #include "bytestring.h" |
25 | #include <openssl/mlkem.h> | 27 | #include "mlkem.h" |
26 | 28 | ||
27 | #include "mlkem_tests_util.h" | 29 | #include "mlkem_tests_util.h" |
28 | 30 | ||
29 | static void | 31 | static int |
30 | MlkemDecapFileTest(CBS *c, CBS *k, CBS *dk, int should_fail) | 32 | MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb, |
33 | CBB *private_key_cbb, int should_fail, size_t line) | ||
31 | { | 34 | { |
32 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
33 | struct MLKEM768_private_key priv; | 35 | struct MLKEM768_private_key priv; |
34 | int parse_ok, decap_ok; | 36 | uint8_t *ciphertext = NULL, *shared_secret = NULL, *private_key = NULL; |
37 | size_t ciphertext_len = 0, shared_secret_len = 0, private_key_len = 0; | ||
38 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | ||
39 | CBS private_key_cbs; | ||
40 | int failed = 1; | ||
35 | 41 | ||
36 | parse_ok = MLKEM768_parse_private_key(&priv, dk); | 42 | if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len)) |
37 | if (!parse_ok) { | 43 | goto err; |
38 | TEST(!should_fail, "parse_private_key"); | 44 | if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len)) |
39 | return; | 45 | goto err; |
46 | if (!CBB_finish(private_key_cbb, &private_key, &private_key_len)) | ||
47 | goto err; | ||
48 | |||
49 | CBS_init(&private_key_cbs, private_key, private_key_len); | ||
50 | |||
51 | if (!MLKEM768_parse_private_key(&priv, &private_key_cbs)) { | ||
52 | if ((failed = !should_fail)) | ||
53 | warnx("#%zu: parse_private_key", line); | ||
54 | goto err; | ||
55 | } | ||
56 | if (!MLKEM768_decap(shared_secret_buf, ciphertext, ciphertext_len, | ||
57 | &priv)) { | ||
58 | if ((failed = !should_fail)) | ||
59 | warnx("#%zu: decap", line); | ||
60 | goto err; | ||
40 | } | 61 | } |
41 | decap_ok = MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), | 62 | |
42 | &priv); | 63 | failed = compare_data(shared_secret, shared_secret_buf, |
43 | if (!decap_ok) { | 64 | MLKEM_SHARED_SECRET_BYTES, line, "shared_secret"); |
44 | TEST(!should_fail, "decap"); | 65 | |
45 | return; | 66 | if (should_fail != failed) { |
67 | warnx("FAIL: #%zu: should_fail %d, failed %d", | ||
68 | line, should_fail, failed); | ||
69 | failed = 1; | ||
46 | } | 70 | } |
47 | TEST_DATAEQ(shared_secret, CBS_data(k), | 71 | |
48 | MLKEM_SHARED_SECRET_BYTES, "shared_secret"); | 72 | err: |
73 | CBB_cleanup(ciphertext_cbb); | ||
74 | CBB_cleanup(shared_secret_cbb); | ||
75 | CBB_cleanup(private_key_cbb); | ||
76 | freezero(ciphertext, ciphertext_len); | ||
77 | freezero(shared_secret, shared_secret_len); | ||
78 | freezero(private_key, private_key_len); | ||
79 | |||
80 | return failed; | ||
49 | } | 81 | } |
50 | 82 | ||
51 | #define S_START 0 | 83 | #define S_START 0 |
52 | #define S_COMMENT 1 | 84 | #define S_COMMENT 1 |
53 | #define S_PRIVATE_KEY 2 | 85 | #define S_PRIVATE_KEY 2 |
54 | #define S_CIPHERTEXT 3 | 86 | #define S_CIPHERTEXT 3 |
55 | #define S_RESULT 4 | 87 | #define S_RESULT 4 |
56 | #define S_SHARED_SECRET 5 | 88 | #define S_SHARED_SECRET 5 |
89 | |||
90 | #define S2S(x) case x: return #x | ||
91 | |||
92 | static const char * | ||
93 | state2str(int state) | ||
94 | { | ||
95 | switch (state) { | ||
96 | S2S(S_START); | ||
97 | S2S(S_COMMENT); | ||
98 | S2S(S_PRIVATE_KEY); | ||
99 | S2S(S_CIPHERTEXT); | ||
100 | S2S(S_RESULT); | ||
101 | S2S(S_SHARED_SECRET); | ||
102 | default: | ||
103 | errx(1, "unknown state %d", state); | ||
104 | } | ||
105 | } | ||
57 | 106 | ||
58 | int | 107 | int |
59 | main(int argc, char **argv) | 108 | main(int argc, char **argv) |
60 | { | 109 | { |
61 | CBS ciphertext, shared_secret, private_key; | 110 | CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 }; |
62 | const uint8_t *p = NULL; | ||
63 | int should_fail = 0; | 111 | int should_fail = 0; |
64 | char *buf; | 112 | const char *test; |
113 | size_t line = 0; | ||
114 | char *buf = NULL; | ||
115 | size_t buflen = 0; | ||
116 | ssize_t len; | ||
65 | FILE *fp; | 117 | FILE *fp; |
66 | int state; | 118 | int state; |
119 | int failed = 0; | ||
120 | |||
121 | if (argc < 2) | ||
122 | errx(1, "%s: missing test file", argv[0]); | ||
123 | |||
124 | test = argv[1]; | ||
125 | |||
126 | if ((fp = fopen(test, "r")) == NULL) | ||
127 | err(1, "cant't open test file"); | ||
67 | 128 | ||
68 | fprintf(stderr, "Testing decap test vectors in %s\n", argv[1]); | ||
69 | TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file"); | ||
70 | MALLOC(buf, 16*1024); | ||
71 | state = S_COMMENT; | 129 | state = S_COMMENT; |
72 | test_number = 1; | 130 | line = 0; |
73 | while (fgets(buf, 16*1024, fp) != NULL) { | 131 | |
132 | while ((len = getline(&buf, &buflen, fp)) != -1) { | ||
133 | const char *msg = state2str(state); | ||
134 | CBS cbs; | ||
135 | uint8_t u8; | ||
136 | |||
137 | line++; | ||
138 | CBS_init(&cbs, buf, len); | ||
139 | |||
140 | if (!CBS_get_last_u8(&cbs, &u8)) | ||
141 | errx(1, "#%zu %s: CBB_get_last_u8", line, msg); | ||
142 | assert(u8 == '\n'); | ||
143 | |||
74 | switch (state) { | 144 | switch (state) { |
75 | case S_START: | 145 | case S_START: |
76 | if (strcmp(buf, "\n") != 0) | ||
77 | break; | ||
78 | state = S_COMMENT; | 146 | state = S_COMMENT; |
79 | break; | 147 | break; |
80 | case S_COMMENT: | 148 | case S_COMMENT: |
81 | if (strncmp(buf, "#", 1) != 0) | 149 | if (!CBS_get_u8(&cbs, &u8)) |
82 | break; | 150 | errx(1, "#%zu %s: CBB_get_u8", line, msg); |
151 | assert(u8 == '#'); | ||
152 | if (!CBS_skip(&cbs, CBS_len(&cbs))) | ||
153 | errx(1, "#%zu %s: CBB_skip", line, msg); | ||
83 | state = S_PRIVATE_KEY; | 154 | state = S_PRIVATE_KEY; |
84 | break; | 155 | break; |
85 | case S_PRIVATE_KEY: | 156 | case S_PRIVATE_KEY: |
86 | if (strncmp(buf, "private_key: ", | 157 | if (!get_string_cbs(&cbs, "private_key: ", line, msg)) |
87 | strlen("private_key: ")) != 0) | 158 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
88 | break; | 159 | hex_decode_cbs(&cbs, &private_key, line, msg); |
89 | grab_data(&private_key, buf, strlen("private_key: ")); | ||
90 | p = CBS_data(&private_key); | ||
91 | state = S_CIPHERTEXT; | 160 | state = S_CIPHERTEXT; |
92 | break; | 161 | break; |
93 | case S_CIPHERTEXT: | 162 | case S_CIPHERTEXT: |
94 | if (strncmp(buf, "ciphertext: ", | 163 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) |
95 | strlen("ciphertext: ")) != 0) | 164 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
96 | break; | 165 | hex_decode_cbs(&cbs, &ciphertext, line, msg); |
97 | grab_data(&ciphertext, buf, strlen("ciphertext: ")); | ||
98 | state = S_RESULT; | 166 | state = S_RESULT; |
99 | break; | 167 | break; |
100 | case S_RESULT: | 168 | case S_RESULT: |
101 | if (strncmp(buf, "result: pass", | 169 | if (!get_string_cbs(&cbs, "result: ", line, msg)) |
102 | strlen("result: pass")) != 0) | 170 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
103 | should_fail = 1; | 171 | should_fail = get_string_cbs(&cbs, "fail", line, msg); |
104 | else | ||
105 | should_fail = 0; | ||
106 | state = S_SHARED_SECRET; | 172 | state = S_SHARED_SECRET; |
107 | break; | 173 | break; |
108 | case S_SHARED_SECRET: | 174 | case S_SHARED_SECRET: |
109 | if (strncmp(buf, "shared_secret: ", | 175 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) |
110 | strlen("shared_secret: ")) != 0) | 176 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
111 | break; | 177 | hex_decode_cbs(&cbs, &shared_secret, line, msg); |
112 | grab_data(&shared_secret, buf, | 178 | |
113 | strlen("shared_secret: ")); | 179 | failed |= MlkemDecapFileTest(&ciphertext, &shared_secret, |
114 | MlkemDecapFileTest(&ciphertext, &shared_secret, | 180 | &private_key, should_fail, line); |
115 | &private_key, should_fail); | 181 | |
116 | free((void *)CBS_data(&ciphertext)); | ||
117 | free((void *)CBS_data(&shared_secret)); | ||
118 | free((void *)p); | ||
119 | |||
120 | test_number++; | ||
121 | state = S_START; | 182 | state = S_START; |
122 | break; | 183 | break; |
123 | } | 184 | } |
185 | if (CBS_len(&cbs) > 0) | ||
186 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
124 | } | 187 | } |
125 | |||
126 | free(buf); | 188 | free(buf); |
127 | exit(failure); | 189 | |
190 | if (ferror(fp)) | ||
191 | err(1, NULL); | ||
192 | fclose(fp); | ||
193 | |||
194 | return failed; | ||
128 | } | 195 | } |