1 /* $OpenBSD: rsa_method_test.c,v 1.3 2025/01/04 21:29:45 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, "%s: ASN1_IA5STRING_new", __func__); 77 if (!ASN1_STRING_set(message, msg, sizeof(msg))) 78 errx(1, "%s: ASN1_STRING_set", __func__); 79 80 if ((signature = ASN1_BIT_STRING_new()) == NULL) 81 errx(1, "%s: ASN1_BIT_STRING_new", __func__); 82 if ((x509_alg = X509_ALGOR_new()) == NULL) 83 errx(1, "%s: X509_ALGOR_new", __func__); 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 if (!RSA_set_ex_data(rsa_bogus, ex_index, rsa_pub)) 221 errx(1, "%s: RSA_set_ex_data", __func__); 222 223 if ((sign_verify_method = RSA_meth_dup(RSA_get_default_method())) == NULL) 224 errx(1, "%s: RSA_get_default_method", __func__); 225 if (!RSA_meth_set0_app_data(sign_verify_method, rsa_priv)) 226 errx(1, "%s: RSA_meth_set0_app_data", __func__); 227 228 if (!RSA_meth_set_sign(sign_verify_method, rsa_method_app_data_sign)) 229 errx(1, "%s: RSA_meth_set_sign", __func__); 230 if (!RSA_meth_set_verify(sign_verify_method, rsa_ex_data_verify)) 231 errx(1, "%s: RSA_meth_set_verify", __func__); 232 233 RSA_set_flags(rsa_bogus, RSA_FLAG_SIGN_VER); 234 if (!RSA_set_method(rsa_bogus, sign_verify_method)) 235 errx(1, "%s: RSA_set_method", __func__); 236 237 rsa_to_evp(rsa_bogus, &evp_priv); 238 rsa_to_evp(rsa_pub, &evp_pub); 239 240 failed |= sign_and_verify("app data sign method", evp_priv, evp_pub); 241 242 clear_evp_keys(&evp_priv, &evp_pub); 243 244 rsa_to_evp(rsa_priv, &evp_priv); 245 rsa_to_evp(rsa_bogus, &evp_pub); 246 247 failed |= sign_and_verify("ex data verify method", evp_priv, evp_pub); 248 249 clear_evp_keys(&evp_priv, &evp_pub); 250 251 rsa_to_evp(rsa_bogus, &evp_priv); 252 rsa_to_evp(rsa_bogus, &evp_pub); 253 254 failed |= sign_and_verify("both sides bogus", evp_priv, evp_pub); 255 256 RSA_free(rsa_priv); 257 RSA_free(rsa_pub); 258 RSA_free(rsa_bogus); 259 EVP_PKEY_free(evp_priv); 260 EVP_PKEY_free(evp_pub); 261 RSA_meth_free(sign_verify_method); 262 263 return failed; 264 } 265 266 int 267 main(void) 268 { 269 int failed = 0; 270 271 if ((ex_index = RSA_get_ex_new_index(0, NULL, NULL, NULL, NULL)) <= 0) 272 errx(1, "RSA_get_ex_new_index"); 273 274 failed |= sign_and_verify_test(); 275 276 return failed; 277 } 278