static apr_status_t crypto_key()

in crypto/apr_crypto_openssl.c [777:952]


static apr_status_t crypto_key(apr_crypto_key_t **k,
        const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p)
{
    apr_crypto_key_t *key = *k;
    apr_status_t rv;

    if (!key) {
        *k = key = apr_pcalloc(p, sizeof *key);
        if (!key) {
            return APR_ENOMEM;
        }
        apr_pool_cleanup_register(p, key, crypto_key_cleanup_helper,
                                  apr_pool_cleanup_null);
    }
    else {
        crypto_key_cleanup(key);
    }
    key->pool = p;
    key->f = f;
    key->provider = f->provider;
    key->rec = rec;

    switch (rec->ktype) {

    case APR_CRYPTO_KTYPE_PASSPHRASE: {

        /* decide on what cipher mechanism we will be using */
        rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p);
        if (APR_SUCCESS != rv) {
            return rv;
        }

        /* generate the key */
        if (PKCS5_PBKDF2_HMAC_SHA1(rec->k.passphrase.pass,
                rec->k.passphrase.passLen,
                (unsigned char *) rec->k.passphrase.salt,
                rec->k.passphrase.saltLen, rec->k.passphrase.iterations,
                key->keyLen, key->key) == 0) {
            return APR_ENOKEY;
        }

        break;
    }

    case APR_CRYPTO_KTYPE_SECRET: {

        /* decide on what cipher mechanism we will be using */
        rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p);
        if (APR_SUCCESS != rv) {
            return rv;
        }

        /* sanity check - key correct size? */
        if (rec->k.secret.secretLen != key->keyLen) {
            return APR_EKEYLENGTH;
        }

        /* copy the key */
        memcpy(key->key, rec->k.secret.secret, rec->k.secret.secretLen);

        break;
    }
    case APR_CRYPTO_KTYPE_HASH: {

        switch (rec->k.hash.digest) {
        case APR_CRYPTO_DIGEST_MD5:
            key->md = EVP_md5();
            break;
        case APR_CRYPTO_DIGEST_SHA1:
            key->md = EVP_sha1();
            break;
        case APR_CRYPTO_DIGEST_SHA224:
            key->md = EVP_sha224();
            break;
        case APR_CRYPTO_DIGEST_SHA256:
            key->md = EVP_sha256();
            break;
        case APR_CRYPTO_DIGEST_SHA384:
            key->md = EVP_sha384();
            break;
        case APR_CRYPTO_DIGEST_SHA512:
            key->md = EVP_sha512();
            break;
        default:
            return APR_ENODIGEST;
        }

        break;
    }
    case APR_CRYPTO_KTYPE_HMAC:
    case APR_CRYPTO_KTYPE_CMAC: {

        switch (rec->k.hmac.digest) {
        case APR_CRYPTO_DIGEST_MD5:
            key->md = EVP_md5();
            break;
        case APR_CRYPTO_DIGEST_SHA1:
            key->md = EVP_sha1();
            break;
        case APR_CRYPTO_DIGEST_SHA224:
            key->md = EVP_sha224();
            break;
        case APR_CRYPTO_DIGEST_SHA256:
            key->md = EVP_sha256();
            break;
        case APR_CRYPTO_DIGEST_SHA384:
            key->md = EVP_sha384();
            break;
        case APR_CRYPTO_DIGEST_SHA512:
            key->md = EVP_sha512();
            break;
        default:
            return APR_ENODIGEST;
        }

        /* create hmac key */
#if APR_USE_OPENSSL_PRE_3_0_API
        if (rec->ktype == APR_CRYPTO_KTYPE_HMAC) {
            apr_crypto_config_t *config = f->config;
            key->pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC,
                                             config->engine,
                                             rec->k.hmac.secret,
                                             rec->k.hmac.secretLen);
        }
        else {
#if !APR_USE_OPENSSL_PRE_1_1_1_API
            apr_crypto_config_t *config = f->config;
            /* decide on what cipher mechanism we will be using */
            rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p);
            if (APR_SUCCESS != rv) {
                return rv;
            }
            key->pkey = EVP_PKEY_new_CMAC_key(config->engine,
                                              rec->k.cmac.secret,
                                              rec->k.cmac.secretLen,
                                              key->cipher);
#else
            return APR_ENOTIMPL;
#endif
        }
        if (!key->pkey) {
            return APR_ENOKEY;
        }
#else
        if (rec->ktype == APR_CRYPTO_KTYPE_HMAC) {
            key->mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
        }
        else {
            key->mac = EVP_MAC_fetch(NULL, "CMAC", NULL);
        }
        if (!key->mac) {
            return APR_ENOMEM;
        }
#endif

        break;
    }

    default: {

        return APR_ENOKEY;

    }
    }

    key->doPad = rec->pad;

    /* note: openssl incorrectly returns non zero IV size values for ECB
     * algorithms, so work around this by ignoring the IV size.
     */
    if (APR_MODE_ECB != rec->mode && key->cipher) {
        key->ivSize = EVP_CIPHER_iv_length(key->cipher);
    }

    return APR_SUCCESS;
}