From fee0755a48c7bf98a8732070ccbc2da52cbeb983 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 08:11:07 +0900 Subject: [PATCH 1/8] Replace ENGINE-based RSA with OpenSSL 3 Provider The ENGINE API is deprecated in OpenSSL 3.x and the ENGINE-based RSA decrypt path was broken for RSA key exchange ciphers. This commit replaces the ENGINE RSA path with an OpenSSL 3 Provider implementing KEYMGMT, SIGNATURE, and ASYM_CIPHER operations. The provider handles RSA signing (including TLS 1.3 RSA-PSS via the one-shot digest_sign path) and RSA decryption (including constant-time PKCS1 type 2 TLS unpadding as a Bleichenbacher countermeasure). ECDSA continues to use ENGINE temporarily. The BoringSSL path is untouched. All new code is guarded by NEVERBLEED_PROVIDER, defined only for non-BoringSSL, non-LibreSSL OpenSSL >= 3.0. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 896 ++++++++++++++++++++++++++++++++++++++++++++++++++- neverbleed.h | 13 + 2 files changed, 897 insertions(+), 12 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index 4cea5de..14da060 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -67,6 +67,10 @@ #define NEVERBLEED_ECDSA #endif +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#define NEVERBLEED_PROVIDER +#endif + #include #ifdef NEVERBLEED_ECDSA #include @@ -74,6 +78,14 @@ #include #include #include +#ifdef NEVERBLEED_PROVIDER +#include +#include +#include +#include +#include +#include +#endif #ifdef __linux #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) @@ -556,6 +568,7 @@ static void do_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, free(exdata); } +#if !defined(NEVERBLEED_PROVIDER) static int get_rsa_exdata_idx(void); static void rsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) { @@ -581,6 +594,7 @@ static void get_privsep_data(const RSA *rsa, struct st_neverbleed_rsa_exdata_t * } *thdata = get_thread_data((*exdata)->nb); } +#endif /* !NEVERBLEED_PROVIDER */ static struct { struct { @@ -750,6 +764,7 @@ static size_t daemon_set_pkey(EVP_PKEY *pkey) return index; } +#if !defined(NEVERBLEED_PROVIDER) static int priv_encdec_proxy(const char *cmd, int flen, const unsigned char *from, unsigned char *_to, RSA *rsa, int padding) { struct st_neverbleed_rsa_exdata_t *exdata; @@ -777,6 +792,7 @@ static int priv_encdec_proxy(const char *cmd, int flen, const unsigned char *fro return (int)ret; } +#endif /* !NEVERBLEED_PROVIDER */ static int priv_encdec_stub(const char *name, int (*func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), @@ -811,26 +827,31 @@ static int priv_encdec_stub(const char *name, #if !defined(OPENSSL_IS_BORINGSSL) +#if !defined(NEVERBLEED_PROVIDER) static int priv_enc_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { return priv_encdec_proxy("priv_enc", flen, from, to, rsa, padding); } +#endif static int priv_enc_stub(neverbleed_iobuf_t *buf) { return priv_encdec_stub(__FUNCTION__, RSA_private_encrypt, buf); } +#if !defined(NEVERBLEED_PROVIDER) static int priv_dec_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { return priv_encdec_proxy("priv_dec", flen, from, to, rsa, padding); } +#endif static int priv_dec_stub(neverbleed_iobuf_t *buf) { return priv_encdec_stub(__FUNCTION__, RSA_private_decrypt, buf); } +#if !defined(NEVERBLEED_PROVIDER) static int sign_proxy(int type, const unsigned char *m, unsigned int m_len, unsigned char *_sigret, unsigned *_siglen, const RSA *rsa) { @@ -858,6 +879,7 @@ static int sign_proxy(int type, const unsigned char *m, unsigned int m_len, unsi return (int)ret; } +#endif static int sign_stub(neverbleed_iobuf_t *buf) { @@ -887,10 +909,801 @@ static int sign_stub(neverbleed_iobuf_t *buf) return 0; } -#endif +#endif /* !OPENSSL_IS_BORINGSSL */ + +#ifdef NEVERBLEED_PROVIDER + +/* ======================== OpenSSL 3 Provider ======================== */ + +#define NEVERBLEED_PARAM_KEY_INDEX "neverbleed-key-index" + +static neverbleed_t *nb_provider_global_nb; + +struct nb_provider_ctx { + neverbleed_t *nb; +}; + +struct nb_rsa_keydata { + neverbleed_t *nb; + size_t key_index; + BIGNUM *n, *e; + int has_private; +}; + +struct nb_sig_ctx { + struct nb_provider_ctx *provctx; + struct nb_rsa_keydata *keydata; + unsigned char *tbsdata; + size_t tbslen, tbscap; + int md_nid; + int padding; + int pss_saltlen; +}; + +struct nb_asym_cipher_ctx { + struct nb_provider_ctx *provctx; + struct nb_rsa_keydata *keydata; + int padding; + unsigned int tls_client_version; + unsigned int tls_negotiated_version; +}; + +/* --- constant-time helpers for TLS padding check (all return 0 or 0xFFFFFFFF masks) --- */ + +static inline unsigned int ct_is_zero_mask(unsigned int x) +{ + /* returns 0xFFFFFFFF if x == 0, 0 otherwise */ + return 0u - (1u ^ ((x | (0u - x)) >> (sizeof(unsigned int) * 8 - 1))); +} + +static inline unsigned int ct_eq_mask(unsigned int a, unsigned int b) +{ + return ct_is_zero_mask(a ^ b); +} + +static inline unsigned char ct_select_8(unsigned int mask, unsigned char a, unsigned char b) +{ + return (unsigned char)((mask & a) | (~mask & b)); +} + +static inline unsigned int ct_ge_mask(unsigned int a, unsigned int b) +{ + /* returns 0xFFFFFFFF if a >= b, 0 otherwise (a, b must be < 2^31) */ + return 0u - (1u & ~((a - b) >> (sizeof(unsigned int) * 8 - 1))); +} + +/* --- KEYMGMT --- */ + +static void *nb_keymgmt_new(void *provctx) +{ + struct nb_rsa_keydata *key = OPENSSL_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + key->nb = ((struct nb_provider_ctx *)provctx)->nb; + key->key_index = SIZE_MAX; + return key; +} + +static void nb_keymgmt_free(void *keydata) +{ + struct nb_rsa_keydata *key = keydata; + if (key == NULL) + return; + if (key->key_index != SIZE_MAX && key->has_private) { + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "del_pkey"); + iobuf_push_num(&buf, key->key_index); + iobuf_transaction_no_response(&buf, thdata); + } + BN_free(key->n); + BN_free(key->e); + OPENSSL_free(key); +} + +static int nb_keymgmt_has(const void *keydata, int selection) +{ + const struct nb_rsa_keydata *key = keydata; + if (key == NULL) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0 && (key->n == NULL || key->e == NULL)) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 && !key->has_private) + return 0; + return 1; +} + +static int nb_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + struct nb_rsa_keydata *key = keydata; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N)) != NULL) { + BN_free(key->n); + key->n = NULL; + if (!OSSL_PARAM_get_BN(p, &key->n)) + return 0; + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E)) != NULL) { + BN_free(key->e); + key->e = NULL; + if (!OSSL_PARAM_get_BN(p, &key->e)) + return 0; + } + if ((p = OSSL_PARAM_locate_const(params, NEVERBLEED_PARAM_KEY_INDEX)) != NULL) { + if (!OSSL_PARAM_get_size_t(p, &key->key_index)) + return 0; + key->has_private = 1; + } + return 1; +} + +static const OSSL_PARAM *nb_keymgmt_import_types(int selection) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), + OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) +{ + struct nb_rsa_keydata *key = keydata; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL) { + if (!OSSL_PARAM_set_int(p, key->n ? BN_num_bits(key->n) : 0)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL) { + int bits = key->n ? BN_num_bits(key->n) : 0; + int sec_bits = bits >= 3072 ? 128 : (bits >= 2048 ? 112 : (bits >= 1024 ? 80 : 0)); + if (!OSSL_PARAM_set_int(p, sec_bits)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL) { + if (!OSSL_PARAM_set_int(p, key->n ? BN_num_bytes(key->n) : 0)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_N)) != NULL) { + if (!OSSL_PARAM_set_BN(p, key->n)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_E)) != NULL) { + if (!OSSL_PARAM_set_BN(p, key->e)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, NEVERBLEED_PARAM_KEY_INDEX)) != NULL) { + if (!OSSL_PARAM_set_size_t(p, key->key_index)) + return 0; + } + return 1; +} + +static const OSSL_PARAM *nb_keymgmt_gettable_params(void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), + OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) +{ + struct nb_rsa_keydata *key = keydata; + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params; + int ret; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + return 0; + if (key->n == NULL || key->e == NULL) + return 0; + + if ((bld = OSSL_PARAM_BLD_new()) == NULL) + return 0; + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, key->n); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, key->e); + params = OSSL_PARAM_BLD_to_param(bld); + ret = param_cb(params, cbarg); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return ret; +} + +static const OSSL_PARAM *nb_keymgmt_export_types(int selection) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static const OSSL_DISPATCH nb_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))nb_keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))nb_keymgmt_free}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))nb_keymgmt_has}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))nb_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))nb_keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))nb_keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))nb_keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))nb_keymgmt_export}, + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))nb_keymgmt_export_types}, + {0, NULL}, +}; + +/* --- SIGNATURE --- */ + +static void *nb_sig_newctx(void *provctx, const char *propq) +{ + struct nb_sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + ctx->provctx = provctx; + ctx->padding = RSA_PKCS1_PADDING; + ctx->pss_saltlen = -1; + ctx->md_nid = NID_undef; + return ctx; +} + +static void nb_sig_freectx(void *vctx) +{ + struct nb_sig_ctx *ctx = vctx; + if (ctx == NULL) + return; + OPENSSL_free(ctx->tbsdata); + OPENSSL_free(ctx); +} + +static int nb_sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +{ + struct nb_sig_ctx *ctx = vctx; + ctx->keydata = vkey; + return 1; +} + +static int nb_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + struct nb_sig_ctx *ctx = vctx; + struct nb_rsa_keydata *key = ctx->keydata; + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + neverbleed_iobuf_t buf = {NULL}; + size_t ret; + unsigned char *sigret; + size_t retlen; + + if (sig == NULL) { + *siglen = key->n ? BN_num_bytes(key->n) : 0; + return 1; + } + + iobuf_push_str(&buf, "sign"); + iobuf_push_num(&buf, ctx->md_nid != NID_undef ? ctx->md_nid : NID_md5_sha1); + iobuf_push_bytes(&buf, tbs, tbslen); + iobuf_push_num(&buf, key->key_index); + iobuf_transaction(&buf, thdata); + + if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &retlen)) == NULL) { + iobuf_dispose(&buf); + return 0; + } + if (ret != 1 || retlen > sigsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(sig, sigret, retlen); + *siglen = retlen; + iobuf_dispose(&buf); + return 1; +} + +static int nb_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) +{ + struct nb_sig_ctx *ctx = vctx; + ctx->keydata = vkey; + if (mdname != NULL) { + const EVP_MD *md = EVP_get_digestbyname(mdname); + ctx->md_nid = md ? EVP_MD_type(md) : NID_undef; + } + ctx->tbslen = 0; + return 1; +} + +static int nb_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) +{ + struct nb_sig_ctx *ctx = vctx; + if (ctx->tbslen + datalen > ctx->tbscap) { + ctx->tbscap = ctx->tbslen + datalen + 256; + ctx->tbsdata = OPENSSL_realloc(ctx->tbsdata, ctx->tbscap); + if (ctx->tbsdata == NULL) + return 0; + } + memcpy(ctx->tbsdata + ctx->tbslen, data, datalen); + ctx->tbslen += datalen; + return 1; +} + +static int nb_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) +{ + struct nb_sig_ctx *ctx = vctx; + struct nb_rsa_keydata *key = ctx->keydata; + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + neverbleed_iobuf_t buf = {NULL}; + size_t retlen; + unsigned char *sigret; + + if (sig == NULL) { + *siglen = key->n ? BN_num_bytes(key->n) : 0; + return 1; + } + + iobuf_push_str(&buf, "digestsign-rsa"); + iobuf_push_num(&buf, key->key_index); + iobuf_push_num(&buf, ctx->md_nid != NID_undef ? (size_t)ctx->md_nid : SIZE_MAX); + iobuf_push_bytes(&buf, ctx->tbsdata, ctx->tbslen); + iobuf_push_num(&buf, ctx->padding == RSA_PKCS1_PSS_PADDING ? 1 : 0); + iobuf_transaction(&buf, thdata); + + if ((sigret = iobuf_shift_bytes(&buf, &retlen)) == NULL) { + iobuf_dispose(&buf); + return 0; + } + if (retlen == 0 || retlen > sigsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(sig, sigret, retlen); + *siglen = retlen; + iobuf_dispose(&buf); + return 1; +} + +static int nb_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, + size_t tbslen) +{ + struct nb_sig_ctx *ctx = vctx; + + /* If called for size query, just return max size */ + if (sig == NULL) { + struct nb_rsa_keydata *key = ctx->keydata; + *siglen = key->n ? BN_num_bytes(key->n) : 0; + return 1; + } + + /* Buffer the data and call final */ + ctx->tbslen = 0; + if (!nb_sig_digest_sign_update(vctx, tbs, tbslen)) + return 0; + return nb_sig_digest_sign_final(vctx, sig, siglen, sigsize); +} + +static int nb_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct nb_sig_ctx *ctx = vctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE)) != NULL) { + if (p->data_type == OSSL_PARAM_INTEGER) { + OSSL_PARAM_get_int(p, &ctx->padding); + } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { + if (strcmp(p->data, "pss") == 0) + ctx->padding = RSA_PKCS1_PSS_PADDING; + else if (strcmp(p->data, "pkcs1") == 0) + ctx->padding = RSA_PKCS1_PADDING; + } + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { + char mdname[64] = ""; + OSSL_PARAM_get_utf8_string(p, (char **)&(char *){mdname}, sizeof(mdname)); + const EVP_MD *md = EVP_get_digestbyname(mdname); + if (md != NULL) + ctx->md_nid = EVP_MD_type(md); + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN)) != NULL) { + if (p->data_type == OSSL_PARAM_INTEGER) + OSSL_PARAM_get_int(p, &ctx->pss_saltlen); + } + return 1; +} + +static const OSSL_PARAM *nb_sig_settable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + struct nb_sig_ctx *ctx = vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE)) != NULL) { + if (!OSSL_PARAM_set_int(p, ctx->padding)) + return 0; + } + if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { + const char *name = ctx->md_nid != NID_undef ? OBJ_nid2sn(ctx->md_nid) : ""; + if (!OSSL_PARAM_set_utf8_string(p, name)) + return 0; + } + /* OSSL_SIGNATURE_PARAM_ALGORITHM_ID not handled; OpenSSL computes it at a higher level */ + return 1; +} + +static const OSSL_PARAM *nb_sig_gettable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static const OSSL_DISPATCH nb_sig_functions[] = { + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))nb_sig_newctx}, + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))nb_sig_freectx}, + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))nb_sig_sign_init}, + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))nb_sig_sign}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))nb_sig_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))nb_sig_digest_sign_update}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))nb_sig_digest_sign_final}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))nb_sig_digest_sign}, + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))nb_sig_set_ctx_params}, + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))nb_sig_settable_ctx_params}, + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))nb_sig_get_ctx_params}, + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))nb_sig_gettable_ctx_params}, + {0, NULL}, +}; + +/* --- ASYM_CIPHER --- */ + +static void *nb_asym_cipher_newctx(void *provctx) +{ + struct nb_asym_cipher_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + ctx->provctx = provctx; + ctx->padding = RSA_PKCS1_PADDING; + return ctx; +} + +static void nb_asym_cipher_freectx(void *vctx) +{ + OPENSSL_free(vctx); +} + +static int nb_asym_cipher_decrypt_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +{ + struct nb_asym_cipher_ctx *ctx = vctx; + ctx->keydata = vkey; + return 1; +} + +static int nb_asym_cipher_decrypt(void *vctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, + size_t inlen) +{ + struct nb_asym_cipher_ctx *ctx = vctx; + struct nb_rsa_keydata *key = ctx->keydata; + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + int rsa_size = key->n ? BN_num_bytes(key->n) : 0; + + if (out == NULL) { + *outlen = rsa_size; + return 1; + } + + if (ctx->padding == RSA_NO_PADDING) { + /* raw decrypt via daemon */ + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "decrypt"); + iobuf_push_num(&buf, key->key_index); + iobuf_push_bytes(&buf, in, inlen); + iobuf_transaction(&buf, thdata); + + size_t declen; + unsigned char *dec; + if ((dec = iobuf_shift_bytes(&buf, &declen)) == NULL || declen == 0) { + iobuf_dispose(&buf); + return 0; + } + if (declen > outsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(out, dec, declen); + *outlen = declen; + iobuf_dispose(&buf); + return 1; + } else if (ctx->padding == RSA_PKCS1_PADDING) { + /* PKCS1 decrypt via daemon priv_dec */ + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "priv_dec"); + iobuf_push_bytes(&buf, in, inlen); + iobuf_push_num(&buf, key->key_index); + iobuf_push_num(&buf, (size_t)RSA_PKCS1_PADDING); + iobuf_transaction(&buf, thdata); + + size_t ret; + unsigned char *dec; + size_t declen; + if (iobuf_shift_num(&buf, &ret) != 0 || (dec = iobuf_shift_bytes(&buf, &declen)) == NULL) { + iobuf_dispose(&buf); + return 0; + } + if ((int)ret <= 0) { + iobuf_dispose(&buf); + return 0; + } + if (declen > outsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(out, dec, declen); + *outlen = declen; + iobuf_dispose(&buf); + return 1; + } else if (ctx->padding == RSA_PKCS1_WITH_TLS_PADDING) { + /* Raw decrypt then constant-time PKCS1 type 2 TLS unpadding */ + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "decrypt"); + iobuf_push_num(&buf, key->key_index); + iobuf_push_bytes(&buf, in, inlen); + iobuf_transaction(&buf, thdata); + + size_t declen; + unsigned char *dec; + if ((dec = iobuf_shift_bytes(&buf, &declen)) == NULL || declen == 0) { + iobuf_dispose(&buf); + /* Even on failure, return random PMS for Bleichenbacher countermeasure */ + unsigned char rand_pms[SSL_MAX_MASTER_KEY_LENGTH]; + RAND_bytes(rand_pms, sizeof(rand_pms)); + if (sizeof(rand_pms) > outsize) + return 0; + memcpy(out, rand_pms, sizeof(rand_pms)); + *outlen = sizeof(rand_pms); + return 1; + } + + /* Constant-time PKCS1 type 2 TLS check */ + unsigned char rand_pms[SSL_MAX_MASTER_KEY_LENGTH]; + RAND_bytes(rand_pms, sizeof(rand_pms)); + + /* Check 0x00 0x02 header */ + unsigned int good = ct_eq_mask(dec[0], 0) & ct_eq_mask(dec[1], 2); + + /* Find 0x00 separator, require at least 8 bytes of padding */ + size_t sep_idx = 0; + unsigned int found_sep = 0; + for (size_t i = 2; i < declen; i++) { + unsigned int is_zero = ct_eq_mask(dec[i], 0); + unsigned int is_first = is_zero & ~found_sep & ct_ge_mask((unsigned int)i, 10u); + /* ct_ge_mask(i, 10u) means i >= 10, i.e., at least 8 bytes of padding (indices 2..9) */ + sep_idx |= is_first & (unsigned int)i; + found_sep |= is_first; + } + good &= found_sep; + + /* PMS starts at sep_idx + 1, length should be 48 */ + size_t pms_start = sep_idx + 1; + size_t pms_len = declen - pms_start; + good &= ct_eq_mask((unsigned int)pms_len, SSL_MAX_MASTER_KEY_LENGTH); + + /* Check TLS version in first two bytes of PMS */ + if (ctx->tls_client_version != 0) { + unsigned int ver_hi = ctx->tls_client_version >> 8; + unsigned int ver_lo = ctx->tls_client_version & 0xff; + /* Only check if pms_start is valid */ + unsigned int check_ver = good; + if (pms_start + 1 < declen) { + check_ver &= ct_eq_mask(dec[pms_start], ver_hi) & ct_eq_mask(dec[pms_start + 1], ver_lo); + } else { + check_ver = 0; + } + good = check_ver; + } + + /* Constant-time select between real PMS and random PMS */ + unsigned char result[SSL_MAX_MASTER_KEY_LENGTH]; + for (size_t i = 0; i < SSL_MAX_MASTER_KEY_LENGTH; i++) { + size_t src_idx = pms_start + i; + unsigned char real_byte = (src_idx < declen) ? dec[src_idx] : 0; + result[i] = ct_select_8(good, real_byte, rand_pms[i]); + } + + iobuf_dispose(&buf); + + if (SSL_MAX_MASTER_KEY_LENGTH > outsize) + return 0; + memcpy(out, result, SSL_MAX_MASTER_KEY_LENGTH); + *outlen = SSL_MAX_MASTER_KEY_LENGTH; + /* Always return success (Bleichenbacher countermeasure) */ + return 1; + } + + return 0; +} + +static int nb_asym_cipher_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct nb_asym_cipher_ctx *ctx = vctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE)) != NULL) { + if (p->data_type == OSSL_PARAM_INTEGER) + OSSL_PARAM_get_int(p, &ctx->padding); + else if (p->data_type == OSSL_PARAM_UTF8_STRING) { + if (strcmp(p->data, "oaep") == 0) + ctx->padding = RSA_PKCS1_OAEP_PADDING; + else if (strcmp(p->data, "pkcs1") == 0) + ctx->padding = RSA_PKCS1_PADDING; + else if (strcmp(p->data, "none") == 0) + ctx->padding = RSA_NO_PADDING; + } + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION)) != NULL) + OSSL_PARAM_get_uint(p, &ctx->tls_client_version); + if ((p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION)) != NULL) + OSSL_PARAM_get_uint(p, &ctx->tls_negotiated_version); + return 1; +} + +static const OSSL_PARAM *nb_asym_cipher_settable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), + OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + struct nb_asym_cipher_ctx *ctx = vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE)) != NULL) { + if (!OSSL_PARAM_set_int(p, ctx->padding)) + return 0; + } + return 1; +} + +static const OSSL_PARAM *nb_asym_cipher_gettable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static const OSSL_DISPATCH nb_asym_cipher_functions[] = { + {OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))nb_asym_cipher_newctx}, + {OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))nb_asym_cipher_freectx}, + {OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))nb_asym_cipher_decrypt_init}, + {OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))nb_asym_cipher_decrypt}, + {OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, (void (*)(void))nb_asym_cipher_set_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))nb_asym_cipher_settable_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, (void (*)(void))nb_asym_cipher_get_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))nb_asym_cipher_gettable_ctx_params}, + {0, NULL}, +}; + +/* --- Provider entry point --- */ + +static const OSSL_ALGORITHM nb_keymgmts[] = { + {"RSA", "provider=neverbleed", nb_keymgmt_functions, "Neverbleed RSA KEYMGMT"}, + {NULL, NULL, NULL, NULL}, +}; + +static const OSSL_ALGORITHM nb_signatures[] = { + {"RSA", "provider=neverbleed", nb_sig_functions, "Neverbleed RSA Signature"}, + {NULL, NULL, NULL, NULL}, +}; + +static const OSSL_ALGORITHM nb_asym_ciphers[] = { + {"RSA", "provider=neverbleed", nb_asym_cipher_functions, "Neverbleed RSA Asymmetric Cipher"}, + {NULL, NULL, NULL, NULL}, +}; + +static const OSSL_ALGORITHM *nb_provider_query_operation(void *provctx, int operation_id, int *no_cache) +{ + *no_cache = 0; + switch (operation_id) { + case OSSL_OP_KEYMGMT: + return nb_keymgmts; + case OSSL_OP_SIGNATURE: + return nb_signatures; + case OSSL_OP_ASYM_CIPHER: + return nb_asym_ciphers; + } + return NULL; +} + +static void nb_provider_teardown(void *provctx) +{ + OPENSSL_free(provctx); +} + +static const OSSL_DISPATCH nb_provider_dispatch[] = { + {OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))nb_provider_teardown}, + {OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))nb_provider_query_operation}, + {0, NULL}, +}; + +static int nb_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, void **provctx) +{ + struct nb_provider_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return 0; + ctx->nb = nb_provider_global_nb; + *provctx = ctx; + *out = nb_provider_dispatch; + return 1; +} + +#endif /* NEVERBLEED_PROVIDER */ static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebuf, const char *nbuf) { +#ifdef NEVERBLEED_PROVIDER + BIGNUM *e = NULL, *n = NULL; + EVP_PKEY *pkey = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + + if (BN_hex2bn(&e, ebuf) == 0) { + fprintf(stderr, "failed to parse e:%s\n", ebuf); + abort(); + } + if (BN_hex2bn(&n, nbuf) == 0) { + fprintf(stderr, "failed to parse n:%s\n", nbuf); + abort(); + } + + if ((bld = OSSL_PARAM_BLD_new()) == NULL) + dief("no memory"); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n); + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e); + OSSL_PARAM_BLD_push_size_t(bld, NEVERBLEED_PARAM_KEY_INDEX, key_index); + if ((params = OSSL_PARAM_BLD_to_param(bld)) == NULL) + dief("OSSL_PARAM_BLD_to_param failed"); + + if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=neverbleed")) == NULL) + dief("EVP_PKEY_CTX_new_from_name failed"); + if (EVP_PKEY_fromdata_init(pctx) <= 0) + dief("EVP_PKEY_fromdata_init failed"); + if (EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) + dief("EVP_PKEY_fromdata failed"); + + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + BN_free(e); + BN_free(n); + return pkey; +#else struct st_neverbleed_rsa_exdata_t *exdata; RSA *rsa; EVP_PKEY *pkey; @@ -923,6 +1736,7 @@ static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebu RSA_free(rsa); return pkey; +#endif /* NEVERBLEED_PROVIDER */ } #ifdef NEVERBLEED_ECDSA @@ -1278,31 +2092,49 @@ Exit: __attribute__((unused)) void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const EVP_MD *md, const void *input, size_t len, int rsa_pss) { - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; + size_t key_index; + neverbleed_t *nb_ref; const char *cmd = "digestsign"; /* obtain reference */ switch (EVP_PKEY_base_id(pkey)) { case EVP_PKEY_RSA: { - RSA *rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ +#ifdef NEVERBLEED_PROVIDER + OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; + if (!EVP_PKEY_get_params(pkey, get_params)) + dief("failed to get key_index from provider key"); + nb_ref = nb_provider_global_nb; +#else + struct st_neverbleed_rsa_exdata_t *exdata; + struct st_neverbleed_thread_data_t *thdata; + RSA *rsa = EVP_PKEY_get1_RSA(pkey); get_privsep_data(rsa, &exdata, &thdata); RSA_free(rsa); + key_index = exdata->key_index; + nb_ref = exdata->nb; +#endif cmd = "digestsign-rsa"; } break; #ifdef NEVERBLEED_ECDSA - case EVP_PKEY_EC: + case EVP_PKEY_EC: { + struct st_neverbleed_rsa_exdata_t *exdata; + struct st_neverbleed_thread_data_t *thdata; ecdsa_get_privsep_data(EVP_PKEY_get0_EC_KEY(pkey), &exdata, &thdata); - break; + key_index = exdata->key_index; + nb_ref = exdata->nb; + } break; #endif default: dief("unexpected private key"); break; } + struct st_neverbleed_thread_data_t *thdata = get_thread_data(nb_ref); + (void)thdata; + *buf = (neverbleed_iobuf_t){NULL}; iobuf_push_str(buf, cmd); - iobuf_push_num(buf, exdata->key_index); + iobuf_push_num(buf, key_index); iobuf_push_num(buf, md != NULL ? (size_t)EVP_MD_nid(md) : SIZE_MAX); iobuf_push_bytes(buf, input, len); iobuf_push_num(buf, rsa_pss); @@ -1378,19 +2210,29 @@ Exit: __attribute__((unused)) void neverbleed_start_decrypt(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const void *input, size_t len) { - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; + size_t key_index; +#ifdef NEVERBLEED_PROVIDER + { + OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; + if (!EVP_PKEY_get_params(pkey, get_params)) + dief("failed to get key_index from provider key"); + } +#else { + struct st_neverbleed_rsa_exdata_t *exdata; + struct st_neverbleed_thread_data_t *thdata; RSA *rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ assert(rsa != NULL); get_privsep_data(rsa, &exdata, &thdata); RSA_free(rsa); + key_index = exdata->key_index; } +#endif *buf = (neverbleed_iobuf_t){NULL}; iobuf_push_str(buf, "decrypt"); - iobuf_push_num(buf, exdata->key_index); + iobuf_push_num(buf, key_index); iobuf_push_bytes(buf, input, len); } @@ -2108,7 +2950,7 @@ static void set_signal_handler(int signo, void (*cb)(int signo)) sigaction(signo, &action, NULL); } -#ifndef NEVERBLEED_OPAQUE_RSA_METHOD +#if !defined(NEVERBLEED_OPAQUE_RSA_METHOD) && !defined(NEVERBLEED_PROVIDER) static RSA_METHOD static_rsa_method = { "privsep RSA method", /* name */ @@ -2197,7 +3039,35 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) pipe_fds[0] = -1; #if defined(OPENSSL_IS_BORINGSSL) - nb->engine = NULL; + /* no engine for BoringSSL */ +#elif defined(NEVERBLEED_PROVIDER) + { /* setup provider for RSA, engine for ECDSA only */ + nb_provider_global_nb = nb; + if (!OSSL_PROVIDER_add_builtin(NULL, "neverbleed", nb_provider_init)) { + snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "OSSL_PROVIDER_add_builtin failed"); + goto Fail; + } + nb->provider = OSSL_PROVIDER_load(NULL, "neverbleed"); + if (nb->provider == NULL) { + snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "OSSL_PROVIDER_load failed"); + goto Fail; + } +#ifdef NEVERBLEED_ECDSA + { /* ECDSA-only ENGINE */ + const EC_KEY_METHOD *ecdsa_default_method = EC_KEY_get_default_method(); + EC_KEY_METHOD *ecdsa_method = EC_KEY_METHOD_new(ecdsa_default_method); + EC_KEY_METHOD_set_sign(ecdsa_method, ecdsa_sign_proxy, NULL, NULL); + + if ((nb->engine = ENGINE_new()) == NULL || !ENGINE_set_id(nb->engine, "neverbleed") || + !ENGINE_set_name(nb->engine, "privilege separation software engine") || + !ENGINE_set_EC(nb->engine, ecdsa_method)) { + snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to initialize the OpenSSL engine for ECDSA"); + goto Fail; + } + ENGINE_add(nb->engine); + } +#endif + } #else { /* setup engine */ const RSA_METHOD *rsa_default_method; @@ -2262,10 +3132,12 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) } if (listen_fd != -1) close(listen_fd); +#if !defined(OPENSSL_IS_BORINGSSL) if (nb->engine != NULL) { ENGINE_free(nb->engine); nb->engine = NULL; } +#endif return -1; } diff --git a/neverbleed.h b/neverbleed.h index 0b2ee95..d53320c 100644 --- a/neverbleed.h +++ b/neverbleed.h @@ -24,8 +24,14 @@ #include #include +#include #include +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#define NEVERBLEED_PROVIDER +#include +#endif + #ifdef __FreeBSD__ #include #endif @@ -46,7 +52,14 @@ extern "C" { #define NEVERBLEED_AUTH_TOKEN_SIZE 32 typedef struct st_neverbleed_t { +#if defined(OPENSSL_IS_BORINGSSL) + /* no engine */ +#else ENGINE *engine; +#endif +#ifdef NEVERBLEED_PROVIDER + OSSL_PROVIDER *provider; +#endif pid_t daemon_pid; struct sockaddr_un sun_; pthread_key_t thread_key; From 3c076fc46964c060c540af7f89404e6df433cc65 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 09:28:17 +0900 Subject: [PATCH 2/8] Replace ENGINE-based ECDSA with OpenSSL 3 Provider Add EC KEYMGMT and ECDSA SIGNATURE to the neverbleed provider, eliminating the ENGINE dependency for ECDSA on the proxy side. Key addition: OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME to map EC keymgmt to ECDSA signature (required for EVP_PKEY_can_sign). Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 492 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 476 insertions(+), 16 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index 14da060..9e9911b 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -1373,6 +1373,437 @@ static const OSSL_DISPATCH nb_sig_functions[] = { {0, NULL}, }; +/* --- EC KEYMGMT --- */ + +struct nb_ec_keydata { + neverbleed_t *nb; + size_t key_index; + int curve_nid; + unsigned char *pub_bytes; + size_t pub_len; + int has_private; +}; + +static void *nb_ec_keymgmt_new(void *provctx) +{ + struct nb_ec_keydata *key = OPENSSL_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + key->nb = ((struct nb_provider_ctx *)provctx)->nb; + key->key_index = SIZE_MAX; + return key; +} + +static void nb_ec_keymgmt_free(void *keydata) +{ + struct nb_ec_keydata *key = keydata; + if (key == NULL) + return; + if (key->has_private && key->key_index != SIZE_MAX) { + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "del_pkey"); + iobuf_push_num(&buf, key->key_index); + iobuf_transaction(&buf, thdata); + iobuf_dispose(&buf); + } + OPENSSL_free(key->pub_bytes); + OPENSSL_free(key); +} + +static int nb_ec_keymgmt_has(const void *keydata, int selection) +{ + const struct nb_ec_keydata *key = keydata; + if (key == NULL) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) && key->pub_bytes == NULL) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) && !key->has_private) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) && key->curve_nid == 0) + return 0; + return 1; +} + +static int nb_ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + struct nb_ec_keydata *key = keydata; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME)) != NULL) { + char name[64] = ""; + OSSL_PARAM_get_utf8_string(p, (char **)&(char *){name}, sizeof(name)); + key->curve_nid = OBJ_txt2nid(name); + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL) { + OPENSSL_free(key->pub_bytes); + key->pub_bytes = NULL; + key->pub_len = p->data_size; + if (key->pub_len > 0) { + key->pub_bytes = OPENSSL_memdup(p->data, key->pub_len); + } + } + if ((p = OSSL_PARAM_locate_const(params, NEVERBLEED_PARAM_KEY_INDEX)) != NULL) { + OSSL_PARAM_get_size_t(p, &key->key_index); + key->has_private = 1; + } + return 1; +} + +static const OSSL_PARAM *nb_ec_keymgmt_import_types(int selection) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_ec_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) +{ + struct nb_ec_keydata *key = keydata; + OSSL_PARAM *p; + int bits = 0; + + if (key->curve_nid != 0) { + EC_GROUP *group = EC_GROUP_new_by_curve_name(key->curve_nid); + if (group != NULL) { + bits = EC_GROUP_get_degree(group); + EC_GROUP_free(group); + } + } + + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL) + OSSL_PARAM_set_int(p, bits); + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL) + OSSL_PARAM_set_int(p, bits / 2); + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL) { + /* max DER-encoded ECDSA signature size: each integer is at most order_size+1 bytes, plus DER overhead */ + int order_bytes = (bits + 7) / 8; + OSSL_PARAM_set_int(p, 2 * (order_bytes + 1) + 6); + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_GROUP_NAME)) != NULL) { + const char *name = key->curve_nid != 0 ? OBJ_nid2sn(key->curve_nid) : ""; + OSSL_PARAM_set_utf8_string(p, name); + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL && key->pub_bytes != NULL) { + OSSL_PARAM_set_octet_string(p, key->pub_bytes, key->pub_len); + } + if ((p = OSSL_PARAM_locate(params, NEVERBLEED_PARAM_KEY_INDEX)) != NULL) + OSSL_PARAM_set_size_t(p, key->key_index); + return 1; +} + +static const OSSL_PARAM *nb_ec_keymgmt_gettable_params(void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), + OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, NULL), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_ec_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) +{ + struct nb_ec_keydata *key = keydata; + if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) + return 0; + OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) + return 0; + if (key->curve_nid != 0) + OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(key->curve_nid), 0); + if (key->pub_bytes != NULL) + OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, key->pub_bytes, key->pub_len); + OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld); + OSSL_PARAM_BLD_free(bld); + if (params == NULL) + return 0; + int ret = param_cb(params, cbarg); + OSSL_PARAM_free(params); + return ret; +} + +static const OSSL_PARAM *nb_ec_keymgmt_export_types(int selection) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static const char *nb_ec_keymgmt_query_operation_name(int operation_id) +{ + switch (operation_id) { + case OSSL_OP_SIGNATURE: + return "ECDSA"; + } + return NULL; +} + +static const OSSL_DISPATCH nb_ec_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))nb_ec_keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))nb_ec_keymgmt_free}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))nb_ec_keymgmt_has}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))nb_ec_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))nb_ec_keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))nb_ec_keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))nb_ec_keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))nb_ec_keymgmt_export}, + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))nb_ec_keymgmt_export_types}, + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))nb_ec_keymgmt_query_operation_name}, + {0, NULL}, +}; + +/* --- EC SIGNATURE --- */ + +struct nb_ec_sig_ctx { + struct nb_provider_ctx *provctx; + struct nb_ec_keydata *keydata; + unsigned char *tbsdata; + size_t tbslen, tbscap; + int md_nid; +}; + +static void *nb_ec_sig_newctx(void *provctx, const char *propq) +{ + struct nb_ec_sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + ctx->provctx = provctx; + ctx->md_nid = NID_undef; + return ctx; +} + +static void nb_ec_sig_freectx(void *vctx) +{ + struct nb_ec_sig_ctx *ctx = vctx; + OPENSSL_free(ctx->tbsdata); + OPENSSL_free(ctx); +} + +static int nb_ec_sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +{ + struct nb_ec_sig_ctx *ctx = vctx; + ctx->keydata = vkey; + return 1; +} + +static int nb_ec_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, + size_t tbslen) +{ + struct nb_ec_sig_ctx *ctx = vctx; + struct nb_ec_keydata *key = ctx->keydata; + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + + /* size query */ + if (sig == NULL) { + int bits = 0; + if (key->curve_nid != 0) { + EC_GROUP *group = EC_GROUP_new_by_curve_name(key->curve_nid); + if (group != NULL) { + bits = EC_GROUP_get_degree(group); + EC_GROUP_free(group); + } + } + int order_bytes = (bits + 7) / 8; + *siglen = 2 * (order_bytes + 1) + 6; + return 1; + } + + /* send "ecdsa_sign" to daemon: type=0, tbs, key_index */ + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "ecdsa_sign"); + iobuf_push_num(&buf, 0); /* type (unused but required by protocol) */ + iobuf_push_bytes(&buf, tbs, tbslen); + iobuf_push_num(&buf, key->key_index); + iobuf_transaction(&buf, thdata); + + size_t ret; + unsigned char *sigret; + size_t sigret_len; + if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &sigret_len)) == NULL) { + iobuf_dispose(&buf); + return 0; + } + if ((int)ret != 1 || sigret_len > sigsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(sig, sigret, sigret_len); + *siglen = sigret_len; + iobuf_dispose(&buf); + return 1; +} + +static int nb_ec_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) +{ + struct nb_ec_sig_ctx *ctx = vctx; + ctx->keydata = vkey; + if (mdname != NULL) { + const EVP_MD *md = EVP_get_digestbyname(mdname); + ctx->md_nid = md != NULL ? EVP_MD_type(md) : NID_undef; + } + ctx->tbslen = 0; + return 1; +} + +static int nb_ec_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) +{ + struct nb_ec_sig_ctx *ctx = vctx; + if (ctx->tbslen + datalen > ctx->tbscap) { + size_t newcap = ctx->tbslen + datalen; + if (newcap < 256) + newcap = 256; + ctx->tbsdata = OPENSSL_realloc(ctx->tbsdata, newcap); + if (ctx->tbsdata == NULL) + return 0; + ctx->tbscap = newcap; + } + memcpy(ctx->tbsdata + ctx->tbslen, data, datalen); + ctx->tbslen += datalen; + return 1; +} + +static int nb_ec_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) +{ + struct nb_ec_sig_ctx *ctx = vctx; + struct nb_ec_keydata *key = ctx->keydata; + struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); + + if (sig == NULL) { + int bits = 0; + if (key->curve_nid != 0) { + EC_GROUP *group = EC_GROUP_new_by_curve_name(key->curve_nid); + if (group != NULL) { + bits = EC_GROUP_get_degree(group); + EC_GROUP_free(group); + } + } + int order_bytes = (bits + 7) / 8; + *siglen = 2 * (order_bytes + 1) + 6; + return 1; + } + + /* send "digestsign" to daemon */ + neverbleed_iobuf_t buf = {NULL}; + iobuf_push_str(&buf, "digestsign"); + iobuf_push_num(&buf, key->key_index); + iobuf_push_num(&buf, (size_t)ctx->md_nid); + iobuf_push_bytes(&buf, ctx->tbsdata, ctx->tbslen); + iobuf_push_num(&buf, 0); /* rsa_pss = 0 */ + iobuf_transaction(&buf, thdata); + + size_t result_len; + unsigned char *result; + if ((result = iobuf_shift_bytes(&buf, &result_len)) == NULL || result_len == 0) { + iobuf_dispose(&buf); + return 0; + } + if (result_len > sigsize) { + iobuf_dispose(&buf); + return 0; + } + memcpy(sig, result, result_len); + *siglen = result_len; + iobuf_dispose(&buf); + return 1; +} + +static int nb_ec_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, + size_t tbslen) +{ + struct nb_ec_sig_ctx *ctx = vctx; + if (sig == NULL) { + struct nb_ec_keydata *key = ctx->keydata; + int bits = 0; + if (key->curve_nid != 0) { + EC_GROUP *group = EC_GROUP_new_by_curve_name(key->curve_nid); + if (group != NULL) { + bits = EC_GROUP_get_degree(group); + EC_GROUP_free(group); + } + } + int order_bytes = (bits + 7) / 8; + *siglen = 2 * (order_bytes + 1) + 6; + return 1; + } + if (!nb_ec_sig_digest_sign_update(vctx, tbs, tbslen)) + return 0; + return nb_ec_sig_digest_sign_final(vctx, sig, siglen, sigsize); +} + +static int nb_ec_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct nb_ec_sig_ctx *ctx = vctx; + const OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { + char mdname[64] = ""; + OSSL_PARAM_get_utf8_string(p, (char **)&(char *){mdname}, sizeof(mdname)); + const EVP_MD *md = EVP_get_digestbyname(mdname); + if (md != NULL) + ctx->md_nid = EVP_MD_type(md); + } + return 1; +} + +static const OSSL_PARAM *nb_ec_sig_settable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static int nb_ec_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + struct nb_ec_sig_ctx *ctx = vctx; + OSSL_PARAM *p; + + if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { + const char *name = ctx->md_nid != NID_undef ? OBJ_nid2sn(ctx->md_nid) : ""; + if (!OSSL_PARAM_set_utf8_string(p, name)) + return 0; + } + return 1; +} + +static const OSSL_PARAM *nb_ec_sig_gettable_ctx_params(void *vctx, void *provctx) +{ + static const OSSL_PARAM types[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END, + }; + return types; +} + +static const OSSL_DISPATCH nb_ec_sig_functions[] = { + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))nb_ec_sig_newctx}, + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))nb_ec_sig_freectx}, + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))nb_ec_sig_sign_init}, + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))nb_ec_sig_sign}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))nb_ec_sig_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))nb_ec_sig_digest_sign_update}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))nb_ec_sig_digest_sign_final}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))nb_ec_sig_digest_sign}, + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))nb_ec_sig_set_ctx_params}, + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))nb_ec_sig_settable_ctx_params}, + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))nb_ec_sig_get_ctx_params}, + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))nb_ec_sig_gettable_ctx_params}, + {0, NULL}, +}; + /* --- ASYM_CIPHER --- */ static void *nb_asym_cipher_newctx(void *provctx) @@ -1613,11 +2044,13 @@ static const OSSL_DISPATCH nb_asym_cipher_functions[] = { static const OSSL_ALGORITHM nb_keymgmts[] = { {"RSA", "provider=neverbleed", nb_keymgmt_functions, "Neverbleed RSA KEYMGMT"}, + {"EC", "provider=neverbleed", nb_ec_keymgmt_functions, "Neverbleed EC KEYMGMT"}, {NULL, NULL, NULL, NULL}, }; static const OSSL_ALGORITHM nb_signatures[] = { {"RSA", "provider=neverbleed", nb_sig_functions, "Neverbleed RSA Signature"}, + {"ECDSA", "provider=neverbleed", nb_ec_sig_functions, "Neverbleed ECDSA Signature"}, {NULL, NULL, NULL, NULL}, }; @@ -1783,6 +2216,8 @@ static int ecdsa_sign_stub(neverbleed_iobuf_t *buf) return 0; } +#if !defined(NEVERBLEED_PROVIDER) + static int get_ecdsa_exdata_idx(void); static void ecdsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) { @@ -1846,8 +2281,40 @@ static int ecdsa_sign_proxy(int type, const unsigned char *m, int m_len, unsigne return (int)ret; } +#endif /* !NEVERBLEED_PROVIDER */ + static EVP_PKEY *ecdsa_create_pkey(neverbleed_t *nb, size_t key_index, int curve_name, const void *pubkey, size_t pubkey_len) { +#ifdef NEVERBLEED_PROVIDER + EVP_PKEY *pkey = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + const char *curve_sn = OBJ_nid2sn(curve_name); + + if (curve_sn == NULL) + dief("unknown curve NID: %d", curve_name); + + if ((bld = OSSL_PARAM_BLD_new()) == NULL) + dief("no memory"); + OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, curve_sn, 0); + OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pubkey, pubkey_len); + OSSL_PARAM_BLD_push_size_t(bld, NEVERBLEED_PARAM_KEY_INDEX, key_index); + if ((params = OSSL_PARAM_BLD_to_param(bld)) == NULL) + dief("OSSL_PARAM_BLD_to_param failed"); + + if ((pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=neverbleed")) == NULL) + dief("EVP_PKEY_CTX_new_from_name failed"); + if (EVP_PKEY_fromdata_init(pctx) <= 0) + dief("EVP_PKEY_fromdata_init failed"); + if (EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) + dief("EVP_PKEY_fromdata failed"); + + EVP_PKEY_CTX_free(pctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + return pkey; +#else struct st_neverbleed_rsa_exdata_t *exdata; EC_KEY *ec_key; EC_GROUP *ec_group; @@ -1888,6 +2355,7 @@ static EVP_PKEY *ecdsa_create_pkey(neverbleed_t *nb, size_t key_index, int curve EC_KEY_free(ec_key); return pkey; +#endif /* NEVERBLEED_PROVIDER */ } #endif @@ -2117,11 +2585,18 @@ void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const } break; #ifdef NEVERBLEED_ECDSA case EVP_PKEY_EC: { +#ifdef NEVERBLEED_PROVIDER + OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; + if (!EVP_PKEY_get_params(pkey, get_params)) + dief("failed to get key_index from provider key"); + nb_ref = nb_provider_global_nb; +#else struct st_neverbleed_rsa_exdata_t *exdata; struct st_neverbleed_thread_data_t *thdata; ecdsa_get_privsep_data(EVP_PKEY_get0_EC_KEY(pkey), &exdata, &thdata); key_index = exdata->key_index; nb_ref = exdata->nb; +#endif } break; #endif default: @@ -3041,7 +3516,7 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) #if defined(OPENSSL_IS_BORINGSSL) /* no engine for BoringSSL */ #elif defined(NEVERBLEED_PROVIDER) - { /* setup provider for RSA, engine for ECDSA only */ + { /* setup provider for RSA and ECDSA */ nb_provider_global_nb = nb; if (!OSSL_PROVIDER_add_builtin(NULL, "neverbleed", nb_provider_init)) { snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "OSSL_PROVIDER_add_builtin failed"); @@ -3052,21 +3527,6 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "OSSL_PROVIDER_load failed"); goto Fail; } -#ifdef NEVERBLEED_ECDSA - { /* ECDSA-only ENGINE */ - const EC_KEY_METHOD *ecdsa_default_method = EC_KEY_get_default_method(); - EC_KEY_METHOD *ecdsa_method = EC_KEY_METHOD_new(ecdsa_default_method); - EC_KEY_METHOD_set_sign(ecdsa_method, ecdsa_sign_proxy, NULL, NULL); - - if ((nb->engine = ENGINE_new()) == NULL || !ENGINE_set_id(nb->engine, "neverbleed") || - !ENGINE_set_name(nb->engine, "privilege separation software engine") || - !ENGINE_set_EC(nb->engine, ecdsa_method)) { - snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to initialize the OpenSSL engine for ECDSA"); - goto Fail; - } - ENGINE_add(nb->engine); - } -#endif } #else { /* setup engine */ From 1411e452e9e477b4b9ef46753c11d9a640277dbe Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 12:11:49 +0900 Subject: [PATCH 3/8] Remove NEVERBLEED_PROVIDER guard and drop pre-3.0 proxy-side ENGINE code Now that both RSA and ECDSA use the OpenSSL 3 Provider on the proxy side, the NEVERBLEED_PROVIDER macro and the #else ENGINE-based proxy code are dead code. Remove the macro, NEVERBLEED_OPAQUE_RSA_METHOD, and all proxy-side ENGINE code (exdata callbacks, proxy functions, static_rsa_method, engine init/cleanup), while keeping stub-side ENGINE code untouched for QAT offload support. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 399 ++------------------------------------------------- neverbleed.h | 11 +- 2 files changed, 14 insertions(+), 396 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index 9e9911b..bf2bcf2 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -56,29 +56,21 @@ #include #include -#if defined(LIBRESSL_VERSION_NUMBER) ? LIBRESSL_VERSION_NUMBER >= 0x3050000fL : OPENSSL_VERSION_NUMBER >= 0x1010000fL -/* RSA_METHOD is opaque, so RSA_meth* are used. */ -#define NEVERBLEED_OPAQUE_RSA_METHOD -#endif - #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) && \ (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL) /* EC_KEY_METHOD and related APIs are avaliable, so ECDSA is enabled. */ #define NEVERBLEED_ECDSA #endif -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L -#define NEVERBLEED_PROVIDER -#endif - #include #ifdef NEVERBLEED_ECDSA #include #endif +#include #include #include #include -#ifdef NEVERBLEED_PROVIDER +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) #include #include #include @@ -148,11 +140,6 @@ static void RSA_set_flags(RSA *r, int flags) enum neverbleed_type { NEVERBLEED_TYPE_ERROR, NEVERBLEED_TYPE_RSA, NEVERBLEED_TYPE_ECDSA }; -struct st_neverbleed_rsa_exdata_t { - neverbleed_t *nb; - size_t key_index; -}; - struct st_neverbleed_thread_data_t { pid_t self_pid; int fd; @@ -551,51 +538,6 @@ void neverbleed_transaction_write(neverbleed_t *nb, neverbleed_iobuf_t *buf) iobuf_transaction_write(buf, thdata); } -static void do_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) -{ - /* when other engines are used, this callback gets called without neverbleed data */ - if (ptr == NULL) - return; - struct st_neverbleed_rsa_exdata_t *exdata = ptr; - struct st_neverbleed_thread_data_t *thdata = get_thread_data(exdata->nb); - - neverbleed_iobuf_t buf = {NULL}; - iobuf_push_str(&buf, "del_pkey"); - iobuf_push_num(&buf, exdata->key_index); - // "del_pkey" command is fire-and-forget, it cannot fail, so doesn't have a response - iobuf_transaction_no_response(&buf, thdata); - - free(exdata); -} - -#if !defined(NEVERBLEED_PROVIDER) -static int get_rsa_exdata_idx(void); -static void rsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) -{ - assert(idx == get_rsa_exdata_idx()); - do_exdata_free_callback(parent, ptr, ad, idx, argl, argp); -} - -static int get_rsa_exdata_idx(void) -{ - static volatile int index; - NEVERBLEED_MULTITHREAD_ONCE({ - index = RSA_get_ex_new_index(0, NULL, NULL, NULL, rsa_exdata_free_callback); - }); - return index; -} -static void get_privsep_data(const RSA *rsa, struct st_neverbleed_rsa_exdata_t **exdata, - struct st_neverbleed_thread_data_t **thdata) -{ - *exdata = RSA_get_ex_data(rsa, get_rsa_exdata_idx()); - if (*exdata == NULL) { - errno = 0; - dief("invalid internal ref"); - } - *thdata = get_thread_data((*exdata)->nb); -} -#endif /* !NEVERBLEED_PROVIDER */ - static struct { struct { pthread_mutex_t lock; @@ -764,36 +706,6 @@ static size_t daemon_set_pkey(EVP_PKEY *pkey) return index; } -#if !defined(NEVERBLEED_PROVIDER) -static int priv_encdec_proxy(const char *cmd, int flen, const unsigned char *from, unsigned char *_to, RSA *rsa, int padding) -{ - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - neverbleed_iobuf_t buf = {NULL}; - size_t ret; - unsigned char *to; - size_t tolen; - - get_privsep_data(rsa, &exdata, &thdata); - - iobuf_push_str(&buf, cmd); - iobuf_push_bytes(&buf, from, flen); - iobuf_push_num(&buf, exdata->key_index); - iobuf_push_num(&buf, padding); - - iobuf_transaction(&buf, thdata); - - if (iobuf_shift_num(&buf, &ret) != 0 || (to = iobuf_shift_bytes(&buf, &tolen)) == NULL) { - errno = 0; - dief("failed to parse response"); - } - memcpy(_to, to, tolen); - iobuf_dispose(&buf); - - return (int)ret; -} -#endif /* !NEVERBLEED_PROVIDER */ - static int priv_encdec_stub(const char *name, int (*func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), neverbleed_iobuf_t *buf) @@ -827,60 +739,16 @@ static int priv_encdec_stub(const char *name, #if !defined(OPENSSL_IS_BORINGSSL) -#if !defined(NEVERBLEED_PROVIDER) -static int priv_enc_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - return priv_encdec_proxy("priv_enc", flen, from, to, rsa, padding); -} -#endif - static int priv_enc_stub(neverbleed_iobuf_t *buf) { return priv_encdec_stub(__FUNCTION__, RSA_private_encrypt, buf); } -#if !defined(NEVERBLEED_PROVIDER) -static int priv_dec_proxy(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - return priv_encdec_proxy("priv_dec", flen, from, to, rsa, padding); -} -#endif - static int priv_dec_stub(neverbleed_iobuf_t *buf) { return priv_encdec_stub(__FUNCTION__, RSA_private_decrypt, buf); } -#if !defined(NEVERBLEED_PROVIDER) -static int sign_proxy(int type, const unsigned char *m, unsigned int m_len, unsigned char *_sigret, unsigned *_siglen, - const RSA *rsa) -{ - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - neverbleed_iobuf_t buf = {NULL}; - size_t ret, siglen; - unsigned char *sigret; - - get_privsep_data(rsa, &exdata, &thdata); - - iobuf_push_str(&buf, "sign"); - iobuf_push_num(&buf, type); - iobuf_push_bytes(&buf, m, m_len); - iobuf_push_num(&buf, exdata->key_index); - iobuf_transaction(&buf, thdata); - - if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &siglen)) == NULL) { - errno = 0; - dief("failed to parse response"); - } - memcpy(_sigret, sigret, siglen); - *_siglen = (unsigned)siglen; - iobuf_dispose(&buf); - - return (int)ret; -} -#endif - static int sign_stub(neverbleed_iobuf_t *buf) { unsigned char *m, sigret[4096]; @@ -909,10 +777,6 @@ static int sign_stub(neverbleed_iobuf_t *buf) return 0; } -#endif /* !OPENSSL_IS_BORINGSSL */ - -#ifdef NEVERBLEED_PROVIDER - /* ======================== OpenSSL 3 Provider ======================== */ #define NEVERBLEED_PARAM_KEY_INDEX "neverbleed-key-index" @@ -2095,11 +1959,11 @@ static int nb_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH return 1; } -#endif /* NEVERBLEED_PROVIDER */ +#endif /* !OPENSSL_IS_BORINGSSL */ static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebuf, const char *nbuf) { -#ifdef NEVERBLEED_PROVIDER + (void)nb; BIGNUM *e = NULL, *n = NULL; EVP_PKEY *pkey = NULL; OSSL_PARAM_BLD *bld = NULL; @@ -2136,40 +2000,6 @@ static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebu BN_free(e); BN_free(n); return pkey; -#else - struct st_neverbleed_rsa_exdata_t *exdata; - RSA *rsa; - EVP_PKEY *pkey; - BIGNUM *e = NULL, *n = NULL; - - if ((exdata = malloc(sizeof(*exdata))) == NULL) { - fprintf(stderr, "no memory\n"); - abort(); - } - exdata->nb = nb; - exdata->key_index = key_index; - - rsa = RSA_new_method(nb->engine); - RSA_set_ex_data(rsa, get_rsa_exdata_idx(), exdata); - if (BN_hex2bn(&e, ebuf) == 0) { - fprintf(stderr, "failed to parse e:%s\n", ebuf); - abort(); - } - if (BN_hex2bn(&n, nbuf) == 0) { - fprintf(stderr, "failed to parse n:%s\n", nbuf); - abort(); - } - RSA_set0_key(rsa, n, e, NULL); -#if !defined(OPENSSL_IS_BORINGSSL) - RSA_set_flags(rsa, RSA_FLAG_EXT_PKEY); -#endif - - pkey = EVP_PKEY_new(); - EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - - return pkey; -#endif /* NEVERBLEED_PROVIDER */ } #ifdef NEVERBLEED_ECDSA @@ -2216,76 +2046,10 @@ static int ecdsa_sign_stub(neverbleed_iobuf_t *buf) return 0; } -#if !defined(NEVERBLEED_PROVIDER) - -static int get_ecdsa_exdata_idx(void); -static void ecdsa_exdata_free_callback(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) -{ - assert(idx == get_ecdsa_exdata_idx()); - do_exdata_free_callback(parent, ptr, ad, idx, argl, argp); -} - -static int get_ecdsa_exdata_idx(void) -{ - static volatile int index; - NEVERBLEED_MULTITHREAD_ONCE({ - index = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, ecdsa_exdata_free_callback); - }); - return index; -} - -static void ecdsa_get_privsep_data(const EC_KEY *ec_key, struct st_neverbleed_rsa_exdata_t **exdata, - struct st_neverbleed_thread_data_t **thdata) -{ - *exdata = EC_KEY_get_ex_data(ec_key, get_ecdsa_exdata_idx()); - if (*exdata == NULL) { - errno = 0; - dief("invalid internal ref"); - } - *thdata = get_thread_data((*exdata)->nb); -} - -static int ecdsa_sign_proxy(int type, const unsigned char *m, int m_len, unsigned char *_sigret, unsigned int *_siglen, - const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *ec_key) -{ - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - neverbleed_iobuf_t buf = {NULL}; - size_t ret, siglen; - unsigned char *sigret; - - ecdsa_get_privsep_data(ec_key, &exdata, &thdata); - - /* as far as I've tested so far, kinv and rp are always NULL. - Looks like setup_sign will precompute this, but it is only - called sign_sig, and it seems to be not used in TLS ECDSA */ - if (kinv != NULL || rp != NULL) { - errno = 0; - dief("unexpected non-NULL kinv and rp"); - } - - iobuf_push_str(&buf, "ecdsa_sign"); - iobuf_push_num(&buf, type); - iobuf_push_bytes(&buf, m, m_len); - iobuf_push_num(&buf, exdata->key_index); - iobuf_transaction(&buf, thdata); - - if (iobuf_shift_num(&buf, &ret) != 0 || (sigret = iobuf_shift_bytes(&buf, &siglen)) == NULL) { - errno = 0; - dief("failed to parse response"); - } - memcpy(_sigret, sigret, siglen); - *_siglen = (unsigned)siglen; - iobuf_dispose(&buf); - - return (int)ret; -} - -#endif /* !NEVERBLEED_PROVIDER */ - static EVP_PKEY *ecdsa_create_pkey(neverbleed_t *nb, size_t key_index, int curve_name, const void *pubkey, size_t pubkey_len) { -#ifdef NEVERBLEED_PROVIDER + (void)nb; + EVP_PKEY *pkey = NULL; OSSL_PARAM_BLD *bld = NULL; OSSL_PARAM *params = NULL; @@ -2314,48 +2078,6 @@ static EVP_PKEY *ecdsa_create_pkey(neverbleed_t *nb, size_t key_index, int curve OSSL_PARAM_free(params); OSSL_PARAM_BLD_free(bld); return pkey; -#else - struct st_neverbleed_rsa_exdata_t *exdata; - EC_KEY *ec_key; - EC_GROUP *ec_group; - EC_POINT *ec_pubkey; - EVP_PKEY *pkey; - - if ((exdata = malloc(sizeof(*exdata))) == NULL) { - fprintf(stderr, "no memory\n"); - abort(); - } - exdata->nb = nb; - exdata->key_index = key_index; - - ec_key = EC_KEY_new_method(nb->engine); - EC_KEY_set_ex_data(ec_key, get_ecdsa_exdata_idx(), exdata); - - ec_group = EC_GROUP_new_by_curve_name(curve_name); - if (!ec_group) { - fprintf(stderr, "could not create EC_GROUP\n"); - abort(); - } - - EC_KEY_set_group(ec_key, ec_group); - - ec_pubkey = EC_POINT_new(ec_group); - assert(ec_pubkey != NULL); - if (!EC_POINT_oct2point(ec_group, ec_pubkey, pubkey, pubkey_len, NULL)) { - fprintf(stderr, "failed to get ECDSA ephemeral public key from BIGNUM\n"); - abort(); - } - EC_KEY_set_public_key(ec_key, ec_pubkey); - - pkey = EVP_PKEY_new(); - EVP_PKEY_set1_EC_KEY(pkey, ec_key); - - EC_POINT_free(ec_pubkey); - EC_GROUP_free(ec_group); - EC_KEY_free(ec_key); - - return pkey; -#endif /* NEVERBLEED_PROVIDER */ } #endif @@ -2567,36 +2289,18 @@ void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const /* obtain reference */ switch (EVP_PKEY_base_id(pkey)) { case EVP_PKEY_RSA: { -#ifdef NEVERBLEED_PROVIDER OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; if (!EVP_PKEY_get_params(pkey, get_params)) dief("failed to get key_index from provider key"); nb_ref = nb_provider_global_nb; -#else - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - get_privsep_data(rsa, &exdata, &thdata); - RSA_free(rsa); - key_index = exdata->key_index; - nb_ref = exdata->nb; -#endif cmd = "digestsign-rsa"; } break; #ifdef NEVERBLEED_ECDSA case EVP_PKEY_EC: { -#ifdef NEVERBLEED_PROVIDER OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; if (!EVP_PKEY_get_params(pkey, get_params)) dief("failed to get key_index from provider key"); nb_ref = nb_provider_global_nb; -#else - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - ecdsa_get_privsep_data(EVP_PKEY_get0_EC_KEY(pkey), &exdata, &thdata); - key_index = exdata->key_index; - nb_ref = exdata->nb; -#endif } break; #endif default: @@ -2687,23 +2391,11 @@ void neverbleed_start_decrypt(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const voi { size_t key_index; -#ifdef NEVERBLEED_PROVIDER { OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; if (!EVP_PKEY_get_params(pkey, get_params)) dief("failed to get key_index from provider key"); } -#else - { - struct st_neverbleed_rsa_exdata_t *exdata; - struct st_neverbleed_thread_data_t *thdata; - RSA *rsa = EVP_PKEY_get1_RSA(pkey); /* get0 is available not available in OpenSSL 1.0.2 */ - assert(rsa != NULL); - get_privsep_data(rsa, &exdata, &thdata); - RSA_free(rsa); - key_index = exdata->key_index; - } -#endif *buf = (neverbleed_iobuf_t){NULL}; iobuf_push_str(buf, "decrypt"); @@ -3425,27 +3117,6 @@ static void set_signal_handler(int signo, void (*cb)(int signo)) sigaction(signo, &action, NULL); } -#if !defined(NEVERBLEED_OPAQUE_RSA_METHOD) && !defined(NEVERBLEED_PROVIDER) - -static RSA_METHOD static_rsa_method = { - "privsep RSA method", /* name */ - NULL, /* rsa_pub_enc */ - NULL, /* rsa_pub_dec */ - priv_enc_proxy, /* rsa_priv_enc */ - priv_dec_proxy, /* rsa_priv_dec */ - NULL, /* rsa_mod_exp */ - NULL, /* bn_mod_exp */ - NULL, /* init */ - NULL, /* finish */ - RSA_FLAG_SIGN_VER, /* flags */ - NULL, /* app data */ - sign_proxy, /* rsa_sign */ - NULL, /* rsa_verify */ - NULL /* rsa_keygen */ -}; - -#endif - int neverbleed_init(neverbleed_t *nb, char *errbuf) { int pipe_fds[2] = {-1, -1}, listen_fd = -1; @@ -3514,8 +3185,8 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) pipe_fds[0] = -1; #if defined(OPENSSL_IS_BORINGSSL) - /* no engine for BoringSSL */ -#elif defined(NEVERBLEED_PROVIDER) + /* no engine/provider for BoringSSL */ +#else { /* setup provider for RSA and ECDSA */ nb_provider_global_nb = nb; if (!OSSL_PROVIDER_add_builtin(NULL, "neverbleed", nb_provider_init)) { @@ -3528,52 +3199,6 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) goto Fail; } } -#else - { /* setup engine */ - const RSA_METHOD *rsa_default_method; - RSA_METHOD *rsa_method; -#ifdef NEVERBLEED_ECDSA - const EC_KEY_METHOD *ecdsa_default_method; - EC_KEY_METHOD *ecdsa_method; -#endif - -#ifdef NEVERBLEED_OPAQUE_RSA_METHOD - rsa_default_method = RSA_PKCS1_OpenSSL(); - rsa_method = RSA_meth_dup(rsa_default_method); - - RSA_meth_set1_name(rsa_method, "privsep RSA method"); - RSA_meth_set_priv_enc(rsa_method, priv_enc_proxy); - RSA_meth_set_priv_dec(rsa_method, priv_dec_proxy); - RSA_meth_set_sign(rsa_method, sign_proxy); -#else - rsa_default_method = RSA_PKCS1_SSLeay(); - rsa_method = &static_rsa_method; - - rsa_method->rsa_pub_enc = rsa_default_method->rsa_pub_enc; - rsa_method->rsa_pub_dec = rsa_default_method->rsa_pub_dec; - rsa_method->rsa_verify = rsa_default_method->rsa_verify; - rsa_method->bn_mod_exp = rsa_default_method->bn_mod_exp; -#endif - -#ifdef NEVERBLEED_ECDSA - ecdsa_default_method = EC_KEY_get_default_method(); - ecdsa_method = EC_KEY_METHOD_new(ecdsa_default_method); - - /* it seems sign_sig and sign_setup is not used in TLS ECDSA. */ - EC_KEY_METHOD_set_sign(ecdsa_method, ecdsa_sign_proxy, NULL, NULL); -#endif - - if ((nb->engine = ENGINE_new()) == NULL || !ENGINE_set_id(nb->engine, "neverbleed") || - !ENGINE_set_name(nb->engine, "privilege separation software engine") || !ENGINE_set_RSA(nb->engine, rsa_method) -#ifdef NEVERBLEED_ECDSA - || !ENGINE_set_EC(nb->engine, ecdsa_method) -#endif - ) { - snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "failed to initialize the OpenSSL engine"); - goto Fail; - } - ENGINE_add(nb->engine); - } #endif /* setup thread key */ @@ -3592,10 +3217,10 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) } if (listen_fd != -1) close(listen_fd); -#if !defined(OPENSSL_IS_BORINGSSL) - if (nb->engine != NULL) { - ENGINE_free(nb->engine); - nb->engine = NULL; +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) + if (nb->provider != NULL) { + OSSL_PROVIDER_unload(nb->provider); + nb->provider = NULL; } #endif return -1; diff --git a/neverbleed.h b/neverbleed.h index d53320c..7292573 100644 --- a/neverbleed.h +++ b/neverbleed.h @@ -25,10 +25,8 @@ #include #include #include -#include -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L -#define NEVERBLEED_PROVIDER +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) #include #endif @@ -52,12 +50,7 @@ extern "C" { #define NEVERBLEED_AUTH_TOKEN_SIZE 32 typedef struct st_neverbleed_t { -#if defined(OPENSSL_IS_BORINGSSL) - /* no engine */ -#else - ENGINE *engine; -#endif -#ifdef NEVERBLEED_PROVIDER +#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) OSSL_PROVIDER *provider; #endif pid_t daemon_pid; From b7b25704e3b5552ddcd45026a0f7f872f7738e9b Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 12:13:51 +0900 Subject: [PATCH 4/8] Drop LibreSSL support LibreSSL has dropped ENGINE API support in newer versions, and neverbleed now requires OpenSSL 3.x Provider API for non-BoringSSL builds. Remove all LIBRESSL_VERSION_NUMBER conditionals and the pre-1.0.1 OpenSSL compat shims that were only needed for old LibreSSL/OpenSSL. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 52 ++++------------------------------------------------ neverbleed.h | 4 ++-- test.c | 3 +-- 3 files changed, 7 insertions(+), 52 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index bf2bcf2..f2777cf 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -56,9 +56,7 @@ #include #include -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) && \ - (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL) -/* EC_KEY_METHOD and related APIs are avaliable, so ECDSA is enabled. */ +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) #define NEVERBLEED_ECDSA #endif @@ -70,7 +68,7 @@ #include #include #include -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) +#if !defined(OPENSSL_IS_BORINGSSL) #include #include #include @@ -80,7 +78,7 @@ #endif #ifdef __linux -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_IS_BORINGSSL) #define USE_OFFLOAD 1 #endif #if defined(OPENSSL_IS_BORINGSSL) && defined(NEVERBLEED_BORINGSSL_USE_QAT) @@ -94,48 +92,6 @@ extern int bssl_async_wait_ctx_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *f #endif #endif -#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - -static void RSA_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) -{ - if (n) { - *n = rsa->n; - } - - if (e) { - *e = rsa->e; - } - - if (d) { - *d = rsa->d; - } -} - -static int RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d) -{ - if (n == NULL || e == NULL) { - return 0; - } - - BN_free(rsa->n); - BN_free(rsa->e); - BN_free(rsa->d); - rsa->n = n; - rsa->e = e; - rsa->d = d; - - return 1; -} - -static void RSA_set_flags(RSA *r, int flags) -{ - r->flags |= flags; -} - -#define EVP_PKEY_up_ref(p) CRYPTO_add(&(p)->references, 1, CRYPTO_LOCK_EVP_PKEY) - -#endif - #include "neverbleed.h" enum neverbleed_type { NEVERBLEED_TYPE_ERROR, NEVERBLEED_TYPE_RSA, NEVERBLEED_TYPE_ECDSA }; @@ -3217,7 +3173,7 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) } if (listen_fd != -1) close(listen_fd); -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) +#if !defined(OPENSSL_IS_BORINGSSL) if (nb->provider != NULL) { OSSL_PROVIDER_unload(nb->provider); nb->provider = NULL; diff --git a/neverbleed.h b/neverbleed.h index 7292573..ba95ece 100644 --- a/neverbleed.h +++ b/neverbleed.h @@ -26,7 +26,7 @@ #include #include -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) +#if !defined(OPENSSL_IS_BORINGSSL) #include #endif @@ -50,7 +50,7 @@ extern "C" { #define NEVERBLEED_AUTH_TOKEN_SIZE 32 typedef struct st_neverbleed_t { -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER) +#if !defined(OPENSSL_IS_BORINGSSL) OSSL_PROVIDER *provider; #endif pid_t daemon_pid; diff --git a/test.c b/test.c index 0d366fc..36066e4 100644 --- a/test.c +++ b/test.c @@ -33,8 +33,7 @@ #include #include -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) && \ - (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL) +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) #define NEVERBLEED_TEST_ECDSA #endif From bb25d8ffe782ae7a8537b190670fe5f48b0fb0b5 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 12:17:15 +0900 Subject: [PATCH 5/8] Remove nb_ prefix from static provider functions and types The original codebase does not use prefixes for static (file-scoped) identifiers. Rename all nb_-prefixed provider functions, structs, and variables to follow the existing convention. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 392 ++++++++++++++++++++++++++------------------------- 1 file changed, 198 insertions(+), 194 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index f2777cf..5834dbf 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -733,26 +733,30 @@ static int sign_stub(neverbleed_iobuf_t *buf) return 0; } +#endif /* !OPENSSL_IS_BORINGSSL */ + +#if !defined(OPENSSL_IS_BORINGSSL) + /* ======================== OpenSSL 3 Provider ======================== */ #define NEVERBLEED_PARAM_KEY_INDEX "neverbleed-key-index" -static neverbleed_t *nb_provider_global_nb; +static neverbleed_t *provider_global_nb; -struct nb_provider_ctx { +struct provider_ctx { neverbleed_t *nb; }; -struct nb_rsa_keydata { +struct rsa_keydata { neverbleed_t *nb; size_t key_index; BIGNUM *n, *e; int has_private; }; -struct nb_sig_ctx { - struct nb_provider_ctx *provctx; - struct nb_rsa_keydata *keydata; +struct sig_ctx { + struct provider_ctx *provctx; + struct rsa_keydata *keydata; unsigned char *tbsdata; size_t tbslen, tbscap; int md_nid; @@ -760,9 +764,9 @@ struct nb_sig_ctx { int pss_saltlen; }; -struct nb_asym_cipher_ctx { - struct nb_provider_ctx *provctx; - struct nb_rsa_keydata *keydata; +struct asym_cipher_ctx { + struct provider_ctx *provctx; + struct rsa_keydata *keydata; int padding; unsigned int tls_client_version; unsigned int tls_negotiated_version; @@ -794,19 +798,19 @@ static inline unsigned int ct_ge_mask(unsigned int a, unsigned int b) /* --- KEYMGMT --- */ -static void *nb_keymgmt_new(void *provctx) +static void *keymgmt_new(void *provctx) { - struct nb_rsa_keydata *key = OPENSSL_zalloc(sizeof(*key)); + struct rsa_keydata *key = OPENSSL_zalloc(sizeof(*key)); if (key == NULL) return NULL; - key->nb = ((struct nb_provider_ctx *)provctx)->nb; + key->nb = ((struct provider_ctx *)provctx)->nb; key->key_index = SIZE_MAX; return key; } -static void nb_keymgmt_free(void *keydata) +static void keymgmt_free(void *keydata) { - struct nb_rsa_keydata *key = keydata; + struct rsa_keydata *key = keydata; if (key == NULL) return; if (key->key_index != SIZE_MAX && key->has_private) { @@ -821,9 +825,9 @@ static void nb_keymgmt_free(void *keydata) OPENSSL_free(key); } -static int nb_keymgmt_has(const void *keydata, int selection) +static int keymgmt_has(const void *keydata, int selection) { - const struct nb_rsa_keydata *key = keydata; + const struct rsa_keydata *key = keydata; if (key == NULL) return 0; if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0 && (key->n == NULL || key->e == NULL)) @@ -833,9 +837,9 @@ static int nb_keymgmt_has(const void *keydata, int selection) return 1; } -static int nb_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +static int keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) { - struct nb_rsa_keydata *key = keydata; + struct rsa_keydata *key = keydata; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N)) != NULL) { @@ -858,7 +862,7 @@ static int nb_keymgmt_import(void *keydata, int selection, const OSSL_PARAM para return 1; } -static const OSSL_PARAM *nb_keymgmt_import_types(int selection) +static const OSSL_PARAM *keymgmt_import_types(int selection) { static const OSSL_PARAM types[] = { OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), @@ -869,9 +873,9 @@ static const OSSL_PARAM *nb_keymgmt_import_types(int selection) return types; } -static int nb_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) +static int keymgmt_get_params(void *keydata, OSSL_PARAM params[]) { - struct nb_rsa_keydata *key = keydata; + struct rsa_keydata *key = keydata; OSSL_PARAM *p; if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL) { @@ -903,7 +907,7 @@ static int nb_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_keymgmt_gettable_params(void *provctx) +static const OSSL_PARAM *keymgmt_gettable_params(void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), @@ -917,9 +921,9 @@ static const OSSL_PARAM *nb_keymgmt_gettable_params(void *provctx) return types; } -static int nb_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) +static int keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) { - struct nb_rsa_keydata *key = keydata; + struct rsa_keydata *key = keydata; OSSL_PARAM_BLD *bld; OSSL_PARAM *params; int ret; @@ -940,7 +944,7 @@ static int nb_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_ return ret; } -static const OSSL_PARAM *nb_keymgmt_export_types(int selection) +static const OSSL_PARAM *keymgmt_export_types(int selection) { static const OSSL_PARAM types[] = { OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), @@ -950,24 +954,24 @@ static const OSSL_PARAM *nb_keymgmt_export_types(int selection) return types; } -static const OSSL_DISPATCH nb_keymgmt_functions[] = { - {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))nb_keymgmt_new}, - {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))nb_keymgmt_free}, - {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))nb_keymgmt_has}, - {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))nb_keymgmt_import}, - {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))nb_keymgmt_import_types}, - {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))nb_keymgmt_get_params}, - {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))nb_keymgmt_gettable_params}, - {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))nb_keymgmt_export}, - {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))nb_keymgmt_export_types}, +static const OSSL_DISPATCH keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))keymgmt_export}, + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))keymgmt_export_types}, {0, NULL}, }; /* --- SIGNATURE --- */ -static void *nb_sig_newctx(void *provctx, const char *propq) +static void *sig_newctx(void *provctx, const char *propq) { - struct nb_sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + struct sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->provctx = provctx; @@ -977,26 +981,26 @@ static void *nb_sig_newctx(void *provctx, const char *propq) return ctx; } -static void nb_sig_freectx(void *vctx) +static void sig_freectx(void *vctx) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; if (ctx == NULL) return; OPENSSL_free(ctx->tbsdata); OPENSSL_free(ctx); } -static int nb_sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +static int sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; ctx->keydata = vkey; return 1; } -static int nb_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) +static int sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { - struct nb_sig_ctx *ctx = vctx; - struct nb_rsa_keydata *key = ctx->keydata; + struct sig_ctx *ctx = vctx; + struct rsa_keydata *key = ctx->keydata; struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); neverbleed_iobuf_t buf = {NULL}; size_t ret; @@ -1028,9 +1032,9 @@ static int nb_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t si return 1; } -static int nb_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) +static int sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; ctx->keydata = vkey; if (mdname != NULL) { const EVP_MD *md = EVP_get_digestbyname(mdname); @@ -1040,9 +1044,9 @@ static int nb_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, c return 1; } -static int nb_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) +static int sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; if (ctx->tbslen + datalen > ctx->tbscap) { ctx->tbscap = ctx->tbslen + datalen + 256; ctx->tbsdata = OPENSSL_realloc(ctx->tbsdata, ctx->tbscap); @@ -1054,10 +1058,10 @@ static int nb_sig_digest_sign_update(void *vctx, const unsigned char *data, size return 1; } -static int nb_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) +static int sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) { - struct nb_sig_ctx *ctx = vctx; - struct nb_rsa_keydata *key = ctx->keydata; + struct sig_ctx *ctx = vctx; + struct rsa_keydata *key = ctx->keydata; struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); neverbleed_iobuf_t buf = {NULL}; size_t retlen; @@ -1089,28 +1093,28 @@ static int nb_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *sigl return 1; } -static int nb_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, +static int sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; /* If called for size query, just return max size */ if (sig == NULL) { - struct nb_rsa_keydata *key = ctx->keydata; + struct rsa_keydata *key = ctx->keydata; *siglen = key->n ? BN_num_bytes(key->n) : 0; return 1; } /* Buffer the data and call final */ ctx->tbslen = 0; - if (!nb_sig_digest_sign_update(vctx, tbs, tbslen)) + if (!sig_digest_sign_update(vctx, tbs, tbslen)) return 0; - return nb_sig_digest_sign_final(vctx, sig, siglen, sigsize); + return sig_digest_sign_final(vctx, sig, siglen, sigsize); } -static int nb_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +static int sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE)) != NULL) { @@ -1137,7 +1141,7 @@ static int nb_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_sig_settable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *sig_settable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), @@ -1149,9 +1153,9 @@ static const OSSL_PARAM *nb_sig_settable_ctx_params(void *vctx, void *provctx) return types; } -static int nb_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) +static int sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) { - struct nb_sig_ctx *ctx = vctx; + struct sig_ctx *ctx = vctx; OSSL_PARAM *p; if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE)) != NULL) { @@ -1167,7 +1171,7 @@ static int nb_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_sig_gettable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *sig_gettable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL), @@ -1177,25 +1181,25 @@ static const OSSL_PARAM *nb_sig_gettable_ctx_params(void *vctx, void *provctx) return types; } -static const OSSL_DISPATCH nb_sig_functions[] = { - {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))nb_sig_newctx}, - {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))nb_sig_freectx}, - {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))nb_sig_sign_init}, - {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))nb_sig_sign}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))nb_sig_digest_sign_init}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))nb_sig_digest_sign_update}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))nb_sig_digest_sign_final}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))nb_sig_digest_sign}, - {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))nb_sig_set_ctx_params}, - {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))nb_sig_settable_ctx_params}, - {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))nb_sig_get_ctx_params}, - {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))nb_sig_gettable_ctx_params}, +static const OSSL_DISPATCH sig_functions[] = { + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sig_newctx}, + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sig_freectx}, + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))sig_sign_init}, + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sig_sign}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))sig_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))sig_digest_sign_update}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))sig_digest_sign_final}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))sig_digest_sign}, + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))sig_set_ctx_params}, + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))sig_settable_ctx_params}, + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))sig_get_ctx_params}, + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))sig_gettable_ctx_params}, {0, NULL}, }; /* --- EC KEYMGMT --- */ -struct nb_ec_keydata { +struct ec_keydata { neverbleed_t *nb; size_t key_index; int curve_nid; @@ -1204,19 +1208,19 @@ struct nb_ec_keydata { int has_private; }; -static void *nb_ec_keymgmt_new(void *provctx) +static void *ec_keymgmt_new(void *provctx) { - struct nb_ec_keydata *key = OPENSSL_zalloc(sizeof(*key)); + struct ec_keydata *key = OPENSSL_zalloc(sizeof(*key)); if (key == NULL) return NULL; - key->nb = ((struct nb_provider_ctx *)provctx)->nb; + key->nb = ((struct provider_ctx *)provctx)->nb; key->key_index = SIZE_MAX; return key; } -static void nb_ec_keymgmt_free(void *keydata) +static void ec_keymgmt_free(void *keydata) { - struct nb_ec_keydata *key = keydata; + struct ec_keydata *key = keydata; if (key == NULL) return; if (key->has_private && key->key_index != SIZE_MAX) { @@ -1231,9 +1235,9 @@ static void nb_ec_keymgmt_free(void *keydata) OPENSSL_free(key); } -static int nb_ec_keymgmt_has(const void *keydata, int selection) +static int ec_keymgmt_has(const void *keydata, int selection) { - const struct nb_ec_keydata *key = keydata; + const struct ec_keydata *key = keydata; if (key == NULL) return 0; if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) && key->pub_bytes == NULL) @@ -1245,9 +1249,9 @@ static int nb_ec_keymgmt_has(const void *keydata, int selection) return 1; } -static int nb_ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +static int ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) { - struct nb_ec_keydata *key = keydata; + struct ec_keydata *key = keydata; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME)) != NULL) { @@ -1270,7 +1274,7 @@ static int nb_ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM p return 1; } -static const OSSL_PARAM *nb_ec_keymgmt_import_types(int selection) +static const OSSL_PARAM *ec_keymgmt_import_types(int selection) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), @@ -1281,9 +1285,9 @@ static const OSSL_PARAM *nb_ec_keymgmt_import_types(int selection) return types; } -static int nb_ec_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) +static int ec_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) { - struct nb_ec_keydata *key = keydata; + struct ec_keydata *key = keydata; OSSL_PARAM *p; int bits = 0; @@ -1316,7 +1320,7 @@ static int nb_ec_keymgmt_get_params(void *keydata, OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_ec_keymgmt_gettable_params(void *provctx) +static const OSSL_PARAM *ec_keymgmt_gettable_params(void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), @@ -1330,9 +1334,9 @@ static const OSSL_PARAM *nb_ec_keymgmt_gettable_params(void *provctx) return types; } -static int nb_ec_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) +static int ec_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) { - struct nb_ec_keydata *key = keydata; + struct ec_keydata *key = keydata; if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) return 0; OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); @@ -1351,7 +1355,7 @@ static int nb_ec_keymgmt_export(void *keydata, int selection, OSSL_CALLBACK *par return ret; } -static const OSSL_PARAM *nb_ec_keymgmt_export_types(int selection) +static const OSSL_PARAM *ec_keymgmt_export_types(int selection) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), @@ -1361,7 +1365,7 @@ static const OSSL_PARAM *nb_ec_keymgmt_export_types(int selection) return types; } -static const char *nb_ec_keymgmt_query_operation_name(int operation_id) +static const char *ec_keymgmt_query_operation_name(int operation_id) { switch (operation_id) { case OSSL_OP_SIGNATURE: @@ -1370,33 +1374,33 @@ static const char *nb_ec_keymgmt_query_operation_name(int operation_id) return NULL; } -static const OSSL_DISPATCH nb_ec_keymgmt_functions[] = { - {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))nb_ec_keymgmt_new}, - {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))nb_ec_keymgmt_free}, - {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))nb_ec_keymgmt_has}, - {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))nb_ec_keymgmt_import}, - {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))nb_ec_keymgmt_import_types}, - {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))nb_ec_keymgmt_get_params}, - {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))nb_ec_keymgmt_gettable_params}, - {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))nb_ec_keymgmt_export}, - {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))nb_ec_keymgmt_export_types}, - {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))nb_ec_keymgmt_query_operation_name}, +static const OSSL_DISPATCH ec_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_keymgmt_free}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_keymgmt_has}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))ec_keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))ec_keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_keymgmt_export}, + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_keymgmt_export_types}, + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))ec_keymgmt_query_operation_name}, {0, NULL}, }; /* --- EC SIGNATURE --- */ -struct nb_ec_sig_ctx { - struct nb_provider_ctx *provctx; - struct nb_ec_keydata *keydata; +struct ec_sig_ctx { + struct provider_ctx *provctx; + struct ec_keydata *keydata; unsigned char *tbsdata; size_t tbslen, tbscap; int md_nid; }; -static void *nb_ec_sig_newctx(void *provctx, const char *propq) +static void *ec_sig_newctx(void *provctx, const char *propq) { - struct nb_ec_sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + struct ec_sig_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->provctx = provctx; @@ -1404,25 +1408,25 @@ static void *nb_ec_sig_newctx(void *provctx, const char *propq) return ctx; } -static void nb_ec_sig_freectx(void *vctx) +static void ec_sig_freectx(void *vctx) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; OPENSSL_free(ctx->tbsdata); OPENSSL_free(ctx); } -static int nb_ec_sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +static int ec_sig_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; ctx->keydata = vkey; return 1; } -static int nb_ec_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, +static int ec_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { - struct nb_ec_sig_ctx *ctx = vctx; - struct nb_ec_keydata *key = ctx->keydata; + struct ec_sig_ctx *ctx = vctx; + struct ec_keydata *key = ctx->keydata; struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); /* size query */ @@ -1465,9 +1469,9 @@ static int nb_ec_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t return 1; } -static int nb_ec_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) +static int ec_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; ctx->keydata = vkey; if (mdname != NULL) { const EVP_MD *md = EVP_get_digestbyname(mdname); @@ -1477,9 +1481,9 @@ static int nb_ec_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey return 1; } -static int nb_ec_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) +static int ec_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; if (ctx->tbslen + datalen > ctx->tbscap) { size_t newcap = ctx->tbslen + datalen; if (newcap < 256) @@ -1494,10 +1498,10 @@ static int nb_ec_sig_digest_sign_update(void *vctx, const unsigned char *data, s return 1; } -static int nb_ec_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) +static int ec_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) { - struct nb_ec_sig_ctx *ctx = vctx; - struct nb_ec_keydata *key = ctx->keydata; + struct ec_sig_ctx *ctx = vctx; + struct ec_keydata *key = ctx->keydata; struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); if (sig == NULL) { @@ -1539,12 +1543,12 @@ static int nb_ec_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *s return 1; } -static int nb_ec_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, +static int ec_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; if (sig == NULL) { - struct nb_ec_keydata *key = ctx->keydata; + struct ec_keydata *key = ctx->keydata; int bits = 0; if (key->curve_nid != 0) { EC_GROUP *group = EC_GROUP_new_by_curve_name(key->curve_nid); @@ -1557,14 +1561,14 @@ static int nb_ec_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, *siglen = 2 * (order_bytes + 1) + 6; return 1; } - if (!nb_ec_sig_digest_sign_update(vctx, tbs, tbslen)) + if (!ec_sig_digest_sign_update(vctx, tbs, tbslen)) return 0; - return nb_ec_sig_digest_sign_final(vctx, sig, siglen, sigsize); + return ec_sig_digest_sign_final(vctx, sig, siglen, sigsize); } -static int nb_ec_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +static int ec_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { @@ -1577,7 +1581,7 @@ static int nb_ec_sig_set_ctx_params(void *vctx, const OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_ec_sig_settable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *ec_sig_settable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), @@ -1586,9 +1590,9 @@ static const OSSL_PARAM *nb_ec_sig_settable_ctx_params(void *vctx, void *provctx return types; } -static int nb_ec_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) +static int ec_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) { - struct nb_ec_sig_ctx *ctx = vctx; + struct ec_sig_ctx *ctx = vctx; OSSL_PARAM *p; if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST)) != NULL) { @@ -1599,7 +1603,7 @@ static int nb_ec_sig_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_ec_sig_gettable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *ec_sig_gettable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), @@ -1608,27 +1612,27 @@ static const OSSL_PARAM *nb_ec_sig_gettable_ctx_params(void *vctx, void *provctx return types; } -static const OSSL_DISPATCH nb_ec_sig_functions[] = { - {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))nb_ec_sig_newctx}, - {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))nb_ec_sig_freectx}, - {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))nb_ec_sig_sign_init}, - {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))nb_ec_sig_sign}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))nb_ec_sig_digest_sign_init}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))nb_ec_sig_digest_sign_update}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))nb_ec_sig_digest_sign_final}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))nb_ec_sig_digest_sign}, - {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))nb_ec_sig_set_ctx_params}, - {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))nb_ec_sig_settable_ctx_params}, - {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))nb_ec_sig_get_ctx_params}, - {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))nb_ec_sig_gettable_ctx_params}, +static const OSSL_DISPATCH ec_sig_functions[] = { + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ec_sig_newctx}, + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ec_sig_freectx}, + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))ec_sig_sign_init}, + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ec_sig_sign}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))ec_sig_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))ec_sig_digest_sign_update}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))ec_sig_digest_sign_final}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))ec_sig_digest_sign}, + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))ec_sig_set_ctx_params}, + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))ec_sig_settable_ctx_params}, + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))ec_sig_get_ctx_params}, + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))ec_sig_gettable_ctx_params}, {0, NULL}, }; /* --- ASYM_CIPHER --- */ -static void *nb_asym_cipher_newctx(void *provctx) +static void *asym_cipher_newctx(void *provctx) { - struct nb_asym_cipher_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + struct asym_cipher_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->provctx = provctx; @@ -1636,23 +1640,23 @@ static void *nb_asym_cipher_newctx(void *provctx) return ctx; } -static void nb_asym_cipher_freectx(void *vctx) +static void asym_cipher_freectx(void *vctx) { OPENSSL_free(vctx); } -static int nb_asym_cipher_decrypt_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +static int asym_cipher_decrypt_init(void *vctx, void *vkey, const OSSL_PARAM params[]) { - struct nb_asym_cipher_ctx *ctx = vctx; + struct asym_cipher_ctx *ctx = vctx; ctx->keydata = vkey; return 1; } -static int nb_asym_cipher_decrypt(void *vctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, +static int asym_cipher_decrypt(void *vctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) { - struct nb_asym_cipher_ctx *ctx = vctx; - struct nb_rsa_keydata *key = ctx->keydata; + struct asym_cipher_ctx *ctx = vctx; + struct rsa_keydata *key = ctx->keydata; struct st_neverbleed_thread_data_t *thdata = get_thread_data(key->nb); int rsa_size = key->n ? BN_num_bytes(key->n) : 0; @@ -1792,9 +1796,9 @@ static int nb_asym_cipher_decrypt(void *vctx, unsigned char *out, size_t *outlen return 0; } -static int nb_asym_cipher_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +static int asym_cipher_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { - struct nb_asym_cipher_ctx *ctx = vctx; + struct asym_cipher_ctx *ctx = vctx; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE)) != NULL) { @@ -1816,7 +1820,7 @@ static int nb_asym_cipher_set_ctx_params(void *vctx, const OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_asym_cipher_settable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *asym_cipher_settable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), @@ -1827,9 +1831,9 @@ static const OSSL_PARAM *nb_asym_cipher_settable_ctx_params(void *vctx, void *pr return types; } -static int nb_asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) +static int asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) { - struct nb_asym_cipher_ctx *ctx = vctx; + struct asym_cipher_ctx *ctx = vctx; OSSL_PARAM *p; if ((p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE)) != NULL) { @@ -1839,7 +1843,7 @@ static int nb_asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 1; } -static const OSSL_PARAM *nb_asym_cipher_gettable_ctx_params(void *vctx, void *provctx) +static const OSSL_PARAM *asym_cipher_gettable_ctx_params(void *vctx, void *provctx) { static const OSSL_PARAM types[] = { OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL), @@ -1848,70 +1852,70 @@ static const OSSL_PARAM *nb_asym_cipher_gettable_ctx_params(void *vctx, void *pr return types; } -static const OSSL_DISPATCH nb_asym_cipher_functions[] = { - {OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))nb_asym_cipher_newctx}, - {OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))nb_asym_cipher_freectx}, - {OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))nb_asym_cipher_decrypt_init}, - {OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))nb_asym_cipher_decrypt}, - {OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, (void (*)(void))nb_asym_cipher_set_ctx_params}, - {OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))nb_asym_cipher_settable_ctx_params}, - {OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, (void (*)(void))nb_asym_cipher_get_ctx_params}, - {OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))nb_asym_cipher_gettable_ctx_params}, +static const OSSL_DISPATCH asym_cipher_functions[] = { + {OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))asym_cipher_newctx}, + {OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))asym_cipher_freectx}, + {OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))asym_cipher_decrypt_init}, + {OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))asym_cipher_decrypt}, + {OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, (void (*)(void))asym_cipher_set_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))asym_cipher_settable_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, (void (*)(void))asym_cipher_get_ctx_params}, + {OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))asym_cipher_gettable_ctx_params}, {0, NULL}, }; /* --- Provider entry point --- */ -static const OSSL_ALGORITHM nb_keymgmts[] = { - {"RSA", "provider=neverbleed", nb_keymgmt_functions, "Neverbleed RSA KEYMGMT"}, - {"EC", "provider=neverbleed", nb_ec_keymgmt_functions, "Neverbleed EC KEYMGMT"}, +static const OSSL_ALGORITHM keymgmts[] = { + {"RSA", "provider=neverbleed", keymgmt_functions, "Neverbleed RSA KEYMGMT"}, + {"EC", "provider=neverbleed", ec_keymgmt_functions, "Neverbleed EC KEYMGMT"}, {NULL, NULL, NULL, NULL}, }; -static const OSSL_ALGORITHM nb_signatures[] = { - {"RSA", "provider=neverbleed", nb_sig_functions, "Neverbleed RSA Signature"}, - {"ECDSA", "provider=neverbleed", nb_ec_sig_functions, "Neverbleed ECDSA Signature"}, +static const OSSL_ALGORITHM signatures[] = { + {"RSA", "provider=neverbleed", sig_functions, "Neverbleed RSA Signature"}, + {"ECDSA", "provider=neverbleed", ec_sig_functions, "Neverbleed ECDSA Signature"}, {NULL, NULL, NULL, NULL}, }; -static const OSSL_ALGORITHM nb_asym_ciphers[] = { - {"RSA", "provider=neverbleed", nb_asym_cipher_functions, "Neverbleed RSA Asymmetric Cipher"}, +static const OSSL_ALGORITHM asym_ciphers[] = { + {"RSA", "provider=neverbleed", asym_cipher_functions, "Neverbleed RSA Asymmetric Cipher"}, {NULL, NULL, NULL, NULL}, }; -static const OSSL_ALGORITHM *nb_provider_query_operation(void *provctx, int operation_id, int *no_cache) +static const OSSL_ALGORITHM *provider_query_operation(void *provctx, int operation_id, int *no_cache) { *no_cache = 0; switch (operation_id) { case OSSL_OP_KEYMGMT: - return nb_keymgmts; + return keymgmts; case OSSL_OP_SIGNATURE: - return nb_signatures; + return signatures; case OSSL_OP_ASYM_CIPHER: - return nb_asym_ciphers; + return asym_ciphers; } return NULL; } -static void nb_provider_teardown(void *provctx) +static void provider_teardown(void *provctx) { OPENSSL_free(provctx); } -static const OSSL_DISPATCH nb_provider_dispatch[] = { - {OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))nb_provider_teardown}, - {OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))nb_provider_query_operation}, +static const OSSL_DISPATCH provider_dispatch[] = { + {OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))provider_teardown}, + {OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))provider_query_operation}, {0, NULL}, }; -static int nb_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, void **provctx) +static int provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, void **provctx) { - struct nb_provider_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + struct provider_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) return 0; - ctx->nb = nb_provider_global_nb; + ctx->nb = provider_global_nb; *provctx = ctx; - *out = nb_provider_dispatch; + *out = provider_dispatch; return 1; } @@ -2248,7 +2252,7 @@ void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; if (!EVP_PKEY_get_params(pkey, get_params)) dief("failed to get key_index from provider key"); - nb_ref = nb_provider_global_nb; + nb_ref = provider_global_nb; cmd = "digestsign-rsa"; } break; #ifdef NEVERBLEED_ECDSA @@ -2256,7 +2260,7 @@ void neverbleed_start_digestsign(neverbleed_iobuf_t *buf, EVP_PKEY *pkey, const OSSL_PARAM get_params[] = {OSSL_PARAM_size_t(NEVERBLEED_PARAM_KEY_INDEX, &key_index), OSSL_PARAM_END}; if (!EVP_PKEY_get_params(pkey, get_params)) dief("failed to get key_index from provider key"); - nb_ref = nb_provider_global_nb; + nb_ref = provider_global_nb; } break; #endif default: @@ -3144,8 +3148,8 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf) /* no engine/provider for BoringSSL */ #else { /* setup provider for RSA and ECDSA */ - nb_provider_global_nb = nb; - if (!OSSL_PROVIDER_add_builtin(NULL, "neverbleed", nb_provider_init)) { + provider_global_nb = nb; + if (!OSSL_PROVIDER_add_builtin(NULL, "neverbleed", provider_init)) { snprintf(errbuf, NEVERBLEED_ERRBUF_SIZE, "OSSL_PROVIDER_add_builtin failed"); goto Fail; } From e402d46df06cba48a7161542c42912b574720b05 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 5 Mar 2026 12:41:21 +0900 Subject: [PATCH 6/8] Reuse sig_digest_sign_init and sig_digest_sign_update for EC These functions work solely at the digest level (storing md_nid, buffering TBS data) with no algorithm-specific logic, so the EC versions were redundant. The EC dispatch table now references the shared implementations directly. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index 5834dbf..f5cefe6 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -1469,35 +1469,6 @@ static int ec_sig_sign(void *vctx, unsigned char *sig, size_t *siglen, size_t si return 1; } -static int ec_sig_digest_sign_init(void *vctx, const char *mdname, void *vkey, const OSSL_PARAM params[]) -{ - struct ec_sig_ctx *ctx = vctx; - ctx->keydata = vkey; - if (mdname != NULL) { - const EVP_MD *md = EVP_get_digestbyname(mdname); - ctx->md_nid = md != NULL ? EVP_MD_type(md) : NID_undef; - } - ctx->tbslen = 0; - return 1; -} - -static int ec_sig_digest_sign_update(void *vctx, const unsigned char *data, size_t datalen) -{ - struct ec_sig_ctx *ctx = vctx; - if (ctx->tbslen + datalen > ctx->tbscap) { - size_t newcap = ctx->tbslen + datalen; - if (newcap < 256) - newcap = 256; - ctx->tbsdata = OPENSSL_realloc(ctx->tbsdata, newcap); - if (ctx->tbsdata == NULL) - return 0; - ctx->tbscap = newcap; - } - memcpy(ctx->tbsdata + ctx->tbslen, data, datalen); - ctx->tbslen += datalen; - return 1; -} - static int ec_sig_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen, size_t sigsize) { struct ec_sig_ctx *ctx = vctx; @@ -1561,7 +1532,7 @@ static int ec_sig_digest_sign(void *vctx, unsigned char *sig, size_t *siglen, si *siglen = 2 * (order_bytes + 1) + 6; return 1; } - if (!ec_sig_digest_sign_update(vctx, tbs, tbslen)) + if (!sig_digest_sign_update(vctx, tbs, tbslen)) return 0; return ec_sig_digest_sign_final(vctx, sig, siglen, sigsize); } @@ -1617,8 +1588,8 @@ static const OSSL_DISPATCH ec_sig_functions[] = { {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ec_sig_freectx}, {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))ec_sig_sign_init}, {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ec_sig_sign}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))ec_sig_digest_sign_init}, - {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))ec_sig_digest_sign_update}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))sig_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))sig_digest_sign_update}, {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))ec_sig_digest_sign_final}, {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void))ec_sig_digest_sign}, {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))ec_sig_set_ctx_params}, From 8b9ad685e72c3b5156d81765b3bc156463e00aa2 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 6 Mar 2026 07:38:56 +0900 Subject: [PATCH 7/8] Delegate RSA_PKCS1_WITH_TLS_PADDING to EVP_PKEY_decrypt on daemon side Instead of implementing constant-time PKCS#1 type 2 TLS unpadding on the proxy side, delegate RSA_PKCS1_WITH_TLS_PADDING handling to the daemon via EVP_PKEY_decrypt which handles CT padding check and Bleichenbacher countermeasure internally. The raw RSA operation still goes through RSA_private_decrypt within the default provider, so QAT ENGINE acceleration is preserved. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 168 ++++++++++++++++++++++++--------------------------- 1 file changed, 78 insertions(+), 90 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index f5cefe6..b337dfc 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -611,6 +611,8 @@ static int send_responses(int cleanup) return result; } +static EVP_PKEY *daemon_get_pkey(size_t key_index); + static RSA *daemon_get_rsa(size_t key_index) { RSA *rsa = NULL; @@ -702,7 +704,67 @@ static int priv_enc_stub(neverbleed_iobuf_t *buf) static int priv_dec_stub(neverbleed_iobuf_t *buf) { - return priv_encdec_stub(__FUNCTION__, RSA_private_decrypt, buf); + unsigned char *from; + size_t flen, key_index, padding; + + if ((from = iobuf_shift_bytes(buf, &flen)) == NULL || iobuf_shift_num(buf, &key_index) != 0 || + iobuf_shift_num(buf, &padding) != 0) { + errno = 0; + warnf("%s: failed to parse request", __FUNCTION__); + return -1; + } + + if (padding == RSA_PKCS1_WITH_TLS_PADDING) { + /* TLS RSA key exchange: delegate to EVP_PKEY_decrypt which handles CT padding check and Bleichenbacher countermeasure. + * The raw RSA operation goes through RSA_private_decrypt internally, so QAT ENGINE is used if available. */ + size_t tls_client_version; + if (iobuf_shift_num(buf, &tls_client_version) != 0) { + errno = 0; + warnf("%s: failed to parse tls_client_version", __FUNCTION__); + return -1; + } + EVP_PKEY *pkey = daemon_get_pkey(key_index); + if (pkey == NULL) { + errno = 0; + warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); + return -1; + } + unsigned char out[SSL_MAX_MASTER_KEY_LENGTH]; + size_t outlen = sizeof(out); + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); + int ok = 0; + if (ctx != NULL && EVP_PKEY_decrypt_init(ctx) > 0 && + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_WITH_TLS_PADDING) > 0) { + OSSL_PARAM params[3], *p = params; + *p++ = OSSL_PARAM_construct_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, + (unsigned int *)&tls_client_version); + *p++ = OSSL_PARAM_construct_end(); + if (EVP_PKEY_CTX_set_params(ctx, params) > 0 && + EVP_PKEY_decrypt(ctx, out, &outlen, from, flen) > 0) + ok = 1; + } + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + iobuf_dispose(buf); + iobuf_push_num(buf, ok ? (size_t)outlen : 0); + iobuf_push_bytes(buf, out, ok ? outlen : 0); + return 0; + } + + /* other padding modes: use RSA_private_decrypt directly */ + RSA *rsa = daemon_get_rsa(key_index); + if (rsa == NULL) { + errno = 0; + warnf("%s: invalid key index:%zu", __FUNCTION__, key_index); + return -1; + } + unsigned char to[4096]; + int ret = RSA_private_decrypt((int)flen, from, to, rsa, (int)padding); + iobuf_dispose(buf); + RSA_free(rsa); + iobuf_push_num(buf, ret); + iobuf_push_bytes(buf, to, ret > 0 ? ret : 0); + return 0; } static int sign_stub(neverbleed_iobuf_t *buf) @@ -772,30 +834,6 @@ struct asym_cipher_ctx { unsigned int tls_negotiated_version; }; -/* --- constant-time helpers for TLS padding check (all return 0 or 0xFFFFFFFF masks) --- */ - -static inline unsigned int ct_is_zero_mask(unsigned int x) -{ - /* returns 0xFFFFFFFF if x == 0, 0 otherwise */ - return 0u - (1u ^ ((x | (0u - x)) >> (sizeof(unsigned int) * 8 - 1))); -} - -static inline unsigned int ct_eq_mask(unsigned int a, unsigned int b) -{ - return ct_is_zero_mask(a ^ b); -} - -static inline unsigned char ct_select_8(unsigned int mask, unsigned char a, unsigned char b) -{ - return (unsigned char)((mask & a) | (~mask & b)); -} - -static inline unsigned int ct_ge_mask(unsigned int a, unsigned int b) -{ - /* returns 0xFFFFFFFF if a >= b, 0 otherwise (a, b must be < 2^31) */ - return 0u - (1u & ~((a - b) >> (sizeof(unsigned int) * 8 - 1))); -} - /* --- KEYMGMT --- */ static void *keymgmt_new(void *provctx) @@ -1687,80 +1725,30 @@ static int asym_cipher_decrypt(void *vctx, unsigned char *out, size_t *outlen, s iobuf_dispose(&buf); return 1; } else if (ctx->padding == RSA_PKCS1_WITH_TLS_PADDING) { - /* Raw decrypt then constant-time PKCS1 type 2 TLS unpadding */ + /* TLS RSA key exchange: delegate to daemon which uses EVP_PKEY_decrypt(RSA_PKCS1_WITH_TLS_PADDING) for CT padding check + * and Bleichenbacher countermeasure */ neverbleed_iobuf_t buf = {NULL}; - iobuf_push_str(&buf, "decrypt"); - iobuf_push_num(&buf, key->key_index); + iobuf_push_str(&buf, "priv_dec"); iobuf_push_bytes(&buf, in, inlen); + iobuf_push_num(&buf, key->key_index); + iobuf_push_num(&buf, (size_t)RSA_PKCS1_WITH_TLS_PADDING); + iobuf_push_num(&buf, (size_t)ctx->tls_client_version); iobuf_transaction(&buf, thdata); - size_t declen; + size_t ret; unsigned char *dec; - if ((dec = iobuf_shift_bytes(&buf, &declen)) == NULL || declen == 0) { + size_t declen; + if (iobuf_shift_num(&buf, &ret) != 0 || (dec = iobuf_shift_bytes(&buf, &declen)) == NULL) { iobuf_dispose(&buf); - /* Even on failure, return random PMS for Bleichenbacher countermeasure */ - unsigned char rand_pms[SSL_MAX_MASTER_KEY_LENGTH]; - RAND_bytes(rand_pms, sizeof(rand_pms)); - if (sizeof(rand_pms) > outsize) - return 0; - memcpy(out, rand_pms, sizeof(rand_pms)); - *outlen = sizeof(rand_pms); - return 1; - } - - /* Constant-time PKCS1 type 2 TLS check */ - unsigned char rand_pms[SSL_MAX_MASTER_KEY_LENGTH]; - RAND_bytes(rand_pms, sizeof(rand_pms)); - - /* Check 0x00 0x02 header */ - unsigned int good = ct_eq_mask(dec[0], 0) & ct_eq_mask(dec[1], 2); - - /* Find 0x00 separator, require at least 8 bytes of padding */ - size_t sep_idx = 0; - unsigned int found_sep = 0; - for (size_t i = 2; i < declen; i++) { - unsigned int is_zero = ct_eq_mask(dec[i], 0); - unsigned int is_first = is_zero & ~found_sep & ct_ge_mask((unsigned int)i, 10u); - /* ct_ge_mask(i, 10u) means i >= 10, i.e., at least 8 bytes of padding (indices 2..9) */ - sep_idx |= is_first & (unsigned int)i; - found_sep |= is_first; - } - good &= found_sep; - - /* PMS starts at sep_idx + 1, length should be 48 */ - size_t pms_start = sep_idx + 1; - size_t pms_len = declen - pms_start; - good &= ct_eq_mask((unsigned int)pms_len, SSL_MAX_MASTER_KEY_LENGTH); - - /* Check TLS version in first two bytes of PMS */ - if (ctx->tls_client_version != 0) { - unsigned int ver_hi = ctx->tls_client_version >> 8; - unsigned int ver_lo = ctx->tls_client_version & 0xff; - /* Only check if pms_start is valid */ - unsigned int check_ver = good; - if (pms_start + 1 < declen) { - check_ver &= ct_eq_mask(dec[pms_start], ver_hi) & ct_eq_mask(dec[pms_start + 1], ver_lo); - } else { - check_ver = 0; - } - good = check_ver; - } - - /* Constant-time select between real PMS and random PMS */ - unsigned char result[SSL_MAX_MASTER_KEY_LENGTH]; - for (size_t i = 0; i < SSL_MAX_MASTER_KEY_LENGTH; i++) { - size_t src_idx = pms_start + i; - unsigned char real_byte = (src_idx < declen) ? dec[src_idx] : 0; - result[i] = ct_select_8(good, real_byte, rand_pms[i]); + return 0; } - - iobuf_dispose(&buf); - - if (SSL_MAX_MASTER_KEY_LENGTH > outsize) + if (ret != SSL_MAX_MASTER_KEY_LENGTH || declen != SSL_MAX_MASTER_KEY_LENGTH || declen > outsize) { + iobuf_dispose(&buf); return 0; - memcpy(out, result, SSL_MAX_MASTER_KEY_LENGTH); + } + memcpy(out, dec, SSL_MAX_MASTER_KEY_LENGTH); *outlen = SSL_MAX_MASTER_KEY_LENGTH; - /* Always return success (Bleichenbacher countermeasure) */ + iobuf_dispose(&buf); return 1; } From 9af843eb9df85a1cf7e25a53fe8ea5f98478cee8 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Fri, 6 Mar 2026 07:41:33 +0900 Subject: [PATCH 8/8] Remove dead priv_enc IPC command and priv_encdec_stub priv_enc (RSA_private_encrypt) was only used by the ENGINE-based proxy code which has been removed. priv_encdec_stub is no longer needed since priv_dec_stub now handles its own parsing directly. Co-Authored-By: Claude Opus 4.6 --- neverbleed.c | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/neverbleed.c b/neverbleed.c index b337dfc..facf674 100644 --- a/neverbleed.c +++ b/neverbleed.c @@ -664,44 +664,8 @@ static size_t daemon_set_pkey(EVP_PKEY *pkey) return index; } -static int priv_encdec_stub(const char *name, - int (*func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), - neverbleed_iobuf_t *buf) -{ - unsigned char *from, to[4096]; - size_t flen; - size_t key_index, padding; - RSA *rsa; - int ret; - - if ((from = iobuf_shift_bytes(buf, &flen)) == NULL || iobuf_shift_num(buf, &key_index) != 0 || - iobuf_shift_num(buf, &padding) != 0) { - errno = 0; - warnf("%s: failed to parse request", name); - return -1; - } - if ((rsa = daemon_get_rsa(key_index)) == NULL) { - errno = 0; - warnf("%s: invalid key index:%zu\n", name, key_index); - return -1; - } - ret = func((int)flen, from, to, rsa, (int)padding); - iobuf_dispose(buf); - RSA_free(rsa); - - iobuf_push_num(buf, ret); - iobuf_push_bytes(buf, to, ret > 0 ? ret : 0); - - return 0; -} - #if !defined(OPENSSL_IS_BORINGSSL) -static int priv_enc_stub(neverbleed_iobuf_t *buf) -{ - return priv_encdec_stub(__FUNCTION__, RSA_private_encrypt, buf); -} - static int priv_dec_stub(neverbleed_iobuf_t *buf) { unsigned char *from; @@ -2872,10 +2836,7 @@ static void *daemon_conn_thread(void *_sock_fd) break; } #if !defined(OPENSSL_IS_BORINGSSL) - if (strcmp(cmd, "priv_enc") == 0) { - if (offload_start(priv_enc_stub, buf) != 0) - break; - } else if (strcmp(cmd, "priv_dec") == 0) { + if (strcmp(cmd, "priv_dec") == 0) { if (offload_start(priv_dec_stub, buf) != 0) break; } else if (strcmp(cmd, "sign") == 0) {