Skip to content

Commit

Permalink
tls: basic OpenSSL 3 support of provider keys (replaces ENGINE)
Browse files Browse the repository at this point in the history
- initial support for v3 provider keys (replaces ENGINE from v1.1.1)
- can be disabled behind build flag -DOPENSSL_NO_PROVIDER
- provider keys start with /uri: e.g
  private_key = /uri:pkcs11:token=NSS%20Certificate%20DB;type=private;object=Fork-Test-c67cc0e0
- global config:
  provider_quirks: 0 | 1
  - 0 - default
  - 1 - create a new OSS_LIB_CTX* in the child

This integration does not load any providers itself and depends on
the usual

export OPENSSL_CONF=my-openssl.cnf

to configure providers.

(cherry picked from commit 69883dd)
  • Loading branch information
space88man committed Mar 23, 2024
1 parent 88429b9 commit 822960b
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 30 deletions.
40 changes: 24 additions & 16 deletions src/modules/tls/tls_domain.c
Expand Up @@ -32,13 +32,21 @@

/* only OpenSSL <= 1.1.1 */
#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_VERSION_NUMBER < 0x030000000L
#define KSR_SSL_COMMON
#define KSR_SSL_ENGINE
#define KEY_PREFIX "/engine:"
#define KEY_PREFIX_LEN (strlen(KEY_PREFIX))
#include <openssl/engine.h>
extern EVP_PKEY *tls_engine_private_key(const char *key_id);
#endif

#ifdef KSR_SSL_ENGINE
#include <openssl/engine.h>
#if !defined(OPENSSL_NO_PROVIDER) && OPENSSL_VERSION_NUMBER >= 0x030000000L
#define KSR_SSL_COMMON
#define KSR_SSL_PROVIDER
#define KEY_PREFIX "/uri:"
#define KEY_PREFIX_LEN (strlen(KEY_PREFIX))
extern EVP_PKEY *tls_engine_private_key(const char *key_id);
#endif /* KSR_SSL_ENGINE */
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00907000L
#include <openssl/ui.h>
Expand Down Expand Up @@ -1227,7 +1235,7 @@ static int passwd_cb(char *buf, int size, int rwflag, void *filename)
#endif
}

#ifdef KSR_SSL_ENGINE
#ifdef KSR_SSL_COMMON
/**
* @brief Load a private key from an OpenSSL engine
* @param d TLS domain
Expand All @@ -1237,7 +1245,7 @@ static int passwd_cb(char *buf, int size, int rwflag, void *filename)
* to be fork() safe
*
* private_key setting which starts with /engine: is assumed to be
* an HSM key and not a file-based key
* an HSM key and not a file-based key (/uri: for OpenSSL 3 key URIs)
*
* We store the private key in a local memory hash table as
* HSM keys must be process-local. We use the SSL_CTX* address
Expand All @@ -1253,13 +1261,13 @@ static int load_engine_private_key(tls_domain_t *d)
DBG("%s: No private key specified\n", tls_domain_str(d));
return 0;
}
if(strncmp(d->pkey_file.s, "/engine:", 8) != 0)
if(strncmp(d->pkey_file.s, KEY_PREFIX, KEY_PREFIX_LEN) != 0)
return 0;

do {
i = process_no;
for(idx = 0, ret_pwd = 0; idx < 3; idx++) {
pkey = tls_engine_private_key(d->pkey_file.s + 8);
pkey = tls_engine_private_key(d->pkey_file.s + KEY_PREFIX_LEN);
if(pkey) {
ret_pwd = SSL_CTX_use_PrivateKey(d->ctx[i], pkey);
} else {
Expand Down Expand Up @@ -1295,7 +1303,7 @@ static int load_engine_private_key(tls_domain_t *d)
d->pkey_file.s);
return 0;
}
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_COMMON */
/**
* @brief Load a private key from a file
* @param d TLS domain
Expand All @@ -1319,10 +1327,10 @@ static int load_private_key(tls_domain_t *d)
SSL_CTX_set_default_passwd_cb_userdata(d->ctx[i], d->pkey_file.s);

for(idx = 0, ret_pwd = 0; idx < 3; idx++) {
#ifdef KSR_SSL_ENGINE
#ifdef KSR_SSL_COMMON
// in PROC_INIT skip loading HSM keys due to
// fork() issues with PKCS#11 libraries
if(strncmp(d->pkey_file.s, "/engine:", 8) != 0) {
if(strncmp(d->pkey_file.s, KEY_PREFIX, KEY_PREFIX_LEN) != 0) {
ret_pwd = SSL_CTX_use_PrivateKey_file(
d->ctx[i], d->pkey_file.s, SSL_FILETYPE_PEM);
} else {
Expand All @@ -1331,7 +1339,7 @@ static int load_private_key(tls_domain_t *d)
#else
ret_pwd = SSL_CTX_use_PrivateKey_file(
d->ctx[i], d->pkey_file.s, SSL_FILETYPE_PEM);
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_COMMON */
if(ret_pwd) {
break;
} else {
Expand All @@ -1348,12 +1356,12 @@ static int load_private_key(tls_domain_t *d)
TLS_ERR("load_private_key:");
return -1;
}
#ifdef KSR_SSL_ENGINE
if(strncmp(d->pkey_file.s, "/engine:", 8) == 0) {
#ifdef KSR_SSL_COMMON
if(strncmp(d->pkey_file.s, KEY_PREFIX, KEY_PREFIX_LEN) == 0) {
// skip private key validity check for HSM keys
continue;
}
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_COMMON */
if(!SSL_CTX_check_private_key(d->ctx[i])) {
ERR("%s: Key '%s' does not match the public key of the"
" certificate\n",
Expand All @@ -1369,7 +1377,7 @@ static int load_private_key(tls_domain_t *d)
}


#ifdef KSR_SSL_ENGINE
#ifdef KSR_SSL_COMMON
/**
* @brief Initialize engine private keys
*
Expand Down Expand Up @@ -1401,7 +1409,7 @@ int tls_fix_engine_keys(tls_domains_cfg_t *cfg, tls_domain_t *srv_defaults,

return 0;
}
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_COMMON */
/**
* @brief Initialize attributes of all domains from default domains if necessary
*
Expand Down
109 changes: 95 additions & 14 deletions src/modules/tls/tls_mod.c
Expand Up @@ -93,9 +93,21 @@ MODULE_VERSION

/* Engine is deprecated in OpenSSL 3 */
#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_VERSION_NUMBER < 0x030000000L
#define KSR_SSL_COMMON
#define KSR_SSL_ENGINE
#define KEY_PREFIX "/engine:"
#define KEY_PREFIX_LEN (strlen(KEY_PREFIX))
#endif

#if !defined(OPENSSL_NO_PROVIDER) && OPENSSL_VERSION_NUMBER >= 0x030000000L
#define KSR_SSL_COMMON
#define KSR_SSL_PROVIDER
#include <openssl/store.h>
#define KEY_PREFIX "/uri:"
#define KEY_PREFIX_LEN (strlen(KEY_PREFIX))
#endif


extern str sr_tls_event_callback;
str sr_tls_xavp_cfg = {0, 0};
/*
Expand Down Expand Up @@ -151,23 +163,28 @@ tls_domain_t srv_defaults = {


#ifdef KSR_SSL_ENGINE

typedef struct tls_engine
{
str engine;
str engine_config;
str engine_algorithms;
} tls_engine_t;
#include <openssl/conf.h>
#include <openssl/engine.h>

static ENGINE *ksr_tls_engine;
static tls_engine_t tls_engine_settings = {
STR_STATIC_INIT("NONE"),
STR_STATIC_INIT("NONE"),
STR_STATIC_INIT("ALL"),
};
#endif /* KSR_SSL_ENGINE */

#include <openssl/conf.h>
#include <openssl/engine.h>

static ENGINE *ksr_tls_engine;
#endif

#ifdef KSR_SSL_PROVIDER
static int tls_provider_quirks;
#endif

/*
* Default settings for client domains when using external config file
*/
Expand Down Expand Up @@ -238,6 +255,10 @@ static param_export_t params[] = {
{"engine_algorithms", PARAM_STR,
&tls_engine_settings.engine_algorithms},
#endif /* KSR_SSL_ENGINE */
#ifdef KSR_SSL_PROVIDER
{"provider_quirks", PARAM_INT,
&tls_provider_quirks}, /* OpenSSL 3 provider that needs new OSSL_LIB_CTX in child */
#endif /* KSR_SSL_PROVIDER */
{"tls_log", PARAM_INT, &default_tls_cfg.log},
{"tls_debug", PARAM_INT, &default_tls_cfg.debug},
{"session_cache", PARAM_INT, &default_tls_cfg.session_cache},
Expand Down Expand Up @@ -316,7 +337,6 @@ static tls_domains_cfg_t* tls_use_modparams(void)
}
#endif


static int mod_init(void)
{
int method;
Expand Down Expand Up @@ -433,10 +453,10 @@ static int mod_init(void)
}


#ifdef KSR_SSL_ENGINE
#ifdef KSR_SSL_COMMON
static int tls_engine_init();
int tls_fix_engine_keys(tls_domains_cfg_t *, tls_domain_t *, tls_domain_t *);
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_COMMON */

/*
* OpenSSL 1.1.1+: SSL_CTX is repeated in each worker
Expand All @@ -450,9 +470,10 @@ int tls_fix_engine_keys(tls_domains_cfg_t *, tls_domain_t *, tls_domain_t *);
*/
static int mod_child_hook(int *rank, void *dummy)
{
LM_DBG("Loading SSL_CTX in process_no=%d rank=%d "
"ksr_tls_threads_mode=%d\n",
LM_INFO("Loading SSL_CTX in process_no=%d rank=%d "
"ksr_tls_threads_mode=%d\n",
process_no, *rank, ksr_tls_threads_mode);

if(cfg_get(tls, tls_cfg, config_file).s) {
if(tls_fix_domains_cfg(*tls_domains_cfg, &srv_defaults, &cli_defaults)
< 0)
Expand All @@ -464,6 +485,10 @@ static int mod_child_hook(int *rank, void *dummy)
return 0;
}

#ifdef KSR_SSL_PROVIDER
static OSSL_LIB_CTX *orig_ctx;
static OSSL_LIB_CTX *new_ctx;
#endif
static int mod_child(int rank)
{
if(tls_disable || (tls_domains_cfg == 0))
Expand All @@ -477,23 +502,32 @@ static int mod_child(int rank)
return run_thread4PP((_thread_proto4PP)mod_child_hook, &rank, NULL);
}

#ifdef KSR_SSL_ENGINE
#ifdef KSR_SSL_COMMON
/*
* after the child is fork()ed we go through the TLS domains
* and fix up private keys from engine
*/
#ifdef KSR_SSL_ENGINE
if(!strncmp(tls_engine_settings.engine.s, "NONE", 4))
return 0;
#endif /* KSR_SSL_ENGINE */

if(rank > 0) {
#ifdef KSR_SSL_PROVIDER
if(tls_provider_quirks & 1) {
new_ctx = OSSL_LIB_CTX_new();
orig_ctx = OSSL_LIB_CTX_set0_default(new_ctx);
CONF_modules_load_file(CONF_get1_default_config_file(), NULL, 0L);
}
#endif /* KSR_SSL_PROVIDER */
if(tls_engine_init() < 0)
return -1;
if(tls_fix_engine_keys(*tls_domains_cfg, &srv_defaults, &cli_defaults)
< 0)
return -1;
LM_INFO("OpenSSL Engine loaded private keys in child: %d\n", rank);
LM_INFO("OpenSSL loaded private keys in child: %d\n", rank);
}
#endif /* KSR_SSL_ENGINE */
#endif /* KSR_SSL_PROVIDER */
return 0;
}

Expand Down Expand Up @@ -798,3 +832,50 @@ EVP_PKEY *tls_engine_private_key(const char *key_id)
return ENGINE_load_private_key(ksr_tls_engine, key_id, NULL, NULL);
}
#endif /* KSR_SSL_ENGINE */

#ifdef KSR_SSL_PROVIDER
#include <openssl/store.h>
static int tls_engine_init()
{
return 0;
}
EVP_PKEY *tls_engine_private_key(const char *key_id)
{
OSSL_STORE_CTX *ctx;
EVP_PKEY *pkey = NULL;

ctx = OSSL_STORE_open_ex(key_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if(!ctx) {
LM_ERR("[ERR] could not load URI %s\n", key_id);
goto error;
}

OSSL_STORE_expect(ctx, OSSL_STORE_INFO_PKEY);

while(!(OSSL_STORE_eof(ctx))) {
OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);

int type;
type = OSSL_STORE_INFO_get_type(info);

switch(type) {
case OSSL_STORE_INFO_PKEY:
pkey = OSSL_STORE_INFO_get1_PKEY(info);
break;
default:
continue;
break;
}
OSSL_STORE_INFO_free(info);
if(pkey)
break;
}

LM_INFO("Loaded private key = %p\n", pkey);

error:
OSSL_STORE_close(ctx);

return pkey;
}
#endif

0 comments on commit 822960b

Please sign in to comment.