in crypto/apr_crypto_openssl.c [456:639]
static apr_status_t crypto_make(apr_crypto_t **ff,
const apr_crypto_driver_t *provider, const char *params,
apr_pool_t *pool)
{
apr_crypto_t *f;
apr_crypto_config_t *config;
const char *engine = NULL;
apr_status_t status = APR_SUCCESS;
struct {
const char *field;
const char *value;
int set;
} fields[] = {
{ "engine", NULL, 0 },
{ NULL, NULL, 0 }
};
const char *ptr;
size_t klen;
char **elts = NULL;
char *elt;
int i = 0, j;
#if APR_USE_OPENSSL_PROVIDER_API
OSSL_PROVIDER *prov = NULL;
const char *path = NULL;
#endif
*ff = NULL;
f = apr_pcalloc(pool, sizeof(apr_crypto_t));
if (!f) {
return APR_ENOMEM;
}
f->config = config = apr_pcalloc(pool, sizeof(apr_crypto_config_t));
if (!config) {
return APR_ENOMEM;
}
f->pool = pool;
f->provider = provider;
if (params) {
if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) {
return status;
}
while ((elt = elts[i])) {
ptr = strchr(elt, '=');
if (ptr) {
for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen)
;
ptr++;
}
else {
for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen)
;
}
elt[klen] = 0;
for (j = 0; fields[j].field != NULL; ++j) {
if (!strcasecmp(fields[j].field, elt)) {
fields[j].set = 1;
if (ptr) {
fields[j].value = ptr;
}
break;
}
}
#if APR_USE_OPENSSL_PROVIDER_API
if (!strcasecmp("provider-path", elt)) {
path = ptr;
}
else if (!strcasecmp("provider", elt)) {
/* first provider, avoid loading the default by loading null */
if (!config->libctx) {
prov = OSSL_PROVIDER_load(NULL, "null");
config->libctx = OSSL_LIB_CTX_new();
if (!config->libctx) {
return APR_ENOMEM;
}
apr_pool_cleanup_register(pool, prov, provider_cleanup,
apr_pool_cleanup_null);
}
if (path) {
OSSL_PROVIDER_set_default_search_path(config->libctx, path);
path = NULL;
}
prov = OSSL_PROVIDER_load(config->libctx, ptr);
if (!prov) {
return APR_ENOENGINE;
}
apr_pool_cleanup_register(pool, prov, provider_cleanup,
apr_pool_cleanup_null);
}
else if (prov) {
/* options after a provider apply to the provider */
#if !APR_USE_OPENSSL_PRE_3_5_API
if (!OSSL_PROVIDER_add_conf_parameter(prov, elt, ptr)) {
return APR_EINVAL;
}
#else
return APR_ENOTIMPL;
#endif
}
#endif
i++;
}
engine = fields[0].value;
}
/* The default/builtin "openssl" engine is the same as NULL though with
* openssl-3+ it's called something else, keep NULL for that name.
*/
if (engine && strcasecmp(engine, "openssl") != 0) {
#if APR_USE_OPENSSL_ENGINE_API
config->engine = ENGINE_by_id(engine);
if (!config->engine) {
return APR_ENOENGINE;
}
if (!ENGINE_init(config->engine)) {
status = APR_EINITENGINE;
goto cleanup;
}
#else
return APR_ENOTIMPL;
#endif
}
f->result = apr_pcalloc(pool, sizeof(apu_err_t));
if (!f->result) {
status = APR_ENOMEM;
goto cleanup;
}
f->digests = apr_hash_make(pool);
if (!f->digests) {
status = APR_ENOMEM;
goto cleanup;
}
apr_hash_set(f->digests, "md5", APR_HASH_KEY_STRING, &(key_digests[i = 0]));
apr_hash_set(f->digests, "sha1", APR_HASH_KEY_STRING, &(key_digests[++i]));
apr_hash_set(f->digests, "sha224", APR_HASH_KEY_STRING, &(key_digests[++i]));
apr_hash_set(f->digests, "sha256", APR_HASH_KEY_STRING, &(key_digests[++i]));
apr_hash_set(f->digests, "sha384", APR_HASH_KEY_STRING, &(key_digests[++i]));
apr_hash_set(f->digests, "sha512", APR_HASH_KEY_STRING, &(key_digests[++i]));
f->types = apr_hash_make(pool);
if (!f->types) {
status = APR_ENOMEM;
goto cleanup;
}
apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[i = 0]));
apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[++i]));
apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[++i]));
apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[++i]));
f->modes = apr_hash_make(pool);
if (!f->modes) {
status = APR_ENOMEM;
goto cleanup;
}
apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[i = 0]));
apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[++i]));
f->digests = apr_hash_make(pool);
if (!f->digests) {
status = APR_ENOMEM;
goto cleanup;
}
*ff = f;
apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
apr_pool_cleanup_null);
return APR_SUCCESS;
cleanup:
crypto_cleanup(f);
return status;
}