diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/regress/lib/libcrypto/rsa/Makefile | 3 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/rsa/rsa_method_test.c | 278 |
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 | ||
| 3 | PROGS += rsa_test | 3 | PROGS += rsa_test |
| 4 | PROGS += rsa_method_test | ||
| 4 | PROGS += rsa_padding_test | 5 | PROGS += rsa_padding_test |
| 5 | 6 | ||
| 6 | LDADD = -lcrypto | 7 | LDADD = -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 */ | ||
| 37 | static int ex_index; | ||
| 38 | |||
| 39 | /* Unsure if this applies to RSA, ASN.1, or the OpenSSL code base altogether. */ | ||
| 40 | static 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 | |||
| 65 | static int | ||
| 66 | sign_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 | |||
| 117 | static void | ||
| 118 | generate_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 | |||
| 150 | static void | ||
| 151 | rsa_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 | |||
| 161 | static void | ||
| 162 | clear_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 | |||
| 170 | static int | ||
| 171 | rsa_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 | |||
| 180 | static int | ||
| 181 | rsa_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 | |||
| 194 | static int | ||
| 195 | sign_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 | |||
| 267 | int | ||
| 268 | main(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 | } | ||
