1*668e5ba9Sclaudio /* $OpenBSD: ca.c,v 1.45 2024/11/21 13:21:34 claudio Exp $ */ 23d77879fSreyk 33d77879fSreyk /* 43d77879fSreyk * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> 53d77879fSreyk * 63d77879fSreyk * Permission to use, copy, modify, and distribute this software for any 73d77879fSreyk * purpose with or without fee is hereby granted, provided that the above 83d77879fSreyk * copyright notice and this permission notice appear in all copies. 93d77879fSreyk * 103d77879fSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 113d77879fSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 123d77879fSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 133d77879fSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 143d77879fSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 153d77879fSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 163d77879fSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 173d77879fSreyk */ 183d77879fSreyk 19f04ff968Sreyk #include <sys/types.h> 203d77879fSreyk #include <sys/queue.h> 213d77879fSreyk #include <sys/uio.h> 223d77879fSreyk 233d77879fSreyk #include <unistd.h> 243d77879fSreyk #include <string.h> 253d77879fSreyk #include <stdlib.h> 266778e0bdSclaudio #include <poll.h> 27f04ff968Sreyk #include <imsg.h> 283d77879fSreyk 29f04ff968Sreyk #include <openssl/bio.h> 30f1b4a8a5Stb #include <openssl/err.h> 313d77879fSreyk #include <openssl/evp.h> 32f1b4a8a5Stb #include <openssl/pem.h> 333d77879fSreyk #include <openssl/rsa.h> 343d77879fSreyk #include <openssl/engine.h> 353d77879fSreyk 363d77879fSreyk #include "relayd.h" 373d77879fSreyk 383d77879fSreyk void ca_init(struct privsep *, struct privsep_proc *p, void *); 393d77879fSreyk void ca_launch(void); 403d77879fSreyk 413d77879fSreyk int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *); 423d77879fSreyk int ca_dispatch_relay(int, struct privsep_proc *, struct imsg *); 433d77879fSreyk 443d77879fSreyk int rsae_priv_enc(int, const u_char *, u_char *, RSA *, int); 453d77879fSreyk int rsae_priv_dec(int, const u_char *, u_char *, RSA *, int); 463d77879fSreyk 473d77879fSreyk static struct relayd *env = NULL; 483d77879fSreyk 493d77879fSreyk static struct privsep_proc procs[] = { 503d77879fSreyk { "parent", PROC_PARENT, ca_dispatch_parent }, 513d77879fSreyk { "relay", PROC_RELAY, ca_dispatch_relay }, 523d77879fSreyk }; 533d77879fSreyk 54f910ac11Sreyk void 553d77879fSreyk ca(struct privsep *ps, struct privsep_proc *p) 563d77879fSreyk { 573d77879fSreyk env = ps->ps_env; 583d77879fSreyk 59f910ac11Sreyk proc_run(ps, p, procs, nitems(procs), ca_init, NULL); 603d77879fSreyk } 613d77879fSreyk 623d77879fSreyk void 633d77879fSreyk ca_init(struct privsep *ps, struct privsep_proc *p, void *arg) 643d77879fSreyk { 653d6ff6edSreyk if (pledge("stdio recvfd", NULL) == -1) 669d396bfeSbenno fatal("pledge"); 679d396bfeSbenno 683d77879fSreyk if (config_init(ps->ps_env) == -1) 693d77879fSreyk fatal("failed to initialize configuration"); 703d77879fSreyk 713d77879fSreyk env->sc_id = getpid() & 0xffff; 723d77879fSreyk } 733d77879fSreyk 74f8a1e24fSbluhm void 75f8a1e24fSbluhm hash_x509(X509 *cert, char *hash, size_t hashlen) 7685e5f500Sclaudio { 7785e5f500Sclaudio static const char hex[] = "0123456789abcdef"; 78f8a1e24fSbluhm size_t off; 79f8a1e24fSbluhm char digest[EVP_MAX_MD_SIZE]; 80f8a1e24fSbluhm int dlen, i; 81f8a1e24fSbluhm 8223276981Sclaudio if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1) 8323276981Sclaudio fatalx("%s: X509_pubkey_digest failed", __func__); 8485e5f500Sclaudio 8585e5f500Sclaudio if (hashlen < 2 * dlen + sizeof("SHA256:")) 867078bf6aSop fatalx("%s: hash buffer too small", __func__); 8785e5f500Sclaudio 8885e5f500Sclaudio off = strlcpy(hash, "SHA256:", hashlen); 8985e5f500Sclaudio 9085e5f500Sclaudio for (i = 0; i < dlen; i++) { 91f8a1e24fSbluhm hash[off++] = hex[(digest[i] >> 4) & 0x0f]; 92f8a1e24fSbluhm hash[off++] = hex[digest[i] & 0x0f]; 9385e5f500Sclaudio } 9485e5f500Sclaudio hash[off] = 0; 9585e5f500Sclaudio } 9685e5f500Sclaudio 973d77879fSreyk void 983d77879fSreyk ca_launch(void) 993d77879fSreyk { 100f8a1e24fSbluhm char hash[TLS_CERT_HASH_SIZE]; 101114ce177Sclaudio char *buf; 1023d77879fSreyk BIO *in = NULL; 1033d77879fSreyk EVP_PKEY *pkey = NULL; 1043d77879fSreyk struct relay *rlay; 105f2f4e153Sreyk struct relay_cert *cert; 106f2f4e153Sreyk X509 *x509 = NULL; 107114ce177Sclaudio off_t len; 1083d77879fSreyk 109f2f4e153Sreyk TAILQ_FOREACH(cert, env->sc_certs, cert_entry) { 110f2f4e153Sreyk if (cert->cert_fd == -1 || cert->cert_key_fd == -1) 1113d77879fSreyk continue; 1123d77879fSreyk 113f2f4e153Sreyk if ((buf = relay_load_fd(cert->cert_fd, &len)) == NULL) 1140987b10dSclaudio fatal("ca_launch: cert relay_load_fd"); 115114ce177Sclaudio 116114ce177Sclaudio if ((in = BIO_new_mem_buf(buf, len)) == NULL) 117a7c0a300Sbluhm fatalx("ca_launch: cert BIO_new_mem_buf"); 11885e5f500Sclaudio 119f2f4e153Sreyk if ((x509 = PEM_read_bio_X509(in, NULL, 12085e5f500Sclaudio NULL, NULL)) == NULL) 121a7c0a300Sbluhm fatalx("ca_launch: cert PEM_read_bio_X509"); 12285e5f500Sclaudio 123f2f4e153Sreyk hash_x509(x509, hash, sizeof(hash)); 12485e5f500Sclaudio 12585e5f500Sclaudio BIO_free(in); 126f2f4e153Sreyk X509_free(x509); 127114ce177Sclaudio purge_key(&buf, len); 128f2f4e153Sreyk 129f2f4e153Sreyk if ((buf = relay_load_fd(cert->cert_key_fd, &len)) == NULL) 130f2f4e153Sreyk fatal("ca_launch: key relay_load_fd"); 131f2f4e153Sreyk 132f2f4e153Sreyk if ((in = BIO_new_mem_buf(buf, len)) == NULL) 133efc39811Sbenno fatalx("%s: key", __func__); 1343d77879fSreyk 1353d77879fSreyk if ((pkey = PEM_read_bio_PrivateKey(in, 1363d77879fSreyk NULL, NULL, NULL)) == NULL) 137efc39811Sbenno fatalx("%s: PEM", __func__); 1383d77879fSreyk 139f2f4e153Sreyk cert->cert_pkey = pkey; 1403d77879fSreyk 14185e5f500Sclaudio if (pkey_add(env, pkey, hash) == NULL) 1427bb52228Sreyk fatalx("tls pkey"); 14300ae3104Sreyk 144f2f4e153Sreyk BIO_free(in); 145f2f4e153Sreyk purge_key(&buf, len); 14632a86e7dSreyk } 14785e5f500Sclaudio 148f2f4e153Sreyk TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) { 149f2f4e153Sreyk if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0) 150f2f4e153Sreyk continue; 151f2f4e153Sreyk 152f2f4e153Sreyk if (rlay->rl_tls_cacert_fd != -1 && 153f2f4e153Sreyk rlay->rl_conf.tls_cakey_len) { 154114ce177Sclaudio if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd, 155114ce177Sclaudio &len)) == NULL) 1560987b10dSclaudio fatal("ca_launch: cacert relay_load_fd"); 157114ce177Sclaudio 158114ce177Sclaudio if ((in = BIO_new_mem_buf(buf, len)) == NULL) 159a7c0a300Sbluhm fatalx("ca_launch: cacert BIO_new_mem_buf"); 16085e5f500Sclaudio 161f2f4e153Sreyk if ((x509 = PEM_read_bio_X509(in, NULL, 16285e5f500Sclaudio NULL, NULL)) == NULL) 163a7c0a300Sbluhm fatalx("ca_launch: cacert PEM_read_bio_X509"); 16485e5f500Sclaudio 165f2f4e153Sreyk hash_x509(x509, hash, sizeof(hash)); 16685e5f500Sclaudio 16785e5f500Sclaudio BIO_free(in); 168f2f4e153Sreyk X509_free(x509); 169114ce177Sclaudio purge_key(&buf, len); 170f2f4e153Sreyk 1717bb52228Sreyk if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey, 1727bb52228Sreyk rlay->rl_conf.tls_cakey_len)) == NULL) 173efc39811Sbenno fatalx("%s: key", __func__); 17400ae3104Sreyk 17500ae3104Sreyk if ((pkey = PEM_read_bio_PrivateKey(in, 17600ae3104Sreyk NULL, NULL, NULL)) == NULL) 177efc39811Sbenno fatalx("%s: PEM", __func__); 17800ae3104Sreyk BIO_free(in); 17900ae3104Sreyk 1807bb52228Sreyk rlay->rl_tls_capkey = pkey; 18100ae3104Sreyk 18285e5f500Sclaudio if (pkey_add(env, pkey, hash) == NULL) 18300ae3104Sreyk fatalx("ca pkey"); 18400ae3104Sreyk 1857bb52228Sreyk purge_key(&rlay->rl_tls_cakey, 1867bb52228Sreyk rlay->rl_conf.tls_cakey_len); 18700ae3104Sreyk } 188114ce177Sclaudio close(rlay->rl_tls_ca_fd); 1893d77879fSreyk } 1903d77879fSreyk } 1913d77879fSreyk 1923d77879fSreyk int 1933d77879fSreyk ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) 1943d77879fSreyk { 1953d77879fSreyk switch (imsg->hdr.type) { 1963d77879fSreyk case IMSG_CFG_RELAY: 1973d77879fSreyk config_getrelay(env, imsg); 1983d77879fSreyk break; 199114ce177Sclaudio case IMSG_CFG_RELAY_FD: 200114ce177Sclaudio config_getrelayfd(env, imsg); 201114ce177Sclaudio break; 2023d77879fSreyk case IMSG_CFG_DONE: 2033d77879fSreyk config_getcfg(env, imsg); 2043d77879fSreyk break; 2053d77879fSreyk case IMSG_CTL_START: 2063d77879fSreyk ca_launch(); 2073d77879fSreyk break; 2083d77879fSreyk case IMSG_CTL_RESET: 2093d77879fSreyk config_getreset(env, imsg); 2103d77879fSreyk break; 2113d77879fSreyk default: 212ad3e8fb5Stb return -1; 2133d77879fSreyk } 2143d77879fSreyk 215ad3e8fb5Stb return 0; 2163d77879fSreyk } 2173d77879fSreyk 2183d77879fSreyk int 2193d77879fSreyk ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg) 2203d77879fSreyk { 2213d77879fSreyk struct ctl_keyop cko; 2223d77879fSreyk EVP_PKEY *pkey; 2233d77879fSreyk RSA *rsa; 2243d77879fSreyk u_char *from = NULL, *to = NULL; 2253d77879fSreyk struct iovec iov[2]; 2263d77879fSreyk int c = 0; 2273d77879fSreyk 2283d77879fSreyk switch (imsg->hdr.type) { 2293d77879fSreyk case IMSG_CA_PRIVENC: 2303d77879fSreyk case IMSG_CA_PRIVDEC: 2313d77879fSreyk IMSG_SIZE_CHECK(imsg, (&cko)); 2323d77879fSreyk bcopy(imsg->data, &cko, sizeof(cko)); 233586b5f8aSreyk if (cko.cko_proc > env->sc_conf.prefork_relay) 234efc39811Sbenno fatalx("%s: invalid relay proc", __func__); 2353d77879fSreyk if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen)) 236efc39811Sbenno fatalx("%s: invalid key operation", __func__); 237f8a1e24fSbluhm if ((pkey = pkey_find(env, cko.cko_hash)) == NULL) 238f8a1e24fSbluhm fatalx("%s: invalid relay hash '%s'", 239f8a1e24fSbluhm __func__, cko.cko_hash); 240f8a1e24fSbluhm if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) 241f8a1e24fSbluhm fatalx("%s: invalid relay key", __func__); 2423d77879fSreyk 24385e5f500Sclaudio DPRINTF("%s:%d: key hash %s proc %d", 24485e5f500Sclaudio __func__, __LINE__, cko.cko_hash, cko.cko_proc); 24500ae3104Sreyk 2463d77879fSreyk from = (u_char *)imsg->data + sizeof(cko); 2473d77879fSreyk if ((to = calloc(1, cko.cko_tlen)) == NULL) 248efc39811Sbenno fatalx("%s: calloc", __func__); 2493d77879fSreyk 2503d77879fSreyk switch (imsg->hdr.type) { 2513d77879fSreyk case IMSG_CA_PRIVENC: 2523d77879fSreyk cko.cko_tlen = RSA_private_encrypt(cko.cko_flen, 2533d77879fSreyk from, to, rsa, cko.cko_padding); 2543d77879fSreyk break; 2553d77879fSreyk case IMSG_CA_PRIVDEC: 2563d77879fSreyk cko.cko_tlen = RSA_private_decrypt(cko.cko_flen, 2573d77879fSreyk from, to, rsa, cko.cko_padding); 2583d77879fSreyk break; 2593d77879fSreyk } 2603d77879fSreyk 261e45fc33aSclaudio if (cko.cko_tlen == -1) { 262e45fc33aSclaudio char buf[256]; 263e45fc33aSclaudio log_warnx("%s: %s", __func__, 264e45fc33aSclaudio ERR_error_string(ERR_get_error(), buf)); 265e45fc33aSclaudio } 266e45fc33aSclaudio 2673d77879fSreyk iov[c].iov_base = &cko; 2683d77879fSreyk iov[c++].iov_len = sizeof(cko); 269e45fc33aSclaudio if (cko.cko_tlen > 0) { 2703d77879fSreyk iov[c].iov_base = to; 2713d77879fSreyk iov[c++].iov_len = cko.cko_tlen; 2723d77879fSreyk } 2733d77879fSreyk 2747084d095Sclaudio if (proc_composev_imsg(env->sc_ps, PROC_RELAY, cko.cko_proc, 2757084d095Sclaudio imsg->hdr.type, -1, -1, iov, c) == -1) 2767084d095Sclaudio log_warn("%s: proc_composev_imsg", __func__); 2773d77879fSreyk 2783d77879fSreyk free(to); 2793d77879fSreyk RSA_free(rsa); 2803d77879fSreyk break; 2813d77879fSreyk default: 282ad3e8fb5Stb return -1; 2833d77879fSreyk } 2843d77879fSreyk 285ad3e8fb5Stb return 0; 2863d77879fSreyk } 2873d77879fSreyk 2883d77879fSreyk /* 2893d77879fSreyk * RSA privsep engine (called from unprivileged processes) 2903d77879fSreyk */ 2913d77879fSreyk 29227f65520Stb static const RSA_METHOD *rsa_default; 293ad3e8fb5Stb static RSA_METHOD *rsae_method; 2943d77879fSreyk 2953d77879fSreyk static int 2968b624d89Sreyk rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa, 2978b624d89Sreyk int padding, u_int cmd) 2983d77879fSreyk { 299325f6e14Sreyk struct privsep *ps = env->sc_ps; 3006778e0bdSclaudio struct pollfd pfd[1]; 3013d77879fSreyk struct ctl_keyop cko; 3023d77879fSreyk int ret = 0; 30385e5f500Sclaudio char *hash; 3043d77879fSreyk struct iovec iov[2]; 3053d77879fSreyk struct imsgbuf *ibuf; 3063d77879fSreyk struct imsgev *iev; 3073d77879fSreyk struct imsg imsg; 3083d77879fSreyk int n, done = 0, cnt = 0; 3093d77879fSreyk u_char *toptr; 310c7e61995Sclaudio static u_int seq = 0; 3113d77879fSreyk 31285e5f500Sclaudio if ((hash = RSA_get_ex_data(rsa, 0)) == NULL) 313ad3e8fb5Stb return 0; 3143d77879fSreyk 315325f6e14Sreyk iev = proc_iev(ps, PROC_CA, ps->ps_instance); 3163d77879fSreyk ibuf = &iev->ibuf; 3173d77879fSreyk 3183d77879fSreyk /* 3193d77879fSreyk * XXX this could be nicer... 3203d77879fSreyk */ 3213d77879fSreyk 32285e5f500Sclaudio (void)strlcpy(cko.cko_hash, hash, sizeof(cko.cko_hash)); 323325f6e14Sreyk cko.cko_proc = ps->ps_instance; 3243d77879fSreyk cko.cko_flen = flen; 3253d77879fSreyk cko.cko_tlen = RSA_size(rsa); 3263d77879fSreyk cko.cko_padding = padding; 327c7e61995Sclaudio cko.cko_cookie = seq++; 3283d77879fSreyk 3293d77879fSreyk iov[cnt].iov_base = &cko; 3303d77879fSreyk iov[cnt++].iov_len = sizeof(cko); 331f9b0f55cSreyk iov[cnt].iov_base = (void *)(uintptr_t)from; 3323d77879fSreyk iov[cnt++].iov_len = flen; 3333d77879fSreyk 3343d77879fSreyk /* 3353d77879fSreyk * Send a synchronous imsg because we cannot defer the RSA 3363d77879fSreyk * operation in OpenSSL's engine layer. 3373d77879fSreyk */ 3387084d095Sclaudio if (imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt) == -1) 3397084d095Sclaudio log_warn("%s: imsg_composev", __func__); 340dd7efffeSclaudio if (imsgbuf_flush(ibuf) == -1) 341dd7efffeSclaudio log_warn("%s: imsgbuf_flush", __func__); 3423d77879fSreyk 3436778e0bdSclaudio pfd[0].fd = ibuf->fd; 3446778e0bdSclaudio pfd[0].events = POLLIN; 3453d77879fSreyk while (!done) { 3466778e0bdSclaudio switch (poll(pfd, 1, RELAY_TLS_PRIV_TIMEOUT)) { 3476778e0bdSclaudio case -1: 3485fa7fa1aSbenno if (errno != EINTR) 349efc39811Sbenno fatal("%s: poll", __func__); 3505fa7fa1aSbenno continue; 3516778e0bdSclaudio case 0: 352c7e61995Sclaudio log_warnx("%s: priv%s poll timeout, keyop #%x", 353c7e61995Sclaudio __func__, 354c7e61995Sclaudio cmd == IMSG_CA_PRIVENC ? "enc" : "dec", 355c7e61995Sclaudio cko.cko_cookie); 356ad3e8fb5Stb return -1; 3576778e0bdSclaudio default: 3586778e0bdSclaudio break; 3596778e0bdSclaudio } 360*668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 361dd7efffeSclaudio fatalx("imsgbuf_read"); 3623d77879fSreyk if (n == 0) 3633d77879fSreyk fatalx("pipe closed"); 3643d77879fSreyk 3653d77879fSreyk while (!done) { 3663d77879fSreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 3673d77879fSreyk fatalx("imsg_get error"); 3683d77879fSreyk if (n == 0) 3693d77879fSreyk break; 3703d77879fSreyk 3713d77879fSreyk IMSG_SIZE_CHECK(&imsg, (&cko)); 3723d77879fSreyk memcpy(&cko, imsg.data, sizeof(cko)); 3733d77879fSreyk 374c7e61995Sclaudio /* 375c7e61995Sclaudio * Due to earlier timed out requests, there may be 376c7e61995Sclaudio * responses that need to be skipped. 377c7e61995Sclaudio */ 378c7e61995Sclaudio if (cko.cko_cookie != seq - 1) { 379c7e61995Sclaudio log_warnx( 380c7e61995Sclaudio "%s: priv%s obsolete keyop #%x", __func__, 381c7e61995Sclaudio cmd == IMSG_CA_PRIVENC ? "enc" : "dec", 382c7e61995Sclaudio cko.cko_cookie); 383c7e61995Sclaudio continue; 384c7e61995Sclaudio } 385c7e61995Sclaudio 386c7e61995Sclaudio if (imsg.hdr.type != cmd) 387c7e61995Sclaudio fatalx("invalid response"); 388c7e61995Sclaudio 3893d77879fSreyk ret = cko.cko_tlen; 390e45fc33aSclaudio if (ret > 0) { 391e45fc33aSclaudio if (IMSG_DATA_SIZE(&imsg) != 392e45fc33aSclaudio (sizeof(cko) + ret)) 393e45fc33aSclaudio fatalx("data size"); 3943d77879fSreyk toptr = (u_char *)imsg.data + sizeof(cko); 3953d77879fSreyk memcpy(to, toptr, ret); 3963d77879fSreyk } 3973d77879fSreyk done = 1; 3983d77879fSreyk 3993d77879fSreyk imsg_free(&imsg); 4003d77879fSreyk } 4013d77879fSreyk } 4023d77879fSreyk imsg_event_add(iev); 4033d77879fSreyk 404ad3e8fb5Stb return ret; 4053d77879fSreyk } 4063d77879fSreyk 4073d77879fSreyk int 4088b624d89Sreyk rsae_priv_enc(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) 4093d77879fSreyk { 4103d77879fSreyk DPRINTF("%s:%d", __func__, __LINE__); 411ad3e8fb5Stb return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVENC); 4123d77879fSreyk } 4133d77879fSreyk 4143d77879fSreyk int 4158b624d89Sreyk rsae_priv_dec(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) 4163d77879fSreyk { 4173d77879fSreyk DPRINTF("%s:%d", __func__, __LINE__); 418ad3e8fb5Stb return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVDEC); 4193d77879fSreyk } 4203d77879fSreyk 4211013dd2eSreyk void 4223d77879fSreyk ca_engine_init(struct relayd *x_env) 4233d77879fSreyk { 42427f65520Stb const char *errstr; 4253d77879fSreyk 4263d77879fSreyk if (env == NULL) 4273d77879fSreyk env = x_env; 4283d77879fSreyk 4292c8c2287Sclaudio if (rsa_default != NULL) 4302c8c2287Sclaudio return; 4312c8c2287Sclaudio 4321013dd2eSreyk if ((rsa_default = RSA_get_default_method()) == NULL) { 4331013dd2eSreyk errstr = "RSA_get_default_method"; 4341013dd2eSreyk goto fail; 4351013dd2eSreyk } 43627f65520Stb 43727f65520Stb if ((rsae_method = RSA_meth_dup(rsa_default)) == NULL) { 43827f65520Stb errstr = "RSA_meth_dup"; 4391013dd2eSreyk goto fail; 4401013dd2eSreyk } 4411013dd2eSreyk 44227f65520Stb RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc); 44327f65520Stb RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec); 4441013dd2eSreyk 445ad3e8fb5Stb RSA_meth_set_flags(rsae_method, 446ad3e8fb5Stb RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK); 447ad3e8fb5Stb RSA_meth_set0_app_data(rsae_method, 448ad3e8fb5Stb RSA_meth_get0_app_data(rsa_default)); 4493d77879fSreyk 45027f65520Stb RSA_set_default_method(rsae_method); 4513d77879fSreyk 4521013dd2eSreyk return; 4531013dd2eSreyk 4541013dd2eSreyk fail: 455ad3e8fb5Stb RSA_meth_free(rsae_method); 45685e5f500Sclaudio fatalx("%s: %s", __func__, errstr); 4573d77879fSreyk } 458