summaryrefslogtreecommitdiff
path: root/src/regress
diff options
context:
space:
mode:
authortb <>2022-01-11 19:20:36 +0000
committertb <>2022-01-11 19:20:36 +0000
commit7cf312febdc2fe98f0be04638741c476a65ade1c (patch)
treedce6ffd62648d46a2cc11bff0803891a32ce63e0 /src/regress
parent9c34baf70c4739d0533e2fd4fe0c75a5acdbd135 (diff)
downloadopenbsd-7cf312febdc2fe98f0be04638741c476a65ade1c.tar.gz
openbsd-7cf312febdc2fe98f0be04638741c476a65ade1c.tar.bz2
openbsd-7cf312febdc2fe98f0be04638741c476a65ade1c.zip
Add regress for EVP_PKEY_{,public_,param_}check()
Diffstat (limited to 'src/regress')
-rw-r--r--src/regress/lib/libcrypto/evp/Makefile18
-rw-r--r--src/regress/lib/libcrypto/evp/evp_pkey_check.c404
2 files changed, 415 insertions, 7 deletions
diff --git a/src/regress/lib/libcrypto/evp/Makefile b/src/regress/lib/libcrypto/evp/Makefile
index 33c77fc1dd..89779ae22a 100644
--- a/src/regress/lib/libcrypto/evp/Makefile
+++ b/src/regress/lib/libcrypto/evp/Makefile
@@ -1,14 +1,18 @@
1# $OpenBSD: Makefile,v 1.3 2014/07/08 15:53:52 jsing Exp $ 1# $OpenBSD: Makefile,v 1.4 2022/01/11 19:20:36 tb Exp $
2 2
3PROG= evptest 3PROGS= evptest evp_pkey_check
4LDADD= -lcrypto 4LDADD= ${CRYPTO_INT}
5DPADD= ${LIBCRYPTO} 5DPADD= ${LIBCRYPTO}
6WARNINGS= Yes 6WARNINGS= Yes
7CFLAGS+= -DLIBRESSL_INTERNAL -Werror 7CFLAGS+= -DLIBRESSL_INTERNAL -DLIBRESSL_CRYPTO_INTERNAL -Werror
8 8
9REGRESS_TARGETS=regress-evptest 9REGRESS_TARGETS+= regress-evptest
10REGRESS_TARGETS+= regress-evp_pkey_check
10 11
11regress-evptest: ${PROG} 12regress-evptest: evptest
12 ./${PROG} ${.CURDIR}/evptests.txt 13 ./evptest ${.CURDIR}/evptests.txt
14
15regress-evp_pkey_check: evp_pkey_check
16 ./evp_pkey_check
13 17
14.include <bsd.regress.mk> 18.include <bsd.regress.mk>
diff --git a/src/regress/lib/libcrypto/evp/evp_pkey_check.c b/src/regress/lib/libcrypto/evp/evp_pkey_check.c
new file mode 100644
index 0000000000..cc3d0390d2
--- /dev/null
+++ b/src/regress/lib/libcrypto/evp/evp_pkey_check.c
@@ -0,0 +1,404 @@
1/* $OpenBSD: evp_pkey_check.c,v 1.1 2022/01/11 19:20:36 tb Exp $ */
2/*
3 * Copyright (c) 2021-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 <stdio.h>
19
20#include <openssl/bn.h>
21#include <openssl/ec.h>
22#include <openssl/err.h>
23#include <openssl/evp.h>
24#include <openssl/rsa.h>
25
26#define EVP_TEST_RSA_BITS 2048
27
28static int
29evp_pkey_check_rsa(void)
30{
31 EVP_PKEY_CTX *pkey_ctx = NULL;
32 EVP_PKEY *pkey = NULL;
33 RSA *rsa = NULL;
34 BIGNUM *rsa_d;
35 int ret;
36 int fail_soft = 0;
37 int failed = 1;
38
39 /*
40 * Generate a run-off-the-mill RSA key.
41 */
42
43 if ((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
44 fprintf(stderr, "%s: EVP_PKEY_CTX_new_id()\n", __func__);
45 goto err;
46 }
47 if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
48 fprintf(stderr, "%s: EVP_PKEY_keygen_init\n", __func__);
49 goto err;
50 }
51 if (!EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, EVP_TEST_RSA_BITS)) {
52 fprintf(stderr, "%s: EVP_PKEY_CTX_set_rsa_keygen_bits\n",
53 __func__);
54 goto err;
55 }
56 if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
57 fprintf(stderr, "%s: EVP_PKEY_keygen\n", __func__);
58 goto err;
59 }
60
61 /* At this point, no pkey is set on pkey_ctx, we should fail with 0. */
62 if (EVP_PKEY_check(pkey_ctx) != 0) {
63 fprintf(stderr, "%s: EVP_PKEY_check() succeeded without pkey\n",
64 __func__);
65 ERR_print_errors_fp(stderr);
66 fail_soft = 1;
67 }
68
69 ERR_clear_error();
70
71 /*
72 * Create a new EVP_PKEY_CTX with pkey set.
73 */
74
75 EVP_PKEY_CTX_free(pkey_ctx);
76 if ((pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
77 fprintf(stderr, "%s: EVP_PKEY_CTX_new\n", __func__);
78 goto err;
79 }
80
81 /* The freshly generated pkey is set on pkey_ctx. We should succeed. */
82 if ((ret = EVP_PKEY_check(pkey_ctx)) <= 0) {
83 fprintf(stderr, "%s: EVP_PKEY_check(), generated pkey: %d\n",
84 __func__, ret);
85 ERR_print_errors_fp(stderr);
86 ERR_clear_error();
87 fail_soft = 1;
88 }
89
90 /* Public key checking for RSA is not supported. */
91 if ((ret = EVP_PKEY_public_check(pkey_ctx)) != -2) {
92 fprintf(stderr,
93 "%s: EVP_PKEY_public_check() supported for RSA?\n",
94 __func__);
95 goto err;
96 }
97 ERR_clear_error();
98
99 /* Parameter checking for RSA is not supported. */
100 if ((ret = EVP_PKEY_param_check(pkey_ctx)) != -2) {
101 fprintf(stderr,
102 "%s: EVP_PKEY_param_check() supported for RSA?\n",
103 __func__);
104 goto err;
105 }
106 ERR_clear_error();
107
108 /*
109 * Now modify the RSA key a bit. The check should then fail.
110 */
111
112 if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
113 fprintf(stderr, "%s: EVP_PKEY_get0_RSA\n", __func__);
114 goto err;
115 }
116 /* We're lazy and modify rsa->d directly, hence the ugly cast. */
117 if ((rsa_d = (BIGNUM *)RSA_get0_d(rsa)) == NULL) {
118 fprintf(stderr, "%s: RSA_get0_d()\n", __func__);
119 goto err;
120 }
121 if (!BN_add_word(rsa_d, 2)) {
122 fprintf(stderr, "%s: BN_add_word\n", __func__);
123 goto err;
124 }
125
126 /* Since (d+2) * e != 1 mod (p-1)*(q-1), we should fail */
127 if (EVP_PKEY_check(pkey_ctx) == 1) {
128 fprintf(stderr, "%s: EVP_PKEY_check success with modified d\n",
129 __func__);
130 fail_soft = 1;
131 }
132
133 /*
134 * Spew some garbage to stderr.
135 */
136
137 fprintf(stderr, "We should see some errors about RSA d:\n");
138 ERR_print_errors_fp(stderr);
139 ERR_clear_error();
140 fprintf(stderr, "EVP_PKEY_check test for RSA done.\n");
141
142 failed = 0;
143
144 err:
145 EVP_PKEY_CTX_free(pkey_ctx);
146 EVP_PKEY_free(pkey);
147
148 return failed | fail_soft;
149}
150
151static int
152evp_pkey_check_ec(void)
153{
154 EVP_PKEY_CTX *pkey_ctx = NULL;
155 EVP_PKEY *pkey = NULL;
156 EC_KEY *eckey = NULL;
157 BIGNUM *private_key = NULL;
158 EC_GROUP *group;
159 const EC_POINT *generator;
160 BIGNUM *cofactor = NULL, *order = NULL;
161 int ret;
162 int fail_soft = 0;
163 int failed = 1;
164
165 /*
166 * Generate an elliptic curve key on secp384r1
167 */
168
169 if ((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) {
170 fprintf(stderr, "%s: EVP_PKEY_CTX_new_id\n", __func__);
171 goto err;
172 }
173 if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
174 fprintf(stderr, "%s: EVP_PKEY_keygen_init\n", __func__);
175 goto err;
176 }
177 if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx,
178 NID_secp384r1) <= 0) {
179 fprintf(stderr, "%s: EVP_PKEY_CTX_set_ec_paramgen_curve_nid\n",
180 __func__);
181 goto err;
182 }
183 if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
184 fprintf(stderr, "%s: EVP_PKEY_keygen\n", __func__);
185 goto err;
186 }
187
188 /* At this point, no pkey is set on pkey_ctx, we should fail with 0. */
189 if (EVP_PKEY_check(pkey_ctx) != 0) {
190 fprintf(stderr, "%s: EVP_PKEY_check() succeeded without pkey\n",
191 __func__);
192 ERR_print_errors_fp(stderr);
193 fail_soft = 1;
194 }
195
196 ERR_clear_error();
197
198 /*
199 * Create a new EVP_PKEY_CTX with pkey set.
200 */
201
202 EVP_PKEY_CTX_free(pkey_ctx);
203 if ((pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
204 fprintf(stderr, "%s: EVP_PKEY_CTX_new\n", __func__);
205 goto err;
206 }
207
208 /* The freshly generated pkey is set on pkey_ctx. We should succeed. */
209 if ((ret = EVP_PKEY_check(pkey_ctx)) <= 0) {
210 fprintf(stderr, "%s: EVP_PKEY_check(), generated pkey: %d\n",
211 __func__, ret);
212 ERR_print_errors_fp(stderr);
213 ERR_clear_error();
214 fail_soft = 1;
215 }
216
217 /* We should also succeed the public check. */
218 if ((ret = EVP_PKEY_public_check(pkey_ctx)) <= 0) {
219 fprintf(stderr,
220 "%s: EVP_PKEY_public_check(), generated pkey: %d\n",
221 __func__, ret);
222 ERR_print_errors_fp(stderr);
223 ERR_clear_error();
224 fail_soft = 1;
225 }
226
227 /* We should also succeed the parameter check. */
228 if ((ret = EVP_PKEY_param_check(pkey_ctx)) <= 0) {
229 fprintf(stderr,
230 "%s: EVP_PKEY_param_check(), generated pkey: %d\n",
231 __func__, ret);
232 ERR_print_errors_fp(stderr);
233 ERR_clear_error();
234 fail_soft = 1;
235 }
236
237 /*
238 * Modify the private key slightly.
239 */
240
241 if ((eckey = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
242 fprintf(stderr, "%s: EVP_PKEY_get0_EC_KEY\n", __func__);
243 goto err;
244 }
245
246 /* We're lazy and modify the private key directly. */
247 if ((private_key = (BIGNUM *)EC_KEY_get0_private_key(eckey)) == NULL) {
248 fprintf(stderr, "%s: EC_KEY_get0_private_key\n", __func__);
249 goto err;
250 }
251
252 /*
253 * The private key is a random number in [1, order). Preserve this
254 * property by adding 1 if it is equal to 1 and subtracting 1 otherwise.
255 */
256 if (BN_cmp(private_key, BN_value_one()) == 0) {
257 if (!BN_add_word(private_key, 1)) {
258 fprintf(stderr, "%s: BN_add_word\n", __func__);
259 goto err;
260 }
261 } else {
262 if (!BN_sub_word(private_key, 1)) {
263 fprintf(stderr, "%s: BN_sub_word\n", __func__);
264 goto err;
265 }
266 }
267
268 /* Generator times private key will no longer be equal to public key. */
269 if (EVP_PKEY_check(pkey_ctx) == 1) {
270 fprintf(stderr, "%s: EVP_PKEY_check succeeded unexpectedly\n",
271 __func__);
272 fail_soft = 1;
273 }
274
275 /*
276 * Spew some garbage to stderr.
277 */
278
279 fprintf(stderr, "We should see an error about the EC private key:\n");
280 ERR_print_errors_fp(stderr);
281 ERR_clear_error();
282
283 /* EVP_PKEY_public_check checks the private key (sigh), so we fail. */
284 if ((ret = EVP_PKEY_public_check(pkey_ctx)) == 1) {
285 fprintf(stderr,
286 "%s: EVP_PKEY_public_check succeeded unexpectedly\n",
287 __func__);
288 fail_soft = 1;
289 }
290
291 /* We should still succeed the parameter check. */
292 if ((ret = EVP_PKEY_param_check(pkey_ctx)) <= 0) {
293 fprintf(stderr,
294 "%s: EVP_PKEY_param_check(), modified privkey pkey: %d\n",
295 __func__, ret);
296 ERR_print_errors_fp(stderr);
297 ERR_clear_error();
298 fail_soft = 1;
299 }
300
301 /* Now set the private key to NULL. The API will think malloc failed. */
302 if (EC_KEY_set_private_key(eckey, NULL) != 0) {
303 fprintf(stderr, "%s: EC_KEY_set_private_key succeeded?!",
304 __func__);
305 goto err;
306 }
307
308 /*
309 * EVP_PKEY_public_check now only checks that the public key is on the
310 * curve. We should succeed again.
311 */
312
313 if ((ret = EVP_PKEY_public_check(pkey_ctx)) <= 0) {
314 fprintf(stderr, "%s: EVP_PKEY_check(), generated pkey: %d\n",
315 __func__, ret);
316 fail_soft = 1;
317 }
318
319 ERR_clear_error();
320
321 /*
322 * Now let's modify the group to trip the parameter check.
323 */
324
325 if ((group = (EC_GROUP *)EC_KEY_get0_group(eckey)) == NULL) {
326 fprintf(stderr, "%s: EC_KEY_get0_group() failed\n", __func__);
327 goto err;
328 }
329
330 if ((generator = EC_GROUP_get0_generator(group)) == NULL) {
331 fprintf(stderr, "%s: EC_GROUP_get0_generator() failed\n",
332 __func__);
333 goto err;
334 }
335
336 if ((order = BN_new()) == NULL) {
337 fprintf(stderr, "%s: order = BN_new() failed\n", __func__);
338 goto err;
339 }
340 if ((cofactor = BN_new()) == NULL) {
341 fprintf(stderr, "%s: cofactor = BN_new() failed\n", __func__);
342 goto err;
343 }
344
345 if (!EC_GROUP_get_order(group, order, NULL)) {
346 fprintf(stderr, "%s: EC_GROUP_get_order() failed\n", __func__);
347 goto err;
348 }
349 if (!EC_GROUP_get_cofactor(group, cofactor, NULL)) {
350 fprintf(stderr, "%s: EC_GROUP_get_cofactor() failed\n",
351 __func__);
352 goto err;
353 }
354
355 /* Decrement order so order * generator != (point at infinity). */
356 if (!BN_sub_word(order, 1)) {
357 fprintf(stderr, "%s: BN_sub_word() failed\n", __func__);
358 goto err;
359 }
360
361 /* Now set this nonsense on the group. */
362 if (!EC_GROUP_set_generator(group, generator, order, cofactor)) {
363 fprintf(stderr, "%s: EC_GROUP_set_generator() failed\n",
364 __func__);
365 goto err;
366 }
367
368 /* We should now fail the parameter check. */
369 if (EVP_PKEY_param_check(pkey_ctx) == 1) {
370 fprintf(stderr,
371 "%s: EVP_PKEY_param_check(), succeeded unexpectedly\n",
372 __func__);
373 fail_soft = 1;
374 }
375
376 fprintf(stderr, "We should see an error on invalid group order\n");
377 ERR_print_errors_fp(stderr);
378 ERR_clear_error();
379
380 fprintf(stderr, "EVP_PKEY_check test for EC done.\n");
381
382 failed = 0;
383
384 err:
385 EVP_PKEY_CTX_free(pkey_ctx);
386 EVP_PKEY_free(pkey);
387 BN_free(order);
388 BN_free(cofactor);
389
390 return failed | fail_soft;
391}
392
393int
394main(void)
395{
396 int failed = 0;
397
398 failed |= evp_pkey_check_rsa();
399 failed |= evp_pkey_check_ec();
400
401 printf("%s\n", failed ? "FAILED" : "SUCCESS");
402
403 return failed;
404}