1*16b0c81bSclaudio /* $OpenBSD: ca.c,v 1.49 2024/11/21 13:22:21 claudio Exp $ */ 265c4fdfbSgilles 365c4fdfbSgilles /* 4c4df3bf2Sreyk * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> 565c4fdfbSgilles * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 665c4fdfbSgilles * 765c4fdfbSgilles * Permission to use, copy, modify, and distribute this software for any 865c4fdfbSgilles * purpose with or without fee is hereby granted, provided that the above 965c4fdfbSgilles * copyright notice and this permission notice appear in all copies. 1065c4fdfbSgilles * 1165c4fdfbSgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1265c4fdfbSgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1365c4fdfbSgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1465c4fdfbSgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1565c4fdfbSgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1665c4fdfbSgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1765c4fdfbSgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1865c4fdfbSgilles */ 1965c4fdfbSgilles 20b6a48d3eStb #include <openssl/err.h> 2141b8cf0bSmillert #include <openssl/pem.h> 2205ec4924Sgilles #include <pwd.h> 2305ec4924Sgilles #include <signal.h> 2405ec4924Sgilles #include <string.h> 2505ec4924Sgilles #include <unistd.h> 2665c4fdfbSgilles 27c4df3bf2Sreyk #include "smtpd.h" 283abbdc76Seric #include "log.h" 2941b8cf0bSmillert #include "ssl.h" 3039542f0aSeric 3141b8cf0bSmillert static int rsae_send_imsg(int, const unsigned char *, unsigned char *, 3241b8cf0bSmillert RSA *, int, unsigned int); 3341b8cf0bSmillert static int rsae_priv_enc(int, const unsigned char *, unsigned char *, 3441b8cf0bSmillert RSA *, int); 3541b8cf0bSmillert static int rsae_priv_dec(int, const unsigned char *, unsigned char *, 3641b8cf0bSmillert RSA *, int); 3741b8cf0bSmillert static ECDSA_SIG *ecdsae_do_sign(const unsigned char *, int, const BIGNUM *, 3841b8cf0bSmillert const BIGNUM *, EC_KEY *); 3941b8cf0bSmillert 4041b8cf0bSmillert static struct dict pkeys; 414b5cbcb9Sgilles static uint64_t reqid = 0; 42576d0b55Sreyk 4376eb97c5Sreyk static void 4476eb97c5Sreyk ca_shutdown(void) 4576eb97c5Sreyk { 4643962b9cSeric log_debug("debug: ca agent exiting"); 4776eb97c5Sreyk _exit(0); 4876eb97c5Sreyk } 4976eb97c5Sreyk 50b88ab68dSeric int 5176eb97c5Sreyk ca(void) 5276eb97c5Sreyk { 5376eb97c5Sreyk struct passwd *pw; 5476eb97c5Sreyk 5541b8cf0bSmillert purge_config(PURGE_LISTENERS|PURGE_TABLES|PURGE_RULES|PURGE_DISPATCHERS); 5676eb97c5Sreyk 5776eb97c5Sreyk if ((pw = getpwnam(SMTPD_USER)) == NULL) 5876eb97c5Sreyk fatalx("unknown user " SMTPD_USER); 5976eb97c5Sreyk 6076eb97c5Sreyk if (chroot(PATH_CHROOT) == -1) 6176eb97c5Sreyk fatal("ca: chroot"); 6276eb97c5Sreyk if (chdir("/") == -1) 6376eb97c5Sreyk fatal("ca: chdir(\"/\")"); 6476eb97c5Sreyk 6576eb97c5Sreyk config_process(PROC_CA); 6676eb97c5Sreyk 6776eb97c5Sreyk if (setgroups(1, &pw->pw_gid) || 6876eb97c5Sreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 6976eb97c5Sreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 7076eb97c5Sreyk fatal("ca: cannot drop privileges"); 7176eb97c5Sreyk 7276eb97c5Sreyk imsg_callback = ca_imsg; 7376eb97c5Sreyk event_init(); 7476eb97c5Sreyk 7543962b9cSeric signal(SIGINT, SIG_IGN); 7643962b9cSeric signal(SIGTERM, SIG_IGN); 7776eb97c5Sreyk signal(SIGPIPE, SIG_IGN); 7876eb97c5Sreyk signal(SIGHUP, SIG_IGN); 7976eb97c5Sreyk 8057d312f7Seric config_peer(PROC_CONTROL); 8176eb97c5Sreyk config_peer(PROC_PARENT); 821a5b831aSmartijn config_peer(PROC_DISPATCHER); 8376eb97c5Sreyk 8441b8cf0bSmillert /* Ignore them until we get our config */ 8541b8cf0bSmillert mproc_disable(p_dispatcher); 8641b8cf0bSmillert 8791ea8c26Sgilles if (pledge("stdio", NULL) == -1) 88ff01b044Seric fatal("pledge"); 8991ea8c26Sgilles 90f94528c3Seric event_dispatch(); 91f94528c3Seric fatalx("exited event loop"); 9276eb97c5Sreyk 9376eb97c5Sreyk return (0); 9476eb97c5Sreyk } 9576eb97c5Sreyk 9641b8cf0bSmillert void 97c4df3bf2Sreyk ca_init(void) 98c4df3bf2Sreyk { 9941b8cf0bSmillert BIO *in = NULL; 10041b8cf0bSmillert EVP_PKEY *pkey = NULL; 101c4df3bf2Sreyk struct pki *pki; 10241b8cf0bSmillert const char *k; 103c4df3bf2Sreyk void *iter_dict; 10441b8cf0bSmillert char *hash; 105c4df3bf2Sreyk 10641b8cf0bSmillert log_debug("debug: init private ssl-tree"); 10741b8cf0bSmillert dict_init(&pkeys); 108c4df3bf2Sreyk iter_dict = NULL; 10941b8cf0bSmillert while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) { 110c4df3bf2Sreyk if (pki->pki_key == NULL) 111c4df3bf2Sreyk continue; 11241b8cf0bSmillert 11341b8cf0bSmillert in = BIO_new_mem_buf(pki->pki_key, pki->pki_key_len); 11441b8cf0bSmillert if (in == NULL) 11541b8cf0bSmillert fatalx("ca_init: key"); 11641b8cf0bSmillert pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); 11741b8cf0bSmillert if (pkey == NULL) 11841b8cf0bSmillert fatalx("ca_init: PEM"); 11941b8cf0bSmillert BIO_free(in); 12041b8cf0bSmillert 12141b8cf0bSmillert hash = ssl_pubkey_hash(pki->pki_cert, pki->pki_cert_len); 12241b8cf0bSmillert if (dict_check(&pkeys, hash)) 12341b8cf0bSmillert EVP_PKEY_free(pkey); 12441b8cf0bSmillert else 12541b8cf0bSmillert dict_xset(&pkeys, hash, pkey); 12641b8cf0bSmillert free(hash); 127c4df3bf2Sreyk } 128c4df3bf2Sreyk } 12965c4fdfbSgilles 13041b8cf0bSmillert int 13141b8cf0bSmillert ca_X509_verify(void *certificate, void *chain, const char *CAfile, 13241b8cf0bSmillert const char *CRLfile, const char **errstr) 13341b8cf0bSmillert { 13441b8cf0bSmillert X509_STORE *store = NULL; 13541b8cf0bSmillert X509_STORE_CTX *xsc = NULL; 13641b8cf0bSmillert int ret = 0; 13741b8cf0bSmillert long error = 0; 13841b8cf0bSmillert 13941b8cf0bSmillert if ((store = X509_STORE_new()) == NULL) 14041b8cf0bSmillert goto end; 14141b8cf0bSmillert 14241b8cf0bSmillert if (!X509_STORE_load_locations(store, CAfile, NULL)) { 14341b8cf0bSmillert log_warn("warn: unable to load CA file %s", CAfile); 14441b8cf0bSmillert goto end; 14541b8cf0bSmillert } 14641b8cf0bSmillert X509_STORE_set_default_paths(store); 14741b8cf0bSmillert 14841b8cf0bSmillert if ((xsc = X509_STORE_CTX_new()) == NULL) 14941b8cf0bSmillert goto end; 15041b8cf0bSmillert 15141b8cf0bSmillert if (X509_STORE_CTX_init(xsc, store, certificate, chain) != 1) 15241b8cf0bSmillert goto end; 15341b8cf0bSmillert 15441b8cf0bSmillert ret = X509_verify_cert(xsc); 15541b8cf0bSmillert 15641b8cf0bSmillert end: 15741b8cf0bSmillert *errstr = NULL; 15841b8cf0bSmillert if (ret != 1) { 15941b8cf0bSmillert if (xsc) { 16041b8cf0bSmillert error = X509_STORE_CTX_get_error(xsc); 16141b8cf0bSmillert *errstr = X509_verify_cert_error_string(error); 16241b8cf0bSmillert } 16341b8cf0bSmillert else if (ERR_peek_last_error()) 16441b8cf0bSmillert *errstr = ERR_error_string(ERR_peek_last_error(), NULL); 16541b8cf0bSmillert } 16641b8cf0bSmillert 16741b8cf0bSmillert X509_STORE_CTX_free(xsc); 16841b8cf0bSmillert X509_STORE_free(store); 16941b8cf0bSmillert 17041b8cf0bSmillert return ret > 0 ? 1 : 0; 17141b8cf0bSmillert } 17241b8cf0bSmillert 17341b8cf0bSmillert void 174c4df3bf2Sreyk ca_imsg(struct mproc *p, struct imsg *imsg) 175c4df3bf2Sreyk { 17641b8cf0bSmillert EVP_PKEY *pkey; 17741b8cf0bSmillert RSA *rsa = NULL; 17841b8cf0bSmillert EC_KEY *ecdsa = NULL; 17941b8cf0bSmillert const void *from = NULL; 18041b8cf0bSmillert unsigned char *to = NULL; 181c4df3bf2Sreyk struct msg m; 182eed85469Seric const char *hash; 18341b8cf0bSmillert size_t flen, tlen, padding; 18441b8cf0bSmillert int buf_len; 18541b8cf0bSmillert int ret = 0; 186576d0b55Sreyk uint64_t id; 18741b8cf0bSmillert int v; 188c4df3bf2Sreyk 18943962b9cSeric if (imsg == NULL) 19043962b9cSeric ca_shutdown(); 19143962b9cSeric 19276eb97c5Sreyk switch (imsg->hdr.type) { 19376eb97c5Sreyk case IMSG_CONF_START: 19476eb97c5Sreyk return; 19576eb97c5Sreyk case IMSG_CONF_END: 19641b8cf0bSmillert ca_init(); 19741b8cf0bSmillert 19841b8cf0bSmillert /* Start fulfilling requests */ 19941b8cf0bSmillert mproc_enable(p_dispatcher); 20076eb97c5Sreyk return; 20157d312f7Seric 20276eb97c5Sreyk case IMSG_CTL_VERBOSE: 20376eb97c5Sreyk m_msg(&m, imsg); 20476eb97c5Sreyk m_get_int(&m, &v); 20576eb97c5Sreyk m_end(&m); 206f24248b7Sreyk log_trace_verbose(v); 20776eb97c5Sreyk return; 208ffdd47f9Seric 20976eb97c5Sreyk case IMSG_CTL_PROFILE: 21076eb97c5Sreyk m_msg(&m, imsg); 21176eb97c5Sreyk m_get_int(&m, &v); 21276eb97c5Sreyk m_end(&m); 21376eb97c5Sreyk profiling = v; 21476eb97c5Sreyk return; 21576eb97c5Sreyk 21641b8cf0bSmillert case IMSG_CA_RSA_PRIVENC: 21741b8cf0bSmillert case IMSG_CA_RSA_PRIVDEC: 218c4df3bf2Sreyk m_msg(&m, imsg); 219576d0b55Sreyk m_get_id(&m, &id); 220eed85469Seric m_get_string(&m, &hash); 22141b8cf0bSmillert m_get_data(&m, &from, &flen); 22241b8cf0bSmillert m_get_size(&m, &tlen); 22341b8cf0bSmillert m_get_size(&m, &padding); 224c4df3bf2Sreyk m_end(&m); 225c4df3bf2Sreyk 22641b8cf0bSmillert pkey = dict_get(&pkeys, hash); 22741b8cf0bSmillert if (pkey == NULL || (rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) 22841b8cf0bSmillert fatalx("ca_imsg: invalid pkey hash"); 22941b8cf0bSmillert 23041b8cf0bSmillert if ((to = calloc(1, tlen)) == NULL) 23141b8cf0bSmillert fatalx("ca_imsg: calloc"); 23241b8cf0bSmillert 23341b8cf0bSmillert switch (imsg->hdr.type) { 23441b8cf0bSmillert case IMSG_CA_RSA_PRIVENC: 23541b8cf0bSmillert ret = RSA_private_encrypt(flen, from, to, rsa, 23641b8cf0bSmillert padding); 23741b8cf0bSmillert break; 23841b8cf0bSmillert case IMSG_CA_RSA_PRIVDEC: 23941b8cf0bSmillert ret = RSA_private_decrypt(flen, from, to, rsa, 24041b8cf0bSmillert padding); 24141b8cf0bSmillert break; 24241b8cf0bSmillert } 243c4df3bf2Sreyk 244c4df3bf2Sreyk m_create(p, imsg->hdr.type, 0, 0, -1); 245576d0b55Sreyk m_add_id(p, id); 246c4df3bf2Sreyk m_add_int(p, ret); 24741b8cf0bSmillert if (ret > 0) 24841b8cf0bSmillert m_add_data(p, to, (size_t)ret); 249c4df3bf2Sreyk m_close(p); 25041b8cf0bSmillert 25141b8cf0bSmillert free(to); 25241b8cf0bSmillert RSA_free(rsa); 25341b8cf0bSmillert return; 25441b8cf0bSmillert 25541b8cf0bSmillert case IMSG_CA_ECDSA_SIGN: 25641b8cf0bSmillert m_msg(&m, imsg); 25741b8cf0bSmillert m_get_id(&m, &id); 25841b8cf0bSmillert m_get_string(&m, &hash); 25941b8cf0bSmillert m_get_data(&m, &from, &flen); 26041b8cf0bSmillert m_end(&m); 26141b8cf0bSmillert 26241b8cf0bSmillert pkey = dict_get(&pkeys, hash); 26341b8cf0bSmillert if (pkey == NULL || 26441b8cf0bSmillert (ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) 26541b8cf0bSmillert fatalx("ca_imsg: invalid pkey hash"); 26641b8cf0bSmillert 26741b8cf0bSmillert buf_len = ECDSA_size(ecdsa); 26841b8cf0bSmillert if ((to = calloc(1, buf_len)) == NULL) 26941b8cf0bSmillert fatalx("ca_imsg: calloc"); 27041b8cf0bSmillert ret = ECDSA_sign(0, from, flen, to, &buf_len, ecdsa); 27141b8cf0bSmillert m_create(p, imsg->hdr.type, 0, 0, -1); 27241b8cf0bSmillert m_add_id(p, id); 27341b8cf0bSmillert m_add_int(p, ret); 27441b8cf0bSmillert if (ret > 0) 27541b8cf0bSmillert m_add_data(p, to, (size_t)buf_len); 27641b8cf0bSmillert m_close(p); 27741b8cf0bSmillert free(to); 27841b8cf0bSmillert EC_KEY_free(ecdsa); 27976eb97c5Sreyk return; 28076eb97c5Sreyk } 28176eb97c5Sreyk 282ff01b044Seric fatalx("ca_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); 283c4df3bf2Sreyk } 284c4df3bf2Sreyk 28541b8cf0bSmillert /* 28641b8cf0bSmillert * RSA privsep engine (called from unprivileged processes) 28741b8cf0bSmillert */ 28841b8cf0bSmillert 28941b8cf0bSmillert const RSA_METHOD *rsa_default = NULL; 29041b8cf0bSmillert 29141b8cf0bSmillert static RSA_METHOD *rsae_method = NULL; 29241b8cf0bSmillert 293c4df3bf2Sreyk static int 29441b8cf0bSmillert rsae_send_imsg(int flen, const unsigned char *from, unsigned char *to, 29541b8cf0bSmillert RSA *rsa, int padding, unsigned int cmd) 296c4df3bf2Sreyk { 29741b8cf0bSmillert int ret = 0; 298c4df3bf2Sreyk struct imsgbuf *ibuf; 299c4df3bf2Sreyk struct imsg imsg; 30041b8cf0bSmillert int n, done = 0; 30141b8cf0bSmillert const void *toptr; 30241b8cf0bSmillert char *hash; 30341b8cf0bSmillert size_t tlen; 304c4df3bf2Sreyk struct msg m; 305576d0b55Sreyk uint64_t id; 30641b8cf0bSmillert 30741b8cf0bSmillert if ((hash = RSA_get_ex_data(rsa, 0)) == NULL) 30841b8cf0bSmillert return (0); 30941b8cf0bSmillert 31041b8cf0bSmillert /* 31141b8cf0bSmillert * Send a synchronous imsg because we cannot defer the RSA 31241b8cf0bSmillert * operation in OpenSSL's engine layer. 31341b8cf0bSmillert */ 31441b8cf0bSmillert m_create(p_ca, cmd, 0, 0, -1); 31541b8cf0bSmillert reqid++; 31641b8cf0bSmillert m_add_id(p_ca, reqid); 31741b8cf0bSmillert m_add_string(p_ca, hash); 31841b8cf0bSmillert m_add_data(p_ca, (const void *)from, (size_t)flen); 31941b8cf0bSmillert m_add_size(p_ca, (size_t)RSA_size(rsa)); 32041b8cf0bSmillert m_add_size(p_ca, (size_t)padding); 32141b8cf0bSmillert m_flush(p_ca); 322c4df3bf2Sreyk 32376eb97c5Sreyk ibuf = &p_ca->imsgbuf; 324c4df3bf2Sreyk 325c4df3bf2Sreyk while (!done) { 326*16b0c81bSclaudio if ((n = imsgbuf_read(ibuf)) == -1) 327dd7efffeSclaudio fatalx("imsgbuf_read"); 328c4df3bf2Sreyk if (n == 0) 329c4df3bf2Sreyk fatalx("pipe closed"); 330c4df3bf2Sreyk 331c4df3bf2Sreyk while (!done) { 332c4df3bf2Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 333c4df3bf2Sreyk fatalx("imsg_get error"); 334c4df3bf2Sreyk if (n == 0) 335c4df3bf2Sreyk break; 336576d0b55Sreyk 3371a5b831aSmartijn log_imsg(PROC_DISPATCHER, PROC_CA, &imsg); 338576d0b55Sreyk 33941b8cf0bSmillert switch (imsg.hdr.type) { 34041b8cf0bSmillert case IMSG_CA_RSA_PRIVENC: 34141b8cf0bSmillert case IMSG_CA_RSA_PRIVDEC: 34241b8cf0bSmillert break; 34341b8cf0bSmillert default: 344576d0b55Sreyk /* Another imsg is queued up in the buffer */ 3451a5b831aSmartijn dispatcher_imsg(p_ca, &imsg); 346576d0b55Sreyk imsg_free(&imsg); 347576d0b55Sreyk continue; 348576d0b55Sreyk } 349c4df3bf2Sreyk 350c4df3bf2Sreyk m_msg(&m, &imsg); 351576d0b55Sreyk m_get_id(&m, &id); 3524b5cbcb9Sgilles if (id != reqid) 353576d0b55Sreyk fatalx("invalid response id"); 354c4df3bf2Sreyk m_get_int(&m, &ret); 35541b8cf0bSmillert if (ret > 0) 35641b8cf0bSmillert m_get_data(&m, &toptr, &tlen); 357c4df3bf2Sreyk m_end(&m); 3583abbdc76Seric 35941b8cf0bSmillert if (ret > 0) 36041b8cf0bSmillert memcpy(to, toptr, tlen); 36141b8cf0bSmillert done = 1; 36241b8cf0bSmillert 36341b8cf0bSmillert imsg_free(&imsg); 36441b8cf0bSmillert } 36541b8cf0bSmillert } 36676eb97c5Sreyk mproc_event_add(p_ca); 367c4df3bf2Sreyk 368c4df3bf2Sreyk return (ret); 369c4df3bf2Sreyk } 370c4df3bf2Sreyk 37141b8cf0bSmillert static int 37241b8cf0bSmillert rsae_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, 37341b8cf0bSmillert int padding) 37441b8cf0bSmillert { 37541b8cf0bSmillert log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); 37641b8cf0bSmillert if (RSA_get_ex_data(rsa, 0) != NULL) 37741b8cf0bSmillert return (rsae_send_imsg(flen, from, to, rsa, padding, 37841b8cf0bSmillert IMSG_CA_RSA_PRIVENC)); 37941b8cf0bSmillert return (RSA_meth_get_priv_enc(rsa_default)(flen, from, to, rsa, padding)); 38041b8cf0bSmillert } 38141b8cf0bSmillert 38241b8cf0bSmillert static int 38341b8cf0bSmillert rsae_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, 38441b8cf0bSmillert int padding) 38541b8cf0bSmillert { 38641b8cf0bSmillert log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); 38741b8cf0bSmillert if (RSA_get_ex_data(rsa, 0) != NULL) 38841b8cf0bSmillert return (rsae_send_imsg(flen, from, to, rsa, padding, 38941b8cf0bSmillert IMSG_CA_RSA_PRIVDEC)); 39041b8cf0bSmillert 39141b8cf0bSmillert return (RSA_meth_get_priv_dec(rsa_default)(flen, from, to, rsa, padding)); 39241b8cf0bSmillert } 39341b8cf0bSmillert 39441b8cf0bSmillert /* 39541b8cf0bSmillert * ECDSA privsep engine (called from unprivileged processes) 39641b8cf0bSmillert */ 39741b8cf0bSmillert 3988615c063Sop const EC_KEY_METHOD *ecdsa_default = NULL; 39941b8cf0bSmillert 4008615c063Sop static EC_KEY_METHOD *ecdsae_method = NULL; 40141b8cf0bSmillert 40241b8cf0bSmillert static ECDSA_SIG * 40341b8cf0bSmillert ecdsae_send_enc_imsg(const unsigned char *dgst, int dgst_len, 40441b8cf0bSmillert const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey) 40541b8cf0bSmillert { 40641b8cf0bSmillert int ret = 0; 40741b8cf0bSmillert struct imsgbuf *ibuf; 40841b8cf0bSmillert struct imsg imsg; 40941b8cf0bSmillert int n, done = 0; 41041b8cf0bSmillert const void *toptr; 41141b8cf0bSmillert char *hash; 41241b8cf0bSmillert size_t tlen; 41341b8cf0bSmillert struct msg m; 41441b8cf0bSmillert uint64_t id; 41541b8cf0bSmillert ECDSA_SIG *sig = NULL; 41641b8cf0bSmillert 4178615c063Sop if ((hash = EC_KEY_get_ex_data(eckey, 0)) == NULL) 41841b8cf0bSmillert return (0); 41941b8cf0bSmillert 42041b8cf0bSmillert /* 42141b8cf0bSmillert * Send a synchronous imsg because we cannot defer the ECDSA 42241b8cf0bSmillert * operation in OpenSSL's engine layer. 42341b8cf0bSmillert */ 42441b8cf0bSmillert m_create(p_ca, IMSG_CA_ECDSA_SIGN, 0, 0, -1); 42541b8cf0bSmillert reqid++; 42641b8cf0bSmillert m_add_id(p_ca, reqid); 427eed85469Seric m_add_string(p_ca, hash); 42841b8cf0bSmillert m_add_data(p_ca, (const void *)dgst, (size_t)dgst_len); 4294b5cbcb9Sgilles m_flush(p_ca); 4304b5cbcb9Sgilles 43141b8cf0bSmillert ibuf = &p_ca->imsgbuf; 43241b8cf0bSmillert 43341b8cf0bSmillert while (!done) { 434*16b0c81bSclaudio if ((n = imsgbuf_read(ibuf)) == -1) 435dd7efffeSclaudio fatalx("imsgbuf_read"); 43641b8cf0bSmillert if (n == 0) 43741b8cf0bSmillert fatalx("pipe closed"); 43841b8cf0bSmillert while (!done) { 43941b8cf0bSmillert if ((n = imsg_get(ibuf, &imsg)) == -1) 44041b8cf0bSmillert fatalx("imsg_get error"); 44141b8cf0bSmillert if (n == 0) 44241b8cf0bSmillert break; 44341b8cf0bSmillert 44441b8cf0bSmillert log_imsg(PROC_DISPATCHER, PROC_CA, &imsg); 44541b8cf0bSmillert 44641b8cf0bSmillert switch (imsg.hdr.type) { 44741b8cf0bSmillert case IMSG_CA_ECDSA_SIGN: 44841b8cf0bSmillert break; 44941b8cf0bSmillert default: 45041b8cf0bSmillert /* Another imsg is queued up in the buffer */ 45141b8cf0bSmillert dispatcher_imsg(p_ca, &imsg); 45241b8cf0bSmillert imsg_free(&imsg); 45341b8cf0bSmillert continue; 45441b8cf0bSmillert } 45541b8cf0bSmillert 45641b8cf0bSmillert m_msg(&m, &imsg); 45741b8cf0bSmillert m_get_id(&m, &id); 45841b8cf0bSmillert if (id != reqid) 45941b8cf0bSmillert fatalx("invalid response id"); 46041b8cf0bSmillert m_get_int(&m, &ret); 46141b8cf0bSmillert if (ret > 0) 46241b8cf0bSmillert m_get_data(&m, &toptr, &tlen); 46341b8cf0bSmillert m_end(&m); 46441b8cf0bSmillert done = 1; 46541b8cf0bSmillert 46641b8cf0bSmillert if (ret > 0) 46741b8cf0bSmillert d2i_ECDSA_SIG(&sig, (const unsigned char **)&toptr, tlen); 46841b8cf0bSmillert imsg_free(&imsg); 46941b8cf0bSmillert } 47041b8cf0bSmillert } 47141b8cf0bSmillert mproc_event_add(p_ca); 47241b8cf0bSmillert 47341b8cf0bSmillert return (sig); 47441b8cf0bSmillert } 47541b8cf0bSmillert 4768615c063Sop static ECDSA_SIG * 4778615c063Sop ecdsae_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, 4788615c063Sop const BIGNUM *rp, EC_KEY *eckey) 4798615c063Sop { 4808615c063Sop ECDSA_SIG *(*psign_sig)(const unsigned char *, int, const BIGNUM *, 4818615c063Sop const BIGNUM *, EC_KEY *); 4828615c063Sop 4838615c063Sop log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); 4848615c063Sop if (EC_KEY_get_ex_data(eckey, 0) != NULL) 48541b8cf0bSmillert return (ecdsae_send_enc_imsg(dgst, dgst_len, inv, rp, eckey)); 4868615c063Sop EC_KEY_METHOD_get_sign(ecdsa_default, NULL, NULL, &psign_sig); 4878615c063Sop return (psign_sig(dgst, dgst_len, inv, rp, eckey)); 48841b8cf0bSmillert } 48941b8cf0bSmillert 49041b8cf0bSmillert static void 49141b8cf0bSmillert rsa_engine_init(void) 49241b8cf0bSmillert { 493ed3431f4Sop const char *errstr; 49441b8cf0bSmillert 49541b8cf0bSmillert if ((rsa_default = RSA_get_default_method()) == NULL) { 49641b8cf0bSmillert errstr = "RSA_get_default_method"; 49741b8cf0bSmillert goto fail; 49841b8cf0bSmillert } 49941b8cf0bSmillert 5003f1e3a05Sop if ((rsae_method = RSA_meth_dup(rsa_default)) == NULL) { 5013f1e3a05Sop errstr = "RSA_meth_dup"; 5023f1e3a05Sop goto fail; 5033f1e3a05Sop } 5043f1e3a05Sop 5053f1e3a05Sop RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc); 5063f1e3a05Sop RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec); 5073f1e3a05Sop 50841b8cf0bSmillert RSA_meth_set_flags(rsae_method, 50941b8cf0bSmillert RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK); 51041b8cf0bSmillert RSA_meth_set0_app_data(rsae_method, 51141b8cf0bSmillert RSA_meth_get0_app_data(rsa_default)); 51241b8cf0bSmillert 513ed3431f4Sop RSA_set_default_method(rsae_method); 51441b8cf0bSmillert 51541b8cf0bSmillert return; 51641b8cf0bSmillert 51741b8cf0bSmillert fail: 51841b8cf0bSmillert ssl_error(errstr); 51941b8cf0bSmillert fatalx("%s", errstr); 52041b8cf0bSmillert } 52141b8cf0bSmillert 52241b8cf0bSmillert static void 52341b8cf0bSmillert ecdsa_engine_init(void) 52441b8cf0bSmillert { 5253f1e3a05Sop int (*sign)(int, const unsigned char *, int, unsigned char *, 5263f1e3a05Sop unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *); 5273f1e3a05Sop int (*sign_setup)(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **); 528ed3431f4Sop const char *errstr; 52941b8cf0bSmillert 5308615c063Sop if ((ecdsa_default = EC_KEY_get_default_method()) == NULL) { 5318615c063Sop errstr = "EC_KEY_get_default_method"; 53241b8cf0bSmillert goto fail; 53341b8cf0bSmillert } 53441b8cf0bSmillert 5353f1e3a05Sop if ((ecdsae_method = EC_KEY_METHOD_new(ecdsa_default)) == NULL) { 5363f1e3a05Sop errstr = "EC_KEY_METHOD_new"; 5373f1e3a05Sop goto fail; 5383f1e3a05Sop } 5393f1e3a05Sop 5403f1e3a05Sop EC_KEY_METHOD_get_sign(ecdsa_default, &sign, &sign_setup, NULL); 5413f1e3a05Sop EC_KEY_METHOD_set_sign(ecdsae_method, sign, sign_setup, 5423f1e3a05Sop ecdsae_do_sign); 5433f1e3a05Sop 544ed3431f4Sop EC_KEY_set_default_method(ecdsae_method); 54541b8cf0bSmillert 54641b8cf0bSmillert return; 54741b8cf0bSmillert 54841b8cf0bSmillert fail: 54941b8cf0bSmillert ssl_error(errstr); 55041b8cf0bSmillert fatalx("%s", errstr); 55141b8cf0bSmillert } 55241b8cf0bSmillert 55341b8cf0bSmillert void 55441b8cf0bSmillert ca_engine_init(void) 55541b8cf0bSmillert { 55641b8cf0bSmillert rsa_engine_init(); 55741b8cf0bSmillert ecdsa_engine_init(); 5584b5cbcb9Sgilles } 559