static apr_status_t crypto_make()

in crypto/apr_crypto_openssl.c [461:644]


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;
}