summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortb <>2025-01-04 18:16:37 +0000
committertb <>2025-01-04 18:16:37 +0000
commit29b768008903d0bf17e31f30cd791a8153e2d1fb (patch)
treed45949fd45e507c58061c260d36f361bd777dd3a
parentcd8752d60a836e131c86ae2883a1769e20419f3a (diff)
downloadopenbsd-29b768008903d0bf17e31f30cd791a8153e2d1fb.tar.gz
openbsd-29b768008903d0bf17e31f30cd791a8153e2d1fb.tar.bz2
openbsd-29b768008903d0bf17e31f30cd791a8153e2d1fb.zip
Add some regress coverage for custom RSA methods
This currently only covers sign and verify since other parts are already known to work in practice. Prompted by a bug report by kn
-rw-r--r--src/regress/lib/libcrypto/rsa/Makefile3
-rw-r--r--src/regress/lib/libcrypto/rsa/rsa_method_test.c278
2 files changed, 280 insertions, 1 deletions
diff --git a/src/regress/lib/libcrypto/rsa/Makefile b/src/regress/lib/libcrypto/rsa/Makefile
index 6c33c39755..3950ce6813 100644
--- a/src/regress/lib/libcrypto/rsa/Makefile
+++ b/src/regress/lib/libcrypto/rsa/Makefile
@@ -1,6 +1,7 @@
1# $OpenBSD: Makefile,v 1.5 2025/01/04 18:13:58 tb Exp $ 1# $OpenBSD: Makefile,v 1.6 2025/01/04 18:16:37 tb Exp $
2 2
3PROGS += rsa_test 3PROGS += rsa_test
4PROGS += rsa_method_test
4PROGS += rsa_padding_test 5PROGS += rsa_padding_test
5 6
6LDADD = -lcrypto 7LDADD = -lcrypto
diff --git a/src/regress/lib/libcrypto/rsa/rsa_method_test.c b/src/regress/lib/libcrypto/rsa/rsa_method_test.c
new file mode 100644
index 0000000000..9a5bac6513
--- /dev/null
+++ b/src/regress/lib/libcrypto/rsa/rsa_method_test.c
@@ -0,0 +1,278 @@
1/* $OpenBSD: rsa_method_test.c,v 1.1 2025/01/04 18:16:37 tb Exp $ */
2
3/*
4 * Copyright (c) 2025 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
19#include <assert.h>
20#include <err.h>
21#include <stdint.h>
22#include <stdio.h>
23
24#include <openssl/asn1.h>
25#include <openssl/bn.h>
26#include <openssl/err.h>
27#include <openssl/evp.h>
28#include <openssl/objects.h>
29#include <openssl/rsa.h>
30#include <openssl/x509.h>
31
32/*
33 * XXX - This currently only covers sign and verify.
34 */
35
36/* sigh */
37static int ex_index;
38
39/* Unsure if this applies to RSA, ASN.1, or the OpenSSL code base altogether. */
40static const uint8_t msg[] = {
41 0x44, 0x69, 0x65, 0x2c, 0x20, 0x64, 0x69, 0x65,
42 0x2c, 0x20, 0x64, 0x69, 0x65, 0x2c, 0x20, 0x6d,
43 0x79, 0x20, 0x64, 0x61, 0x72, 0x6c, 0x69, 0x6e,
44 0x67, 0x0a, 0x44, 0x6f, 0x6e, 0x27, 0x74, 0x20,
45 0x75, 0x74, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20,
46 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x77,
47 0x6f, 0x72, 0x64, 0x0a, 0x44, 0x69, 0x65, 0x2c,
48 0x20, 0x64, 0x69, 0x65, 0x2c, 0x20, 0x64, 0x69,
49 0x65, 0x2c, 0x20, 0x6d, 0x79, 0x20, 0x64, 0x61,
50 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x0a, 0x53, 0x68,
51 0x75, 0x74, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20,
52 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x20, 0x65,
53 0x79, 0x65, 0x73, 0x0a, 0x0a, 0x49, 0x27, 0x6c,
54 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x65,
55 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f, 0x75, 0x20,
56 0x61, 0x67, 0x61, 0x69, 0x6e, 0x0a, 0x49, 0x27,
57 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65,
58 0x65, 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f, 0x75,
59 0x20, 0x69, 0x6e, 0x20, 0x68, 0x65, 0x6c, 0x6c,
60 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x4d, 0x69,
61 0x73, 0x66, 0x69, 0x74, 0x73, 0x20, 0x7e, 0x20,
62 0x31, 0x39, 0x38, 0x32,
63};
64
65static int
66sign_and_verify(const char *descr, EVP_PKEY *priv, EVP_PKEY *pub)
67{
68 ASN1_IA5STRING *message = NULL;
69 ASN1_BIT_STRING *signature = NULL;
70 X509_ALGOR *x509_alg = NULL;
71 const ASN1_OBJECT *oid;
72 int nid, ret;
73 int failed = 1;
74
75 if ((message = ASN1_IA5STRING_new()) == NULL)
76 errx(1, "ASN1_IA5STRING_new");
77 if (!ASN1_STRING_set(message, msg, sizeof(msg)))
78 errx(1, "ASN1_STRING_set");
79
80 if ((signature = ASN1_BIT_STRING_new()) == NULL)
81 errx(1, "ASN1_BIT_STRING_new");
82 if ((x509_alg = X509_ALGOR_new()) == NULL)
83 errx(1, "X509_ALGOR_new");
84 if ((ret = ASN1_item_sign(&ASN1_IA5STRING_it, x509_alg, NULL, signature,
85 message, priv, EVP_sha256())) <= 0) {
86 fprintf(stderr, "FAIL: %s (%s): ASN1_item_sign() returned %d\n",
87 __func__, descr, ret);
88 ERR_print_errors_fp(stderr);
89 goto err;
90 }
91
92 X509_ALGOR_get0(&oid, NULL, NULL, x509_alg);
93 if ((nid = OBJ_obj2nid(oid)) != NID_sha256WithRSAEncryption) {
94 fprintf(stderr, "FAIL: %s (%s): OBJ_obj2nid(): want %d, got %d\n",
95 __func__, descr, NID_sha256WithRSAEncryption, nid);
96 goto err;
97 }
98
99 if ((ret = ASN1_item_verify(&ASN1_IA5STRING_it, x509_alg, signature,
100 message, pub)) != 1) {
101 fprintf(stderr, "FAIL: %s (%s): ASN1_item_verify() returned %d\n",
102 __func__, descr, ret);
103 ERR_print_errors_fp(stderr);
104 goto err;
105 }
106
107 failed = 0;
108
109 err:
110 ASN1_IA5STRING_free(message);
111 ASN1_BIT_STRING_free(signature);
112 X509_ALGOR_free(x509_alg);
113
114 return failed;
115}
116
117static void
118generate_rsa_keypair(int bits, int exponent, RSA **out_priv, RSA **out_pub)
119{
120 BIGNUM *e;
121 RSA *rsa;
122
123 assert(out_priv == NULL || *out_priv == NULL);
124 assert(out_pub == NULL || *out_pub == NULL);
125
126 if ((e = BN_new()) == NULL)
127 errx(1, "%s: BN_new()", __func__);
128 if (!BN_set_word(e, exponent))
129 errx(1, "%s: BN_set_word()", __func__);
130
131 if ((rsa = RSA_new()) == NULL)
132 errx(1, "%s: RSA_new()", __func__);
133 if (!RSA_generate_key_ex(rsa, bits, e, NULL))
134 errx(1, "%s: RSA_generate_key_ex", __func__);
135
136 /* Take the opportunity to exercise these two functions. */
137 if (out_priv != NULL) {
138 if ((*out_priv = RSAPrivateKey_dup(rsa)) == NULL)
139 errx(1, "%s: RSAPrivateKey_dup", __func__);
140 }
141 if (out_pub != NULL) {
142 if ((*out_pub = RSAPublicKey_dup(rsa)) == NULL)
143 errx(1, "%s: RSAPublicKey_dup", __func__);
144 }
145
146 RSA_free(rsa);
147 BN_free(e);
148}
149
150static void
151rsa_to_evp(RSA *rsa, EVP_PKEY **out_evp)
152{
153 assert(*out_evp == NULL);
154
155 if ((*out_evp = EVP_PKEY_new()) == NULL)
156 errx(1, "%s: EVP_PKEY_new", __func__);
157 if (!EVP_PKEY_set1_RSA(*out_evp, rsa))
158 errx(1, "%s: EVP_PKEY_set1_RSA", __func__);
159}
160
161static void
162clear_evp_keys(EVP_PKEY **evp_priv, EVP_PKEY **evp_pub)
163{
164 EVP_PKEY_free(*evp_priv);
165 EVP_PKEY_free(*evp_pub);
166 *evp_priv = NULL;
167 *evp_pub = NULL;
168}
169
170static int
171rsa_method_app_data_sign(int dtype, const unsigned char *m, unsigned int m_len,
172 unsigned char *sig, unsigned int *sig_len, const RSA *rsa)
173{
174 const RSA_METHOD *method = RSA_get_method(rsa);
175 RSA *sign_rsa = RSA_meth_get0_app_data(method);
176
177 return RSA_sign(dtype, m, m_len, sig, sig_len, sign_rsa);
178}
179
180static int
181rsa_ex_data_verify(int dtype, const unsigned char *m, unsigned int m_len,
182 const unsigned char *sig, unsigned int sig_len, const RSA *rsa)
183{
184 RSA *verify_rsa;
185
186 assert(ex_index != 0);
187
188 if ((verify_rsa = RSA_get_ex_data(rsa, ex_index)) == NULL)
189 errx(1, "%s: RSA_get_ex_data", __func__);
190
191 return RSA_verify(dtype, m, m_len, sig, sig_len, verify_rsa);
192}
193
194static int
195sign_and_verify_test(void)
196{
197 RSA_METHOD *sign_verify_method = NULL;
198 RSA *rsa_priv = NULL, *rsa_pub = NULL, *rsa_bogus = NULL;
199 EVP_PKEY *evp_priv = NULL, *evp_pub = NULL;
200 int failed = 0;
201
202 assert(ex_index != 0);
203
204 /*
205 * XXX - Hilarity ensues if the public key sizes don't match.
206 * One reason is that EVP_PKEY_sign() uses EVP_PKEY_size()
207 * which ignores the RSA method. Awesome design is awesome and
208 * OpenSSL's abstractions are leakier than Manneken Pis.
209 */
210 generate_rsa_keypair(2048, RSA_F4, &rsa_priv, &rsa_pub);
211 generate_rsa_keypair(2048, 3, NULL, &rsa_bogus);
212
213 rsa_to_evp(rsa_priv, &evp_priv);
214 rsa_to_evp(rsa_pub, &evp_pub);
215
216 failed |= sign_and_verify("default method", evp_priv, evp_pub);
217
218 clear_evp_keys(&evp_priv, &evp_pub);
219
220
221 if (!RSA_set_ex_data(rsa_bogus, ex_index, rsa_pub))
222 errx(1, "%s: RSA_set_ex_data", __func__);
223
224 if ((sign_verify_method = RSA_meth_dup(RSA_get_default_method())) == NULL)
225 errx(1, "%s: RSA_get_default_method", __func__);
226 if (!RSA_meth_set0_app_data(sign_verify_method, rsa_priv))
227 errx(1, "%s: RSA_meth_set0_app_data", __func__);
228
229 if (!RSA_meth_set_sign(sign_verify_method, rsa_method_app_data_sign))
230 errx(1, "%s: RSA_meth_set_sign", __func__);
231 if (!RSA_meth_set_verify(sign_verify_method, rsa_ex_data_verify))
232 errx(1, "%s: RSA_meth_set_verify", __func__);
233
234 RSA_set_flags(rsa_bogus, RSA_FLAG_SIGN_VER);
235 if (!RSA_set_method(rsa_bogus, sign_verify_method))
236 errx(1, "%s: RSA_set_method", __func__);
237
238 rsa_to_evp(rsa_bogus, &evp_priv);
239 rsa_to_evp(rsa_pub, &evp_pub);
240
241 failed |= sign_and_verify("app data sign method", evp_priv, evp_pub);
242
243 clear_evp_keys(&evp_priv, &evp_pub);
244
245 rsa_to_evp(rsa_priv, &evp_priv);
246 rsa_to_evp(rsa_bogus, &evp_pub);
247
248 failed |= sign_and_verify("ex data verify method", evp_priv, evp_pub);
249
250 clear_evp_keys(&evp_priv, &evp_pub);
251
252 rsa_to_evp(rsa_bogus, &evp_priv);
253 rsa_to_evp(rsa_bogus, &evp_pub);
254
255 failed |= sign_and_verify("both sides bous", evp_priv, evp_pub);
256
257 RSA_free(rsa_priv);
258 RSA_free(rsa_pub);
259 RSA_free(rsa_bogus);
260 EVP_PKEY_free(evp_priv);
261 EVP_PKEY_free(evp_pub);
262 RSA_meth_free(sign_verify_method);
263
264 return failed;
265}
266
267int
268main(void)
269{
270 int failed = 0;
271
272 if ((ex_index = RSA_get_ex_new_index(0, NULL, NULL, NULL, NULL)) <= 0)
273 errx(1, "RSA_get_ex_new_index");
274
275 failed |= sign_and_verify_test();
276
277 return failed;
278}