add original 3.5.0 and replace with 3.1.7. NOTE:- This commit will NOT COMPILE. (#15)
Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/15 Co-authored-by: siddhant <siddhant.singh@neominds.in> Co-committed-by: siddhant <siddhant.singh@neominds.in>
This commit is contained in:
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
* Copyright 2006-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static void evp_asym_cipher_free(void *data)
|
||||
{
|
||||
EVP_ASYM_CIPHER_free(data);
|
||||
}
|
||||
|
||||
static int evp_asym_cipher_up_ref(void *data)
|
||||
{
|
||||
return EVP_ASYM_CIPHER_up_ref(data);
|
||||
}
|
||||
|
||||
static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
int ret = 0;
|
||||
void *provkey = NULL;
|
||||
EVP_ASYM_CIPHER *cipher = NULL;
|
||||
EVP_KEYMGMT *tmp_keymgmt = NULL;
|
||||
const OSSL_PROVIDER *tmp_prov = NULL;
|
||||
const char *supported_ciph = NULL;
|
||||
int iter;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = operation;
|
||||
|
||||
ERR_set_mark();
|
||||
|
||||
if (evp_pkey_ctx_is_legacy(ctx))
|
||||
goto legacy;
|
||||
|
||||
if (ctx->pkey == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to derive the supported asym cipher from |ctx->keymgmt|.
|
||||
*/
|
||||
if (!ossl_assert(ctx->pkey->keymgmt == NULL
|
||||
|| ctx->pkey->keymgmt == ctx->keymgmt)) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
supported_ciph
|
||||
= evp_keymgmt_util_query_operation_name(ctx->keymgmt,
|
||||
OSSL_OP_ASYM_CIPHER);
|
||||
if (supported_ciph == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We perform two iterations:
|
||||
*
|
||||
* 1. Do the normal asym cipher fetch, using the fetching data given by
|
||||
* the EVP_PKEY_CTX.
|
||||
* 2. Do the provider specific asym cipher fetch, from the same provider
|
||||
* as |ctx->keymgmt|
|
||||
*
|
||||
* We then try to fetch the keymgmt from the same provider as the
|
||||
* asym cipher, and try to export |ctx->pkey| to that keymgmt (when
|
||||
* this keymgmt happens to be the same as |ctx->keymgmt|, the export
|
||||
* is a no-op, but we call it anyway to not complicate the code even
|
||||
* more).
|
||||
* If the export call succeeds (returns a non-NULL provider key pointer),
|
||||
* we're done and can perform the operation itself. If not, we perform
|
||||
* the second iteration, or jump to legacy.
|
||||
*/
|
||||
for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
|
||||
EVP_KEYMGMT *tmp_keymgmt_tofree;
|
||||
|
||||
/*
|
||||
* If we're on the second iteration, free the results from the first.
|
||||
* They are NULL on the first iteration, so no need to check what
|
||||
* iteration we're on.
|
||||
*/
|
||||
EVP_ASYM_CIPHER_free(cipher);
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
|
||||
switch (iter) {
|
||||
case 1:
|
||||
cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph,
|
||||
ctx->propquery);
|
||||
if (cipher != NULL)
|
||||
tmp_prov = EVP_ASYM_CIPHER_get0_provider(cipher);
|
||||
break;
|
||||
case 2:
|
||||
tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
|
||||
cipher =
|
||||
evp_asym_cipher_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
supported_ciph, ctx->propquery);
|
||||
if (cipher == NULL)
|
||||
goto legacy;
|
||||
break;
|
||||
}
|
||||
if (cipher == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure that the key is provided, either natively, or as a cached
|
||||
* export. We start by fetching the keymgmt with the same name as
|
||||
* |ctx->pkey|, but from the provider of the asym cipher method, using
|
||||
* the same property query as when fetching the asym cipher method.
|
||||
* With the keymgmt we found (if we did), we try to export |ctx->pkey|
|
||||
* to it (evp_pkey_export_to_provider() is smart enough to only actually
|
||||
* export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt)
|
||||
*/
|
||||
tmp_keymgmt_tofree = tmp_keymgmt
|
||||
= evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
EVP_KEYMGMT_get0_name(ctx->keymgmt),
|
||||
ctx->propquery);
|
||||
if (tmp_keymgmt != NULL)
|
||||
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
||||
&tmp_keymgmt, ctx->propquery);
|
||||
if (tmp_keymgmt == NULL)
|
||||
EVP_KEYMGMT_free(tmp_keymgmt_tofree);
|
||||
}
|
||||
|
||||
if (provkey == NULL) {
|
||||
EVP_ASYM_CIPHER_free(cipher);
|
||||
goto legacy;
|
||||
}
|
||||
|
||||
ERR_pop_to_mark();
|
||||
|
||||
/* No more legacy from here down to legacy: */
|
||||
|
||||
ctx->op.ciph.cipher = cipher;
|
||||
ctx->op.ciph.algctx = cipher->newctx(ossl_provider_ctx(cipher->prov));
|
||||
if (ctx->op.ciph.algctx == NULL) {
|
||||
/* The provider key can stay in the cache */
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case EVP_PKEY_OP_ENCRYPT:
|
||||
if (cipher->encrypt_init == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto err;
|
||||
}
|
||||
ret = cipher->encrypt_init(ctx->op.ciph.algctx, provkey, params);
|
||||
break;
|
||||
case EVP_PKEY_OP_DECRYPT:
|
||||
if (cipher->decrypt_init == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto err;
|
||||
}
|
||||
ret = cipher->decrypt_init(ctx->op.ciph.algctx, provkey, params);
|
||||
break;
|
||||
default:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ret <= 0)
|
||||
goto err;
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return 1;
|
||||
|
||||
legacy:
|
||||
/*
|
||||
* If we don't have the full support we need with provided methods,
|
||||
* let's go see if legacy does.
|
||||
*/
|
||||
ERR_pop_to_mark();
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
tmp_keymgmt = NULL;
|
||||
|
||||
if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
switch (ctx->operation) {
|
||||
case EVP_PKEY_OP_ENCRYPT:
|
||||
if (ctx->pmeth->encrypt_init == NULL)
|
||||
return 1;
|
||||
ret = ctx->pmeth->encrypt_init(ctx);
|
||||
break;
|
||||
case EVP_PKEY_OP_DECRYPT:
|
||||
if (ctx->pmeth->decrypt_init == NULL)
|
||||
return 1;
|
||||
ret = ctx->pmeth->decrypt_init(ctx);
|
||||
break;
|
||||
default:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
err:
|
||||
if (ret <= 0) {
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
}
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_ENCRYPT, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_encrypt_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_ENCRYPT, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *out, size_t *outlen,
|
||||
const unsigned char *in, size_t inlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.ciph.algctx == NULL)
|
||||
goto legacy;
|
||||
|
||||
ret = ctx->op.ciph.cipher->encrypt(ctx->op.ciph.algctx, out, outlen,
|
||||
(out == NULL ? 0 : *outlen), in, inlen);
|
||||
return ret;
|
||||
|
||||
legacy:
|
||||
if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_ENCRYPT)
|
||||
return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
|
||||
}
|
||||
|
||||
int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_DECRYPT, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_decrypt_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_DECRYPT, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *out, size_t *outlen,
|
||||
const unsigned char *in, size_t inlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.ciph.algctx == NULL)
|
||||
goto legacy;
|
||||
|
||||
ret = ctx->op.ciph.cipher->decrypt(ctx->op.ciph.algctx, out, outlen,
|
||||
(out == NULL ? 0 : *outlen), in, inlen);
|
||||
return ret;
|
||||
|
||||
legacy:
|
||||
if (ctx->pmeth == NULL || ctx->pmeth->decrypt == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_DECRYPT)
|
||||
return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
|
||||
}
|
||||
|
||||
/* decrypt to new buffer of dynamic size, checking any pre-determined size */
|
||||
int evp_pkey_decrypt_alloc(EVP_PKEY_CTX *ctx, unsigned char **outp,
|
||||
size_t *outlenp, size_t expected_outlen,
|
||||
const unsigned char *in, size_t inlen)
|
||||
{
|
||||
if (EVP_PKEY_decrypt(ctx, NULL, outlenp, in, inlen) <= 0
|
||||
|| (*outp = OPENSSL_malloc(*outlenp)) == NULL)
|
||||
return -1;
|
||||
if (EVP_PKEY_decrypt(ctx, *outp, outlenp, in, inlen) <= 0
|
||||
|| *outlenp == 0
|
||||
|| (expected_outlen != 0 && *outlenp != expected_outlen)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
OPENSSL_clear_free(*outp, *outlenp);
|
||||
*outp = NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov)
|
||||
{
|
||||
EVP_ASYM_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_ASYM_CIPHER));
|
||||
|
||||
if (cipher == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_NEW_REF(&cipher->refcnt, 1)
|
||||
|| !ossl_provider_up_ref(prov)) {
|
||||
CRYPTO_FREE_REF(&cipher->refcnt);
|
||||
OPENSSL_free(cipher);
|
||||
return NULL;
|
||||
}
|
||||
cipher->prov = prov;
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
static void *evp_asym_cipher_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_ASYM_CIPHER *cipher = NULL;
|
||||
int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
|
||||
int gparamfncnt = 0, sparamfncnt = 0;
|
||||
|
||||
if ((cipher = evp_asym_cipher_new(prov)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
cipher->name_id = name_id;
|
||||
if ((cipher->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
|
||||
goto err;
|
||||
cipher->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_ASYM_CIPHER_NEWCTX:
|
||||
if (cipher->newctx != NULL)
|
||||
break;
|
||||
cipher->newctx = OSSL_FUNC_asym_cipher_newctx(fns);
|
||||
ctxfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT:
|
||||
if (cipher->encrypt_init != NULL)
|
||||
break;
|
||||
cipher->encrypt_init = OSSL_FUNC_asym_cipher_encrypt_init(fns);
|
||||
encfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_ENCRYPT:
|
||||
if (cipher->encrypt != NULL)
|
||||
break;
|
||||
cipher->encrypt = OSSL_FUNC_asym_cipher_encrypt(fns);
|
||||
encfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT:
|
||||
if (cipher->decrypt_init != NULL)
|
||||
break;
|
||||
cipher->decrypt_init = OSSL_FUNC_asym_cipher_decrypt_init(fns);
|
||||
decfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_DECRYPT:
|
||||
if (cipher->decrypt != NULL)
|
||||
break;
|
||||
cipher->decrypt = OSSL_FUNC_asym_cipher_decrypt(fns);
|
||||
decfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_FREECTX:
|
||||
if (cipher->freectx != NULL)
|
||||
break;
|
||||
cipher->freectx = OSSL_FUNC_asym_cipher_freectx(fns);
|
||||
ctxfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_DUPCTX:
|
||||
if (cipher->dupctx != NULL)
|
||||
break;
|
||||
cipher->dupctx = OSSL_FUNC_asym_cipher_dupctx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS:
|
||||
if (cipher->get_ctx_params != NULL)
|
||||
break;
|
||||
cipher->get_ctx_params
|
||||
= OSSL_FUNC_asym_cipher_get_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS:
|
||||
if (cipher->gettable_ctx_params != NULL)
|
||||
break;
|
||||
cipher->gettable_ctx_params
|
||||
= OSSL_FUNC_asym_cipher_gettable_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS:
|
||||
if (cipher->set_ctx_params != NULL)
|
||||
break;
|
||||
cipher->set_ctx_params
|
||||
= OSSL_FUNC_asym_cipher_set_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS:
|
||||
if (cipher->settable_ctx_params != NULL)
|
||||
break;
|
||||
cipher->settable_ctx_params
|
||||
= OSSL_FUNC_asym_cipher_settable_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ctxfncnt != 2
|
||||
|| (encfncnt != 0 && encfncnt != 2)
|
||||
|| (decfncnt != 0 && decfncnt != 2)
|
||||
|| (encfncnt != 2 && decfncnt != 2)
|
||||
|| (gparamfncnt != 0 && gparamfncnt != 2)
|
||||
|| (sparamfncnt != 0 && sparamfncnt != 2)) {
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a set of context functions (newctx and freectx) as well as a pair of
|
||||
* "cipher" functions: (encrypt_init, encrypt) or
|
||||
* (decrypt_init decrypt). set_ctx_params and settable_ctx_params are
|
||||
* optional, but if one of them is present then the other one must also
|
||||
* be present. The same applies to get_ctx_params and
|
||||
* gettable_ctx_params. The dupctx function is optional.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return cipher;
|
||||
err:
|
||||
EVP_ASYM_CIPHER_free(cipher);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cipher == NULL)
|
||||
return;
|
||||
CRYPTO_DOWN_REF(&cipher->refcnt, &i);
|
||||
if (i > 0)
|
||||
return;
|
||||
OPENSSL_free(cipher->type_name);
|
||||
ossl_provider_free(cipher->prov);
|
||||
CRYPTO_FREE_REF(&cipher->refcnt);
|
||||
OPENSSL_free(cipher);
|
||||
}
|
||||
|
||||
int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&cipher->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_PROVIDER *EVP_ASYM_CIPHER_get0_provider(const EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
return cipher->prov;
|
||||
}
|
||||
|
||||
EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_ASYM_CIPHER, algorithm, properties,
|
||||
evp_asym_cipher_from_algorithm,
|
||||
evp_asym_cipher_up_ref,
|
||||
evp_asym_cipher_free);
|
||||
}
|
||||
|
||||
EVP_ASYM_CIPHER *evp_asym_cipher_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov, OSSL_OP_ASYM_CIPHER,
|
||||
algorithm, properties,
|
||||
evp_asym_cipher_from_algorithm,
|
||||
evp_asym_cipher_up_ref,
|
||||
evp_asym_cipher_free);
|
||||
}
|
||||
|
||||
int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name)
|
||||
{
|
||||
return evp_is_a(cipher->prov, cipher->name_id, NULL, name);
|
||||
}
|
||||
|
||||
int evp_asym_cipher_get_number(const EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
return cipher->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_ASYM_CIPHER_get0_name(const EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
return cipher->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_ASYM_CIPHER_get0_description(const EVP_ASYM_CIPHER *cipher)
|
||||
{
|
||||
return cipher->description;
|
||||
}
|
||||
|
||||
void EVP_ASYM_CIPHER_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_ASYM_CIPHER *cipher,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_ASYM_CIPHER,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
evp_asym_cipher_from_algorithm,
|
||||
evp_asym_cipher_up_ref,
|
||||
evp_asym_cipher_free);
|
||||
}
|
||||
|
||||
|
||||
int EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (cipher->prov != NULL)
|
||||
return evp_names_do_all(cipher->prov, cipher->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_ASYM_CIPHER_gettable_ctx_params(const EVP_ASYM_CIPHER *cip)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (cip == NULL || cip->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_ASYM_CIPHER_get0_provider(cip));
|
||||
return cip->gettable_ctx_params(NULL, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_ASYM_CIPHER_settable_ctx_params(const EVP_ASYM_CIPHER *cip)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (cip == NULL || cip->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_ASYM_CIPHER_get0_provider(cip));
|
||||
return cip->settable_ctx_params(NULL, provctx);
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "internal/bio.h"
|
||||
|
||||
static int b64_write(BIO *h, const char *buf, int num);
|
||||
static int b64_read(BIO *h, char *buf, int size);
|
||||
static int b64_puts(BIO *h, const char *str);
|
||||
static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int b64_new(BIO *h);
|
||||
static int b64_free(BIO *data);
|
||||
static long b64_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
|
||||
#define B64_BLOCK_SIZE 1024
|
||||
#define B64_BLOCK_SIZE2 768
|
||||
#define B64_NONE 0
|
||||
#define B64_ENCODE 1
|
||||
#define B64_DECODE 2
|
||||
|
||||
typedef struct b64_struct {
|
||||
/*
|
||||
* BIO *bio; moved to the BIO structure
|
||||
*/
|
||||
int buf_len;
|
||||
int buf_off;
|
||||
int tmp_len; /* used to find the start when decoding */
|
||||
int tmp_nl; /* If true, scan until '\n' */
|
||||
int encode;
|
||||
int start; /* have we started decoding yet? */
|
||||
int cont; /* <= 0 when finished */
|
||||
EVP_ENCODE_CTX *base64;
|
||||
unsigned char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE) + 10];
|
||||
unsigned char tmp[B64_BLOCK_SIZE];
|
||||
} BIO_B64_CTX;
|
||||
|
||||
static const BIO_METHOD methods_b64 = {
|
||||
BIO_TYPE_BASE64,
|
||||
"base64 encoding",
|
||||
bwrite_conv,
|
||||
b64_write,
|
||||
bread_conv,
|
||||
b64_read,
|
||||
b64_puts,
|
||||
NULL, /* b64_gets, */
|
||||
b64_ctrl,
|
||||
b64_new,
|
||||
b64_free,
|
||||
b64_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_base64(void)
|
||||
{
|
||||
return &methods_b64;
|
||||
}
|
||||
|
||||
static int b64_new(BIO *bi)
|
||||
{
|
||||
BIO_B64_CTX *ctx;
|
||||
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
|
||||
return 0;
|
||||
|
||||
ctx->cont = 1;
|
||||
ctx->start = 1;
|
||||
ctx->base64 = EVP_ENCODE_CTX_new();
|
||||
if (ctx->base64 == NULL) {
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIO_set_data(bi, ctx);
|
||||
BIO_set_init(bi, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int b64_free(BIO *a)
|
||||
{
|
||||
BIO_B64_CTX *ctx;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(a);
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
EVP_ENCODE_CTX_free(ctx->base64);
|
||||
OPENSSL_free(ctx);
|
||||
BIO_set_data(a, NULL);
|
||||
BIO_set_init(a, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless `BIO_FLAGS_BASE64_NO_NL` is set, this BIO ignores leading lines that
|
||||
* aren't exclusively composed of valid Base64 characters (followed by <CRLF>
|
||||
* or <LF>). Once a valid Base64 line is found, `ctx->start` is set to 0 and
|
||||
* lines are processed until EOF or the first line that contains invalid Base64
|
||||
* characters. In a nod to PEM, lines that start with a '-' (hyphen) are
|
||||
* treated as a soft EOF, rather than an error.
|
||||
*/
|
||||
static int b64_read(BIO *b, char *out, int outl)
|
||||
{
|
||||
int ret = 0, i, ii, j, k, x, n, num, ret_code;
|
||||
BIO_B64_CTX *ctx;
|
||||
unsigned char *p, *q;
|
||||
BIO *next;
|
||||
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
ctx = (BIO_B64_CTX *)BIO_get_data(b);
|
||||
|
||||
next = BIO_next(b);
|
||||
if (ctx == NULL || next == NULL)
|
||||
return 0;
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
|
||||
if (ctx->encode != B64_DECODE) {
|
||||
ctx->encode = B64_DECODE;
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
ctx->tmp_len = 0;
|
||||
EVP_DecodeInit(ctx->base64);
|
||||
}
|
||||
|
||||
/* First check if there are buffered bytes already decoded */
|
||||
if (ctx->buf_len > 0) {
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
i = ctx->buf_len - ctx->buf_off;
|
||||
if (i > outl)
|
||||
i = outl;
|
||||
OPENSSL_assert(ctx->buf_off + i < (int)sizeof(ctx->buf));
|
||||
memcpy(out, &(ctx->buf[ctx->buf_off]), i);
|
||||
ret = i;
|
||||
out += i;
|
||||
outl -= i;
|
||||
ctx->buf_off += i;
|
||||
if (ctx->buf_len == ctx->buf_off) {
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore any non-retriable error condition (ctx->cont < 0) */
|
||||
ret_code = ctx->cont < 0 ? ctx->cont : 0;
|
||||
|
||||
/*
|
||||
* At this point, we have room of outl bytes and an either an empty buffer,
|
||||
* or outl == 0, so we'll attempt to read in some more.
|
||||
*/
|
||||
while (outl > 0) {
|
||||
int again = ctx->cont;
|
||||
|
||||
if (again <= 0)
|
||||
break;
|
||||
|
||||
i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]),
|
||||
B64_BLOCK_SIZE - ctx->tmp_len);
|
||||
|
||||
if (i <= 0) {
|
||||
ret_code = i;
|
||||
|
||||
/* Should we continue next time we are called? */
|
||||
if (!BIO_should_retry(next)) {
|
||||
/* Incomplete final Base64 chunk in the decoder is an error */
|
||||
if (ctx->tmp_len == 0) {
|
||||
if (EVP_DecodeFinal(ctx->base64, NULL, &num) < 0)
|
||||
ret_code = -1;
|
||||
EVP_DecodeInit(ctx->base64);
|
||||
}
|
||||
ctx->cont = ret_code;
|
||||
}
|
||||
if (ctx->tmp_len == 0)
|
||||
break;
|
||||
/* Fall through and process what we have */
|
||||
i = 0;
|
||||
/* But don't loop to top-up even if the buffer is not full! */
|
||||
again = 0;
|
||||
}
|
||||
|
||||
i += ctx->tmp_len;
|
||||
ctx->tmp_len = i;
|
||||
|
||||
/*
|
||||
* We need to scan, a line at a time until we have a valid line if we
|
||||
* are starting.
|
||||
*/
|
||||
if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) != 0) {
|
||||
ctx->tmp_len = 0;
|
||||
} else if (ctx->start) {
|
||||
q = p = ctx->tmp;
|
||||
num = 0;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (*(q++) != '\n')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* due to a previous very long line, we need to keep on
|
||||
* scanning for a '\n' before we even start looking for
|
||||
* base64 encoded stuff.
|
||||
*/
|
||||
if (ctx->tmp_nl) {
|
||||
p = q;
|
||||
ctx->tmp_nl = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
k = EVP_DecodeUpdate(ctx->base64, ctx->buf, &num, p, q - p);
|
||||
EVP_DecodeInit(ctx->base64);
|
||||
if (k <= 0 && num == 0) {
|
||||
p = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx->start = 0;
|
||||
if (p != ctx->tmp) {
|
||||
i -= p - ctx->tmp;
|
||||
for (x = 0; x < i; x++)
|
||||
ctx->tmp[x] = p[x];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* we fell off the end without starting */
|
||||
if (ctx->start) {
|
||||
/*
|
||||
* Is this is one long chunk?, if so, keep on reading until a
|
||||
* new line.
|
||||
*/
|
||||
if (p == ctx->tmp) {
|
||||
/* Check buffer full */
|
||||
if (i == B64_BLOCK_SIZE) {
|
||||
ctx->tmp_nl = 1;
|
||||
ctx->tmp_len = 0;
|
||||
}
|
||||
} else if (p != q) {
|
||||
/* Retain partial line at end of buffer */
|
||||
n = q - p;
|
||||
for (ii = 0; ii < n; ii++)
|
||||
ctx->tmp[ii] = p[ii];
|
||||
ctx->tmp_len = n;
|
||||
} else {
|
||||
/* All we have is newline terminated non-start data */
|
||||
ctx->tmp_len = 0;
|
||||
}
|
||||
/*
|
||||
* Try to read more if possible, otherwise we can't make
|
||||
* progress unless the underlying BIO is retriable and may
|
||||
* produce more data next time we're called.
|
||||
*/
|
||||
if (again > 0)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
ctx->tmp_len = 0;
|
||||
}
|
||||
} else if (i < B64_BLOCK_SIZE && again > 0) {
|
||||
/*
|
||||
* If buffer isn't full and we can retry then restart to read in
|
||||
* more data.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
i = EVP_DecodeUpdate(ctx->base64, ctx->buf, &ctx->buf_len,
|
||||
ctx->tmp, i);
|
||||
ctx->tmp_len = 0;
|
||||
/*
|
||||
* If eof or an error was signalled, then the condition
|
||||
* 'ctx->cont <= 0' will prevent b64_read() from reading
|
||||
* more data on subsequent calls. This assignment was
|
||||
* deleted accidentally in commit 5562cfaca4f3.
|
||||
*/
|
||||
ctx->cont = i;
|
||||
|
||||
ctx->buf_off = 0;
|
||||
if (i < 0) {
|
||||
ret_code = ctx->start ? 0 : i;
|
||||
ctx->buf_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->buf_len <= outl)
|
||||
i = ctx->buf_len;
|
||||
else
|
||||
i = outl;
|
||||
|
||||
memcpy(out, ctx->buf, i);
|
||||
ret += i;
|
||||
ctx->buf_off = i;
|
||||
if (ctx->buf_off == ctx->buf_len) {
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
outl -= i;
|
||||
out += i;
|
||||
}
|
||||
/* BIO_clear_retry_flags(b); */
|
||||
BIO_copy_next_retry(b);
|
||||
return ret == 0 ? ret_code : ret;
|
||||
}
|
||||
|
||||
static int b64_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
int ret = 0;
|
||||
int n;
|
||||
int i;
|
||||
BIO_B64_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
ctx = (BIO_B64_CTX *)BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if (ctx == NULL || next == NULL)
|
||||
return 0;
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
|
||||
if (ctx->encode != B64_ENCODE) {
|
||||
ctx->encode = B64_ENCODE;
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
ctx->tmp_len = 0;
|
||||
EVP_EncodeInit(ctx->base64);
|
||||
}
|
||||
|
||||
OPENSSL_assert(ctx->buf_off < (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
n = ctx->buf_len - ctx->buf_off;
|
||||
while (n > 0) {
|
||||
i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
return i;
|
||||
}
|
||||
OPENSSL_assert(i <= n);
|
||||
ctx->buf_off += i;
|
||||
OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
n -= i;
|
||||
}
|
||||
/* at this point all pending data has been written */
|
||||
ctx->buf_off = 0;
|
||||
ctx->buf_len = 0;
|
||||
|
||||
if (in == NULL || inl <= 0)
|
||||
return 0;
|
||||
|
||||
while (inl > 0) {
|
||||
n = inl > B64_BLOCK_SIZE ? B64_BLOCK_SIZE : inl;
|
||||
|
||||
if ((BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) != 0) {
|
||||
if (ctx->tmp_len > 0) {
|
||||
OPENSSL_assert(ctx->tmp_len <= 3);
|
||||
n = 3 - ctx->tmp_len;
|
||||
/*
|
||||
* There's a theoretical possibility for this
|
||||
*/
|
||||
if (n > inl)
|
||||
n = inl;
|
||||
memcpy(&(ctx->tmp[ctx->tmp_len]), in, n);
|
||||
ctx->tmp_len += n;
|
||||
ret += n;
|
||||
if (ctx->tmp_len < 3)
|
||||
break;
|
||||
ctx->buf_len =
|
||||
EVP_EncodeBlock(ctx->buf, ctx->tmp, ctx->tmp_len);
|
||||
OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
/*
|
||||
* Since we're now done using the temporary buffer, the
|
||||
* length should be 0'd
|
||||
*/
|
||||
ctx->tmp_len = 0;
|
||||
} else {
|
||||
if (n < 3) {
|
||||
memcpy(ctx->tmp, in, n);
|
||||
ctx->tmp_len = n;
|
||||
ret += n;
|
||||
break;
|
||||
}
|
||||
n -= n % 3;
|
||||
ctx->buf_len =
|
||||
EVP_EncodeBlock(ctx->buf, (unsigned char *)in, n);
|
||||
OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
ret += n;
|
||||
}
|
||||
} else {
|
||||
if (!EVP_EncodeUpdate(ctx->base64, ctx->buf, &ctx->buf_len,
|
||||
(unsigned char *)in, n))
|
||||
return ret == 0 ? -1 : ret;
|
||||
OPENSSL_assert(ctx->buf_len <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
ret += n;
|
||||
}
|
||||
inl -= n;
|
||||
in += n;
|
||||
|
||||
ctx->buf_off = 0;
|
||||
n = ctx->buf_len;
|
||||
while (n > 0) {
|
||||
i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
return ret == 0 ? i : ret;
|
||||
}
|
||||
OPENSSL_assert(i <= n);
|
||||
n -= i;
|
||||
ctx->buf_off += i;
|
||||
OPENSSL_assert(ctx->buf_off <= (int)sizeof(ctx->buf));
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
}
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long b64_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
BIO_B64_CTX *ctx;
|
||||
long ret = 1;
|
||||
int i;
|
||||
BIO *next;
|
||||
|
||||
ctx = (BIO_B64_CTX *)BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if (ctx == NULL || next == NULL)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
ctx->cont = 1;
|
||||
ctx->start = 1;
|
||||
ctx->encode = B64_NONE;
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_EOF: /* More to read */
|
||||
if (ctx->cont <= 0)
|
||||
ret = 1;
|
||||
else
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_WPENDING: /* More to write in buffer */
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
ret = ctx->buf_len - ctx->buf_off;
|
||||
if (ret == 0 && ctx->encode != B64_NONE
|
||||
&& EVP_ENCODE_CTX_num(ctx->base64) != 0)
|
||||
ret = 1;
|
||||
else if (ret <= 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_PENDING: /* More to read in buffer */
|
||||
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
|
||||
ret = ctx->buf_len - ctx->buf_off;
|
||||
if (ret <= 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_FLUSH:
|
||||
/* do a final write */
|
||||
again:
|
||||
while (ctx->buf_len != ctx->buf_off) {
|
||||
i = b64_write(b, NULL, 0);
|
||||
if (i < 0)
|
||||
return i;
|
||||
}
|
||||
if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) {
|
||||
if (ctx->tmp_len != 0) {
|
||||
ctx->buf_len = EVP_EncodeBlock(ctx->buf,
|
||||
ctx->tmp, ctx->tmp_len);
|
||||
ctx->buf_off = 0;
|
||||
ctx->tmp_len = 0;
|
||||
goto again;
|
||||
}
|
||||
} else if (ctx->encode != B64_NONE
|
||||
&& EVP_ENCODE_CTX_num(ctx->base64) != 0) {
|
||||
ctx->buf_off = 0;
|
||||
EVP_EncodeFinal(ctx->base64, ctx->buf, &(ctx->buf_len));
|
||||
/* push out the bytes */
|
||||
goto again;
|
||||
}
|
||||
/* Finally flush the underlying BIO */
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
BIO_clear_retry_flags(b);
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
|
||||
case BIO_CTRL_DUP:
|
||||
break;
|
||||
case BIO_CTRL_INFO:
|
||||
case BIO_CTRL_GET:
|
||||
case BIO_CTRL_SET:
|
||||
default:
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long b64_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
|
||||
{
|
||||
BIO *next = BIO_next(b);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
return BIO_callback_ctrl(next, cmd, fp);
|
||||
}
|
||||
|
||||
static int b64_puts(BIO *b, const char *str)
|
||||
{
|
||||
return b64_write(b, str, strlen(str));
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED /* for BIO_get_callback */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "internal/bio.h"
|
||||
|
||||
static int enc_write(BIO *h, const char *buf, int num);
|
||||
static int enc_read(BIO *h, char *buf, int size);
|
||||
static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int enc_new(BIO *h);
|
||||
static int enc_free(BIO *data);
|
||||
static long enc_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fps);
|
||||
#define ENC_BLOCK_SIZE (1024*4)
|
||||
#define ENC_MIN_CHUNK (256)
|
||||
#define BUF_OFFSET (ENC_MIN_CHUNK + EVP_MAX_BLOCK_LENGTH)
|
||||
|
||||
typedef struct enc_struct {
|
||||
int buf_len;
|
||||
int buf_off;
|
||||
int cont; /* <= 0 when finished */
|
||||
int finished;
|
||||
int ok; /* bad decrypt */
|
||||
EVP_CIPHER_CTX *cipher;
|
||||
unsigned char *read_start, *read_end;
|
||||
/*
|
||||
* buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return
|
||||
* up to a block more data than is presented to it
|
||||
*/
|
||||
unsigned char buf[BUF_OFFSET + ENC_BLOCK_SIZE];
|
||||
} BIO_ENC_CTX;
|
||||
|
||||
static const BIO_METHOD methods_enc = {
|
||||
BIO_TYPE_CIPHER,
|
||||
"cipher",
|
||||
bwrite_conv,
|
||||
enc_write,
|
||||
bread_conv,
|
||||
enc_read,
|
||||
NULL, /* enc_puts, */
|
||||
NULL, /* enc_gets, */
|
||||
enc_ctrl,
|
||||
enc_new,
|
||||
enc_free,
|
||||
enc_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_cipher(void)
|
||||
{
|
||||
return &methods_enc;
|
||||
}
|
||||
|
||||
static int enc_new(BIO *bi)
|
||||
{
|
||||
BIO_ENC_CTX *ctx;
|
||||
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
|
||||
return 0;
|
||||
|
||||
ctx->cipher = EVP_CIPHER_CTX_new();
|
||||
if (ctx->cipher == NULL) {
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
ctx->cont = 1;
|
||||
ctx->ok = 1;
|
||||
ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]);
|
||||
BIO_set_data(bi, ctx);
|
||||
BIO_set_init(bi, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int enc_free(BIO *a)
|
||||
{
|
||||
BIO_ENC_CTX *b;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
b = BIO_get_data(a);
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
|
||||
EVP_CIPHER_CTX_free(b->cipher);
|
||||
OPENSSL_clear_free(b, sizeof(BIO_ENC_CTX));
|
||||
BIO_set_data(a, NULL);
|
||||
BIO_set_init(a, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int enc_read(BIO *b, char *out, int outl)
|
||||
{
|
||||
int ret = 0, i, blocksize;
|
||||
BIO_ENC_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
ctx = BIO_get_data(b);
|
||||
|
||||
next = BIO_next(b);
|
||||
if ((ctx == NULL) || (next == NULL))
|
||||
return 0;
|
||||
|
||||
/* First check if there are bytes decoded/encoded */
|
||||
if (ctx->buf_len > 0) {
|
||||
i = ctx->buf_len - ctx->buf_off;
|
||||
if (i > outl)
|
||||
i = outl;
|
||||
memcpy(out, &(ctx->buf[ctx->buf_off]), i);
|
||||
ret = i;
|
||||
out += i;
|
||||
outl -= i;
|
||||
ctx->buf_off += i;
|
||||
if (ctx->buf_len == ctx->buf_off) {
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
}
|
||||
|
||||
blocksize = EVP_CIPHER_CTX_get_block_size(ctx->cipher);
|
||||
|
||||
if (blocksize == 0)
|
||||
return 0;
|
||||
|
||||
if (blocksize == 1)
|
||||
blocksize = 0;
|
||||
|
||||
/*
|
||||
* At this point, we have room of outl bytes and an empty buffer, so we
|
||||
* should read in some more.
|
||||
*/
|
||||
|
||||
while (outl > 0) {
|
||||
if (ctx->cont <= 0)
|
||||
break;
|
||||
|
||||
if (ctx->read_start == ctx->read_end) { /* time to read more data */
|
||||
ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]);
|
||||
i = BIO_read(next, ctx->read_start, ENC_BLOCK_SIZE);
|
||||
if (i > 0)
|
||||
ctx->read_end += i;
|
||||
} else {
|
||||
i = ctx->read_end - ctx->read_start;
|
||||
}
|
||||
|
||||
if (i <= 0) {
|
||||
/* Should be continue next time we are called? */
|
||||
if (!BIO_should_retry(next)) {
|
||||
ctx->cont = i;
|
||||
i = EVP_CipherFinal_ex(ctx->cipher,
|
||||
ctx->buf, &(ctx->buf_len));
|
||||
ctx->ok = i;
|
||||
ctx->buf_off = 0;
|
||||
} else {
|
||||
ret = (ret == 0) ? i : ret;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (outl > ENC_MIN_CHUNK) {
|
||||
/*
|
||||
* Depending on flags block cipher decrypt can write
|
||||
* one extra block and then back off, i.e. output buffer
|
||||
* has to accommodate extra block...
|
||||
*/
|
||||
int j = outl - blocksize, buf_len;
|
||||
|
||||
if (!EVP_CipherUpdate(ctx->cipher,
|
||||
(unsigned char *)out, &buf_len,
|
||||
ctx->read_start, i > j ? j : i)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
ret += buf_len;
|
||||
out += buf_len;
|
||||
outl -= buf_len;
|
||||
|
||||
if ((i -= j) <= 0) {
|
||||
ctx->read_start = ctx->read_end;
|
||||
continue;
|
||||
}
|
||||
ctx->read_start += j;
|
||||
}
|
||||
if (i > ENC_MIN_CHUNK)
|
||||
i = ENC_MIN_CHUNK;
|
||||
if (!EVP_CipherUpdate(ctx->cipher,
|
||||
ctx->buf, &ctx->buf_len,
|
||||
ctx->read_start, i)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
ctx->ok = 0;
|
||||
return 0;
|
||||
}
|
||||
ctx->read_start += i;
|
||||
ctx->cont = 1;
|
||||
/*
|
||||
* Note: it is possible for EVP_CipherUpdate to decrypt zero
|
||||
* bytes because this is or looks like the final block: if this
|
||||
* happens we should retry and either read more data or decrypt
|
||||
* the final block
|
||||
*/
|
||||
if (ctx->buf_len == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->buf_len <= outl)
|
||||
i = ctx->buf_len;
|
||||
else
|
||||
i = outl;
|
||||
if (i <= 0)
|
||||
break;
|
||||
memcpy(out, ctx->buf, i);
|
||||
ret += i;
|
||||
ctx->buf_off = i;
|
||||
outl -= i;
|
||||
out += i;
|
||||
}
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
return ((ret == 0) ? ctx->cont : ret);
|
||||
}
|
||||
|
||||
static int enc_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
int ret = 0, n, i;
|
||||
BIO_ENC_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if ((ctx == NULL) || (next == NULL))
|
||||
return 0;
|
||||
|
||||
ret = inl;
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
n = ctx->buf_len - ctx->buf_off;
|
||||
while (n > 0) {
|
||||
i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
return i;
|
||||
}
|
||||
ctx->buf_off += i;
|
||||
n -= i;
|
||||
}
|
||||
/* at this point all pending data has been written */
|
||||
|
||||
if ((in == NULL) || (inl <= 0))
|
||||
return 0;
|
||||
|
||||
ctx->buf_off = 0;
|
||||
while (inl > 0) {
|
||||
n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl;
|
||||
if (!EVP_CipherUpdate(ctx->cipher,
|
||||
ctx->buf, &ctx->buf_len,
|
||||
(const unsigned char *)in, n)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
ctx->ok = 0;
|
||||
return 0;
|
||||
}
|
||||
inl -= n;
|
||||
in += n;
|
||||
|
||||
ctx->buf_off = 0;
|
||||
n = ctx->buf_len;
|
||||
while (n > 0) {
|
||||
i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
return (ret == inl) ? i : ret - inl;
|
||||
}
|
||||
n -= i;
|
||||
ctx->buf_off += i;
|
||||
}
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
BIO_copy_next_retry(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long enc_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
BIO *dbio;
|
||||
BIO_ENC_CTX *ctx, *dctx;
|
||||
long ret = 1;
|
||||
int i;
|
||||
EVP_CIPHER_CTX **c_ctx;
|
||||
BIO *next;
|
||||
int pend;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
ctx->ok = 1;
|
||||
ctx->finished = 0;
|
||||
if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx->cipher)))
|
||||
return 0;
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_EOF: /* More to read */
|
||||
if (ctx->cont <= 0)
|
||||
ret = 1;
|
||||
else
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_WPENDING:
|
||||
ret = ctx->buf_len - ctx->buf_off;
|
||||
if (ret <= 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_PENDING: /* More to read in buffer */
|
||||
ret = ctx->buf_len - ctx->buf_off;
|
||||
if (ret <= 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_FLUSH:
|
||||
/* do a final write */
|
||||
again:
|
||||
while (ctx->buf_len != ctx->buf_off) {
|
||||
pend = ctx->buf_len - ctx->buf_off;
|
||||
i = enc_write(b, NULL, 0);
|
||||
/*
|
||||
* i should never be > 0 here because we didn't ask to write any
|
||||
* new data. We stop if we get an error or we failed to make any
|
||||
* progress writing pending data.
|
||||
*/
|
||||
if (i < 0 || (ctx->buf_len - ctx->buf_off) == pend)
|
||||
return i;
|
||||
}
|
||||
|
||||
if (!ctx->finished) {
|
||||
ctx->finished = 1;
|
||||
ctx->buf_off = 0;
|
||||
ret = EVP_CipherFinal_ex(ctx->cipher,
|
||||
(unsigned char *)ctx->buf,
|
||||
&(ctx->buf_len));
|
||||
ctx->ok = (int)ret;
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
/* push out the bytes */
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* Finally flush the underlying BIO */
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
case BIO_C_GET_CIPHER_STATUS:
|
||||
ret = (long)ctx->ok;
|
||||
break;
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
BIO_clear_retry_flags(b);
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
case BIO_C_GET_CIPHER_CTX:
|
||||
c_ctx = (EVP_CIPHER_CTX **)ptr;
|
||||
*c_ctx = ctx->cipher;
|
||||
BIO_set_init(b, 1);
|
||||
break;
|
||||
case BIO_CTRL_DUP:
|
||||
dbio = (BIO *)ptr;
|
||||
dctx = BIO_get_data(dbio);
|
||||
dctx->cipher = EVP_CIPHER_CTX_new();
|
||||
if (dctx->cipher == NULL)
|
||||
return 0;
|
||||
ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher);
|
||||
if (ret)
|
||||
BIO_set_init(dbio, 1);
|
||||
break;
|
||||
default:
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long enc_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
|
||||
{
|
||||
BIO *next = BIO_next(b);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
return BIO_callback_ctrl(next, cmd, fp);
|
||||
}
|
||||
|
||||
int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
|
||||
const unsigned char *i, int e)
|
||||
{
|
||||
BIO_ENC_CTX *ctx;
|
||||
BIO_callback_fn_ex callback_ex;
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
long (*callback) (struct bio_st *, int, const char *, int, long, long) = NULL;
|
||||
#endif
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
if ((callback_ex = BIO_get_callback_ex(b)) != NULL) {
|
||||
if (callback_ex(b, BIO_CB_CTRL, (const char *)c, 0, BIO_CTRL_SET,
|
||||
e, 1, NULL) <= 0)
|
||||
return 0;
|
||||
}
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
else {
|
||||
callback = BIO_get_callback(b);
|
||||
|
||||
if ((callback != NULL) &&
|
||||
(callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e,
|
||||
0L) <= 0))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
BIO_set_init(b, 1);
|
||||
|
||||
if (!EVP_CipherInit_ex(ctx->cipher, c, NULL, k, i, e))
|
||||
return 0;
|
||||
|
||||
if (callback_ex != NULL)
|
||||
return callback_ex(b, BIO_CB_CTRL | BIO_CB_RETURN, (const char *)c, 0,
|
||||
BIO_CTRL_SET, e, 1, NULL);
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
else if (callback != NULL)
|
||||
return callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "internal/bio.h"
|
||||
|
||||
/*
|
||||
* BIO_put and BIO_get both add to the digest, BIO_gets returns the digest
|
||||
*/
|
||||
|
||||
static int md_write(BIO *h, char const *buf, int num);
|
||||
static int md_read(BIO *h, char *buf, int size);
|
||||
static int md_gets(BIO *h, char *str, int size);
|
||||
static long md_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int md_new(BIO *h);
|
||||
static int md_free(BIO *data);
|
||||
static long md_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
|
||||
|
||||
static const BIO_METHOD methods_md = {
|
||||
BIO_TYPE_MD,
|
||||
"message digest",
|
||||
bwrite_conv,
|
||||
md_write,
|
||||
bread_conv,
|
||||
md_read,
|
||||
NULL, /* md_puts, */
|
||||
md_gets,
|
||||
md_ctrl,
|
||||
md_new,
|
||||
md_free,
|
||||
md_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_md(void)
|
||||
{
|
||||
return &methods_md;
|
||||
}
|
||||
|
||||
static int md_new(BIO *bi)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
ctx = EVP_MD_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
BIO_set_init(bi, 1);
|
||||
BIO_set_data(bi, ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int md_free(BIO *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
EVP_MD_CTX_free(BIO_get_data(a));
|
||||
BIO_set_data(a, NULL);
|
||||
BIO_set_init(a, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int md_read(BIO *b, char *out, int outl)
|
||||
{
|
||||
int ret = 0;
|
||||
EVP_MD_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
|
||||
if ((ctx == NULL) || (next == NULL))
|
||||
return 0;
|
||||
|
||||
ret = BIO_read(next, out, outl);
|
||||
if (BIO_get_init(b)) {
|
||||
if (ret > 0) {
|
||||
if (EVP_DigestUpdate(ctx, (unsigned char *)out,
|
||||
(unsigned int)ret) <= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int md_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
int ret = 0;
|
||||
EVP_MD_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
if ((in == NULL) || (inl <= 0))
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if ((ctx != NULL) && (next != NULL))
|
||||
ret = BIO_write(next, in, inl);
|
||||
|
||||
if (BIO_get_init(b)) {
|
||||
if (ret > 0) {
|
||||
if (!EVP_DigestUpdate(ctx, (const unsigned char *)in,
|
||||
(unsigned int)ret)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next != NULL) {
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long md_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
EVP_MD_CTX *ctx, *dctx, **pctx;
|
||||
const EVP_MD **ppmd;
|
||||
EVP_MD *md;
|
||||
long ret = 1;
|
||||
BIO *dbio, *next;
|
||||
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
if (BIO_get_init(b))
|
||||
ret = EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL);
|
||||
else
|
||||
ret = 0;
|
||||
if (ret > 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_C_GET_MD:
|
||||
if (BIO_get_init(b)) {
|
||||
ppmd = ptr;
|
||||
*ppmd = EVP_MD_CTX_get0_md(ctx);
|
||||
} else
|
||||
ret = 0;
|
||||
break;
|
||||
case BIO_C_GET_MD_CTX:
|
||||
pctx = ptr;
|
||||
*pctx = ctx;
|
||||
BIO_set_init(b, 1);
|
||||
break;
|
||||
case BIO_C_SET_MD_CTX:
|
||||
if (BIO_get_init(b))
|
||||
BIO_set_data(b, ptr);
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
BIO_clear_retry_flags(b);
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
|
||||
case BIO_C_SET_MD:
|
||||
md = ptr;
|
||||
ret = EVP_DigestInit_ex(ctx, md, NULL);
|
||||
if (ret > 0)
|
||||
BIO_set_init(b, 1);
|
||||
break;
|
||||
case BIO_CTRL_DUP:
|
||||
dbio = ptr;
|
||||
dctx = BIO_get_data(dbio);
|
||||
if (!EVP_MD_CTX_copy_ex(dctx, ctx))
|
||||
return 0;
|
||||
BIO_set_init(b, 1);
|
||||
break;
|
||||
default:
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long md_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
|
||||
{
|
||||
BIO *next;
|
||||
|
||||
next = BIO_next(b);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
return BIO_callback_ctrl(next, cmd, fp);
|
||||
}
|
||||
|
||||
static int md_gets(BIO *bp, char *buf, int size)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
unsigned int ret;
|
||||
|
||||
ctx = BIO_get_data(bp);
|
||||
|
||||
if (size < EVP_MD_CTX_get_size(ctx))
|
||||
return 0;
|
||||
|
||||
if (EVP_DigestFinal_ex(ctx, (unsigned char *)buf, &ret) <= 0)
|
||||
return -1;
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*-
|
||||
From: Arne Ansper
|
||||
|
||||
Why BIO_f_reliable?
|
||||
|
||||
I wrote function which took BIO* as argument, read data from it
|
||||
and processed it. Then I wanted to store the input file in
|
||||
encrypted form. OK I pushed BIO_f_cipher to the BIO stack
|
||||
and everything was OK. BUT if user types wrong password
|
||||
BIO_f_cipher outputs only garbage and my function crashes. Yes
|
||||
I can and I should fix my function, but BIO_f_cipher is
|
||||
easy way to add encryption support to many existing applications
|
||||
and it's hard to debug and fix them all.
|
||||
|
||||
So I wanted another BIO which would catch the incorrect passwords and
|
||||
file damages which cause garbage on BIO_f_cipher's output.
|
||||
|
||||
The easy way is to push the BIO_f_md and save the checksum at
|
||||
the end of the file. However there are several problems with this
|
||||
approach:
|
||||
|
||||
1) you must somehow separate checksum from actual data.
|
||||
2) you need lot's of memory when reading the file, because you
|
||||
must read to the end of the file and verify the checksum before
|
||||
letting the application to read the data.
|
||||
|
||||
BIO_f_reliable tries to solve both problems, so that you can
|
||||
read and write arbitrary long streams using only fixed amount
|
||||
of memory.
|
||||
|
||||
BIO_f_reliable splits data stream into blocks. Each block is prefixed
|
||||
with its length and suffixed with its digest. So you need only
|
||||
several Kbytes of memory to buffer single block before verifying
|
||||
its digest.
|
||||
|
||||
BIO_f_reliable goes further and adds several important capabilities:
|
||||
|
||||
1) the digest of the block is computed over the whole stream
|
||||
-- so nobody can rearrange the blocks or remove or replace them.
|
||||
|
||||
2) to detect invalid passwords right at the start BIO_f_reliable
|
||||
adds special prefix to the stream. In order to avoid known plain-text
|
||||
attacks this prefix is generated as follows:
|
||||
|
||||
*) digest is initialized with random seed instead of
|
||||
standardized one.
|
||||
*) same seed is written to output
|
||||
*) well-known text is then hashed and the output
|
||||
of the digest is also written to output.
|
||||
|
||||
reader can now read the seed from stream, hash the same string
|
||||
and then compare the digest output.
|
||||
|
||||
Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
|
||||
initially wrote and tested this code on x86 machine and wrote the
|
||||
digests out in machine-dependent order :( There are people using
|
||||
this code and I cannot change this easily without making existing
|
||||
data files unreadable.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include "internal/bio.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "internal/endian.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
static int ok_write(BIO *h, const char *buf, int num);
|
||||
static int ok_read(BIO *h, char *buf, int size);
|
||||
static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int ok_new(BIO *h);
|
||||
static int ok_free(BIO *data);
|
||||
static long ok_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
|
||||
|
||||
static __owur int sig_out(BIO *b);
|
||||
static __owur int sig_in(BIO *b);
|
||||
static __owur int block_out(BIO *b);
|
||||
static __owur int block_in(BIO *b);
|
||||
#define OK_BLOCK_SIZE (1024*4)
|
||||
#define OK_BLOCK_BLOCK 4
|
||||
#define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
|
||||
#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
|
||||
|
||||
typedef struct ok_struct {
|
||||
size_t buf_len;
|
||||
size_t buf_off;
|
||||
size_t buf_len_save;
|
||||
size_t buf_off_save;
|
||||
int cont; /* <= 0 when finished */
|
||||
int finished;
|
||||
EVP_MD_CTX *md;
|
||||
int blockout; /* output block is ready */
|
||||
int sigio; /* must process signature */
|
||||
unsigned char buf[IOBS];
|
||||
} BIO_OK_CTX;
|
||||
|
||||
static const BIO_METHOD methods_ok = {
|
||||
BIO_TYPE_CIPHER,
|
||||
"reliable",
|
||||
bwrite_conv,
|
||||
ok_write,
|
||||
bread_conv,
|
||||
ok_read,
|
||||
NULL, /* ok_puts, */
|
||||
NULL, /* ok_gets, */
|
||||
ok_ctrl,
|
||||
ok_new,
|
||||
ok_free,
|
||||
ok_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_reliable(void)
|
||||
{
|
||||
return &methods_ok;
|
||||
}
|
||||
|
||||
static int ok_new(BIO *bi)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
|
||||
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
|
||||
return 0;
|
||||
|
||||
ctx->cont = 1;
|
||||
ctx->sigio = 1;
|
||||
ctx->md = EVP_MD_CTX_new();
|
||||
if (ctx->md == NULL) {
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
BIO_set_init(bi, 0);
|
||||
BIO_set_data(bi, ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ok_free(BIO *a)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(a);
|
||||
|
||||
EVP_MD_CTX_free(ctx->md);
|
||||
OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
|
||||
BIO_set_data(a, NULL);
|
||||
BIO_set_init(a, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ok_read(BIO *b, char *out, int outl)
|
||||
{
|
||||
int ret = 0, i, n;
|
||||
BIO_OK_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
|
||||
if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
|
||||
return 0;
|
||||
|
||||
while (outl > 0) {
|
||||
|
||||
/* copy clean bytes to output buffer */
|
||||
if (ctx->blockout) {
|
||||
i = ctx->buf_len - ctx->buf_off;
|
||||
if (i > outl)
|
||||
i = outl;
|
||||
memcpy(out, &(ctx->buf[ctx->buf_off]), i);
|
||||
ret += i;
|
||||
out += i;
|
||||
outl -= i;
|
||||
ctx->buf_off += i;
|
||||
|
||||
/* all clean bytes are out */
|
||||
if (ctx->buf_len == ctx->buf_off) {
|
||||
ctx->buf_off = 0;
|
||||
|
||||
/*
|
||||
* copy start of the next block into proper place
|
||||
*/
|
||||
if (ctx->buf_len_save > ctx->buf_off_save) {
|
||||
ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
|
||||
memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
|
||||
ctx->buf_len);
|
||||
} else {
|
||||
ctx->buf_len = 0;
|
||||
}
|
||||
ctx->blockout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* output buffer full -- cancel */
|
||||
if (outl == 0)
|
||||
break;
|
||||
|
||||
/* no clean bytes in buffer -- fill it */
|
||||
n = IOBS - ctx->buf_len;
|
||||
i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
|
||||
|
||||
if (i <= 0)
|
||||
break; /* nothing new */
|
||||
|
||||
ctx->buf_len += i;
|
||||
|
||||
/* no signature yet -- check if we got one */
|
||||
if (ctx->sigio == 1) {
|
||||
if (!sig_in(b)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* signature ok -- check if we got block */
|
||||
if (ctx->sigio == 0) {
|
||||
if (!block_in(b)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* invalid block -- cancel */
|
||||
if (ctx->cont <= 0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ok_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
int ret = 0, n, i;
|
||||
BIO_OK_CTX *ctx;
|
||||
BIO *next;
|
||||
|
||||
if (inl <= 0)
|
||||
return inl;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
ret = inl;
|
||||
|
||||
if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
|
||||
return 0;
|
||||
|
||||
if (ctx->sigio && !sig_out(b))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
BIO_clear_retry_flags(b);
|
||||
n = ctx->buf_len - ctx->buf_off;
|
||||
while (ctx->blockout && n > 0) {
|
||||
i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
if (!BIO_should_retry(b))
|
||||
ctx->cont = 0;
|
||||
return i;
|
||||
}
|
||||
ctx->buf_off += i;
|
||||
n -= i;
|
||||
}
|
||||
|
||||
/* at this point all pending data has been written */
|
||||
ctx->blockout = 0;
|
||||
if (ctx->buf_len == ctx->buf_off) {
|
||||
ctx->buf_len = OK_BLOCK_BLOCK;
|
||||
ctx->buf_off = 0;
|
||||
}
|
||||
|
||||
if ((in == NULL) || (inl <= 0))
|
||||
return 0;
|
||||
|
||||
n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
|
||||
(int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
|
||||
|
||||
memcpy(&ctx->buf[ctx->buf_len], in, n);
|
||||
ctx->buf_len += n;
|
||||
inl -= n;
|
||||
in += n;
|
||||
|
||||
if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
|
||||
if (!block_out(b)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (inl > 0);
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
EVP_MD *md;
|
||||
const EVP_MD **ppmd;
|
||||
long ret = 1;
|
||||
int i;
|
||||
BIO *next;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
ctx->buf_len = 0;
|
||||
ctx->buf_off = 0;
|
||||
ctx->buf_len_save = 0;
|
||||
ctx->buf_off_save = 0;
|
||||
ctx->cont = 1;
|
||||
ctx->finished = 0;
|
||||
ctx->blockout = 0;
|
||||
ctx->sigio = 1;
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_EOF: /* More to read */
|
||||
if (ctx->cont <= 0)
|
||||
ret = 1;
|
||||
else
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_PENDING: /* More to read in buffer */
|
||||
case BIO_CTRL_WPENDING: /* More to read in buffer */
|
||||
ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
|
||||
if (ret <= 0)
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
case BIO_CTRL_FLUSH:
|
||||
/* do a final write */
|
||||
if (ctx->blockout == 0)
|
||||
if (!block_out(b))
|
||||
return 0;
|
||||
|
||||
while (ctx->blockout) {
|
||||
i = ok_write(b, NULL, 0);
|
||||
if (i < 0) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->finished = 1;
|
||||
ctx->buf_off = ctx->buf_len = 0;
|
||||
ctx->cont = (int)ret;
|
||||
|
||||
/* Finally flush the underlying BIO */
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
BIO_clear_retry_flags(b);
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
case BIO_CTRL_INFO:
|
||||
ret = (long)ctx->cont;
|
||||
break;
|
||||
case BIO_C_SET_MD:
|
||||
md = ptr;
|
||||
if (!EVP_DigestInit_ex(ctx->md, md, NULL))
|
||||
return 0;
|
||||
BIO_set_init(b, 1);
|
||||
break;
|
||||
case BIO_C_GET_MD:
|
||||
if (BIO_get_init(b)) {
|
||||
ppmd = ptr;
|
||||
*ppmd = EVP_MD_CTX_get0_md(ctx->md);
|
||||
} else
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
|
||||
{
|
||||
BIO *next;
|
||||
|
||||
next = BIO_next(b);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
return BIO_callback_ctrl(next, cmd, fp);
|
||||
}
|
||||
|
||||
static void longswap(void *_ptr, size_t len)
|
||||
{
|
||||
DECLARE_IS_ENDIAN;
|
||||
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
size_t i;
|
||||
unsigned char *p = _ptr, c;
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
c = p[0], p[0] = p[3], p[3] = c;
|
||||
c = p[1], p[1] = p[2], p[2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sig_out(BIO *b)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
EVP_MD_CTX *md;
|
||||
const EVP_MD *digest;
|
||||
int md_size;
|
||||
void *md_data;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
md = ctx->md;
|
||||
digest = EVP_MD_CTX_get0_md(md);
|
||||
md_size = EVP_MD_get_size(digest);
|
||||
md_data = EVP_MD_CTX_get0_md_data(md);
|
||||
|
||||
if (md_size <= 0)
|
||||
goto berr;
|
||||
if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
|
||||
return 1;
|
||||
|
||||
if (!EVP_DigestInit_ex(md, digest, NULL))
|
||||
goto berr;
|
||||
/*
|
||||
* FIXME: there's absolutely no guarantee this makes any sense at all,
|
||||
* particularly now EVP_MD_CTX has been restructured.
|
||||
*/
|
||||
if (RAND_bytes(md_data, md_size) <= 0)
|
||||
goto berr;
|
||||
memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
|
||||
longswap(&(ctx->buf[ctx->buf_len]), md_size);
|
||||
ctx->buf_len += md_size;
|
||||
|
||||
if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
|
||||
goto berr;
|
||||
if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
|
||||
goto berr;
|
||||
ctx->buf_len += md_size;
|
||||
ctx->blockout = 1;
|
||||
ctx->sigio = 0;
|
||||
return 1;
|
||||
berr:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sig_in(BIO *b)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
EVP_MD_CTX *md;
|
||||
unsigned char tmp[EVP_MAX_MD_SIZE];
|
||||
int ret = 0;
|
||||
const EVP_MD *digest;
|
||||
int md_size;
|
||||
void *md_data;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
if ((md = ctx->md) == NULL)
|
||||
goto berr;
|
||||
digest = EVP_MD_CTX_get0_md(md);
|
||||
if ((md_size = EVP_MD_get_size(digest)) <= 0)
|
||||
goto berr;
|
||||
md_data = EVP_MD_CTX_get0_md_data(md);
|
||||
|
||||
if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
|
||||
return 1;
|
||||
|
||||
if (!EVP_DigestInit_ex(md, digest, NULL))
|
||||
goto berr;
|
||||
memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
|
||||
longswap(md_data, md_size);
|
||||
ctx->buf_off += md_size;
|
||||
|
||||
if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
|
||||
goto berr;
|
||||
if (!EVP_DigestFinal_ex(md, tmp, NULL))
|
||||
goto berr;
|
||||
ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
|
||||
ctx->buf_off += md_size;
|
||||
if (ret == 1) {
|
||||
ctx->sigio = 0;
|
||||
if (ctx->buf_len != ctx->buf_off) {
|
||||
memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
|
||||
ctx->buf_len - ctx->buf_off);
|
||||
}
|
||||
ctx->buf_len -= ctx->buf_off;
|
||||
ctx->buf_off = 0;
|
||||
} else {
|
||||
ctx->cont = 0;
|
||||
}
|
||||
return 1;
|
||||
berr:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int block_out(BIO *b)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
EVP_MD_CTX *md;
|
||||
unsigned long tl;
|
||||
const EVP_MD *digest;
|
||||
int md_size;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
md = ctx->md;
|
||||
digest = EVP_MD_CTX_get0_md(md);
|
||||
md_size = EVP_MD_get_size(digest);
|
||||
if (md_size <= 0)
|
||||
goto berr;
|
||||
|
||||
tl = ctx->buf_len - OK_BLOCK_BLOCK;
|
||||
ctx->buf[0] = (unsigned char)(tl >> 24);
|
||||
ctx->buf[1] = (unsigned char)(tl >> 16);
|
||||
ctx->buf[2] = (unsigned char)(tl >> 8);
|
||||
ctx->buf[3] = (unsigned char)(tl);
|
||||
if (!EVP_DigestUpdate(md,
|
||||
(unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
|
||||
goto berr;
|
||||
if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
|
||||
goto berr;
|
||||
ctx->buf_len += md_size;
|
||||
ctx->blockout = 1;
|
||||
return 1;
|
||||
berr:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int block_in(BIO *b)
|
||||
{
|
||||
BIO_OK_CTX *ctx;
|
||||
EVP_MD_CTX *md;
|
||||
unsigned long tl = 0;
|
||||
unsigned char tmp[EVP_MAX_MD_SIZE];
|
||||
int md_size;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
md = ctx->md;
|
||||
md_size = EVP_MD_get_size(EVP_MD_CTX_get0_md(md));
|
||||
if (md_size <= 0)
|
||||
goto berr;
|
||||
|
||||
assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
|
||||
tl = ctx->buf[0];
|
||||
tl <<= 8;
|
||||
tl |= ctx->buf[1];
|
||||
tl <<= 8;
|
||||
tl |= ctx->buf[2];
|
||||
tl <<= 8;
|
||||
tl |= ctx->buf[3];
|
||||
|
||||
if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
|
||||
return 1;
|
||||
|
||||
if (!EVP_DigestUpdate(md,
|
||||
(unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
|
||||
goto berr;
|
||||
if (!EVP_DigestFinal_ex(md, tmp, NULL))
|
||||
goto berr;
|
||||
if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
|
||||
/* there might be parts from next block lurking around ! */
|
||||
ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
|
||||
ctx->buf_len_save = ctx->buf_len;
|
||||
ctx->buf_off = OK_BLOCK_BLOCK;
|
||||
ctx->buf_len = tl + OK_BLOCK_BLOCK;
|
||||
ctx->blockout = 1;
|
||||
} else {
|
||||
ctx->cont = 0;
|
||||
}
|
||||
return 1;
|
||||
berr:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
LIBS=../../libcrypto
|
||||
$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c evp_utils.c \
|
||||
mac_lib.c mac_meth.c keymgmt_meth.c keymgmt_lib.c kdf_lib.c kdf_meth.c \
|
||||
skeymgmt_meth.c \
|
||||
pmeth_lib.c signature.c p_lib.c s_lib.c pmeth_gn.c exchange.c \
|
||||
evp_rand.c asymcipher.c kem.c dh_support.c ec_support.c pmeth_check.c
|
||||
|
||||
SOURCE[../../libcrypto]=$COMMON\
|
||||
encode.c evp_key.c evp_cnf.c \
|
||||
e_des.c e_bf.c e_idea.c e_des3.c \
|
||||
e_rc4.c e_aes.c names.c e_aria.c e_sm4.c \
|
||||
e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c m_null.c \
|
||||
p_seal.c p_sign.c p_verify.c p_legacy.c \
|
||||
bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \
|
||||
c_allc.c c_alld.c bio_ok.c \
|
||||
evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c pbe_scrypt.c \
|
||||
e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \
|
||||
e_chacha20_poly1305.c \
|
||||
legacy_sha.c ctrl_params_translate.c \
|
||||
cmeth_lib.c m_sigver.c
|
||||
|
||||
# Diverse type specific ctrl functions. They are kinda sorta legacy, kinda
|
||||
# sorta not.
|
||||
SOURCE[../../libcrypto]=dh_ctrl.c dsa_ctrl.c ec_ctrl.c
|
||||
|
||||
IF[{- !$disabled{'deprecated-3.0'} -}]
|
||||
SOURCE[../../libcrypto]=p_enc.c p_dec.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{'deprecated-0.9.8'} -}]
|
||||
SOURCE[../../libcrypto]=e_old.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{'rsa'} -}]
|
||||
SOURCE[../../libcrypto]=p_open.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{md2} -}]
|
||||
SOURCE[../../libcrypto]=legacy_md2.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{md4} -}]
|
||||
SOURCE[../../libcrypto]=legacy_md4.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{md5} -}]
|
||||
SOURCE[../../libcrypto]=legacy_md5.c legacy_md5_sha1.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{mdc2} -}]
|
||||
SOURCE[../../libcrypto]=legacy_mdc2.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{blake2} -}]
|
||||
SOURCE[../../libcrypto]=legacy_blake2.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{whirlpool} -}]
|
||||
SOURCE[../../libcrypto]=legacy_wp.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{rmd160} -}]
|
||||
SOURCE[../../libcrypto]=legacy_ripemd.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{seed} -}]
|
||||
SOURCE[../../libcrypto]=e_seed.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{camellia} -}]
|
||||
SOURCE[../../libcrypto]=e_camellia.c
|
||||
INCLUDE[e_camellia.o]=.. ../modes
|
||||
ENDIF
|
||||
|
||||
SOURCE[../../providers/libfips.a]=$COMMON
|
||||
|
||||
INCLUDE[e_aes.o]=.. ../modes
|
||||
INCLUDE[e_aes_cbc_hmac_sha1.o]=../modes
|
||||
INCLUDE[e_aes_cbc_hmac_sha256.o]=../modes
|
||||
INCLUDE[e_aria.o]=.. ../modes
|
||||
INCLUDE[e_sm4.o]=.. ../modes
|
||||
INCLUDE[e_des.o]=..
|
||||
INCLUDE[e_des3.o]=..
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/evp.h"
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
void openssl_add_all_ciphers_int(void)
|
||||
{
|
||||
|
||||
#ifndef OPENSSL_NO_DES
|
||||
EVP_add_cipher(EVP_des_cfb());
|
||||
EVP_add_cipher(EVP_des_cfb1());
|
||||
EVP_add_cipher(EVP_des_cfb8());
|
||||
EVP_add_cipher(EVP_des_ede_cfb());
|
||||
EVP_add_cipher(EVP_des_ede3_cfb());
|
||||
EVP_add_cipher(EVP_des_ede3_cfb1());
|
||||
EVP_add_cipher(EVP_des_ede3_cfb8());
|
||||
|
||||
EVP_add_cipher(EVP_des_ofb());
|
||||
EVP_add_cipher(EVP_des_ede_ofb());
|
||||
EVP_add_cipher(EVP_des_ede3_ofb());
|
||||
|
||||
EVP_add_cipher(EVP_desx_cbc());
|
||||
EVP_add_cipher_alias(SN_desx_cbc, "DESX");
|
||||
EVP_add_cipher_alias(SN_desx_cbc, "desx");
|
||||
|
||||
EVP_add_cipher(EVP_des_cbc());
|
||||
EVP_add_cipher_alias(SN_des_cbc, "DES");
|
||||
EVP_add_cipher_alias(SN_des_cbc, "des");
|
||||
EVP_add_cipher(EVP_des_ede_cbc());
|
||||
EVP_add_cipher(EVP_des_ede3_cbc());
|
||||
EVP_add_cipher_alias(SN_des_ede3_cbc, "DES3");
|
||||
EVP_add_cipher_alias(SN_des_ede3_cbc, "des3");
|
||||
|
||||
EVP_add_cipher(EVP_des_ecb());
|
||||
EVP_add_cipher(EVP_des_ede());
|
||||
EVP_add_cipher_alias(SN_des_ede_ecb, "DES-EDE-ECB");
|
||||
EVP_add_cipher_alias(SN_des_ede_ecb, "des-ede-ecb");
|
||||
EVP_add_cipher(EVP_des_ede3());
|
||||
EVP_add_cipher_alias(SN_des_ede3_ecb, "DES-EDE3-ECB");
|
||||
EVP_add_cipher_alias(SN_des_ede3_ecb, "des-ede3-ecb");
|
||||
EVP_add_cipher(EVP_des_ede3_wrap());
|
||||
EVP_add_cipher_alias(SN_id_smime_alg_CMS3DESwrap, "des3-wrap");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
EVP_add_cipher(EVP_rc4());
|
||||
EVP_add_cipher(EVP_rc4_40());
|
||||
# ifndef OPENSSL_NO_MD5
|
||||
EVP_add_cipher(EVP_rc4_hmac_md5());
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_IDEA
|
||||
EVP_add_cipher(EVP_idea_ecb());
|
||||
EVP_add_cipher(EVP_idea_cfb());
|
||||
EVP_add_cipher(EVP_idea_ofb());
|
||||
EVP_add_cipher(EVP_idea_cbc());
|
||||
EVP_add_cipher_alias(SN_idea_cbc, "IDEA");
|
||||
EVP_add_cipher_alias(SN_idea_cbc, "idea");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_SEED
|
||||
EVP_add_cipher(EVP_seed_ecb());
|
||||
EVP_add_cipher(EVP_seed_cfb());
|
||||
EVP_add_cipher(EVP_seed_ofb());
|
||||
EVP_add_cipher(EVP_seed_cbc());
|
||||
EVP_add_cipher_alias(SN_seed_cbc, "SEED");
|
||||
EVP_add_cipher_alias(SN_seed_cbc, "seed");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_SM4
|
||||
EVP_add_cipher(EVP_sm4_ecb());
|
||||
EVP_add_cipher(EVP_sm4_cbc());
|
||||
EVP_add_cipher(EVP_sm4_cfb());
|
||||
EVP_add_cipher(EVP_sm4_ofb());
|
||||
EVP_add_cipher(EVP_sm4_ctr());
|
||||
EVP_add_cipher_alias(SN_sm4_cbc, "SM4");
|
||||
EVP_add_cipher_alias(SN_sm4_cbc, "sm4");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RC2
|
||||
EVP_add_cipher(EVP_rc2_ecb());
|
||||
EVP_add_cipher(EVP_rc2_cfb());
|
||||
EVP_add_cipher(EVP_rc2_ofb());
|
||||
EVP_add_cipher(EVP_rc2_cbc());
|
||||
EVP_add_cipher(EVP_rc2_40_cbc());
|
||||
EVP_add_cipher(EVP_rc2_64_cbc());
|
||||
EVP_add_cipher_alias(SN_rc2_cbc, "RC2");
|
||||
EVP_add_cipher_alias(SN_rc2_cbc, "rc2");
|
||||
EVP_add_cipher_alias(SN_rc2_cbc, "rc2-128");
|
||||
EVP_add_cipher_alias(SN_rc2_64_cbc, "rc2-64");
|
||||
EVP_add_cipher_alias(SN_rc2_40_cbc, "rc2-40");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_BF
|
||||
EVP_add_cipher(EVP_bf_ecb());
|
||||
EVP_add_cipher(EVP_bf_cfb());
|
||||
EVP_add_cipher(EVP_bf_ofb());
|
||||
EVP_add_cipher(EVP_bf_cbc());
|
||||
EVP_add_cipher_alias(SN_bf_cbc, "BF");
|
||||
EVP_add_cipher_alias(SN_bf_cbc, "bf");
|
||||
EVP_add_cipher_alias(SN_bf_cbc, "blowfish");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
EVP_add_cipher(EVP_cast5_ecb());
|
||||
EVP_add_cipher(EVP_cast5_cfb());
|
||||
EVP_add_cipher(EVP_cast5_ofb());
|
||||
EVP_add_cipher(EVP_cast5_cbc());
|
||||
EVP_add_cipher_alias(SN_cast5_cbc, "CAST");
|
||||
EVP_add_cipher_alias(SN_cast5_cbc, "cast");
|
||||
EVP_add_cipher_alias(SN_cast5_cbc, "CAST-cbc");
|
||||
EVP_add_cipher_alias(SN_cast5_cbc, "cast-cbc");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RC5
|
||||
EVP_add_cipher(EVP_rc5_32_12_16_ecb());
|
||||
EVP_add_cipher(EVP_rc5_32_12_16_cfb());
|
||||
EVP_add_cipher(EVP_rc5_32_12_16_ofb());
|
||||
EVP_add_cipher(EVP_rc5_32_12_16_cbc());
|
||||
EVP_add_cipher_alias(SN_rc5_cbc, "rc5");
|
||||
EVP_add_cipher_alias(SN_rc5_cbc, "RC5");
|
||||
#endif
|
||||
|
||||
EVP_add_cipher(EVP_aes_128_ecb());
|
||||
EVP_add_cipher(EVP_aes_128_cbc());
|
||||
EVP_add_cipher(EVP_aes_128_cfb());
|
||||
EVP_add_cipher(EVP_aes_128_cfb1());
|
||||
EVP_add_cipher(EVP_aes_128_cfb8());
|
||||
EVP_add_cipher(EVP_aes_128_ofb());
|
||||
EVP_add_cipher(EVP_aes_128_ctr());
|
||||
EVP_add_cipher(EVP_aes_128_gcm());
|
||||
#ifndef OPENSSL_NO_OCB
|
||||
EVP_add_cipher(EVP_aes_128_ocb());
|
||||
#endif
|
||||
EVP_add_cipher(EVP_aes_128_xts());
|
||||
EVP_add_cipher(EVP_aes_128_ccm());
|
||||
EVP_add_cipher(EVP_aes_128_wrap());
|
||||
EVP_add_cipher_alias(SN_id_aes128_wrap, "aes128-wrap");
|
||||
EVP_add_cipher(EVP_aes_128_wrap_pad());
|
||||
EVP_add_cipher_alias(SN_id_aes128_wrap_pad, "aes128-wrap-pad");
|
||||
EVP_add_cipher_alias(SN_aes_128_cbc, "AES128");
|
||||
EVP_add_cipher_alias(SN_aes_128_cbc, "aes128");
|
||||
EVP_add_cipher(EVP_aes_192_ecb());
|
||||
EVP_add_cipher(EVP_aes_192_cbc());
|
||||
EVP_add_cipher(EVP_aes_192_cfb());
|
||||
EVP_add_cipher(EVP_aes_192_cfb1());
|
||||
EVP_add_cipher(EVP_aes_192_cfb8());
|
||||
EVP_add_cipher(EVP_aes_192_ofb());
|
||||
EVP_add_cipher(EVP_aes_192_ctr());
|
||||
EVP_add_cipher(EVP_aes_192_gcm());
|
||||
#ifndef OPENSSL_NO_OCB
|
||||
EVP_add_cipher(EVP_aes_192_ocb());
|
||||
#endif
|
||||
EVP_add_cipher(EVP_aes_192_ccm());
|
||||
EVP_add_cipher(EVP_aes_192_wrap());
|
||||
EVP_add_cipher_alias(SN_id_aes192_wrap, "aes192-wrap");
|
||||
EVP_add_cipher(EVP_aes_192_wrap_pad());
|
||||
EVP_add_cipher_alias(SN_id_aes192_wrap_pad, "aes192-wrap-pad");
|
||||
EVP_add_cipher_alias(SN_aes_192_cbc, "AES192");
|
||||
EVP_add_cipher_alias(SN_aes_192_cbc, "aes192");
|
||||
EVP_add_cipher(EVP_aes_256_ecb());
|
||||
EVP_add_cipher(EVP_aes_256_cbc());
|
||||
EVP_add_cipher(EVP_aes_256_cfb());
|
||||
EVP_add_cipher(EVP_aes_256_cfb1());
|
||||
EVP_add_cipher(EVP_aes_256_cfb8());
|
||||
EVP_add_cipher(EVP_aes_256_ofb());
|
||||
EVP_add_cipher(EVP_aes_256_ctr());
|
||||
EVP_add_cipher(EVP_aes_256_gcm());
|
||||
#ifndef OPENSSL_NO_OCB
|
||||
EVP_add_cipher(EVP_aes_256_ocb());
|
||||
#endif
|
||||
EVP_add_cipher(EVP_aes_256_xts());
|
||||
EVP_add_cipher(EVP_aes_256_ccm());
|
||||
EVP_add_cipher(EVP_aes_256_wrap());
|
||||
EVP_add_cipher_alias(SN_id_aes256_wrap, "aes256-wrap");
|
||||
EVP_add_cipher(EVP_aes_256_wrap_pad());
|
||||
EVP_add_cipher_alias(SN_id_aes256_wrap_pad, "aes256-wrap-pad");
|
||||
EVP_add_cipher_alias(SN_aes_256_cbc, "AES256");
|
||||
EVP_add_cipher_alias(SN_aes_256_cbc, "aes256");
|
||||
EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1());
|
||||
EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
|
||||
EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256());
|
||||
EVP_add_cipher(EVP_aes_256_cbc_hmac_sha256());
|
||||
#ifndef OPENSSL_NO_ARIA
|
||||
EVP_add_cipher(EVP_aria_128_ecb());
|
||||
EVP_add_cipher(EVP_aria_128_cbc());
|
||||
EVP_add_cipher(EVP_aria_128_cfb());
|
||||
EVP_add_cipher(EVP_aria_128_cfb1());
|
||||
EVP_add_cipher(EVP_aria_128_cfb8());
|
||||
EVP_add_cipher(EVP_aria_128_ctr());
|
||||
EVP_add_cipher(EVP_aria_128_ofb());
|
||||
EVP_add_cipher(EVP_aria_128_gcm());
|
||||
EVP_add_cipher(EVP_aria_128_ccm());
|
||||
EVP_add_cipher_alias(SN_aria_128_cbc, "ARIA128");
|
||||
EVP_add_cipher_alias(SN_aria_128_cbc, "aria128");
|
||||
EVP_add_cipher(EVP_aria_192_ecb());
|
||||
EVP_add_cipher(EVP_aria_192_cbc());
|
||||
EVP_add_cipher(EVP_aria_192_cfb());
|
||||
EVP_add_cipher(EVP_aria_192_cfb1());
|
||||
EVP_add_cipher(EVP_aria_192_cfb8());
|
||||
EVP_add_cipher(EVP_aria_192_ctr());
|
||||
EVP_add_cipher(EVP_aria_192_ofb());
|
||||
EVP_add_cipher(EVP_aria_192_gcm());
|
||||
EVP_add_cipher(EVP_aria_192_ccm());
|
||||
EVP_add_cipher_alias(SN_aria_192_cbc, "ARIA192");
|
||||
EVP_add_cipher_alias(SN_aria_192_cbc, "aria192");
|
||||
EVP_add_cipher(EVP_aria_256_ecb());
|
||||
EVP_add_cipher(EVP_aria_256_cbc());
|
||||
EVP_add_cipher(EVP_aria_256_cfb());
|
||||
EVP_add_cipher(EVP_aria_256_cfb1());
|
||||
EVP_add_cipher(EVP_aria_256_cfb8());
|
||||
EVP_add_cipher(EVP_aria_256_ctr());
|
||||
EVP_add_cipher(EVP_aria_256_ofb());
|
||||
EVP_add_cipher(EVP_aria_256_gcm());
|
||||
EVP_add_cipher(EVP_aria_256_ccm());
|
||||
EVP_add_cipher_alias(SN_aria_256_cbc, "ARIA256");
|
||||
EVP_add_cipher_alias(SN_aria_256_cbc, "aria256");
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_CAMELLIA
|
||||
EVP_add_cipher(EVP_camellia_128_ecb());
|
||||
EVP_add_cipher(EVP_camellia_128_cbc());
|
||||
EVP_add_cipher(EVP_camellia_128_cfb());
|
||||
EVP_add_cipher(EVP_camellia_128_cfb1());
|
||||
EVP_add_cipher(EVP_camellia_128_cfb8());
|
||||
EVP_add_cipher(EVP_camellia_128_ofb());
|
||||
EVP_add_cipher_alias(SN_camellia_128_cbc, "CAMELLIA128");
|
||||
EVP_add_cipher_alias(SN_camellia_128_cbc, "camellia128");
|
||||
EVP_add_cipher(EVP_camellia_192_ecb());
|
||||
EVP_add_cipher(EVP_camellia_192_cbc());
|
||||
EVP_add_cipher(EVP_camellia_192_cfb());
|
||||
EVP_add_cipher(EVP_camellia_192_cfb1());
|
||||
EVP_add_cipher(EVP_camellia_192_cfb8());
|
||||
EVP_add_cipher(EVP_camellia_192_ofb());
|
||||
EVP_add_cipher_alias(SN_camellia_192_cbc, "CAMELLIA192");
|
||||
EVP_add_cipher_alias(SN_camellia_192_cbc, "camellia192");
|
||||
EVP_add_cipher(EVP_camellia_256_ecb());
|
||||
EVP_add_cipher(EVP_camellia_256_cbc());
|
||||
EVP_add_cipher(EVP_camellia_256_cfb());
|
||||
EVP_add_cipher(EVP_camellia_256_cfb1());
|
||||
EVP_add_cipher(EVP_camellia_256_cfb8());
|
||||
EVP_add_cipher(EVP_camellia_256_ofb());
|
||||
EVP_add_cipher_alias(SN_camellia_256_cbc, "CAMELLIA256");
|
||||
EVP_add_cipher_alias(SN_camellia_256_cbc, "camellia256");
|
||||
EVP_add_cipher(EVP_camellia_128_ctr());
|
||||
EVP_add_cipher(EVP_camellia_192_ctr());
|
||||
EVP_add_cipher(EVP_camellia_256_ctr());
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_CHACHA
|
||||
EVP_add_cipher(EVP_chacha20());
|
||||
# ifndef OPENSSL_NO_POLY1305
|
||||
EVP_add_cipher(EVP_chacha20_poly1305());
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/evp.h"
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
void openssl_add_all_digests_int(void)
|
||||
{
|
||||
#ifndef OPENSSL_NO_MD4
|
||||
EVP_add_digest(EVP_md4());
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
EVP_add_digest(EVP_md5());
|
||||
EVP_add_digest_alias(SN_md5, "ssl3-md5");
|
||||
EVP_add_digest(EVP_md5_sha1());
|
||||
#endif
|
||||
EVP_add_digest(EVP_sha1());
|
||||
EVP_add_digest_alias(SN_sha1, "ssl3-sha1");
|
||||
EVP_add_digest_alias(SN_sha1WithRSAEncryption, SN_sha1WithRSA);
|
||||
#if !defined(OPENSSL_NO_MDC2) && !defined(OPENSSL_NO_DES)
|
||||
EVP_add_digest(EVP_mdc2());
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_RMD160
|
||||
EVP_add_digest(EVP_ripemd160());
|
||||
EVP_add_digest_alias(SN_ripemd160, "ripemd");
|
||||
EVP_add_digest_alias(SN_ripemd160, "rmd160");
|
||||
#endif
|
||||
EVP_add_digest(EVP_sha224());
|
||||
EVP_add_digest(EVP_sha256());
|
||||
EVP_add_digest(EVP_sha384());
|
||||
EVP_add_digest(EVP_sha512());
|
||||
EVP_add_digest(EVP_sha512_224());
|
||||
EVP_add_digest(EVP_sha512_256());
|
||||
#ifndef OPENSSL_NO_WHIRLPOOL
|
||||
EVP_add_digest(EVP_whirlpool());
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SM3
|
||||
EVP_add_digest(EVP_sm3());
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_BLAKE2
|
||||
EVP_add_digest(EVP_blake2b512());
|
||||
EVP_add_digest(EVP_blake2s256());
|
||||
#endif
|
||||
EVP_add_digest(EVP_sha3_224());
|
||||
EVP_add_digest(EVP_sha3_256());
|
||||
EVP_add_digest(EVP_sha3_384());
|
||||
EVP_add_digest(EVP_sha3_512());
|
||||
EVP_add_digest(EVP_shake128());
|
||||
EVP_add_digest(EVP_shake256());
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* EVP _meth_ APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/provider.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len)
|
||||
{
|
||||
EVP_CIPHER *cipher = evp_cipher_new();
|
||||
|
||||
if (cipher != NULL) {
|
||||
cipher->nid = cipher_type;
|
||||
cipher->block_size = block_size;
|
||||
cipher->key_len = key_len;
|
||||
cipher->origin = EVP_ORIG_METH;
|
||||
}
|
||||
return cipher;
|
||||
}
|
||||
|
||||
EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher)
|
||||
{
|
||||
EVP_CIPHER *to = NULL;
|
||||
|
||||
/*
|
||||
* Non-legacy EVP_CIPHERs can't be duplicated like this.
|
||||
* Use EVP_CIPHER_up_ref() instead.
|
||||
*/
|
||||
if (cipher->prov != NULL)
|
||||
return NULL;
|
||||
|
||||
if ((to = EVP_CIPHER_meth_new(cipher->nid, cipher->block_size,
|
||||
cipher->key_len)) != NULL) {
|
||||
CRYPTO_REF_COUNT refcnt = to->refcnt;
|
||||
|
||||
memcpy(to, cipher, sizeof(*to));
|
||||
to->refcnt = refcnt;
|
||||
to->origin = EVP_ORIG_METH;
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
void EVP_CIPHER_meth_free(EVP_CIPHER *cipher)
|
||||
{
|
||||
if (cipher == NULL || cipher->origin != EVP_ORIG_METH)
|
||||
return;
|
||||
|
||||
evp_cipher_free_int(cipher);
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len)
|
||||
{
|
||||
if (cipher->iv_len != 0)
|
||||
return 0;
|
||||
|
||||
cipher->iv_len = iv_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags)
|
||||
{
|
||||
if (cipher->flags != 0)
|
||||
return 0;
|
||||
|
||||
cipher->flags = flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_impl_ctx_size(EVP_CIPHER *cipher, int ctx_size)
|
||||
{
|
||||
if (cipher->ctx_size != 0)
|
||||
return 0;
|
||||
|
||||
cipher->ctx_size = ctx_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher,
|
||||
int (*init) (EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *key,
|
||||
const unsigned char *iv,
|
||||
int enc))
|
||||
{
|
||||
if (cipher->init != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->init = init;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher,
|
||||
int (*do_cipher) (EVP_CIPHER_CTX *ctx,
|
||||
unsigned char *out,
|
||||
const unsigned char *in,
|
||||
size_t inl))
|
||||
{
|
||||
if (cipher->do_cipher != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->do_cipher = do_cipher;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher,
|
||||
int (*cleanup) (EVP_CIPHER_CTX *))
|
||||
{
|
||||
if (cipher->cleanup != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->cleanup = cleanup;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_set_asn1_params(EVP_CIPHER *cipher,
|
||||
int (*set_asn1_parameters) (EVP_CIPHER_CTX *,
|
||||
ASN1_TYPE *))
|
||||
{
|
||||
if (cipher->set_asn1_parameters != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->set_asn1_parameters = set_asn1_parameters;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_get_asn1_params(EVP_CIPHER *cipher,
|
||||
int (*get_asn1_parameters) (EVP_CIPHER_CTX *,
|
||||
ASN1_TYPE *))
|
||||
{
|
||||
if (cipher->get_asn1_parameters != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->get_asn1_parameters = get_asn1_parameters;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher,
|
||||
int (*ctrl) (EVP_CIPHER_CTX *, int type,
|
||||
int arg, void *ptr))
|
||||
{
|
||||
if (cipher->ctrl != NULL)
|
||||
return 0;
|
||||
|
||||
cipher->ctrl = ctrl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *key,
|
||||
const unsigned char *iv,
|
||||
int enc)
|
||||
{
|
||||
return cipher->init;
|
||||
}
|
||||
int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
|
||||
unsigned char *out,
|
||||
const unsigned char *in,
|
||||
size_t inl)
|
||||
{
|
||||
return cipher->do_cipher;
|
||||
}
|
||||
|
||||
int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *)
|
||||
{
|
||||
return cipher->cleanup;
|
||||
}
|
||||
|
||||
int (*EVP_CIPHER_meth_get_set_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
|
||||
ASN1_TYPE *)
|
||||
{
|
||||
return cipher->set_asn1_parameters;
|
||||
}
|
||||
|
||||
int (*EVP_CIPHER_meth_get_get_asn1_params(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
|
||||
ASN1_TYPE *)
|
||||
{
|
||||
return cipher->get_asn1_parameters;
|
||||
}
|
||||
|
||||
int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
|
||||
int type, int arg,
|
||||
void *ptr)
|
||||
{
|
||||
return cipher->ctrl;
|
||||
}
|
||||
|
||||
+2956
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/params.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/dh.h>
|
||||
#include "crypto/dh.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
static int dh_paramgen_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
/* Uses the same return values as EVP_PKEY_CTX_ctrl */
|
||||
return -2;
|
||||
}
|
||||
/* If key type not DH return error */
|
||||
if (evp_pkey_ctx_is_legacy(ctx)
|
||||
&& ctx->pmeth->pkey_id != EVP_PKEY_DH
|
||||
&& ctx->pmeth->pkey_id != EVP_PKEY_DHX)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dh_param_derive_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
/* Uses the same return values as EVP_PKEY_CTX_ctrl */
|
||||
return -2;
|
||||
}
|
||||
/* If key type not DH return error */
|
||||
if (evp_pkey_ctx_is_legacy(ctx)
|
||||
&& ctx->pmeth->pkey_id != EVP_PKEY_DH
|
||||
&& ctx->pmeth->pkey_id != EVP_PKEY_DHX)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dh_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
return evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *seed,
|
||||
size_t seedlen)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dh_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED,
|
||||
(void *)seed, seedlen);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
return evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
|
||||
EVP_PKEY_CTRL_DH_PARAMGEN_TYPE, typ, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
size_t bits = pbits;
|
||||
|
||||
if ((ret = dh_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
return evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qbits)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
size_t bits2 = qbits;
|
||||
|
||||
if ((ret = dh_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
return evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dh_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_DH_GENERATOR, &gen);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
return evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN,
|
||||
EVP_PKEY_CTRL_DH_RFC5114, gen, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen)
|
||||
{
|
||||
return EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH,
|
||||
EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN,
|
||||
EVP_PKEY_CTRL_DH_NID, nid, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
|
||||
{
|
||||
OSSL_PARAM dh_pad_params[2];
|
||||
unsigned int upad = pad;
|
||||
|
||||
/* We use EVP_PKEY_CTX_ctrl return values */
|
||||
if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
return -2;
|
||||
}
|
||||
|
||||
dh_pad_params[0] = OSSL_PARAM_construct_uint(OSSL_EXCHANGE_PARAM_PAD, &upad);
|
||||
dh_pad_params[1] = OSSL_PARAM_construct_end();
|
||||
|
||||
return evp_pkey_ctx_set_params_strict(ctx, dh_pad_params);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_DH_KDF_TYPE, kdf, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_get_dh_kdf_type(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_DH_KDF_TYPE, -2, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT *oid)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_DH_KDF_OID, 0, (void *)(oid));
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_get0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT **oid)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_GET_DH_KDF_OID, 0, (void *)(oid));
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_DH_KDF_MD, 0, (void *)(md));
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_get_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_GET_DH_KDF_MD, 0, (void *)(pmd));
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int outlen)
|
||||
{
|
||||
int ret;
|
||||
size_t len = outlen;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = dh_param_derive_check(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
if (outlen <= 0) {
|
||||
/*
|
||||
* This would ideally be -1 or 0, but we have to retain compatibility
|
||||
* with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if
|
||||
* inlen <= 0
|
||||
*/
|
||||
return -2;
|
||||
}
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
|
||||
&len);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_get_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen)
|
||||
{
|
||||
int ret;
|
||||
size_t len = UINT_MAX;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = dh_param_derive_check(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
|
||||
&len);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_get_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
if (ret != 1 || len > INT_MAX)
|
||||
return -1;
|
||||
|
||||
*plen = (int)len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
ret = dh_param_derive_check(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM,
|
||||
/*
|
||||
* Cast away the const. This is read
|
||||
* only so should be safe
|
||||
*/
|
||||
(void *)ukm,
|
||||
(size_t)len);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
if (ret == 1)
|
||||
OPENSSL_free(ukm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm)
|
||||
{
|
||||
int ret;
|
||||
size_t ukmlen;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = dh_param_derive_check(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM,
|
||||
(void **)pukm, 0);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_get_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
|
||||
ukmlen = params[0].return_size;
|
||||
if (ukmlen > INT_MAX)
|
||||
return -1;
|
||||
|
||||
return (int)ukmlen;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <string.h> /* strcmp */
|
||||
#include <openssl/dh.h>
|
||||
#include "internal/nelem.h"
|
||||
#include "crypto/dh.h"
|
||||
|
||||
typedef struct dh_name2id_st {
|
||||
const char *name;
|
||||
int id;
|
||||
int type;
|
||||
} DH_GENTYPE_NAME2ID;
|
||||
|
||||
/* Indicates that the paramgen_type can be used for either DH or DHX */
|
||||
#define TYPE_ANY -1
|
||||
#ifndef OPENSSL_NO_DH
|
||||
# define TYPE_DH DH_FLAG_TYPE_DH
|
||||
# define TYPE_DHX DH_FLAG_TYPE_DHX
|
||||
#else
|
||||
# define TYPE_DH 0
|
||||
# define TYPE_DHX 0
|
||||
#endif
|
||||
|
||||
static const DH_GENTYPE_NAME2ID dhtype2id[] = {
|
||||
{ "group", DH_PARAMGEN_TYPE_GROUP, TYPE_ANY },
|
||||
{ "generator", DH_PARAMGEN_TYPE_GENERATOR, TYPE_DH },
|
||||
{ "fips186_4", DH_PARAMGEN_TYPE_FIPS_186_4, TYPE_DHX },
|
||||
{ "fips186_2", DH_PARAMGEN_TYPE_FIPS_186_2, TYPE_DHX },
|
||||
};
|
||||
|
||||
const char *ossl_dh_gen_type_id2name(int id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
|
||||
if (dhtype2id[i].id == id)
|
||||
return dhtype2id[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
int ossl_dh_gen_type_name2id(const char *name, int type)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(dhtype2id); ++i) {
|
||||
if ((dhtype2id[i].type == TYPE_ANY
|
||||
|| type == dhtype2id[i].type)
|
||||
&& strcmp(dhtype2id[i].name, name) == 0)
|
||||
return dhtype2id[i].id;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
static int dsa_paramgen_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
/* Uses the same return values as EVP_PKEY_CTX_ctrl */
|
||||
return -2;
|
||||
}
|
||||
/* If key type not DSA return error */
|
||||
if (ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_DSA)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_type(EVP_PKEY_CTX *ctx, const char *name)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_TYPE,
|
||||
(char *)name, 0);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_seed(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *seed,
|
||||
size_t seedlen)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED,
|
||||
(void *)seed, seedlen);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
size_t bits = nbits;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
size_t bits2 = qbits;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_md_props(EVP_PKEY_CTX *ctx,
|
||||
const char *md_name,
|
||||
const char *md_properties)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[3], *p = params;
|
||||
|
||||
if ((ret = dsa_paramgen_check(ctx)) <= 0)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST,
|
||||
(char *)md_name, 0);
|
||||
if (md_properties != NULL)
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_FFC_DIGEST_PROPS,
|
||||
(char *)md_properties, 0);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_PKEY_CTX_set_params(ctx, params);
|
||||
}
|
||||
|
||||
#if !defined(FIPS_MODULE)
|
||||
int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
|
||||
EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)(md));
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
+976
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
* Copyright 2011-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use where we're using them to implement the higher level EVP interface, as is
|
||||
* the case here.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/modes.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/constant_time.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
typedef struct {
|
||||
AES_KEY ks;
|
||||
SHA_CTX head, tail, md;
|
||||
size_t payload_length; /* AAD length in decrypt case */
|
||||
union {
|
||||
unsigned int tls_ver;
|
||||
unsigned char tls_aad[16]; /* 13 used */
|
||||
} aux;
|
||||
} EVP_AES_HMAC_SHA1;
|
||||
|
||||
#define NO_PAYLOAD_LENGTH ((size_t)-1)
|
||||
|
||||
#if defined(AES_ASM) && ( \
|
||||
defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(_M_X64) )
|
||||
|
||||
# define AESNI_CAPABLE (1<<(57-32))
|
||||
|
||||
int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
|
||||
void aesni_cbc_encrypt(const unsigned char *in,
|
||||
unsigned char *out,
|
||||
size_t length,
|
||||
const AES_KEY *key, unsigned char *ivec, int enc);
|
||||
|
||||
void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks,
|
||||
const AES_KEY *key, unsigned char iv[16],
|
||||
SHA_CTX *ctx, const void *in0);
|
||||
|
||||
void aesni256_cbc_sha1_dec(const void *inp, void *out, size_t blocks,
|
||||
const AES_KEY *key, unsigned char iv[16],
|
||||
SHA_CTX *ctx, const void *in0);
|
||||
|
||||
# define data(ctx) ((EVP_AES_HMAC_SHA1 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
|
||||
|
||||
static int aesni_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *inkey,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
EVP_AES_HMAC_SHA1 *key = data(ctx);
|
||||
int ret;
|
||||
const int keylen = EVP_CIPHER_CTX_get_key_length(ctx) * 8;
|
||||
|
||||
if (keylen <= 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
if (enc)
|
||||
ret = aesni_set_encrypt_key(inkey, keylen, &key->ks);
|
||||
else
|
||||
ret = aesni_set_decrypt_key(inkey, keylen, &key->ks);
|
||||
|
||||
SHA1_Init(&key->head); /* handy when benchmarking */
|
||||
key->tail = key->head;
|
||||
key->md = key->head;
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
return ret < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
# define STITCHED_CALL
|
||||
# undef STITCHED_DECRYPT_CALL
|
||||
|
||||
# if !defined(STITCHED_CALL)
|
||||
# define aes_off 0
|
||||
# endif
|
||||
|
||||
void sha1_block_data_order(void *c, const void *p, size_t len);
|
||||
|
||||
static void sha1_update(SHA_CTX *c, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *ptr = data;
|
||||
size_t res;
|
||||
|
||||
if ((res = c->num)) {
|
||||
res = SHA_CBLOCK - res;
|
||||
if (len < res)
|
||||
res = len;
|
||||
SHA1_Update(c, ptr, res);
|
||||
ptr += res;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
res = len % SHA_CBLOCK;
|
||||
len -= res;
|
||||
|
||||
if (len) {
|
||||
sha1_block_data_order(c, ptr, len / SHA_CBLOCK);
|
||||
|
||||
ptr += len;
|
||||
c->Nh += len >> 29;
|
||||
c->Nl += len <<= 3;
|
||||
if (c->Nl < (unsigned int)len)
|
||||
c->Nh++;
|
||||
}
|
||||
|
||||
if (res)
|
||||
SHA1_Update(c, ptr, res);
|
||||
}
|
||||
|
||||
# ifdef SHA1_Update
|
||||
# undef SHA1_Update
|
||||
# endif
|
||||
# define SHA1_Update sha1_update
|
||||
|
||||
# if !defined(OPENSSL_NO_MULTIBLOCK)
|
||||
|
||||
typedef struct {
|
||||
unsigned int A[8], B[8], C[8], D[8], E[8];
|
||||
} SHA1_MB_CTX;
|
||||
typedef struct {
|
||||
const unsigned char *ptr;
|
||||
int blocks;
|
||||
} HASH_DESC;
|
||||
|
||||
void sha1_multi_block(SHA1_MB_CTX *, const HASH_DESC *, int);
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *inp;
|
||||
unsigned char *out;
|
||||
int blocks;
|
||||
u64 iv[2];
|
||||
} CIPH_DESC;
|
||||
|
||||
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
|
||||
|
||||
static size_t tls1_1_multi_block_encrypt(EVP_AES_HMAC_SHA1 *key,
|
||||
unsigned char *out,
|
||||
const unsigned char *inp,
|
||||
size_t inp_len, int n4x)
|
||||
{ /* n4x is 1 or 2 */
|
||||
HASH_DESC hash_d[8], edges[8];
|
||||
CIPH_DESC ciph_d[8];
|
||||
unsigned char storage[sizeof(SHA1_MB_CTX) + 32];
|
||||
union {
|
||||
u64 q[16];
|
||||
u32 d[32];
|
||||
u8 c[128];
|
||||
} blocks[8];
|
||||
SHA1_MB_CTX *ctx;
|
||||
unsigned int frag, last, packlen, i, x4 = 4 * n4x, minblocks, processed =
|
||||
0;
|
||||
size_t ret = 0;
|
||||
u8 *IVs;
|
||||
# if defined(BSWAP8)
|
||||
u64 seqnum;
|
||||
# endif
|
||||
|
||||
/* ask for IVs in bulk */
|
||||
if (RAND_bytes((IVs = blocks[0].c), 16 * x4) <= 0)
|
||||
return 0;
|
||||
|
||||
ctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
|
||||
|
||||
frag = (unsigned int)inp_len >> (1 + n4x);
|
||||
last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
|
||||
if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
|
||||
frag++;
|
||||
last -= x4 - 1;
|
||||
}
|
||||
|
||||
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
|
||||
|
||||
/* populate descriptors with pointers and IVs */
|
||||
hash_d[0].ptr = inp;
|
||||
ciph_d[0].inp = inp;
|
||||
/* 5+16 is place for header and explicit IV */
|
||||
ciph_d[0].out = out + 5 + 16;
|
||||
memcpy(ciph_d[0].out - 16, IVs, 16);
|
||||
memcpy(ciph_d[0].iv, IVs, 16);
|
||||
IVs += 16;
|
||||
|
||||
for (i = 1; i < x4; i++) {
|
||||
ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
|
||||
ciph_d[i].out = ciph_d[i - 1].out + packlen;
|
||||
memcpy(ciph_d[i].out - 16, IVs, 16);
|
||||
memcpy(ciph_d[i].iv, IVs, 16);
|
||||
IVs += 16;
|
||||
}
|
||||
|
||||
# if defined(BSWAP8)
|
||||
memcpy(blocks[0].c, key->md.data, 8);
|
||||
seqnum = BSWAP8(blocks[0].q[0]);
|
||||
# endif
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag);
|
||||
# if !defined(BSWAP8)
|
||||
unsigned int carry, j;
|
||||
# endif
|
||||
|
||||
ctx->A[i] = key->md.h0;
|
||||
ctx->B[i] = key->md.h1;
|
||||
ctx->C[i] = key->md.h2;
|
||||
ctx->D[i] = key->md.h3;
|
||||
ctx->E[i] = key->md.h4;
|
||||
|
||||
/* fix seqnum */
|
||||
# if defined(BSWAP8)
|
||||
blocks[i].q[0] = BSWAP8(seqnum + i);
|
||||
# else
|
||||
for (carry = i, j = 8; j--;) {
|
||||
blocks[i].c[j] = ((u8 *)key->md.data)[j] + carry;
|
||||
carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
|
||||
}
|
||||
# endif
|
||||
blocks[i].c[8] = ((u8 *)key->md.data)[8];
|
||||
blocks[i].c[9] = ((u8 *)key->md.data)[9];
|
||||
blocks[i].c[10] = ((u8 *)key->md.data)[10];
|
||||
/* fix length */
|
||||
blocks[i].c[11] = (u8)(len >> 8);
|
||||
blocks[i].c[12] = (u8)(len);
|
||||
|
||||
memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
|
||||
hash_d[i].ptr += 64 - 13;
|
||||
hash_d[i].blocks = (len - (64 - 13)) / 64;
|
||||
|
||||
edges[i].ptr = blocks[i].c;
|
||||
edges[i].blocks = 1;
|
||||
}
|
||||
|
||||
/* hash 13-byte headers and first 64-13 bytes of inputs */
|
||||
sha1_multi_block(ctx, edges, n4x);
|
||||
/* hash bulk inputs */
|
||||
# define MAXCHUNKSIZE 2048
|
||||
# if MAXCHUNKSIZE%64
|
||||
# error "MAXCHUNKSIZE is not divisible by 64"
|
||||
# elif MAXCHUNKSIZE
|
||||
/*
|
||||
* goal is to minimize pressure on L1 cache by moving in shorter steps,
|
||||
* so that hashed data is still in the cache by the time we encrypt it
|
||||
*/
|
||||
minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
|
||||
if (minblocks > MAXCHUNKSIZE / 64) {
|
||||
for (i = 0; i < x4; i++) {
|
||||
edges[i].ptr = hash_d[i].ptr;
|
||||
edges[i].blocks = MAXCHUNKSIZE / 64;
|
||||
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
|
||||
}
|
||||
do {
|
||||
sha1_multi_block(ctx, edges, n4x);
|
||||
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
|
||||
|
||||
for (i = 0; i < x4; i++) {
|
||||
edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
|
||||
hash_d[i].blocks -= MAXCHUNKSIZE / 64;
|
||||
edges[i].blocks = MAXCHUNKSIZE / 64;
|
||||
ciph_d[i].inp += MAXCHUNKSIZE;
|
||||
ciph_d[i].out += MAXCHUNKSIZE;
|
||||
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
|
||||
memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
|
||||
}
|
||||
processed += MAXCHUNKSIZE;
|
||||
minblocks -= MAXCHUNKSIZE / 64;
|
||||
} while (minblocks > MAXCHUNKSIZE / 64);
|
||||
}
|
||||
# endif
|
||||
# undef MAXCHUNKSIZE
|
||||
sha1_multi_block(ctx, hash_d, n4x);
|
||||
|
||||
memset(blocks, 0, sizeof(blocks));
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag),
|
||||
off = hash_d[i].blocks * 64;
|
||||
const unsigned char *ptr = hash_d[i].ptr + off;
|
||||
|
||||
off = (len - processed) - (64 - 13) - off; /* remainder actually */
|
||||
memcpy(blocks[i].c, ptr, off);
|
||||
blocks[i].c[off] = 0x80;
|
||||
len += 64 + 13; /* 64 is HMAC header */
|
||||
len *= 8; /* convert to bits */
|
||||
if (off < (64 - 8)) {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[15] = BSWAP4(len);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 60, len);
|
||||
# endif
|
||||
edges[i].blocks = 1;
|
||||
} else {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[31] = BSWAP4(len);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 124, len);
|
||||
# endif
|
||||
edges[i].blocks = 2;
|
||||
}
|
||||
edges[i].ptr = blocks[i].c;
|
||||
}
|
||||
|
||||
/* hash input tails and finalize */
|
||||
sha1_multi_block(ctx, edges, n4x);
|
||||
|
||||
memset(blocks, 0, sizeof(blocks));
|
||||
for (i = 0; i < x4; i++) {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[0] = BSWAP4(ctx->A[i]);
|
||||
ctx->A[i] = key->tail.h0;
|
||||
blocks[i].d[1] = BSWAP4(ctx->B[i]);
|
||||
ctx->B[i] = key->tail.h1;
|
||||
blocks[i].d[2] = BSWAP4(ctx->C[i]);
|
||||
ctx->C[i] = key->tail.h2;
|
||||
blocks[i].d[3] = BSWAP4(ctx->D[i]);
|
||||
ctx->D[i] = key->tail.h3;
|
||||
blocks[i].d[4] = BSWAP4(ctx->E[i]);
|
||||
ctx->E[i] = key->tail.h4;
|
||||
blocks[i].c[20] = 0x80;
|
||||
blocks[i].d[15] = BSWAP4((64 + 20) * 8);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 0, ctx->A[i]);
|
||||
ctx->A[i] = key->tail.h0;
|
||||
PUTU32(blocks[i].c + 4, ctx->B[i]);
|
||||
ctx->B[i] = key->tail.h1;
|
||||
PUTU32(blocks[i].c + 8, ctx->C[i]);
|
||||
ctx->C[i] = key->tail.h2;
|
||||
PUTU32(blocks[i].c + 12, ctx->D[i]);
|
||||
ctx->D[i] = key->tail.h3;
|
||||
PUTU32(blocks[i].c + 16, ctx->E[i]);
|
||||
ctx->E[i] = key->tail.h4;
|
||||
blocks[i].c[20] = 0x80;
|
||||
PUTU32(blocks[i].c + 60, (64 + 20) * 8);
|
||||
# endif
|
||||
edges[i].ptr = blocks[i].c;
|
||||
edges[i].blocks = 1;
|
||||
}
|
||||
|
||||
/* finalize MACs */
|
||||
sha1_multi_block(ctx, edges, n4x);
|
||||
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
|
||||
unsigned char *out0 = out;
|
||||
|
||||
memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
|
||||
ciph_d[i].inp = ciph_d[i].out;
|
||||
|
||||
out += 5 + 16 + len;
|
||||
|
||||
/* write MAC */
|
||||
PUTU32(out + 0, ctx->A[i]);
|
||||
PUTU32(out + 4, ctx->B[i]);
|
||||
PUTU32(out + 8, ctx->C[i]);
|
||||
PUTU32(out + 12, ctx->D[i]);
|
||||
PUTU32(out + 16, ctx->E[i]);
|
||||
out += 20;
|
||||
len += 20;
|
||||
|
||||
/* pad */
|
||||
pad = 15 - len % 16;
|
||||
for (j = 0; j <= pad; j++)
|
||||
*(out++) = pad;
|
||||
len += pad + 1;
|
||||
|
||||
ciph_d[i].blocks = (len - processed) / 16;
|
||||
len += 16; /* account for explicit iv */
|
||||
|
||||
/* arrange header */
|
||||
out0[0] = ((u8 *)key->md.data)[8];
|
||||
out0[1] = ((u8 *)key->md.data)[9];
|
||||
out0[2] = ((u8 *)key->md.data)[10];
|
||||
out0[3] = (u8)(len >> 8);
|
||||
out0[4] = (u8)(len);
|
||||
|
||||
ret += len + 5;
|
||||
inp += frag;
|
||||
}
|
||||
|
||||
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
|
||||
|
||||
OPENSSL_cleanse(blocks, sizeof(blocks));
|
||||
OPENSSL_cleanse(ctx, sizeof(*ctx));
|
||||
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_AES_HMAC_SHA1 *key = data(ctx);
|
||||
unsigned int l;
|
||||
size_t plen = key->payload_length, iv = 0, /* explicit IV in TLS 1.1 and
|
||||
* later */
|
||||
sha_off = 0;
|
||||
# if defined(STITCHED_CALL)
|
||||
size_t aes_off = 0, blocks;
|
||||
|
||||
sha_off = SHA_CBLOCK - key->md.num;
|
||||
# endif
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
if (len % AES_BLOCK_SIZE)
|
||||
return 0;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (plen == NO_PAYLOAD_LENGTH)
|
||||
plen = len;
|
||||
else if (len !=
|
||||
((plen + SHA_DIGEST_LENGTH +
|
||||
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
|
||||
return 0;
|
||||
else if (key->aux.tls_ver >= TLS1_1_VERSION)
|
||||
iv = AES_BLOCK_SIZE;
|
||||
|
||||
# if defined(STITCHED_CALL)
|
||||
if (plen > (sha_off + iv)
|
||||
&& (blocks = (plen - (sha_off + iv)) / SHA_CBLOCK)) {
|
||||
SHA1_Update(&key->md, in + iv, sha_off);
|
||||
|
||||
aesni_cbc_sha1_enc(in, out, blocks, &key->ks, ctx->iv,
|
||||
&key->md, in + iv + sha_off);
|
||||
blocks *= SHA_CBLOCK;
|
||||
aes_off += blocks;
|
||||
sha_off += blocks;
|
||||
key->md.Nh += blocks >> 29;
|
||||
key->md.Nl += blocks <<= 3;
|
||||
if (key->md.Nl < (unsigned int)blocks)
|
||||
key->md.Nh++;
|
||||
} else {
|
||||
sha_off = 0;
|
||||
}
|
||||
# endif
|
||||
sha_off += iv;
|
||||
SHA1_Update(&key->md, in + sha_off, plen - sha_off);
|
||||
|
||||
if (plen != len) { /* "TLS" mode of operation */
|
||||
if (in != out)
|
||||
memcpy(out + aes_off, in + aes_off, plen - aes_off);
|
||||
|
||||
/* calculate HMAC and append it to payload */
|
||||
SHA1_Final(out + plen, &key->md);
|
||||
key->md = key->tail;
|
||||
SHA1_Update(&key->md, out + plen, SHA_DIGEST_LENGTH);
|
||||
SHA1_Final(out + plen, &key->md);
|
||||
|
||||
/* pad the payload|hmac */
|
||||
plen += SHA_DIGEST_LENGTH;
|
||||
for (l = len - plen - 1; plen < len; plen++)
|
||||
out[plen] = l;
|
||||
/* encrypt HMAC|padding at once */
|
||||
aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
|
||||
&key->ks, ctx->iv, 1);
|
||||
} else {
|
||||
aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
|
||||
&key->ks, ctx->iv, 1);
|
||||
}
|
||||
} else {
|
||||
union {
|
||||
unsigned int u[SHA_DIGEST_LENGTH / sizeof(unsigned int)];
|
||||
unsigned char c[32 + SHA_DIGEST_LENGTH];
|
||||
} mac, *pmac;
|
||||
|
||||
/* arrange cache line alignment */
|
||||
pmac = (void *)(((size_t)mac.c + 31) & ((size_t)0 - 32));
|
||||
|
||||
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
|
||||
size_t inp_len, mask, j, i;
|
||||
unsigned int res, maxpad, pad, bitlen;
|
||||
int ret = 1;
|
||||
union {
|
||||
unsigned int u[SHA_LBLOCK];
|
||||
unsigned char c[SHA_CBLOCK];
|
||||
} *data = (void *)key->md.data;
|
||||
# if defined(STITCHED_DECRYPT_CALL)
|
||||
unsigned char tail_iv[AES_BLOCK_SIZE];
|
||||
int stitch = 0;
|
||||
const int keylen = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
|
||||
if (keylen <= 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
if ((key->aux.tls_aad[plen - 4] << 8 | key->aux.tls_aad[plen - 3])
|
||||
>= TLS1_1_VERSION) {
|
||||
if (len < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1))
|
||||
return 0;
|
||||
|
||||
/* omit explicit iv */
|
||||
memcpy(ctx->iv, in, AES_BLOCK_SIZE);
|
||||
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else if (len < (SHA_DIGEST_LENGTH + 1))
|
||||
return 0;
|
||||
|
||||
# if defined(STITCHED_DECRYPT_CALL)
|
||||
if (len >= 1024 && keylen == 32) {
|
||||
/* decrypt last block */
|
||||
memcpy(tail_iv, in + len - 2 * AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE);
|
||||
aesni_cbc_encrypt(in + len - AES_BLOCK_SIZE,
|
||||
out + len - AES_BLOCK_SIZE, AES_BLOCK_SIZE,
|
||||
&key->ks, tail_iv, 0);
|
||||
stitch = 1;
|
||||
} else
|
||||
# endif
|
||||
/* decrypt HMAC|padding at once */
|
||||
aesni_cbc_encrypt(in, out, len, &key->ks,
|
||||
ctx->iv, 0);
|
||||
|
||||
/* figure out payload length */
|
||||
pad = out[len - 1];
|
||||
maxpad = len - (SHA_DIGEST_LENGTH + 1);
|
||||
maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
|
||||
maxpad &= 255;
|
||||
|
||||
mask = constant_time_ge(maxpad, pad);
|
||||
ret &= mask;
|
||||
/*
|
||||
* If pad is invalid then we will fail the above test but we must
|
||||
* continue anyway because we are in constant time code. However,
|
||||
* we'll use the maxpad value instead of the supplied pad to make
|
||||
* sure we perform well defined pointer arithmetic.
|
||||
*/
|
||||
pad = constant_time_select(mask, pad, maxpad);
|
||||
|
||||
inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);
|
||||
|
||||
key->aux.tls_aad[plen - 2] = inp_len >> 8;
|
||||
key->aux.tls_aad[plen - 1] = inp_len;
|
||||
|
||||
/* calculate HMAC */
|
||||
key->md = key->head;
|
||||
SHA1_Update(&key->md, key->aux.tls_aad, plen);
|
||||
|
||||
# if defined(STITCHED_DECRYPT_CALL)
|
||||
if (stitch) {
|
||||
blocks = (len - (256 + 32 + SHA_CBLOCK)) / SHA_CBLOCK;
|
||||
aes_off = len - AES_BLOCK_SIZE - blocks * SHA_CBLOCK;
|
||||
sha_off = SHA_CBLOCK - plen;
|
||||
|
||||
aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
|
||||
|
||||
SHA1_Update(&key->md, out, sha_off);
|
||||
aesni256_cbc_sha1_dec(in + aes_off,
|
||||
out + aes_off, blocks, &key->ks,
|
||||
ctx->iv, &key->md, out + sha_off);
|
||||
|
||||
sha_off += blocks *= SHA_CBLOCK;
|
||||
out += sha_off;
|
||||
len -= sha_off;
|
||||
inp_len -= sha_off;
|
||||
|
||||
key->md.Nl += (blocks << 3); /* at most 18 bits */
|
||||
memcpy(ctx->iv, tail_iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
# endif
|
||||
|
||||
# if 1 /* see original reference version in #else */
|
||||
len -= SHA_DIGEST_LENGTH; /* amend mac */
|
||||
if (len >= (256 + SHA_CBLOCK)) {
|
||||
j = (len - (256 + SHA_CBLOCK)) & (0 - SHA_CBLOCK);
|
||||
j += SHA_CBLOCK - key->md.num;
|
||||
SHA1_Update(&key->md, out, j);
|
||||
out += j;
|
||||
len -= j;
|
||||
inp_len -= j;
|
||||
}
|
||||
|
||||
/* but pretend as if we hashed padded payload */
|
||||
bitlen = key->md.Nl + (inp_len << 3); /* at most 18 bits */
|
||||
# ifdef BSWAP4
|
||||
bitlen = BSWAP4(bitlen);
|
||||
# else
|
||||
mac.c[0] = 0;
|
||||
mac.c[1] = (unsigned char)(bitlen >> 16);
|
||||
mac.c[2] = (unsigned char)(bitlen >> 8);
|
||||
mac.c[3] = (unsigned char)bitlen;
|
||||
bitlen = mac.u[0];
|
||||
# endif
|
||||
|
||||
pmac->u[0] = 0;
|
||||
pmac->u[1] = 0;
|
||||
pmac->u[2] = 0;
|
||||
pmac->u[3] = 0;
|
||||
pmac->u[4] = 0;
|
||||
|
||||
for (res = key->md.num, j = 0; j < len; j++) {
|
||||
size_t c = out[j];
|
||||
mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
|
||||
c &= mask;
|
||||
c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
|
||||
data->c[res++] = (unsigned char)c;
|
||||
|
||||
if (res != SHA_CBLOCK)
|
||||
continue;
|
||||
|
||||
/* j is not incremented yet */
|
||||
mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
|
||||
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
|
||||
sha1_block_data_order(&key->md, data, 1);
|
||||
mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h0 & mask;
|
||||
pmac->u[1] |= key->md.h1 & mask;
|
||||
pmac->u[2] |= key->md.h2 & mask;
|
||||
pmac->u[3] |= key->md.h3 & mask;
|
||||
pmac->u[4] |= key->md.h4 & mask;
|
||||
res = 0;
|
||||
}
|
||||
|
||||
for (i = res; i < SHA_CBLOCK; i++, j++)
|
||||
data->c[i] = 0;
|
||||
|
||||
if (res > SHA_CBLOCK - 8) {
|
||||
mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
|
||||
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
|
||||
sha1_block_data_order(&key->md, data, 1);
|
||||
mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h0 & mask;
|
||||
pmac->u[1] |= key->md.h1 & mask;
|
||||
pmac->u[2] |= key->md.h2 & mask;
|
||||
pmac->u[3] |= key->md.h3 & mask;
|
||||
pmac->u[4] |= key->md.h4 & mask;
|
||||
|
||||
memset(data, 0, SHA_CBLOCK);
|
||||
j += 64;
|
||||
}
|
||||
data->u[SHA_LBLOCK - 1] = bitlen;
|
||||
sha1_block_data_order(&key->md, data, 1);
|
||||
mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h0 & mask;
|
||||
pmac->u[1] |= key->md.h1 & mask;
|
||||
pmac->u[2] |= key->md.h2 & mask;
|
||||
pmac->u[3] |= key->md.h3 & mask;
|
||||
pmac->u[4] |= key->md.h4 & mask;
|
||||
|
||||
# ifdef BSWAP4
|
||||
pmac->u[0] = BSWAP4(pmac->u[0]);
|
||||
pmac->u[1] = BSWAP4(pmac->u[1]);
|
||||
pmac->u[2] = BSWAP4(pmac->u[2]);
|
||||
pmac->u[3] = BSWAP4(pmac->u[3]);
|
||||
pmac->u[4] = BSWAP4(pmac->u[4]);
|
||||
# else
|
||||
for (i = 0; i < 5; i++) {
|
||||
res = pmac->u[i];
|
||||
pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
|
||||
pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
|
||||
pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
|
||||
pmac->c[4 * i + 3] = (unsigned char)res;
|
||||
}
|
||||
# endif
|
||||
len += SHA_DIGEST_LENGTH;
|
||||
# else /* pre-lucky-13 reference version of above */
|
||||
SHA1_Update(&key->md, out, inp_len);
|
||||
res = key->md.num;
|
||||
SHA1_Final(pmac->c, &key->md);
|
||||
|
||||
{
|
||||
unsigned int inp_blocks, pad_blocks;
|
||||
|
||||
/* but pretend as if we hashed padded payload */
|
||||
inp_blocks =
|
||||
1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
|
||||
res += (unsigned int)(len - inp_len);
|
||||
pad_blocks = res / SHA_CBLOCK;
|
||||
res %= SHA_CBLOCK;
|
||||
pad_blocks +=
|
||||
1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
|
||||
for (; inp_blocks < pad_blocks; inp_blocks++)
|
||||
sha1_block_data_order(&key->md, data, 1);
|
||||
}
|
||||
# endif
|
||||
key->md = key->tail;
|
||||
SHA1_Update(&key->md, pmac->c, SHA_DIGEST_LENGTH);
|
||||
SHA1_Final(pmac->c, &key->md);
|
||||
|
||||
/* verify HMAC */
|
||||
out += inp_len;
|
||||
len -= inp_len;
|
||||
# if 1 /* see original reference version in #else */
|
||||
{
|
||||
unsigned char *p = out + len - 1 - maxpad - SHA_DIGEST_LENGTH;
|
||||
size_t off = out - p;
|
||||
unsigned int c, cmask;
|
||||
|
||||
for (res = 0, i = 0, j = 0; j < maxpad + SHA_DIGEST_LENGTH; j++) {
|
||||
c = p[j];
|
||||
cmask =
|
||||
((int)(j - off - SHA_DIGEST_LENGTH)) >> (sizeof(int) *
|
||||
8 - 1);
|
||||
res |= (c ^ pad) & ~cmask; /* ... and padding */
|
||||
cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
|
||||
res |= (c ^ pmac->c[i]) & cmask;
|
||||
i += 1 & cmask;
|
||||
}
|
||||
|
||||
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
|
||||
ret &= (int)~res;
|
||||
}
|
||||
# else /* pre-lucky-13 reference version of above */
|
||||
for (res = 0, i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
res |= out[i] ^ pmac->c[i];
|
||||
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
|
||||
ret &= (int)~res;
|
||||
|
||||
/* verify padding */
|
||||
pad = (pad & ~res) | (maxpad & res);
|
||||
out = out + len - 1 - pad;
|
||||
for (res = 0, i = 0; i < pad; i++)
|
||||
res |= out[i] ^ pad;
|
||||
|
||||
res = (0 - res) >> (sizeof(res) * 8 - 1);
|
||||
ret &= (int)~res;
|
||||
# endif
|
||||
return ret;
|
||||
} else {
|
||||
# if defined(STITCHED_DECRYPT_CALL)
|
||||
if (len >= 1024 && keylen == 32) {
|
||||
if (sha_off %= SHA_CBLOCK)
|
||||
blocks = (len - 3 * SHA_CBLOCK) / SHA_CBLOCK;
|
||||
else
|
||||
blocks = (len - 2 * SHA_CBLOCK) / SHA_CBLOCK;
|
||||
aes_off = len - blocks * SHA_CBLOCK;
|
||||
|
||||
aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
|
||||
SHA1_Update(&key->md, out, sha_off);
|
||||
aesni256_cbc_sha1_dec(in + aes_off,
|
||||
out + aes_off, blocks, &key->ks,
|
||||
ctx->iv, &key->md, out + sha_off);
|
||||
|
||||
sha_off += blocks *= SHA_CBLOCK;
|
||||
out += sha_off;
|
||||
len -= sha_off;
|
||||
|
||||
key->md.Nh += blocks >> 29;
|
||||
key->md.Nl += blocks <<= 3;
|
||||
if (key->md.Nl < (unsigned int)blocks)
|
||||
key->md.Nh++;
|
||||
} else
|
||||
# endif
|
||||
/* decrypt HMAC|padding at once */
|
||||
aesni_cbc_encrypt(in, out, len, &key->ks,
|
||||
ctx->iv, 0);
|
||||
|
||||
SHA1_Update(&key->md, out, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aesni_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
|
||||
void *ptr)
|
||||
{
|
||||
EVP_AES_HMAC_SHA1 *key = data(ctx);
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_AEAD_SET_MAC_KEY:
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char hmac_key[64];
|
||||
|
||||
memset(hmac_key, 0, sizeof(hmac_key));
|
||||
|
||||
if (arg > (int)sizeof(hmac_key)) {
|
||||
SHA1_Init(&key->head);
|
||||
SHA1_Update(&key->head, ptr, arg);
|
||||
SHA1_Final(hmac_key, &key->head);
|
||||
} else {
|
||||
memcpy(hmac_key, ptr, arg);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36; /* ipad */
|
||||
SHA1_Init(&key->head);
|
||||
SHA1_Update(&key->head, hmac_key, sizeof(hmac_key));
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
|
||||
SHA1_Init(&key->tail);
|
||||
SHA1_Update(&key->tail, hmac_key, sizeof(hmac_key));
|
||||
|
||||
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
{
|
||||
unsigned char *p = ptr;
|
||||
unsigned int len;
|
||||
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return -1;
|
||||
|
||||
len = p[arg - 2] << 8 | p[arg - 1];
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
key->payload_length = len;
|
||||
if ((key->aux.tls_ver =
|
||||
p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
|
||||
if (len < AES_BLOCK_SIZE)
|
||||
return 0;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
p[arg - 2] = len >> 8;
|
||||
p[arg - 1] = len;
|
||||
}
|
||||
key->md = key->head;
|
||||
SHA1_Update(&key->md, p, arg);
|
||||
|
||||
return (int)(((len + SHA_DIGEST_LENGTH +
|
||||
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
|
||||
- len);
|
||||
} else {
|
||||
memcpy(key->aux.tls_aad, ptr, arg);
|
||||
key->payload_length = arg;
|
||||
|
||||
return SHA_DIGEST_LENGTH;
|
||||
}
|
||||
}
|
||||
# if !defined(OPENSSL_NO_MULTIBLOCK)
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE:
|
||||
return (int)(5 + 16 + ((arg + 20 + 16) & -16));
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_AAD:
|
||||
{
|
||||
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
|
||||
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
|
||||
unsigned int n4x = 1, x4;
|
||||
unsigned int frag, last, packlen, inp_len;
|
||||
|
||||
if (arg < (int)sizeof(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM))
|
||||
return -1;
|
||||
|
||||
inp_len = param->inp[11] << 8 | param->inp[12];
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
|
||||
return -1;
|
||||
|
||||
if (inp_len) {
|
||||
if (inp_len < 4096)
|
||||
return 0; /* too short */
|
||||
|
||||
if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
|
||||
n4x = 2; /* AVX2 */
|
||||
} else if ((n4x = param->interleave / 4) && n4x <= 2)
|
||||
inp_len = param->len;
|
||||
else
|
||||
return -1;
|
||||
|
||||
key->md = key->head;
|
||||
SHA1_Update(&key->md, param->inp, 13);
|
||||
|
||||
x4 = 4 * n4x;
|
||||
n4x += 1;
|
||||
|
||||
frag = inp_len >> n4x;
|
||||
last = inp_len + frag - (frag << n4x);
|
||||
if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
|
||||
frag++;
|
||||
last -= x4 - 1;
|
||||
}
|
||||
|
||||
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
|
||||
packlen = (packlen << n4x) - packlen;
|
||||
packlen += 5 + 16 + ((last + 20 + 16) & -16);
|
||||
|
||||
param->interleave = x4;
|
||||
|
||||
return (int)packlen;
|
||||
} else
|
||||
return -1; /* not yet */
|
||||
}
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT:
|
||||
{
|
||||
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
|
||||
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
|
||||
|
||||
return (int)tls1_1_multi_block_encrypt(key, param->out,
|
||||
param->inp, param->len,
|
||||
param->interleave / 4);
|
||||
}
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT:
|
||||
# endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static EVP_CIPHER aesni_128_cbc_hmac_sha1_cipher = {
|
||||
# ifdef NID_aes_128_cbc_hmac_sha1
|
||||
NID_aes_128_cbc_hmac_sha1,
|
||||
# else
|
||||
NID_undef,
|
||||
# endif
|
||||
AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
|
||||
EVP_ORIG_GLOBAL,
|
||||
aesni_cbc_hmac_sha1_init_key,
|
||||
aesni_cbc_hmac_sha1_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_AES_HMAC_SHA1),
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
|
||||
aesni_cbc_hmac_sha1_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
static EVP_CIPHER aesni_256_cbc_hmac_sha1_cipher = {
|
||||
# ifdef NID_aes_256_cbc_hmac_sha1
|
||||
NID_aes_256_cbc_hmac_sha1,
|
||||
# else
|
||||
NID_undef,
|
||||
# endif
|
||||
AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
|
||||
EVP_ORIG_GLOBAL,
|
||||
aesni_cbc_hmac_sha1_init_key,
|
||||
aesni_cbc_hmac_sha1_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_AES_HMAC_SHA1),
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
|
||||
aesni_cbc_hmac_sha1_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
|
||||
{
|
||||
return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
|
||||
&aesni_128_cbc_hmac_sha1_cipher : NULL);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
|
||||
{
|
||||
return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
|
||||
&aesni_256_cbc_hmac_sha1_cipher : NULL);
|
||||
}
|
||||
#else
|
||||
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
+955
@@ -0,0 +1,955 @@
|
||||
/*
|
||||
* Copyright 2013-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use where we're using them to implement the higher level EVP interface, as is
|
||||
* the case here.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/modes.h"
|
||||
#include "internal/constant_time.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
typedef struct {
|
||||
AES_KEY ks;
|
||||
SHA256_CTX head, tail, md;
|
||||
size_t payload_length; /* AAD length in decrypt case */
|
||||
union {
|
||||
unsigned int tls_ver;
|
||||
unsigned char tls_aad[16]; /* 13 used */
|
||||
} aux;
|
||||
} EVP_AES_HMAC_SHA256;
|
||||
|
||||
# define NO_PAYLOAD_LENGTH ((size_t)-1)
|
||||
|
||||
#if defined(AES_ASM) && ( \
|
||||
defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(_M_X64) )
|
||||
|
||||
# define AESNI_CAPABLE (1<<(57-32))
|
||||
|
||||
int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
|
||||
void aesni_cbc_encrypt(const unsigned char *in,
|
||||
unsigned char *out,
|
||||
size_t length,
|
||||
const AES_KEY *key, unsigned char *ivec, int enc);
|
||||
|
||||
int aesni_cbc_sha256_enc(const void *inp, void *out, size_t blocks,
|
||||
const AES_KEY *key, unsigned char iv[16],
|
||||
SHA256_CTX *ctx, const void *in0);
|
||||
|
||||
# define data(ctx) ((EVP_AES_HMAC_SHA256 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
|
||||
|
||||
static int aesni_cbc_hmac_sha256_init_key(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *inkey,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
EVP_AES_HMAC_SHA256 *key = data(ctx);
|
||||
int ret;
|
||||
|
||||
if (enc)
|
||||
ret = aesni_set_encrypt_key(inkey,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
&key->ks);
|
||||
else
|
||||
ret = aesni_set_decrypt_key(inkey,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
&key->ks);
|
||||
|
||||
SHA256_Init(&key->head); /* handy when benchmarking */
|
||||
key->tail = key->head;
|
||||
key->md = key->head;
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
return ret < 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
# define STITCHED_CALL
|
||||
|
||||
# if !defined(STITCHED_CALL)
|
||||
# define aes_off 0
|
||||
# endif
|
||||
|
||||
void sha256_block_data_order(void *c, const void *p, size_t len);
|
||||
|
||||
static void sha256_update(SHA256_CTX *c, const void *data, size_t len)
|
||||
{
|
||||
const unsigned char *ptr = data;
|
||||
size_t res;
|
||||
|
||||
if ((res = c->num)) {
|
||||
res = SHA256_CBLOCK - res;
|
||||
if (len < res)
|
||||
res = len;
|
||||
SHA256_Update(c, ptr, res);
|
||||
ptr += res;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
res = len % SHA256_CBLOCK;
|
||||
len -= res;
|
||||
|
||||
if (len) {
|
||||
sha256_block_data_order(c, ptr, len / SHA256_CBLOCK);
|
||||
|
||||
ptr += len;
|
||||
c->Nh += len >> 29;
|
||||
c->Nl += len <<= 3;
|
||||
if (c->Nl < (unsigned int)len)
|
||||
c->Nh++;
|
||||
}
|
||||
|
||||
if (res)
|
||||
SHA256_Update(c, ptr, res);
|
||||
}
|
||||
|
||||
# ifdef SHA256_Update
|
||||
# undef SHA256_Update
|
||||
# endif
|
||||
# define SHA256_Update sha256_update
|
||||
|
||||
# if !defined(OPENSSL_NO_MULTIBLOCK)
|
||||
|
||||
typedef struct {
|
||||
unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8];
|
||||
} SHA256_MB_CTX;
|
||||
typedef struct {
|
||||
const unsigned char *ptr;
|
||||
int blocks;
|
||||
} HASH_DESC;
|
||||
|
||||
void sha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int);
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *inp;
|
||||
unsigned char *out;
|
||||
int blocks;
|
||||
u64 iv[2];
|
||||
} CIPH_DESC;
|
||||
|
||||
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
|
||||
|
||||
static size_t tls1_1_multi_block_encrypt(EVP_AES_HMAC_SHA256 *key,
|
||||
unsigned char *out,
|
||||
const unsigned char *inp,
|
||||
size_t inp_len, int n4x)
|
||||
{ /* n4x is 1 or 2 */
|
||||
HASH_DESC hash_d[8], edges[8];
|
||||
CIPH_DESC ciph_d[8];
|
||||
unsigned char storage[sizeof(SHA256_MB_CTX) + 32];
|
||||
union {
|
||||
u64 q[16];
|
||||
u32 d[32];
|
||||
u8 c[128];
|
||||
} blocks[8];
|
||||
SHA256_MB_CTX *ctx;
|
||||
unsigned int frag, last, packlen, i, x4 = 4 * n4x, minblocks, processed =
|
||||
0;
|
||||
size_t ret = 0;
|
||||
u8 *IVs;
|
||||
# if defined(BSWAP8)
|
||||
u64 seqnum;
|
||||
# endif
|
||||
|
||||
/* ask for IVs in bulk */
|
||||
if (RAND_bytes((IVs = blocks[0].c), 16 * x4) <= 0)
|
||||
return 0;
|
||||
|
||||
/* align */
|
||||
ctx = (SHA256_MB_CTX *) (storage + 32 - ((size_t)storage % 32));
|
||||
|
||||
frag = (unsigned int)inp_len >> (1 + n4x);
|
||||
last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
|
||||
if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
|
||||
frag++;
|
||||
last -= x4 - 1;
|
||||
}
|
||||
|
||||
packlen = 5 + 16 + ((frag + 32 + 16) & -16);
|
||||
|
||||
/* populate descriptors with pointers and IVs */
|
||||
hash_d[0].ptr = inp;
|
||||
ciph_d[0].inp = inp;
|
||||
/* 5+16 is place for header and explicit IV */
|
||||
ciph_d[0].out = out + 5 + 16;
|
||||
memcpy(ciph_d[0].out - 16, IVs, 16);
|
||||
memcpy(ciph_d[0].iv, IVs, 16);
|
||||
IVs += 16;
|
||||
|
||||
for (i = 1; i < x4; i++) {
|
||||
ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
|
||||
ciph_d[i].out = ciph_d[i - 1].out + packlen;
|
||||
memcpy(ciph_d[i].out - 16, IVs, 16);
|
||||
memcpy(ciph_d[i].iv, IVs, 16);
|
||||
IVs += 16;
|
||||
}
|
||||
|
||||
# if defined(BSWAP8)
|
||||
memcpy(blocks[0].c, key->md.data, 8);
|
||||
seqnum = BSWAP8(blocks[0].q[0]);
|
||||
# endif
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag);
|
||||
# if !defined(BSWAP8)
|
||||
unsigned int carry, j;
|
||||
# endif
|
||||
|
||||
ctx->A[i] = key->md.h[0];
|
||||
ctx->B[i] = key->md.h[1];
|
||||
ctx->C[i] = key->md.h[2];
|
||||
ctx->D[i] = key->md.h[3];
|
||||
ctx->E[i] = key->md.h[4];
|
||||
ctx->F[i] = key->md.h[5];
|
||||
ctx->G[i] = key->md.h[6];
|
||||
ctx->H[i] = key->md.h[7];
|
||||
|
||||
/* fix seqnum */
|
||||
# if defined(BSWAP8)
|
||||
blocks[i].q[0] = BSWAP8(seqnum + i);
|
||||
# else
|
||||
for (carry = i, j = 8; j--;) {
|
||||
blocks[i].c[j] = ((u8 *)key->md.data)[j] + carry;
|
||||
carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
|
||||
}
|
||||
# endif
|
||||
blocks[i].c[8] = ((u8 *)key->md.data)[8];
|
||||
blocks[i].c[9] = ((u8 *)key->md.data)[9];
|
||||
blocks[i].c[10] = ((u8 *)key->md.data)[10];
|
||||
/* fix length */
|
||||
blocks[i].c[11] = (u8)(len >> 8);
|
||||
blocks[i].c[12] = (u8)(len);
|
||||
|
||||
memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
|
||||
hash_d[i].ptr += 64 - 13;
|
||||
hash_d[i].blocks = (len - (64 - 13)) / 64;
|
||||
|
||||
edges[i].ptr = blocks[i].c;
|
||||
edges[i].blocks = 1;
|
||||
}
|
||||
|
||||
/* hash 13-byte headers and first 64-13 bytes of inputs */
|
||||
sha256_multi_block(ctx, edges, n4x);
|
||||
/* hash bulk inputs */
|
||||
# define MAXCHUNKSIZE 2048
|
||||
# if MAXCHUNKSIZE%64
|
||||
# error "MAXCHUNKSIZE is not divisible by 64"
|
||||
# elif MAXCHUNKSIZE
|
||||
/*
|
||||
* goal is to minimize pressure on L1 cache by moving in shorter steps,
|
||||
* so that hashed data is still in the cache by the time we encrypt it
|
||||
*/
|
||||
minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
|
||||
if (minblocks > MAXCHUNKSIZE / 64) {
|
||||
for (i = 0; i < x4; i++) {
|
||||
edges[i].ptr = hash_d[i].ptr;
|
||||
edges[i].blocks = MAXCHUNKSIZE / 64;
|
||||
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
|
||||
}
|
||||
do {
|
||||
sha256_multi_block(ctx, edges, n4x);
|
||||
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
|
||||
|
||||
for (i = 0; i < x4; i++) {
|
||||
edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
|
||||
hash_d[i].blocks -= MAXCHUNKSIZE / 64;
|
||||
edges[i].blocks = MAXCHUNKSIZE / 64;
|
||||
ciph_d[i].inp += MAXCHUNKSIZE;
|
||||
ciph_d[i].out += MAXCHUNKSIZE;
|
||||
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
|
||||
memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
|
||||
}
|
||||
processed += MAXCHUNKSIZE;
|
||||
minblocks -= MAXCHUNKSIZE / 64;
|
||||
} while (minblocks > MAXCHUNKSIZE / 64);
|
||||
}
|
||||
# endif
|
||||
# undef MAXCHUNKSIZE
|
||||
sha256_multi_block(ctx, hash_d, n4x);
|
||||
|
||||
memset(blocks, 0, sizeof(blocks));
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag),
|
||||
off = hash_d[i].blocks * 64;
|
||||
const unsigned char *ptr = hash_d[i].ptr + off;
|
||||
|
||||
off = (len - processed) - (64 - 13) - off; /* remainder actually */
|
||||
memcpy(blocks[i].c, ptr, off);
|
||||
blocks[i].c[off] = 0x80;
|
||||
len += 64 + 13; /* 64 is HMAC header */
|
||||
len *= 8; /* convert to bits */
|
||||
if (off < (64 - 8)) {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[15] = BSWAP4(len);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 60, len);
|
||||
# endif
|
||||
edges[i].blocks = 1;
|
||||
} else {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[31] = BSWAP4(len);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 124, len);
|
||||
# endif
|
||||
edges[i].blocks = 2;
|
||||
}
|
||||
edges[i].ptr = blocks[i].c;
|
||||
}
|
||||
|
||||
/* hash input tails and finalize */
|
||||
sha256_multi_block(ctx, edges, n4x);
|
||||
|
||||
memset(blocks, 0, sizeof(blocks));
|
||||
for (i = 0; i < x4; i++) {
|
||||
# ifdef BSWAP4
|
||||
blocks[i].d[0] = BSWAP4(ctx->A[i]);
|
||||
ctx->A[i] = key->tail.h[0];
|
||||
blocks[i].d[1] = BSWAP4(ctx->B[i]);
|
||||
ctx->B[i] = key->tail.h[1];
|
||||
blocks[i].d[2] = BSWAP4(ctx->C[i]);
|
||||
ctx->C[i] = key->tail.h[2];
|
||||
blocks[i].d[3] = BSWAP4(ctx->D[i]);
|
||||
ctx->D[i] = key->tail.h[3];
|
||||
blocks[i].d[4] = BSWAP4(ctx->E[i]);
|
||||
ctx->E[i] = key->tail.h[4];
|
||||
blocks[i].d[5] = BSWAP4(ctx->F[i]);
|
||||
ctx->F[i] = key->tail.h[5];
|
||||
blocks[i].d[6] = BSWAP4(ctx->G[i]);
|
||||
ctx->G[i] = key->tail.h[6];
|
||||
blocks[i].d[7] = BSWAP4(ctx->H[i]);
|
||||
ctx->H[i] = key->tail.h[7];
|
||||
blocks[i].c[32] = 0x80;
|
||||
blocks[i].d[15] = BSWAP4((64 + 32) * 8);
|
||||
# else
|
||||
PUTU32(blocks[i].c + 0, ctx->A[i]);
|
||||
ctx->A[i] = key->tail.h[0];
|
||||
PUTU32(blocks[i].c + 4, ctx->B[i]);
|
||||
ctx->B[i] = key->tail.h[1];
|
||||
PUTU32(blocks[i].c + 8, ctx->C[i]);
|
||||
ctx->C[i] = key->tail.h[2];
|
||||
PUTU32(blocks[i].c + 12, ctx->D[i]);
|
||||
ctx->D[i] = key->tail.h[3];
|
||||
PUTU32(blocks[i].c + 16, ctx->E[i]);
|
||||
ctx->E[i] = key->tail.h[4];
|
||||
PUTU32(blocks[i].c + 20, ctx->F[i]);
|
||||
ctx->F[i] = key->tail.h[5];
|
||||
PUTU32(blocks[i].c + 24, ctx->G[i]);
|
||||
ctx->G[i] = key->tail.h[6];
|
||||
PUTU32(blocks[i].c + 28, ctx->H[i]);
|
||||
ctx->H[i] = key->tail.h[7];
|
||||
blocks[i].c[32] = 0x80;
|
||||
PUTU32(blocks[i].c + 60, (64 + 32) * 8);
|
||||
# endif
|
||||
edges[i].ptr = blocks[i].c;
|
||||
edges[i].blocks = 1;
|
||||
}
|
||||
|
||||
/* finalize MACs */
|
||||
sha256_multi_block(ctx, edges, n4x);
|
||||
|
||||
for (i = 0; i < x4; i++) {
|
||||
unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
|
||||
unsigned char *out0 = out;
|
||||
|
||||
memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
|
||||
ciph_d[i].inp = ciph_d[i].out;
|
||||
|
||||
out += 5 + 16 + len;
|
||||
|
||||
/* write MAC */
|
||||
PUTU32(out + 0, ctx->A[i]);
|
||||
PUTU32(out + 4, ctx->B[i]);
|
||||
PUTU32(out + 8, ctx->C[i]);
|
||||
PUTU32(out + 12, ctx->D[i]);
|
||||
PUTU32(out + 16, ctx->E[i]);
|
||||
PUTU32(out + 20, ctx->F[i]);
|
||||
PUTU32(out + 24, ctx->G[i]);
|
||||
PUTU32(out + 28, ctx->H[i]);
|
||||
out += 32;
|
||||
len += 32;
|
||||
|
||||
/* pad */
|
||||
pad = 15 - len % 16;
|
||||
for (j = 0; j <= pad; j++)
|
||||
*(out++) = pad;
|
||||
len += pad + 1;
|
||||
|
||||
ciph_d[i].blocks = (len - processed) / 16;
|
||||
len += 16; /* account for explicit iv */
|
||||
|
||||
/* arrange header */
|
||||
out0[0] = ((u8 *)key->md.data)[8];
|
||||
out0[1] = ((u8 *)key->md.data)[9];
|
||||
out0[2] = ((u8 *)key->md.data)[10];
|
||||
out0[3] = (u8)(len >> 8);
|
||||
out0[4] = (u8)(len);
|
||||
|
||||
ret += len + 5;
|
||||
inp += frag;
|
||||
}
|
||||
|
||||
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
|
||||
|
||||
OPENSSL_cleanse(blocks, sizeof(blocks));
|
||||
OPENSSL_cleanse(ctx, sizeof(*ctx));
|
||||
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
static int aesni_cbc_hmac_sha256_cipher(EVP_CIPHER_CTX *ctx,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_AES_HMAC_SHA256 *key = data(ctx);
|
||||
unsigned int l;
|
||||
size_t plen = key->payload_length, iv = 0, /* explicit IV in TLS 1.1 and
|
||||
* later */
|
||||
sha_off = 0;
|
||||
# if defined(STITCHED_CALL)
|
||||
size_t aes_off = 0, blocks;
|
||||
|
||||
sha_off = SHA256_CBLOCK - key->md.num;
|
||||
# endif
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
if (len % AES_BLOCK_SIZE)
|
||||
return 0;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (plen == NO_PAYLOAD_LENGTH)
|
||||
plen = len;
|
||||
else if (len !=
|
||||
((plen + SHA256_DIGEST_LENGTH +
|
||||
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
|
||||
return 0;
|
||||
else if (key->aux.tls_ver >= TLS1_1_VERSION)
|
||||
iv = AES_BLOCK_SIZE;
|
||||
|
||||
# if defined(STITCHED_CALL)
|
||||
/*
|
||||
* Assembly stitch handles AVX-capable processors, but its
|
||||
* performance is not optimal on AMD Jaguar, ~40% worse, for
|
||||
* unknown reasons. Incidentally processor in question supports
|
||||
* AVX, but not AMD-specific XOP extension, which can be used
|
||||
* to identify it and avoid stitch invocation. So that after we
|
||||
* establish that current CPU supports AVX, we even see if it's
|
||||
* either even XOP-capable Bulldozer-based or GenuineIntel one.
|
||||
* But SHAEXT-capable go ahead...
|
||||
*/
|
||||
if (((OPENSSL_ia32cap_P[2] & (1 << 29)) || /* SHAEXT? */
|
||||
((OPENSSL_ia32cap_P[1] & (1 << (60 - 32))) && /* AVX? */
|
||||
((OPENSSL_ia32cap_P[1] & (1 << (43 - 32))) /* XOP? */
|
||||
| (OPENSSL_ia32cap_P[0] & (1 << 30))))) && /* "Intel CPU"? */
|
||||
plen > (sha_off + iv) &&
|
||||
(blocks = (plen - (sha_off + iv)) / SHA256_CBLOCK)) {
|
||||
SHA256_Update(&key->md, in + iv, sha_off);
|
||||
|
||||
(void)aesni_cbc_sha256_enc(in, out, blocks, &key->ks,
|
||||
ctx->iv, &key->md, in + iv + sha_off);
|
||||
blocks *= SHA256_CBLOCK;
|
||||
aes_off += blocks;
|
||||
sha_off += blocks;
|
||||
key->md.Nh += blocks >> 29;
|
||||
key->md.Nl += blocks <<= 3;
|
||||
if (key->md.Nl < (unsigned int)blocks)
|
||||
key->md.Nh++;
|
||||
} else {
|
||||
sha_off = 0;
|
||||
}
|
||||
# endif
|
||||
sha_off += iv;
|
||||
SHA256_Update(&key->md, in + sha_off, plen - sha_off);
|
||||
|
||||
if (plen != len) { /* "TLS" mode of operation */
|
||||
if (in != out)
|
||||
memcpy(out + aes_off, in + aes_off, plen - aes_off);
|
||||
|
||||
/* calculate HMAC and append it to payload */
|
||||
SHA256_Final(out + plen, &key->md);
|
||||
key->md = key->tail;
|
||||
SHA256_Update(&key->md, out + plen, SHA256_DIGEST_LENGTH);
|
||||
SHA256_Final(out + plen, &key->md);
|
||||
|
||||
/* pad the payload|hmac */
|
||||
plen += SHA256_DIGEST_LENGTH;
|
||||
for (l = len - plen - 1; plen < len; plen++)
|
||||
out[plen] = l;
|
||||
/* encrypt HMAC|padding at once */
|
||||
aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
|
||||
&key->ks, ctx->iv, 1);
|
||||
} else {
|
||||
aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
|
||||
&key->ks, ctx->iv, 1);
|
||||
}
|
||||
} else {
|
||||
union {
|
||||
unsigned int u[SHA256_DIGEST_LENGTH / sizeof(unsigned int)];
|
||||
unsigned char c[64 + SHA256_DIGEST_LENGTH];
|
||||
} mac, *pmac;
|
||||
|
||||
/* arrange cache line alignment */
|
||||
pmac = (void *)(((size_t)mac.c + 63) & ((size_t)0 - 64));
|
||||
|
||||
/* decrypt HMAC|padding at once */
|
||||
aesni_cbc_encrypt(in, out, len, &key->ks,
|
||||
ctx->iv, 0);
|
||||
|
||||
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
|
||||
size_t inp_len, mask, j, i;
|
||||
unsigned int res, maxpad, pad, bitlen;
|
||||
int ret = 1;
|
||||
union {
|
||||
unsigned int u[SHA_LBLOCK];
|
||||
unsigned char c[SHA256_CBLOCK];
|
||||
} *data = (void *)key->md.data;
|
||||
|
||||
if ((key->aux.tls_aad[plen - 4] << 8 | key->aux.tls_aad[plen - 3])
|
||||
>= TLS1_1_VERSION)
|
||||
iv = AES_BLOCK_SIZE;
|
||||
|
||||
if (len < (iv + SHA256_DIGEST_LENGTH + 1))
|
||||
return 0;
|
||||
|
||||
/* omit explicit iv */
|
||||
out += iv;
|
||||
len -= iv;
|
||||
|
||||
/* figure out payload length */
|
||||
pad = out[len - 1];
|
||||
maxpad = len - (SHA256_DIGEST_LENGTH + 1);
|
||||
maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
|
||||
maxpad &= 255;
|
||||
|
||||
mask = constant_time_ge(maxpad, pad);
|
||||
ret &= mask;
|
||||
/*
|
||||
* If pad is invalid then we will fail the above test but we must
|
||||
* continue anyway because we are in constant time code. However,
|
||||
* we'll use the maxpad value instead of the supplied pad to make
|
||||
* sure we perform well defined pointer arithmetic.
|
||||
*/
|
||||
pad = constant_time_select(mask, pad, maxpad);
|
||||
|
||||
inp_len = len - (SHA256_DIGEST_LENGTH + pad + 1);
|
||||
|
||||
key->aux.tls_aad[plen - 2] = inp_len >> 8;
|
||||
key->aux.tls_aad[plen - 1] = inp_len;
|
||||
|
||||
/* calculate HMAC */
|
||||
key->md = key->head;
|
||||
SHA256_Update(&key->md, key->aux.tls_aad, plen);
|
||||
|
||||
# if 1 /* see original reference version in #else */
|
||||
len -= SHA256_DIGEST_LENGTH; /* amend mac */
|
||||
if (len >= (256 + SHA256_CBLOCK)) {
|
||||
j = (len - (256 + SHA256_CBLOCK)) & (0 - SHA256_CBLOCK);
|
||||
j += SHA256_CBLOCK - key->md.num;
|
||||
SHA256_Update(&key->md, out, j);
|
||||
out += j;
|
||||
len -= j;
|
||||
inp_len -= j;
|
||||
}
|
||||
|
||||
/* but pretend as if we hashed padded payload */
|
||||
bitlen = key->md.Nl + (inp_len << 3); /* at most 18 bits */
|
||||
# ifdef BSWAP4
|
||||
bitlen = BSWAP4(bitlen);
|
||||
# else
|
||||
mac.c[0] = 0;
|
||||
mac.c[1] = (unsigned char)(bitlen >> 16);
|
||||
mac.c[2] = (unsigned char)(bitlen >> 8);
|
||||
mac.c[3] = (unsigned char)bitlen;
|
||||
bitlen = mac.u[0];
|
||||
# endif
|
||||
|
||||
pmac->u[0] = 0;
|
||||
pmac->u[1] = 0;
|
||||
pmac->u[2] = 0;
|
||||
pmac->u[3] = 0;
|
||||
pmac->u[4] = 0;
|
||||
pmac->u[5] = 0;
|
||||
pmac->u[6] = 0;
|
||||
pmac->u[7] = 0;
|
||||
|
||||
for (res = key->md.num, j = 0; j < len; j++) {
|
||||
size_t c = out[j];
|
||||
mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
|
||||
c &= mask;
|
||||
c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
|
||||
data->c[res++] = (unsigned char)c;
|
||||
|
||||
if (res != SHA256_CBLOCK)
|
||||
continue;
|
||||
|
||||
/* j is not incremented yet */
|
||||
mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
|
||||
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
|
||||
sha256_block_data_order(&key->md, data, 1);
|
||||
mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h[0] & mask;
|
||||
pmac->u[1] |= key->md.h[1] & mask;
|
||||
pmac->u[2] |= key->md.h[2] & mask;
|
||||
pmac->u[3] |= key->md.h[3] & mask;
|
||||
pmac->u[4] |= key->md.h[4] & mask;
|
||||
pmac->u[5] |= key->md.h[5] & mask;
|
||||
pmac->u[6] |= key->md.h[6] & mask;
|
||||
pmac->u[7] |= key->md.h[7] & mask;
|
||||
res = 0;
|
||||
}
|
||||
|
||||
for (i = res; i < SHA256_CBLOCK; i++, j++)
|
||||
data->c[i] = 0;
|
||||
|
||||
if (res > SHA256_CBLOCK - 8) {
|
||||
mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
|
||||
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
|
||||
sha256_block_data_order(&key->md, data, 1);
|
||||
mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h[0] & mask;
|
||||
pmac->u[1] |= key->md.h[1] & mask;
|
||||
pmac->u[2] |= key->md.h[2] & mask;
|
||||
pmac->u[3] |= key->md.h[3] & mask;
|
||||
pmac->u[4] |= key->md.h[4] & mask;
|
||||
pmac->u[5] |= key->md.h[5] & mask;
|
||||
pmac->u[6] |= key->md.h[6] & mask;
|
||||
pmac->u[7] |= key->md.h[7] & mask;
|
||||
|
||||
memset(data, 0, SHA256_CBLOCK);
|
||||
j += 64;
|
||||
}
|
||||
data->u[SHA_LBLOCK - 1] = bitlen;
|
||||
sha256_block_data_order(&key->md, data, 1);
|
||||
mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
|
||||
pmac->u[0] |= key->md.h[0] & mask;
|
||||
pmac->u[1] |= key->md.h[1] & mask;
|
||||
pmac->u[2] |= key->md.h[2] & mask;
|
||||
pmac->u[3] |= key->md.h[3] & mask;
|
||||
pmac->u[4] |= key->md.h[4] & mask;
|
||||
pmac->u[5] |= key->md.h[5] & mask;
|
||||
pmac->u[6] |= key->md.h[6] & mask;
|
||||
pmac->u[7] |= key->md.h[7] & mask;
|
||||
|
||||
# ifdef BSWAP4
|
||||
pmac->u[0] = BSWAP4(pmac->u[0]);
|
||||
pmac->u[1] = BSWAP4(pmac->u[1]);
|
||||
pmac->u[2] = BSWAP4(pmac->u[2]);
|
||||
pmac->u[3] = BSWAP4(pmac->u[3]);
|
||||
pmac->u[4] = BSWAP4(pmac->u[4]);
|
||||
pmac->u[5] = BSWAP4(pmac->u[5]);
|
||||
pmac->u[6] = BSWAP4(pmac->u[6]);
|
||||
pmac->u[7] = BSWAP4(pmac->u[7]);
|
||||
# else
|
||||
for (i = 0; i < 8; i++) {
|
||||
res = pmac->u[i];
|
||||
pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
|
||||
pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
|
||||
pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
|
||||
pmac->c[4 * i + 3] = (unsigned char)res;
|
||||
}
|
||||
# endif
|
||||
len += SHA256_DIGEST_LENGTH;
|
||||
# else
|
||||
SHA256_Update(&key->md, out, inp_len);
|
||||
res = key->md.num;
|
||||
SHA256_Final(pmac->c, &key->md);
|
||||
|
||||
{
|
||||
unsigned int inp_blocks, pad_blocks;
|
||||
|
||||
/* but pretend as if we hashed padded payload */
|
||||
inp_blocks =
|
||||
1 + ((SHA256_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
|
||||
res += (unsigned int)(len - inp_len);
|
||||
pad_blocks = res / SHA256_CBLOCK;
|
||||
res %= SHA256_CBLOCK;
|
||||
pad_blocks +=
|
||||
1 + ((SHA256_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
|
||||
for (; inp_blocks < pad_blocks; inp_blocks++)
|
||||
sha1_block_data_order(&key->md, data, 1);
|
||||
}
|
||||
# endif /* pre-lucky-13 reference version of above */
|
||||
key->md = key->tail;
|
||||
SHA256_Update(&key->md, pmac->c, SHA256_DIGEST_LENGTH);
|
||||
SHA256_Final(pmac->c, &key->md);
|
||||
|
||||
/* verify HMAC */
|
||||
out += inp_len;
|
||||
len -= inp_len;
|
||||
# if 1 /* see original reference version in #else */
|
||||
{
|
||||
unsigned char *p =
|
||||
out + len - 1 - maxpad - SHA256_DIGEST_LENGTH;
|
||||
size_t off = out - p;
|
||||
unsigned int c, cmask;
|
||||
|
||||
for (res = 0, i = 0, j = 0; j < maxpad + SHA256_DIGEST_LENGTH;
|
||||
j++) {
|
||||
c = p[j];
|
||||
cmask =
|
||||
((int)(j - off - SHA256_DIGEST_LENGTH)) >>
|
||||
(sizeof(int) * 8 - 1);
|
||||
res |= (c ^ pad) & ~cmask; /* ... and padding */
|
||||
cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
|
||||
res |= (c ^ pmac->c[i]) & cmask;
|
||||
i += 1 & cmask;
|
||||
}
|
||||
|
||||
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
|
||||
ret &= (int)~res;
|
||||
}
|
||||
# else /* pre-lucky-13 reference version of above */
|
||||
for (res = 0, i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||
res |= out[i] ^ pmac->c[i];
|
||||
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
|
||||
ret &= (int)~res;
|
||||
|
||||
/* verify padding */
|
||||
pad = (pad & ~res) | (maxpad & res);
|
||||
out = out + len - 1 - pad;
|
||||
for (res = 0, i = 0; i < pad; i++)
|
||||
res |= out[i] ^ pad;
|
||||
|
||||
res = (0 - res) >> (sizeof(res) * 8 - 1);
|
||||
ret &= (int)~res;
|
||||
# endif
|
||||
return ret;
|
||||
} else {
|
||||
SHA256_Update(&key->md, out, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aesni_cbc_hmac_sha256_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
|
||||
void *ptr)
|
||||
{
|
||||
EVP_AES_HMAC_SHA256 *key = data(ctx);
|
||||
unsigned int u_arg = (unsigned int)arg;
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_AEAD_SET_MAC_KEY:
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char hmac_key[64];
|
||||
|
||||
memset(hmac_key, 0, sizeof(hmac_key));
|
||||
|
||||
if (arg < 0)
|
||||
return -1;
|
||||
|
||||
if (u_arg > sizeof(hmac_key)) {
|
||||
SHA256_Init(&key->head);
|
||||
SHA256_Update(&key->head, ptr, arg);
|
||||
SHA256_Final(hmac_key, &key->head);
|
||||
} else {
|
||||
memcpy(hmac_key, ptr, arg);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36; /* ipad */
|
||||
SHA256_Init(&key->head);
|
||||
SHA256_Update(&key->head, hmac_key, sizeof(hmac_key));
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
|
||||
SHA256_Init(&key->tail);
|
||||
SHA256_Update(&key->tail, hmac_key, sizeof(hmac_key));
|
||||
|
||||
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
{
|
||||
unsigned char *p = ptr;
|
||||
unsigned int len;
|
||||
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return -1;
|
||||
|
||||
len = p[arg - 2] << 8 | p[arg - 1];
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
key->payload_length = len;
|
||||
if ((key->aux.tls_ver =
|
||||
p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
|
||||
if (len < AES_BLOCK_SIZE)
|
||||
return 0;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
p[arg - 2] = len >> 8;
|
||||
p[arg - 1] = len;
|
||||
}
|
||||
key->md = key->head;
|
||||
SHA256_Update(&key->md, p, arg);
|
||||
|
||||
return (int)(((len + SHA256_DIGEST_LENGTH +
|
||||
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
|
||||
- len);
|
||||
} else {
|
||||
memcpy(key->aux.tls_aad, ptr, arg);
|
||||
key->payload_length = arg;
|
||||
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
}
|
||||
}
|
||||
# if !defined(OPENSSL_NO_MULTIBLOCK)
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE:
|
||||
return (int)(5 + 16 + ((arg + 32 + 16) & -16));
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_AAD:
|
||||
{
|
||||
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
|
||||
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
|
||||
unsigned int n4x = 1, x4;
|
||||
unsigned int frag, last, packlen, inp_len;
|
||||
|
||||
if (arg < 0)
|
||||
return -1;
|
||||
|
||||
if (u_arg < sizeof(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM))
|
||||
return -1;
|
||||
|
||||
inp_len = param->inp[11] << 8 | param->inp[12];
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
|
||||
return -1;
|
||||
|
||||
if (inp_len) {
|
||||
if (inp_len < 4096)
|
||||
return 0; /* too short */
|
||||
|
||||
if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
|
||||
n4x = 2; /* AVX2 */
|
||||
} else if ((n4x = param->interleave / 4) && n4x <= 2)
|
||||
inp_len = param->len;
|
||||
else
|
||||
return -1;
|
||||
|
||||
key->md = key->head;
|
||||
SHA256_Update(&key->md, param->inp, 13);
|
||||
|
||||
x4 = 4 * n4x;
|
||||
n4x += 1;
|
||||
|
||||
frag = inp_len >> n4x;
|
||||
last = inp_len + frag - (frag << n4x);
|
||||
if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
|
||||
frag++;
|
||||
last -= x4 - 1;
|
||||
}
|
||||
|
||||
packlen = 5 + 16 + ((frag + 32 + 16) & -16);
|
||||
packlen = (packlen << n4x) - packlen;
|
||||
packlen += 5 + 16 + ((last + 32 + 16) & -16);
|
||||
|
||||
param->interleave = x4;
|
||||
|
||||
return (int)packlen;
|
||||
} else
|
||||
return -1; /* not yet */
|
||||
}
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT:
|
||||
{
|
||||
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
|
||||
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
|
||||
|
||||
return (int)tls1_1_multi_block_encrypt(key, param->out,
|
||||
param->inp, param->len,
|
||||
param->interleave / 4);
|
||||
}
|
||||
case EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT:
|
||||
# endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static EVP_CIPHER aesni_128_cbc_hmac_sha256_cipher = {
|
||||
# ifdef NID_aes_128_cbc_hmac_sha256
|
||||
NID_aes_128_cbc_hmac_sha256,
|
||||
# else
|
||||
NID_undef,
|
||||
# endif
|
||||
AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
|
||||
EVP_ORIG_GLOBAL,
|
||||
aesni_cbc_hmac_sha256_init_key,
|
||||
aesni_cbc_hmac_sha256_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_AES_HMAC_SHA256),
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
|
||||
aesni_cbc_hmac_sha256_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
static EVP_CIPHER aesni_256_cbc_hmac_sha256_cipher = {
|
||||
# ifdef NID_aes_256_cbc_hmac_sha256
|
||||
NID_aes_256_cbc_hmac_sha256,
|
||||
# else
|
||||
NID_undef,
|
||||
# endif
|
||||
AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
|
||||
EVP_ORIG_GLOBAL,
|
||||
aesni_cbc_hmac_sha256_init_key,
|
||||
aesni_cbc_hmac_sha256_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_AES_HMAC_SHA256),
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
|
||||
aesni_cbc_hmac_sha256_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void)
|
||||
{
|
||||
return ((OPENSSL_ia32cap_P[1] & AESNI_CAPABLE) &&
|
||||
aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL) ?
|
||||
&aesni_128_cbc_hmac_sha256_cipher : NULL);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void)
|
||||
{
|
||||
return ((OPENSSL_ia32cap_P[1] & AESNI_CAPABLE) &&
|
||||
aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL) ?
|
||||
&aesni_256_cbc_hmac_sha256_cipher : NULL);
|
||||
}
|
||||
#else
|
||||
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
* Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#ifndef OPENSSL_NO_ARIA
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/modes.h>
|
||||
# include <openssl/rand.h>
|
||||
# include "crypto/aria.h"
|
||||
# include "crypto/evp.h"
|
||||
# include "crypto/modes.h"
|
||||
# include "evp_local.h"
|
||||
|
||||
/* ARIA subkey Structure */
|
||||
typedef struct {
|
||||
ARIA_KEY ks;
|
||||
} EVP_ARIA_KEY;
|
||||
|
||||
/* ARIA GCM context */
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN;
|
||||
ARIA_KEY ks;
|
||||
} ks; /* ARIA subkey to use */
|
||||
int key_set; /* Set if key initialised */
|
||||
int iv_set; /* Set if an iv is set */
|
||||
GCM128_CONTEXT gcm;
|
||||
unsigned char *iv; /* Temporary IV store */
|
||||
int ivlen; /* IV length */
|
||||
int taglen;
|
||||
int iv_gen; /* It is OK to generate IVs */
|
||||
int tls_aad_len; /* TLS AAD length */
|
||||
} EVP_ARIA_GCM_CTX;
|
||||
|
||||
/* ARIA CCM context */
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN;
|
||||
ARIA_KEY ks;
|
||||
} ks; /* ARIA key schedule to use */
|
||||
int key_set; /* Set if key initialised */
|
||||
int iv_set; /* Set if an iv is set */
|
||||
int tag_set; /* Set if tag is valid */
|
||||
int len_set; /* Set if message length set */
|
||||
int L, M; /* L and M parameters from RFC3610 */
|
||||
int tls_aad_len; /* TLS AAD length */
|
||||
CCM128_CONTEXT ccm;
|
||||
ccm128_f str;
|
||||
} EVP_ARIA_CCM_CTX;
|
||||
|
||||
/* The subkey for ARIA is generated. */
|
||||
static int aria_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int ret;
|
||||
int mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
|
||||
if (enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE))
|
||||
ret = ossl_aria_set_encrypt_key(key,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx));
|
||||
else
|
||||
ret = ossl_aria_set_decrypt_key(key,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx));
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aria_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t len, const ARIA_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
|
||||
if (enc)
|
||||
CRYPTO_cbc128_encrypt(in, out, len, key, ivec,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
else
|
||||
CRYPTO_cbc128_decrypt(in, out, len, key, ivec,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
}
|
||||
|
||||
static void aria_cfb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const ARIA_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
|
||||
CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
}
|
||||
|
||||
static void aria_cfb1_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const ARIA_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
CRYPTO_cfb128_1_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
}
|
||||
|
||||
static void aria_cfb8_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const ARIA_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
CRYPTO_cfb128_8_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
}
|
||||
|
||||
static void aria_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const ARIA_KEY *key, const int enc)
|
||||
{
|
||||
ossl_aria_encrypt(in, out, key);
|
||||
}
|
||||
|
||||
static void aria_ofb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const ARIA_KEY *key,
|
||||
unsigned char *ivec, int *num)
|
||||
{
|
||||
CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
}
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(aria_128, ks, aria, EVP_ARIA_KEY,
|
||||
NID_aria_128, 16, 16, 16, 128,
|
||||
0, aria_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPHER_get_asn1_iv,
|
||||
NULL)
|
||||
IMPLEMENT_BLOCK_CIPHER(aria_192, ks, aria, EVP_ARIA_KEY,
|
||||
NID_aria_192, 16, 24, 16, 128,
|
||||
0, aria_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPHER_get_asn1_iv,
|
||||
NULL)
|
||||
IMPLEMENT_BLOCK_CIPHER(aria_256, ks, aria, EVP_ARIA_KEY,
|
||||
NID_aria_256, 16, 32, 16, 128,
|
||||
0, aria_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPHER_get_asn1_iv,
|
||||
NULL)
|
||||
|
||||
# define IMPLEMENT_ARIA_CFBR(ksize,cbits) \
|
||||
IMPLEMENT_CFBR(aria,aria,EVP_ARIA_KEY,ks,ksize,cbits,16,0)
|
||||
IMPLEMENT_ARIA_CFBR(128,1)
|
||||
IMPLEMENT_ARIA_CFBR(192,1)
|
||||
IMPLEMENT_ARIA_CFBR(256,1)
|
||||
IMPLEMENT_ARIA_CFBR(128,8)
|
||||
IMPLEMENT_ARIA_CFBR(192,8)
|
||||
IMPLEMENT_ARIA_CFBR(256,8)
|
||||
|
||||
# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
|
||||
static const EVP_CIPHER aria_##keylen##_##mode = { \
|
||||
nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
|
||||
flags|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
aria_init_key, \
|
||||
aria_##mode##_cipher, \
|
||||
NULL, \
|
||||
sizeof(EVP_ARIA_KEY), \
|
||||
NULL,NULL,NULL,NULL }; \
|
||||
const EVP_CIPHER *EVP_aria_##keylen##_##mode(void) \
|
||||
{ return &aria_##keylen##_##mode; }
|
||||
|
||||
static int aria_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
int n = EVP_CIPHER_CTX_get_num(ctx);
|
||||
unsigned int num;
|
||||
EVP_ARIA_KEY *dat = EVP_C_DATA(EVP_ARIA_KEY, ctx);
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
num = (unsigned int)n;
|
||||
|
||||
CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx), &num,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLOCK_CIPHER_generic(NID_aria, 128, 1, 16, ctr, ctr, CTR, 0)
|
||||
BLOCK_CIPHER_generic(NID_aria, 192, 1, 16, ctr, ctr, CTR, 0)
|
||||
BLOCK_CIPHER_generic(NID_aria, 256, 1, 16, ctr, ctr, CTR, 0)
|
||||
|
||||
/* Authenticated cipher modes (GCM/CCM) */
|
||||
|
||||
/* increment counter (64-bit int) by 1 */
|
||||
static void ctr64_inc(unsigned char *counter)
|
||||
{
|
||||
int n = 8;
|
||||
unsigned char c;
|
||||
|
||||
do {
|
||||
--n;
|
||||
c = counter[n];
|
||||
++c;
|
||||
counter[n] = c;
|
||||
if (c)
|
||||
return;
|
||||
} while (n);
|
||||
}
|
||||
|
||||
static int aria_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int ret;
|
||||
EVP_ARIA_GCM_CTX *gctx = EVP_C_DATA(EVP_ARIA_GCM_CTX, ctx);
|
||||
|
||||
if (!iv && !key)
|
||||
return 1;
|
||||
if (key) {
|
||||
ret = ossl_aria_set_encrypt_key(key,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
&gctx->ks.ks);
|
||||
CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks,
|
||||
(block128_f) ossl_aria_encrypt);
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have an iv can set it directly, otherwise use saved IV.
|
||||
*/
|
||||
if (iv == NULL && gctx->iv_set)
|
||||
iv = gctx->iv;
|
||||
if (iv) {
|
||||
CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
|
||||
gctx->iv_set = 1;
|
||||
}
|
||||
gctx->key_set = 1;
|
||||
} else {
|
||||
/* If key set use IV, otherwise copy */
|
||||
if (gctx->key_set)
|
||||
CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
|
||||
else
|
||||
memcpy(gctx->iv, iv, gctx->ivlen);
|
||||
gctx->iv_set = 1;
|
||||
gctx->iv_gen = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aria_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
|
||||
{
|
||||
EVP_ARIA_GCM_CTX *gctx = EVP_C_DATA(EVP_ARIA_GCM_CTX, c);
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_INIT:
|
||||
gctx->key_set = 0;
|
||||
gctx->iv_set = 0;
|
||||
gctx->ivlen = EVP_CIPHER_get_iv_length(c->cipher);
|
||||
gctx->iv = c->iv;
|
||||
gctx->taglen = -1;
|
||||
gctx->iv_gen = 0;
|
||||
gctx->tls_aad_len = -1;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GET_IVLEN:
|
||||
*(int *)ptr = gctx->ivlen;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_IVLEN:
|
||||
if (arg <= 0)
|
||||
return 0;
|
||||
/* Allocate memory for IV if needed */
|
||||
if ((arg > EVP_MAX_IV_LENGTH) && (arg > gctx->ivlen)) {
|
||||
if (gctx->iv != c->iv)
|
||||
OPENSSL_free(gctx->iv);
|
||||
if ((gctx->iv = OPENSSL_malloc(arg)) == NULL)
|
||||
return 0;
|
||||
}
|
||||
gctx->ivlen = arg;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_TAG:
|
||||
if (arg <= 0 || arg > 16 || EVP_CIPHER_CTX_is_encrypting(c))
|
||||
return 0;
|
||||
memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
|
||||
gctx->taglen = arg;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_GET_TAG:
|
||||
if (arg <= 0 || arg > 16 || !EVP_CIPHER_CTX_is_encrypting(c)
|
||||
|| gctx->taglen < 0)
|
||||
return 0;
|
||||
memcpy(ptr, EVP_CIPHER_CTX_buf_noconst(c), arg);
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GCM_SET_IV_FIXED:
|
||||
/* Special case: -1 length restores whole IV */
|
||||
if (arg == -1) {
|
||||
memcpy(gctx->iv, ptr, gctx->ivlen);
|
||||
gctx->iv_gen = 1;
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Fixed field must be at least 4 bytes and invocation field at least
|
||||
* 8.
|
||||
*/
|
||||
if ((arg < 4) || (gctx->ivlen - arg) < 8)
|
||||
return 0;
|
||||
if (arg)
|
||||
memcpy(gctx->iv, ptr, arg);
|
||||
if (EVP_CIPHER_CTX_is_encrypting(c)
|
||||
&& RAND_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0)
|
||||
return 0;
|
||||
gctx->iv_gen = 1;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GCM_IV_GEN:
|
||||
if (gctx->iv_gen == 0 || gctx->key_set == 0)
|
||||
return 0;
|
||||
CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
|
||||
if (arg <= 0 || arg > gctx->ivlen)
|
||||
arg = gctx->ivlen;
|
||||
memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg);
|
||||
/*
|
||||
* Invocation field will be at least 8 bytes in size and so no need
|
||||
* to check wrap around or increment more than last 8 bytes.
|
||||
*/
|
||||
ctr64_inc(gctx->iv + gctx->ivlen - 8);
|
||||
gctx->iv_set = 1;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GCM_SET_IV_INV:
|
||||
if (gctx->iv_gen == 0 || gctx->key_set == 0
|
||||
|| EVP_CIPHER_CTX_is_encrypting(c))
|
||||
return 0;
|
||||
memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg);
|
||||
CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
|
||||
gctx->iv_set = 1;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
/* Save the AAD for later use */
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return 0;
|
||||
memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
|
||||
gctx->tls_aad_len = arg;
|
||||
{
|
||||
unsigned int len =
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] << 8
|
||||
| EVP_CIPHER_CTX_buf_noconst(c)[arg - 1];
|
||||
/* Correct length for explicit IV */
|
||||
if (len < EVP_GCM_TLS_EXPLICIT_IV_LEN)
|
||||
return 0;
|
||||
len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
|
||||
/* If decrypting correct for tag too */
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(c)) {
|
||||
if (len < EVP_GCM_TLS_TAG_LEN)
|
||||
return 0;
|
||||
len -= EVP_GCM_TLS_TAG_LEN;
|
||||
}
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] = len >> 8;
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 1] = len & 0xff;
|
||||
}
|
||||
/* Extra padding: tag appended to record */
|
||||
return EVP_GCM_TLS_TAG_LEN;
|
||||
|
||||
case EVP_CTRL_COPY:
|
||||
{
|
||||
EVP_CIPHER_CTX *out = ptr;
|
||||
EVP_ARIA_GCM_CTX *gctx_out = EVP_C_DATA(EVP_ARIA_GCM_CTX, out);
|
||||
if (gctx->gcm.key) {
|
||||
if (gctx->gcm.key != &gctx->ks)
|
||||
return 0;
|
||||
gctx_out->gcm.key = &gctx_out->ks;
|
||||
}
|
||||
if (gctx->iv == c->iv)
|
||||
gctx_out->iv = out->iv;
|
||||
else {
|
||||
if ((gctx_out->iv = OPENSSL_malloc(gctx->ivlen)) == NULL)
|
||||
return 0;
|
||||
memcpy(gctx_out->iv, gctx->iv, gctx->ivlen);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int aria_gcm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_ARIA_GCM_CTX *gctx = EVP_C_DATA(EVP_ARIA_GCM_CTX, ctx);
|
||||
int rv = -1;
|
||||
|
||||
/* Encrypt/decrypt must be performed in place */
|
||||
if (out != in
|
||||
|| len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
|
||||
return -1;
|
||||
/*
|
||||
* Set IV from start of buffer or generate IV and write to start of
|
||||
* buffer.
|
||||
*/
|
||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CIPHER_CTX_is_encrypting(ctx) ?
|
||||
EVP_CTRL_GCM_IV_GEN : EVP_CTRL_GCM_SET_IV_INV,
|
||||
EVP_GCM_TLS_EXPLICIT_IV_LEN, out) <= 0)
|
||||
goto err;
|
||||
/* Use saved AAD */
|
||||
if (CRYPTO_gcm128_aad(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
gctx->tls_aad_len))
|
||||
goto err;
|
||||
/* Fix buffer and length to point to payload */
|
||||
in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
|
||||
out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
|
||||
len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
/* Encrypt payload */
|
||||
if (CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, len))
|
||||
goto err;
|
||||
out += len;
|
||||
/* Finally write tag */
|
||||
CRYPTO_gcm128_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
|
||||
rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
|
||||
} else {
|
||||
/* Decrypt */
|
||||
if (CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, len))
|
||||
goto err;
|
||||
/* Retrieve tag */
|
||||
CRYPTO_gcm128_tag(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
EVP_GCM_TLS_TAG_LEN);
|
||||
/* If tag mismatch wipe buffer */
|
||||
if (CRYPTO_memcmp(EVP_CIPHER_CTX_buf_noconst(ctx), in + len,
|
||||
EVP_GCM_TLS_TAG_LEN)) {
|
||||
OPENSSL_cleanse(out, len);
|
||||
goto err;
|
||||
}
|
||||
rv = len;
|
||||
}
|
||||
|
||||
err:
|
||||
gctx->iv_set = 0;
|
||||
gctx->tls_aad_len = -1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int aria_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_ARIA_GCM_CTX *gctx = EVP_C_DATA(EVP_ARIA_GCM_CTX, ctx);
|
||||
|
||||
/* If not set up, return error */
|
||||
if (!gctx->key_set)
|
||||
return -1;
|
||||
|
||||
if (gctx->tls_aad_len >= 0)
|
||||
return aria_gcm_tls_cipher(ctx, out, in, len);
|
||||
|
||||
if (!gctx->iv_set)
|
||||
return -1;
|
||||
if (in) {
|
||||
if (out == NULL) {
|
||||
if (CRYPTO_gcm128_aad(&gctx->gcm, in, len))
|
||||
return -1;
|
||||
} else if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, len))
|
||||
return -1;
|
||||
} else {
|
||||
if (CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, len))
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (gctx->taglen < 0)
|
||||
return -1;
|
||||
if (CRYPTO_gcm128_finish(&gctx->gcm,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
gctx->taglen) != 0)
|
||||
return -1;
|
||||
gctx->iv_set = 0;
|
||||
return 0;
|
||||
}
|
||||
CRYPTO_gcm128_tag(&gctx->gcm, EVP_CIPHER_CTX_buf_noconst(ctx), 16);
|
||||
gctx->taglen = 16;
|
||||
/* Don't reuse the IV */
|
||||
gctx->iv_set = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aria_gcm_cleanup(EVP_CIPHER_CTX *ctx)
|
||||
{
|
||||
EVP_ARIA_GCM_CTX *gctx = EVP_C_DATA(EVP_ARIA_GCM_CTX, ctx);
|
||||
|
||||
if (gctx->iv != ctx->iv)
|
||||
OPENSSL_free(gctx->iv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aria_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int ret;
|
||||
EVP_ARIA_CCM_CTX *cctx = EVP_C_DATA(EVP_ARIA_CCM_CTX, ctx);
|
||||
|
||||
if (!iv && !key)
|
||||
return 1;
|
||||
|
||||
if (key) {
|
||||
ret = ossl_aria_set_encrypt_key(key,
|
||||
EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
&cctx->ks.ks);
|
||||
CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
|
||||
&cctx->ks, (block128_f) ossl_aria_encrypt);
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
cctx->str = NULL;
|
||||
cctx->key_set = 1;
|
||||
}
|
||||
if (iv) {
|
||||
memcpy(ctx->iv, iv, 15 - cctx->L);
|
||||
cctx->iv_set = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aria_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
|
||||
{
|
||||
EVP_ARIA_CCM_CTX *cctx = EVP_C_DATA(EVP_ARIA_CCM_CTX, c);
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_INIT:
|
||||
cctx->key_set = 0;
|
||||
cctx->iv_set = 0;
|
||||
cctx->L = 8;
|
||||
cctx->M = 12;
|
||||
cctx->tag_set = 0;
|
||||
cctx->len_set = 0;
|
||||
cctx->tls_aad_len = -1;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GET_IVLEN:
|
||||
*(int *)ptr = 15 - cctx->L;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
/* Save the AAD for later use */
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return 0;
|
||||
memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
|
||||
cctx->tls_aad_len = arg;
|
||||
{
|
||||
uint16_t len =
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] << 8
|
||||
| EVP_CIPHER_CTX_buf_noconst(c)[arg - 1];
|
||||
/* Correct length for explicit IV */
|
||||
if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN)
|
||||
return 0;
|
||||
len -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
|
||||
/* If decrypting correct for tag too */
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(c)) {
|
||||
if (len < cctx->M)
|
||||
return 0;
|
||||
len -= cctx->M;
|
||||
}
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 2] = len >> 8;
|
||||
EVP_CIPHER_CTX_buf_noconst(c)[arg - 1] = len & 0xff;
|
||||
}
|
||||
/* Extra padding: tag appended to record */
|
||||
return cctx->M;
|
||||
|
||||
case EVP_CTRL_CCM_SET_IV_FIXED:
|
||||
/* Sanity check length */
|
||||
if (arg != EVP_CCM_TLS_FIXED_IV_LEN)
|
||||
return 0;
|
||||
/* Just copy to first part of IV */
|
||||
memcpy(c->iv, ptr, arg);
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_IVLEN:
|
||||
arg = 15 - arg;
|
||||
/* fall through */
|
||||
case EVP_CTRL_CCM_SET_L:
|
||||
if (arg < 2 || arg > 8)
|
||||
return 0;
|
||||
cctx->L = arg;
|
||||
return 1;
|
||||
case EVP_CTRL_AEAD_SET_TAG:
|
||||
if ((arg & 1) || arg < 4 || arg > 16)
|
||||
return 0;
|
||||
if (EVP_CIPHER_CTX_is_encrypting(c) && ptr)
|
||||
return 0;
|
||||
if (ptr) {
|
||||
cctx->tag_set = 1;
|
||||
memcpy(EVP_CIPHER_CTX_buf_noconst(c), ptr, arg);
|
||||
}
|
||||
cctx->M = arg;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_GET_TAG:
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(c) || !cctx->tag_set)
|
||||
return 0;
|
||||
if (!CRYPTO_ccm128_tag(&cctx->ccm, ptr, (size_t)arg))
|
||||
return 0;
|
||||
cctx->tag_set = 0;
|
||||
cctx->iv_set = 0;
|
||||
cctx->len_set = 0;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_COPY:
|
||||
{
|
||||
EVP_CIPHER_CTX *out = ptr;
|
||||
EVP_ARIA_CCM_CTX *cctx_out = EVP_C_DATA(EVP_ARIA_CCM_CTX, out);
|
||||
if (cctx->ccm.key) {
|
||||
if (cctx->ccm.key != &cctx->ks)
|
||||
return 0;
|
||||
cctx_out->ccm.key = &cctx_out->ks;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int aria_ccm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_ARIA_CCM_CTX *cctx = EVP_C_DATA(EVP_ARIA_CCM_CTX, ctx);
|
||||
CCM128_CONTEXT *ccm = &cctx->ccm;
|
||||
|
||||
/* Encrypt/decrypt must be performed in place */
|
||||
if (out != in || len < (EVP_CCM_TLS_EXPLICIT_IV_LEN + (size_t)cctx->M))
|
||||
return -1;
|
||||
/* If encrypting set explicit IV from sequence number (start of AAD) */
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
memcpy(out, EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
EVP_CCM_TLS_EXPLICIT_IV_LEN);
|
||||
/* Get rest of IV from explicit IV */
|
||||
memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in,
|
||||
EVP_CCM_TLS_EXPLICIT_IV_LEN);
|
||||
/* Correct length value */
|
||||
len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
|
||||
if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L,
|
||||
len))
|
||||
return -1;
|
||||
/* Use saved AAD */
|
||||
CRYPTO_ccm128_aad(ccm, EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
cctx->tls_aad_len);
|
||||
/* Fix buffer to point to payload */
|
||||
in += EVP_CCM_TLS_EXPLICIT_IV_LEN;
|
||||
out += EVP_CCM_TLS_EXPLICIT_IV_LEN;
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len, cctx->str)
|
||||
: CRYPTO_ccm128_encrypt(ccm, in, out, len))
|
||||
return -1;
|
||||
if (!CRYPTO_ccm128_tag(ccm, out + len, cctx->M))
|
||||
return -1;
|
||||
return len + EVP_CCM_TLS_EXPLICIT_IV_LEN + cctx->M;
|
||||
} else {
|
||||
if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len, cctx->str)
|
||||
: !CRYPTO_ccm128_decrypt(ccm, in, out, len)) {
|
||||
unsigned char tag[16];
|
||||
if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) {
|
||||
if (!CRYPTO_memcmp(tag, in + len, cctx->M))
|
||||
return len;
|
||||
}
|
||||
}
|
||||
OPENSSL_cleanse(out, len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int aria_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_ARIA_CCM_CTX *cctx = EVP_C_DATA(EVP_ARIA_CCM_CTX, ctx);
|
||||
CCM128_CONTEXT *ccm = &cctx->ccm;
|
||||
|
||||
/* If not set up, return error */
|
||||
if (!cctx->key_set)
|
||||
return -1;
|
||||
|
||||
if (cctx->tls_aad_len >= 0)
|
||||
return aria_ccm_tls_cipher(ctx, out, in, len);
|
||||
|
||||
/* EVP_*Final() doesn't return any data */
|
||||
if (in == NULL && out != NULL)
|
||||
return 0;
|
||||
|
||||
if (!cctx->iv_set)
|
||||
return -1;
|
||||
|
||||
if (!out) {
|
||||
if (!in) {
|
||||
if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L, len))
|
||||
return -1;
|
||||
cctx->len_set = 1;
|
||||
return len;
|
||||
}
|
||||
/* If have AAD need message length */
|
||||
if (!cctx->len_set && len)
|
||||
return -1;
|
||||
CRYPTO_ccm128_aad(ccm, in, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* The tag must be set before actually decrypting data */
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(ctx) && !cctx->tag_set)
|
||||
return -1;
|
||||
|
||||
/* If not set length yet do it */
|
||||
if (!cctx->len_set) {
|
||||
if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L, len))
|
||||
return -1;
|
||||
cctx->len_set = 1;
|
||||
}
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len, cctx->str)
|
||||
: CRYPTO_ccm128_encrypt(ccm, in, out, len))
|
||||
return -1;
|
||||
cctx->tag_set = 1;
|
||||
return len;
|
||||
} else {
|
||||
int rv = -1;
|
||||
if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len,
|
||||
cctx->str) :
|
||||
!CRYPTO_ccm128_decrypt(ccm, in, out, len)) {
|
||||
unsigned char tag[16];
|
||||
if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) {
|
||||
if (!CRYPTO_memcmp(tag, EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
cctx->M))
|
||||
rv = len;
|
||||
}
|
||||
}
|
||||
if (rv == -1)
|
||||
OPENSSL_cleanse(out, len);
|
||||
cctx->iv_set = 0;
|
||||
cctx->tag_set = 0;
|
||||
cctx->len_set = 0;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#define aria_ccm_cleanup NULL
|
||||
|
||||
#define ARIA_AUTH_FLAGS (EVP_CIPH_FLAG_DEFAULT_ASN1 \
|
||||
| EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
|
||||
| EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \
|
||||
| EVP_CIPH_CUSTOM_COPY | EVP_CIPH_FLAG_AEAD_CIPHER \
|
||||
| EVP_CIPH_CUSTOM_IV_LENGTH)
|
||||
|
||||
#define BLOCK_CIPHER_aead(keylen,mode,MODE) \
|
||||
static const EVP_CIPHER aria_##keylen##_##mode = { \
|
||||
NID_aria_##keylen##_##mode, \
|
||||
1, keylen/8, 12, \
|
||||
ARIA_AUTH_FLAGS|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
aria_##mode##_init_key, \
|
||||
aria_##mode##_cipher, \
|
||||
aria_##mode##_cleanup, \
|
||||
sizeof(EVP_ARIA_##MODE##_CTX), \
|
||||
NULL,NULL,aria_##mode##_ctrl,NULL }; \
|
||||
const EVP_CIPHER *EVP_aria_##keylen##_##mode(void) \
|
||||
{ return (EVP_CIPHER*)&aria_##keylen##_##mode; }
|
||||
|
||||
BLOCK_CIPHER_aead(128, gcm, GCM)
|
||||
BLOCK_CIPHER_aead(192, gcm, GCM)
|
||||
BLOCK_CIPHER_aead(256, gcm, GCM)
|
||||
|
||||
BLOCK_CIPHER_aead(128, ccm, CCM)
|
||||
BLOCK_CIPHER_aead(192, ccm, CCM)
|
||||
BLOCK_CIPHER_aead(256, ccm, CCM)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* BF low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#ifndef OPENSSL_NO_BF
|
||||
# include <openssl/evp.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/objects.h>
|
||||
# include <openssl/blowfish.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
static int bf_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
typedef struct {
|
||||
BF_KEY ks;
|
||||
} EVP_BF_KEY;
|
||||
|
||||
# define data(ctx) EVP_C_DATA(EVP_BF_KEY,ctx)
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(bf, ks, BF, EVP_BF_KEY, NID_bf, 8, 16, 8, 64,
|
||||
EVP_CIPH_VARIABLE_LENGTH, bf_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
|
||||
|
||||
static int bf_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int len = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
|
||||
if (len < 0)
|
||||
return 0;
|
||||
BF_set_key(&data(ctx)->ks, len, key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Camellia low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <openssl/camellia.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "crypto/modes.h"
|
||||
#include "crypto/cmll_platform.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
/* Camellia subkey Structure */
|
||||
typedef struct {
|
||||
CAMELLIA_KEY ks;
|
||||
block128_f block;
|
||||
union {
|
||||
cbc128_f cbc;
|
||||
ctr128_f ctr;
|
||||
} stream;
|
||||
} EVP_CAMELLIA_KEY;
|
||||
|
||||
#define MAXBITCHUNK ((size_t)1<<(sizeof(size_t)*8-4))
|
||||
|
||||
/* Attribute operation for Camellia */
|
||||
#define data(ctx) EVP_C_DATA(EVP_CAMELLIA_KEY,ctx)
|
||||
|
||||
#if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
|
||||
/* ---------^^^ this is not a typo, just a way to detect that
|
||||
* assembler support was in general requested... */
|
||||
# include "crypto/sparc_arch.h"
|
||||
|
||||
static int cmll_t4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int ret, mode, bits;
|
||||
EVP_CAMELLIA_KEY *dat =
|
||||
(EVP_CAMELLIA_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx);
|
||||
|
||||
mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
bits = EVP_CIPHER_CTX_get_key_length(ctx) * 8;
|
||||
|
||||
cmll_t4_set_key(key, bits, &dat->ks);
|
||||
|
||||
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
|
||||
&& !enc) {
|
||||
ret = 0;
|
||||
dat->block = (block128_f) cmll_t4_decrypt;
|
||||
switch (bits) {
|
||||
case 128:
|
||||
dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
|
||||
(cbc128_f) cmll128_t4_cbc_decrypt : NULL;
|
||||
break;
|
||||
case 192:
|
||||
case 256:
|
||||
dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
|
||||
(cbc128_f) cmll256_t4_cbc_decrypt : NULL;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
ret = 0;
|
||||
dat->block = (block128_f) cmll_t4_encrypt;
|
||||
switch (bits) {
|
||||
case 128:
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) cmll128_t4_cbc_encrypt;
|
||||
else if (mode == EVP_CIPH_CTR_MODE)
|
||||
dat->stream.ctr = (ctr128_f) cmll128_t4_ctr32_encrypt;
|
||||
else
|
||||
dat->stream.cbc = NULL;
|
||||
break;
|
||||
case 192:
|
||||
case 256:
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) cmll256_t4_cbc_encrypt;
|
||||
else if (mode == EVP_CIPH_CTR_MODE)
|
||||
dat->stream.ctr = (ctr128_f) cmll256_t4_ctr32_encrypt;
|
||||
else
|
||||
dat->stream.cbc = NULL;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_CAMELLIA_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# define cmll_t4_cbc_cipher camellia_cbc_cipher
|
||||
static int cmll_t4_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_ecb_cipher camellia_ecb_cipher
|
||||
static int cmll_t4_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_ofb_cipher camellia_ofb_cipher
|
||||
static int cmll_t4_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_cfb_cipher camellia_cfb_cipher
|
||||
static int cmll_t4_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_cfb8_cipher camellia_cfb8_cipher
|
||||
static int cmll_t4_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_cfb1_cipher camellia_cfb1_cipher
|
||||
static int cmll_t4_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define cmll_t4_ctr_cipher camellia_ctr_cipher
|
||||
static int cmll_t4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len);
|
||||
|
||||
# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
|
||||
static const EVP_CIPHER cmll_t4_##keylen##_##mode = { \
|
||||
nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
|
||||
flags|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
cmll_t4_init_key, \
|
||||
cmll_t4_##mode##_cipher, \
|
||||
NULL, \
|
||||
sizeof(EVP_CAMELLIA_KEY), \
|
||||
NULL,NULL,NULL,NULL }; \
|
||||
static const EVP_CIPHER camellia_##keylen##_##mode = { \
|
||||
nid##_##keylen##_##nmode,blocksize, \
|
||||
keylen/8,ivlen, \
|
||||
flags|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
camellia_init_key, \
|
||||
camellia_##mode##_cipher, \
|
||||
NULL, \
|
||||
sizeof(EVP_CAMELLIA_KEY), \
|
||||
NULL,NULL,NULL,NULL }; \
|
||||
const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
|
||||
{ return SPARC_CMLL_CAPABLE?&cmll_t4_##keylen##_##mode:&camellia_##keylen##_##mode; }
|
||||
|
||||
#else
|
||||
|
||||
# define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
|
||||
static const EVP_CIPHER camellia_##keylen##_##mode = { \
|
||||
nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
|
||||
flags|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
camellia_init_key, \
|
||||
camellia_##mode##_cipher, \
|
||||
NULL, \
|
||||
sizeof(EVP_CAMELLIA_KEY), \
|
||||
NULL,NULL,NULL,NULL }; \
|
||||
const EVP_CIPHER *EVP_camellia_##keylen##_##mode(void) \
|
||||
{ return &camellia_##keylen##_##mode; }
|
||||
|
||||
#endif
|
||||
|
||||
#define BLOCK_CIPHER_generic_pack(nid,keylen,flags) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,1,16,cfb1,cfb1,CFB,flags) \
|
||||
BLOCK_CIPHER_generic(nid,keylen,1,16,cfb8,cfb8,CFB,flags) \
|
||||
BLOCK_CIPHER_generic(nid, keylen, 1, 16, ctr, ctr, CTR, flags)
|
||||
|
||||
/* The subkey for Camellia is generated. */
|
||||
static int camellia_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int ret, mode;
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
ret = Camellia_set_key(key, EVP_CIPHER_CTX_get_key_length(ctx) * 8,
|
||||
&dat->ks);
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_CAMELLIA_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
|
||||
&& !enc) {
|
||||
dat->block = (block128_f) Camellia_decrypt;
|
||||
dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
|
||||
(cbc128_f) Camellia_cbc_encrypt : NULL;
|
||||
} else {
|
||||
dat->block = (block128_f) Camellia_encrypt;
|
||||
dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
|
||||
(cbc128_f) Camellia_cbc_encrypt : NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
if (dat->stream.cbc)
|
||||
(*dat->stream.cbc) (in, out, len, &dat->ks, ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
else if (EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
|
||||
else
|
||||
CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
size_t bl = EVP_CIPHER_CTX_get_block_size(ctx);
|
||||
size_t i;
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
if (len < bl)
|
||||
return 1;
|
||||
|
||||
for (i = 0, len -= bl; i <= len; i += bl)
|
||||
(*dat->block) (in + i, out + i, &dat->ks);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, ctx->iv, &num, dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_cfb128_encrypt(in, out, len, &dat->ks, ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx), dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_cfb128_8_encrypt(in, out, len, &dat->ks, ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx), dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
if (EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS)) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_cfb128_1_encrypt(in, out, len, &dat->ks, ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx),
|
||||
dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (len >= MAXBITCHUNK) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, &dat->ks,
|
||||
ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx),
|
||||
dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
len -= MAXBITCHUNK;
|
||||
out += MAXBITCHUNK;
|
||||
in += MAXBITCHUNK;
|
||||
}
|
||||
if (len) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
CRYPTO_cfb128_1_encrypt(in, out, len * 8, &dat->ks,
|
||||
ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx),
|
||||
dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int camellia_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
int snum = EVP_CIPHER_CTX_get_num(ctx);
|
||||
unsigned int num;
|
||||
EVP_CAMELLIA_KEY *dat = EVP_C_DATA(EVP_CAMELLIA_KEY, ctx);
|
||||
|
||||
if (snum < 0)
|
||||
return 0;
|
||||
num = snum;
|
||||
if (dat->stream.ctr)
|
||||
CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
&num,
|
||||
dat->stream.ctr);
|
||||
else
|
||||
CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx), &num,
|
||||
dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLOCK_CIPHER_generic_pack(NID_camellia, 128, 0)
|
||||
BLOCK_CIPHER_generic_pack(NID_camellia, 192, 0)
|
||||
BLOCK_CIPHER_generic_pack(NID_camellia, 256, 0)
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* CAST low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/cast.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
static int cast_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
typedef struct {
|
||||
CAST_KEY ks;
|
||||
} EVP_CAST_KEY;
|
||||
|
||||
# define data(ctx) EVP_C_DATA(EVP_CAST_KEY,ctx)
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(cast5, ks, CAST, EVP_CAST_KEY,
|
||||
NID_cast5, 8, CAST_KEY_LENGTH, 8, 64,
|
||||
EVP_CIPH_VARIABLE_LENGTH, cast_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
|
||||
|
||||
static int cast_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int keylen = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
|
||||
if (keylen <= 0)
|
||||
return 0;
|
||||
CAST_set_key(&data(ctx)->ks, keylen, key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
+635
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
* Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/endian.h"
|
||||
|
||||
#ifndef OPENSSL_NO_CHACHA
|
||||
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include "evp_local.h"
|
||||
# include "crypto/chacha.h"
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN; /* this ensures even sizeof(EVP_CHACHA_KEY)%8==0 */
|
||||
unsigned int d[CHACHA_KEY_SIZE / 4];
|
||||
} key;
|
||||
unsigned int counter[CHACHA_CTR_SIZE / 4];
|
||||
unsigned char buf[CHACHA_BLK_SIZE];
|
||||
unsigned int partial_len;
|
||||
} EVP_CHACHA_KEY;
|
||||
|
||||
#define data(ctx) ((EVP_CHACHA_KEY *)(ctx)->cipher_data)
|
||||
|
||||
#define CHACHA20_POLY1305_MAX_IVLEN 12
|
||||
|
||||
static int chacha_init_key(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char user_key[CHACHA_KEY_SIZE],
|
||||
const unsigned char iv[CHACHA_CTR_SIZE], int enc)
|
||||
{
|
||||
EVP_CHACHA_KEY *key = data(ctx);
|
||||
unsigned int i;
|
||||
|
||||
if (user_key)
|
||||
for (i = 0; i < CHACHA_KEY_SIZE; i+=4) {
|
||||
key->key.d[i/4] = CHACHA_U8TOU32(user_key+i);
|
||||
}
|
||||
|
||||
if (iv)
|
||||
for (i = 0; i < CHACHA_CTR_SIZE; i+=4) {
|
||||
key->counter[i/4] = CHACHA_U8TOU32(iv+i);
|
||||
}
|
||||
|
||||
key->partial_len = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int chacha_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *inp, size_t len)
|
||||
{
|
||||
EVP_CHACHA_KEY *key = data(ctx);
|
||||
unsigned int n, rem, ctr32;
|
||||
|
||||
if ((n = key->partial_len)) {
|
||||
while (len && n < CHACHA_BLK_SIZE) {
|
||||
*out++ = *inp++ ^ key->buf[n++];
|
||||
len--;
|
||||
}
|
||||
key->partial_len = n;
|
||||
|
||||
if (len == 0)
|
||||
return 1;
|
||||
|
||||
if (n == CHACHA_BLK_SIZE) {
|
||||
key->partial_len = 0;
|
||||
key->counter[0]++;
|
||||
if (key->counter[0] == 0)
|
||||
key->counter[1]++;
|
||||
}
|
||||
}
|
||||
|
||||
rem = (unsigned int)(len % CHACHA_BLK_SIZE);
|
||||
len -= rem;
|
||||
ctr32 = key->counter[0];
|
||||
while (len >= CHACHA_BLK_SIZE) {
|
||||
size_t blocks = len / CHACHA_BLK_SIZE;
|
||||
/*
|
||||
* 1<<28 is just a not-so-small yet not-so-large number...
|
||||
* Below condition is practically never met, but it has to
|
||||
* be checked for code correctness.
|
||||
*/
|
||||
if (sizeof(size_t)>sizeof(unsigned int) && blocks>(1U<<28))
|
||||
blocks = (1U<<28);
|
||||
|
||||
/*
|
||||
* As ChaCha20_ctr32 operates on 32-bit counter, caller
|
||||
* has to handle overflow. 'if' below detects the
|
||||
* overflow, which is then handled by limiting the
|
||||
* amount of blocks to the exact overflow point...
|
||||
*/
|
||||
ctr32 += (unsigned int)blocks;
|
||||
if (ctr32 < blocks) {
|
||||
blocks -= ctr32;
|
||||
ctr32 = 0;
|
||||
}
|
||||
blocks *= CHACHA_BLK_SIZE;
|
||||
ChaCha20_ctr32(out, inp, blocks, key->key.d, key->counter);
|
||||
len -= blocks;
|
||||
inp += blocks;
|
||||
out += blocks;
|
||||
|
||||
key->counter[0] = ctr32;
|
||||
if (ctr32 == 0) key->counter[1]++;
|
||||
}
|
||||
|
||||
if (rem) {
|
||||
memset(key->buf, 0, sizeof(key->buf));
|
||||
ChaCha20_ctr32(key->buf, key->buf, CHACHA_BLK_SIZE,
|
||||
key->key.d, key->counter);
|
||||
for (n = 0; n < rem; n++)
|
||||
out[n] = inp[n] ^ key->buf[n];
|
||||
key->partial_len = rem;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const EVP_CIPHER chacha20 = {
|
||||
NID_chacha20,
|
||||
1, /* block_size */
|
||||
CHACHA_KEY_SIZE, /* key_len */
|
||||
CHACHA_CTR_SIZE, /* iv_len, 128-bit counter in the context */
|
||||
EVP_CIPH_CUSTOM_IV | EVP_CIPH_ALWAYS_CALL_INIT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
chacha_init_key,
|
||||
chacha_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_CHACHA_KEY),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_chacha20(void)
|
||||
{
|
||||
return &chacha20;
|
||||
}
|
||||
|
||||
# ifndef OPENSSL_NO_POLY1305
|
||||
# include "crypto/poly1305.h"
|
||||
|
||||
typedef struct {
|
||||
EVP_CHACHA_KEY key;
|
||||
unsigned int nonce[12/4];
|
||||
unsigned char tag[POLY1305_BLOCK_SIZE];
|
||||
unsigned char tls_aad[POLY1305_BLOCK_SIZE];
|
||||
struct { uint64_t aad, text; } len;
|
||||
int aad, mac_inited, tag_len, nonce_len;
|
||||
size_t tls_payload_length;
|
||||
} EVP_CHACHA_AEAD_CTX;
|
||||
|
||||
# define NO_TLS_PAYLOAD_LENGTH ((size_t)-1)
|
||||
# define aead_data(ctx) ((EVP_CHACHA_AEAD_CTX *)(ctx)->cipher_data)
|
||||
# define POLY1305_ctx(actx) ((POLY1305 *)(actx + 1))
|
||||
|
||||
static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *inkey,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
|
||||
|
||||
if (!inkey && !iv)
|
||||
return 1;
|
||||
|
||||
actx->len.aad = 0;
|
||||
actx->len.text = 0;
|
||||
actx->aad = 0;
|
||||
actx->mac_inited = 0;
|
||||
actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
|
||||
|
||||
if (iv != NULL) {
|
||||
unsigned char temp[CHACHA_CTR_SIZE] = { 0 };
|
||||
|
||||
/* pad on the left */
|
||||
if (actx->nonce_len <= CHACHA_CTR_SIZE)
|
||||
memcpy(temp + CHACHA_CTR_SIZE - actx->nonce_len, iv,
|
||||
actx->nonce_len);
|
||||
|
||||
chacha_init_key(ctx, inkey, temp, enc);
|
||||
|
||||
actx->nonce[0] = actx->key.counter[1];
|
||||
actx->nonce[1] = actx->key.counter[2];
|
||||
actx->nonce[2] = actx->key.counter[3];
|
||||
} else {
|
||||
chacha_init_key(ctx, inkey, NULL, enc);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# if !defined(OPENSSL_SMALL_FOOTPRINT)
|
||||
|
||||
# if defined(POLY1305_ASM) && (defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(_M_X64))
|
||||
# define XOR128_HELPERS
|
||||
void *xor128_encrypt_n_pad(void *out, const void *inp, void *otp, size_t len);
|
||||
void *xor128_decrypt_n_pad(void *out, const void *inp, void *otp, size_t len);
|
||||
static const unsigned char zero[4 * CHACHA_BLK_SIZE] = { 0 };
|
||||
# else
|
||||
static const unsigned char zero[2 * CHACHA_BLK_SIZE] = { 0 };
|
||||
# endif
|
||||
|
||||
static int chacha20_poly1305_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
|
||||
size_t tail, tohash_len, buf_len, plen = actx->tls_payload_length;
|
||||
unsigned char *buf, *tohash, *ctr, storage[sizeof(zero) + 32];
|
||||
|
||||
if (len != plen + POLY1305_BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
buf = storage + ((0 - (size_t)storage) & 15); /* align */
|
||||
ctr = buf + CHACHA_BLK_SIZE;
|
||||
tohash = buf + CHACHA_BLK_SIZE - POLY1305_BLOCK_SIZE;
|
||||
|
||||
# ifdef XOR128_HELPERS
|
||||
if (plen <= 3 * CHACHA_BLK_SIZE) {
|
||||
actx->key.counter[0] = 0;
|
||||
buf_len = (plen + 2 * CHACHA_BLK_SIZE - 1) & (0 - CHACHA_BLK_SIZE);
|
||||
ChaCha20_ctr32(buf, zero, buf_len, actx->key.key.d,
|
||||
actx->key.counter);
|
||||
Poly1305_Init(POLY1305_ctx(actx), buf);
|
||||
actx->key.partial_len = 0;
|
||||
memcpy(tohash, actx->tls_aad, POLY1305_BLOCK_SIZE);
|
||||
tohash_len = POLY1305_BLOCK_SIZE;
|
||||
actx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
|
||||
actx->len.text = plen;
|
||||
|
||||
if (plen) {
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
ctr = xor128_encrypt_n_pad(out, in, ctr, plen);
|
||||
else
|
||||
ctr = xor128_decrypt_n_pad(out, in, ctr, plen);
|
||||
|
||||
in += plen;
|
||||
out += plen;
|
||||
tohash_len = (size_t)(ctr - tohash);
|
||||
}
|
||||
}
|
||||
# else
|
||||
if (plen <= CHACHA_BLK_SIZE) {
|
||||
size_t i;
|
||||
|
||||
actx->key.counter[0] = 0;
|
||||
ChaCha20_ctr32(buf, zero, (buf_len = 2 * CHACHA_BLK_SIZE),
|
||||
actx->key.key.d, actx->key.counter);
|
||||
Poly1305_Init(POLY1305_ctx(actx), buf);
|
||||
actx->key.partial_len = 0;
|
||||
memcpy(tohash, actx->tls_aad, POLY1305_BLOCK_SIZE);
|
||||
tohash_len = POLY1305_BLOCK_SIZE;
|
||||
actx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
|
||||
actx->len.text = plen;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
for (i = 0; i < plen; i++) {
|
||||
out[i] = ctr[i] ^= in[i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < plen; i++) {
|
||||
unsigned char c = in[i];
|
||||
out[i] = ctr[i] ^ c;
|
||||
ctr[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
in += i;
|
||||
out += i;
|
||||
|
||||
tail = (0 - i) & (POLY1305_BLOCK_SIZE - 1);
|
||||
memset(ctr + i, 0, tail);
|
||||
ctr += i + tail;
|
||||
tohash_len += i + tail;
|
||||
}
|
||||
# endif
|
||||
else {
|
||||
actx->key.counter[0] = 0;
|
||||
ChaCha20_ctr32(buf, zero, (buf_len = CHACHA_BLK_SIZE),
|
||||
actx->key.key.d, actx->key.counter);
|
||||
Poly1305_Init(POLY1305_ctx(actx), buf);
|
||||
actx->key.counter[0] = 1;
|
||||
actx->key.partial_len = 0;
|
||||
Poly1305_Update(POLY1305_ctx(actx), actx->tls_aad, POLY1305_BLOCK_SIZE);
|
||||
tohash = ctr;
|
||||
tohash_len = 0;
|
||||
actx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
|
||||
actx->len.text = plen;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
ChaCha20_ctr32(out, in, plen, actx->key.key.d, actx->key.counter);
|
||||
Poly1305_Update(POLY1305_ctx(actx), out, plen);
|
||||
} else {
|
||||
Poly1305_Update(POLY1305_ctx(actx), in, plen);
|
||||
ChaCha20_ctr32(out, in, plen, actx->key.key.d, actx->key.counter);
|
||||
}
|
||||
|
||||
in += plen;
|
||||
out += plen;
|
||||
tail = (0 - plen) & (POLY1305_BLOCK_SIZE - 1);
|
||||
Poly1305_Update(POLY1305_ctx(actx), zero, tail);
|
||||
}
|
||||
|
||||
{
|
||||
DECLARE_IS_ENDIAN;
|
||||
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
memcpy(ctr, (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);
|
||||
} else {
|
||||
ctr[0] = (unsigned char)(actx->len.aad);
|
||||
ctr[1] = (unsigned char)(actx->len.aad>>8);
|
||||
ctr[2] = (unsigned char)(actx->len.aad>>16);
|
||||
ctr[3] = (unsigned char)(actx->len.aad>>24);
|
||||
ctr[4] = (unsigned char)(actx->len.aad>>32);
|
||||
ctr[5] = (unsigned char)(actx->len.aad>>40);
|
||||
ctr[6] = (unsigned char)(actx->len.aad>>48);
|
||||
ctr[7] = (unsigned char)(actx->len.aad>>56);
|
||||
|
||||
ctr[8] = (unsigned char)(actx->len.text);
|
||||
ctr[9] = (unsigned char)(actx->len.text>>8);
|
||||
ctr[10] = (unsigned char)(actx->len.text>>16);
|
||||
ctr[11] = (unsigned char)(actx->len.text>>24);
|
||||
ctr[12] = (unsigned char)(actx->len.text>>32);
|
||||
ctr[13] = (unsigned char)(actx->len.text>>40);
|
||||
ctr[14] = (unsigned char)(actx->len.text>>48);
|
||||
ctr[15] = (unsigned char)(actx->len.text>>56);
|
||||
}
|
||||
tohash_len += POLY1305_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
Poly1305_Update(POLY1305_ctx(actx), tohash, tohash_len);
|
||||
OPENSSL_cleanse(buf, buf_len);
|
||||
Poly1305_Final(POLY1305_ctx(actx),
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx) ? actx->tag : tohash);
|
||||
|
||||
actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
|
||||
} else {
|
||||
if (CRYPTO_memcmp(tohash, in, POLY1305_BLOCK_SIZE)) {
|
||||
memset(out - (len - POLY1305_BLOCK_SIZE), 0,
|
||||
len - POLY1305_BLOCK_SIZE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
# else
|
||||
static const unsigned char zero[CHACHA_BLK_SIZE] = { 0 };
|
||||
# endif
|
||||
|
||||
static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
|
||||
size_t rem, plen = actx->tls_payload_length;
|
||||
|
||||
if (!actx->mac_inited) {
|
||||
# if !defined(OPENSSL_SMALL_FOOTPRINT)
|
||||
if (plen != NO_TLS_PAYLOAD_LENGTH && out != NULL)
|
||||
return chacha20_poly1305_tls_cipher(ctx, out, in, len);
|
||||
# endif
|
||||
actx->key.counter[0] = 0;
|
||||
ChaCha20_ctr32(actx->key.buf, zero, CHACHA_BLK_SIZE,
|
||||
actx->key.key.d, actx->key.counter);
|
||||
Poly1305_Init(POLY1305_ctx(actx), actx->key.buf);
|
||||
actx->key.counter[0] = 1;
|
||||
actx->key.partial_len = 0;
|
||||
actx->len.aad = actx->len.text = 0;
|
||||
actx->mac_inited = 1;
|
||||
if (plen != NO_TLS_PAYLOAD_LENGTH) {
|
||||
Poly1305_Update(POLY1305_ctx(actx), actx->tls_aad,
|
||||
EVP_AEAD_TLS1_AAD_LEN);
|
||||
actx->len.aad = EVP_AEAD_TLS1_AAD_LEN;
|
||||
actx->aad = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (in) { /* aad or text */
|
||||
if (out == NULL) { /* aad */
|
||||
Poly1305_Update(POLY1305_ctx(actx), in, len);
|
||||
actx->len.aad += len;
|
||||
actx->aad = 1;
|
||||
return len;
|
||||
} else { /* plain- or ciphertext */
|
||||
if (actx->aad) { /* wrap up aad */
|
||||
if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
|
||||
Poly1305_Update(POLY1305_ctx(actx), zero,
|
||||
POLY1305_BLOCK_SIZE - rem);
|
||||
actx->aad = 0;
|
||||
}
|
||||
|
||||
actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
|
||||
if (plen == NO_TLS_PAYLOAD_LENGTH)
|
||||
plen = len;
|
||||
else if (len != plen + POLY1305_BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) { /* plaintext */
|
||||
chacha_cipher(ctx, out, in, plen);
|
||||
Poly1305_Update(POLY1305_ctx(actx), out, plen);
|
||||
in += plen;
|
||||
out += plen;
|
||||
actx->len.text += plen;
|
||||
} else { /* ciphertext */
|
||||
Poly1305_Update(POLY1305_ctx(actx), in, plen);
|
||||
chacha_cipher(ctx, out, in, plen);
|
||||
in += plen;
|
||||
out += plen;
|
||||
actx->len.text += plen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (in == NULL /* explicit final */
|
||||
|| plen != len) { /* or tls mode */
|
||||
DECLARE_IS_ENDIAN;
|
||||
unsigned char temp[POLY1305_BLOCK_SIZE];
|
||||
|
||||
if (actx->aad) { /* wrap up aad */
|
||||
if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
|
||||
Poly1305_Update(POLY1305_ctx(actx), zero,
|
||||
POLY1305_BLOCK_SIZE - rem);
|
||||
actx->aad = 0;
|
||||
}
|
||||
|
||||
if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE))
|
||||
Poly1305_Update(POLY1305_ctx(actx), zero,
|
||||
POLY1305_BLOCK_SIZE - rem);
|
||||
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
Poly1305_Update(POLY1305_ctx(actx),
|
||||
(unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);
|
||||
} else {
|
||||
temp[0] = (unsigned char)(actx->len.aad);
|
||||
temp[1] = (unsigned char)(actx->len.aad>>8);
|
||||
temp[2] = (unsigned char)(actx->len.aad>>16);
|
||||
temp[3] = (unsigned char)(actx->len.aad>>24);
|
||||
temp[4] = (unsigned char)(actx->len.aad>>32);
|
||||
temp[5] = (unsigned char)(actx->len.aad>>40);
|
||||
temp[6] = (unsigned char)(actx->len.aad>>48);
|
||||
temp[7] = (unsigned char)(actx->len.aad>>56);
|
||||
|
||||
temp[8] = (unsigned char)(actx->len.text);
|
||||
temp[9] = (unsigned char)(actx->len.text>>8);
|
||||
temp[10] = (unsigned char)(actx->len.text>>16);
|
||||
temp[11] = (unsigned char)(actx->len.text>>24);
|
||||
temp[12] = (unsigned char)(actx->len.text>>32);
|
||||
temp[13] = (unsigned char)(actx->len.text>>40);
|
||||
temp[14] = (unsigned char)(actx->len.text>>48);
|
||||
temp[15] = (unsigned char)(actx->len.text>>56);
|
||||
|
||||
Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE);
|
||||
}
|
||||
Poly1305_Final(POLY1305_ctx(actx),
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx) ? actx->tag : temp);
|
||||
actx->mac_inited = 0;
|
||||
|
||||
if (in != NULL && len != plen) { /* tls mode */
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
|
||||
} else {
|
||||
if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {
|
||||
memset(out - plen, 0, plen);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (CRYPTO_memcmp(temp, actx->tag, actx->tag_len))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_cleanup(EVP_CIPHER_CTX *ctx)
|
||||
{
|
||||
EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
|
||||
if (actx)
|
||||
OPENSSL_cleanse(ctx->cipher_data, sizeof(*actx) + Poly1305_ctx_size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
|
||||
void *ptr)
|
||||
{
|
||||
EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_INIT:
|
||||
if (actx == NULL)
|
||||
actx = ctx->cipher_data
|
||||
= OPENSSL_zalloc(sizeof(*actx) + Poly1305_ctx_size());
|
||||
if (actx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
actx->len.aad = 0;
|
||||
actx->len.text = 0;
|
||||
actx->aad = 0;
|
||||
actx->mac_inited = 0;
|
||||
actx->tag_len = 0;
|
||||
actx->nonce_len = 12;
|
||||
actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
|
||||
memset(actx->tls_aad, 0, POLY1305_BLOCK_SIZE);
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_COPY:
|
||||
if (actx) {
|
||||
EVP_CIPHER_CTX *dst = (EVP_CIPHER_CTX *)ptr;
|
||||
|
||||
dst->cipher_data =
|
||||
OPENSSL_memdup(actx, sizeof(*actx) + Poly1305_ctx_size());
|
||||
if (dst->cipher_data == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COPY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GET_IVLEN:
|
||||
*(int *)ptr = actx->nonce_len;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_IVLEN:
|
||||
if (arg <= 0 || arg > CHACHA20_POLY1305_MAX_IVLEN)
|
||||
return 0;
|
||||
actx->nonce_len = arg;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_IV_FIXED:
|
||||
if (arg != 12)
|
||||
return 0;
|
||||
actx->nonce[0] = actx->key.counter[1]
|
||||
= CHACHA_U8TOU32((unsigned char *)ptr);
|
||||
actx->nonce[1] = actx->key.counter[2]
|
||||
= CHACHA_U8TOU32((unsigned char *)ptr+4);
|
||||
actx->nonce[2] = actx->key.counter[3]
|
||||
= CHACHA_U8TOU32((unsigned char *)ptr+8);
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_SET_TAG:
|
||||
if (arg <= 0 || arg > POLY1305_BLOCK_SIZE)
|
||||
return 0;
|
||||
if (ptr != NULL) {
|
||||
memcpy(actx->tag, ptr, arg);
|
||||
actx->tag_len = arg;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_GET_TAG:
|
||||
if (arg <= 0 || arg > POLY1305_BLOCK_SIZE ||
|
||||
!EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
return 0;
|
||||
memcpy(ptr, actx->tag, arg);
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return 0;
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned char *aad = ptr;
|
||||
|
||||
memcpy(actx->tls_aad, ptr, EVP_AEAD_TLS1_AAD_LEN);
|
||||
len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 |
|
||||
aad[EVP_AEAD_TLS1_AAD_LEN - 1];
|
||||
aad = actx->tls_aad;
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (len < POLY1305_BLOCK_SIZE)
|
||||
return 0;
|
||||
len -= POLY1305_BLOCK_SIZE; /* discount attached tag */
|
||||
aad[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);
|
||||
aad[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;
|
||||
}
|
||||
actx->tls_payload_length = len;
|
||||
|
||||
/*
|
||||
* merge record sequence number as per RFC7905
|
||||
*/
|
||||
actx->key.counter[1] = actx->nonce[0];
|
||||
actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(aad);
|
||||
actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(aad+4);
|
||||
actx->mac_inited = 0;
|
||||
|
||||
return POLY1305_BLOCK_SIZE; /* tag length */
|
||||
}
|
||||
|
||||
case EVP_CTRL_AEAD_SET_MAC_KEY:
|
||||
/* no-op */
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static EVP_CIPHER chacha20_poly1305 = {
|
||||
NID_chacha20_poly1305,
|
||||
1, /* block_size */
|
||||
CHACHA_KEY_SIZE, /* key_len */
|
||||
12, /* iv_len, 96-bit nonce in the context */
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CUSTOM_IV |
|
||||
EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
|
||||
EVP_CIPH_CUSTOM_COPY | EVP_CIPH_FLAG_CUSTOM_CIPHER |
|
||||
EVP_CIPH_CUSTOM_IV_LENGTH,
|
||||
EVP_ORIG_GLOBAL,
|
||||
chacha20_poly1305_init_key,
|
||||
chacha20_poly1305_cipher,
|
||||
chacha20_poly1305_cleanup,
|
||||
0, /* 0 moves context-specific structure allocation to ctrl */
|
||||
NULL, /* set_asn1_parameters */
|
||||
NULL, /* get_asn1_parameters */
|
||||
chacha20_poly1305_ctrl,
|
||||
NULL /* app_data */
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_chacha20_poly1305(void)
|
||||
{
|
||||
return(&chacha20_poly1305);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* DES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#ifndef OPENSSL_NO_DES
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/des.h>
|
||||
# include <openssl/rand.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN;
|
||||
DES_key_schedule ks;
|
||||
} ks;
|
||||
union {
|
||||
void (*cbc) (const void *, void *, size_t,
|
||||
const DES_key_schedule *, unsigned char *);
|
||||
} stream;
|
||||
} EVP_DES_KEY;
|
||||
|
||||
# if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
|
||||
/* ----------^^^ this is not a typo, just a way to detect that
|
||||
* assembler support was in general requested... */
|
||||
# include "crypto/sparc_arch.h"
|
||||
|
||||
# define SPARC_DES_CAPABLE (OPENSSL_sparcv9cap_P[1] & CFR_DES)
|
||||
|
||||
void des_t4_key_expand(const void *key, DES_key_schedule *ks);
|
||||
void des_t4_cbc_encrypt(const void *inp, void *out, size_t len,
|
||||
const DES_key_schedule *ks, unsigned char iv[8]);
|
||||
void des_t4_cbc_decrypt(const void *inp, void *out, size_t len,
|
||||
const DES_key_schedule *ks, unsigned char iv[8]);
|
||||
# endif
|
||||
|
||||
static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
|
||||
|
||||
/*
|
||||
* Because of various casts and different names can't use
|
||||
* IMPLEMENT_BLOCK_CIPHER
|
||||
*/
|
||||
|
||||
static int des_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
BLOCK_CIPHER_ecb_loop()
|
||||
DES_ecb_encrypt((DES_cblock *)(in + i), (DES_cblock *)(out + i),
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ofb64_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv, &num);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ofb64_encrypt(in, out, (long)inl,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv, &num);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
EVP_DES_KEY *dat = (EVP_DES_KEY *) EVP_CIPHER_CTX_get_cipher_data(ctx);
|
||||
|
||||
if (dat->stream.cbc != NULL) {
|
||||
(*dat->stream.cbc) (in, out, inl, &dat->ks.ks, ctx->iv);
|
||||
return 1;
|
||||
}
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
DES_ncbc_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl)
|
||||
DES_ncbc_encrypt(in, out, (long)inl,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_cfb64_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_cfb64_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_cfb64_encrypt(in, out, (long)inl,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although we have a CFB-r implementation for DES, it doesn't pack the right
|
||||
* way, so wrap it here
|
||||
*/
|
||||
static int des_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
size_t n, chunk = EVP_MAXCHUNK / 8;
|
||||
unsigned char c[1];
|
||||
unsigned char d[1] = { 0 }; /* Appease Coverity */
|
||||
|
||||
if (inl < chunk)
|
||||
chunk = inl;
|
||||
|
||||
while (inl && inl >= chunk) {
|
||||
for (n = 0; n < chunk * 8; ++n) {
|
||||
c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
|
||||
DES_cfb_encrypt(c, d, 1, 1, EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
out[n / 8] =
|
||||
(out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) |
|
||||
((d[0] & 0x80) >> (unsigned int)(n % 8));
|
||||
}
|
||||
inl -= chunk;
|
||||
in += chunk;
|
||||
out += chunk;
|
||||
if (inl < chunk)
|
||||
chunk = inl;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
DES_cfb_encrypt(in, out, 8, (long)EVP_MAXCHUNK,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl)
|
||||
DES_cfb_encrypt(in, out, 8, (long)inl,
|
||||
EVP_CIPHER_CTX_get_cipher_data(ctx),
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLOCK_CIPHER_defs(des, EVP_DES_KEY, NID_des, 8, 8, 8, 64,
|
||||
EVP_CIPH_RAND_KEY, des_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
|
||||
|
||||
BLOCK_CIPHER_def_cfb(des, EVP_DES_KEY, NID_des, 8, 8, 1,
|
||||
EVP_CIPH_RAND_KEY, des_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
|
||||
|
||||
BLOCK_CIPHER_def_cfb(des, EVP_DES_KEY, NID_des, 8, 8, 8,
|
||||
EVP_CIPH_RAND_KEY, des_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des_ctrl)
|
||||
|
||||
static int des_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
DES_cblock *deskey = (DES_cblock *)key;
|
||||
EVP_DES_KEY *dat = (EVP_DES_KEY *) EVP_CIPHER_CTX_get_cipher_data(ctx);
|
||||
|
||||
dat->stream.cbc = NULL;
|
||||
# if defined(SPARC_DES_CAPABLE)
|
||||
if (SPARC_DES_CAPABLE) {
|
||||
int mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
|
||||
if (mode == EVP_CIPH_CBC_MODE) {
|
||||
des_t4_key_expand(key, &dat->ks.ks);
|
||||
dat->stream.cbc = enc ? des_t4_cbc_encrypt : des_t4_cbc_decrypt;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
DES_set_key_unchecked(deskey, EVP_CIPHER_CTX_get_cipher_data(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_RAND_KEY:
|
||||
if (RAND_priv_bytes(ptr, 8) <= 0)
|
||||
return 0;
|
||||
DES_set_odd_parity((DES_cblock *)ptr);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* DES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#ifndef OPENSSL_NO_DES
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include "crypto/sha.h"
|
||||
# include <openssl/des.h>
|
||||
# include <openssl/rand.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN;
|
||||
DES_key_schedule ks[3];
|
||||
} ks;
|
||||
union {
|
||||
void (*cbc) (const void *, void *, size_t,
|
||||
const DES_key_schedule *, unsigned char *);
|
||||
} stream;
|
||||
} DES_EDE_KEY;
|
||||
# define ks1 ks.ks[0]
|
||||
# define ks2 ks.ks[1]
|
||||
# define ks3 ks.ks[2]
|
||||
|
||||
# if defined(AES_ASM) && (defined(__sparc) || defined(__sparc__))
|
||||
/* ---------^^^ this is not a typo, just a way to detect that
|
||||
* assembler support was in general requested... */
|
||||
# include "crypto/sparc_arch.h"
|
||||
|
||||
# define SPARC_DES_CAPABLE (OPENSSL_sparcv9cap_P[1] & CFR_DES)
|
||||
|
||||
void des_t4_key_expand(const void *key, DES_key_schedule *ks);
|
||||
void des_t4_ede3_cbc_encrypt(const void *inp, void *out, size_t len,
|
||||
const DES_key_schedule ks[3], unsigned char iv[8]);
|
||||
void des_t4_ede3_cbc_decrypt(const void *inp, void *out, size_t len,
|
||||
const DES_key_schedule ks[3], unsigned char iv[8]);
|
||||
# endif
|
||||
|
||||
static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
static int des3_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
|
||||
|
||||
# define data(ctx) EVP_C_DATA(DES_EDE_KEY,ctx)
|
||||
|
||||
/*
|
||||
* Because of various casts and different args can't use
|
||||
* IMPLEMENT_BLOCK_CIPHER
|
||||
*/
|
||||
|
||||
static int des_ede_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
BLOCK_CIPHER_ecb_loop()
|
||||
DES_ecb3_encrypt((const_DES_cblock *)(in + i),
|
||||
(DES_cblock *)(out + i),
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ede_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ede3_ofb64_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3,
|
||||
(DES_cblock *)ctx->iv,
|
||||
&num);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ede3_ofb64_encrypt(in, out, (long)inl,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3,
|
||||
(DES_cblock *)ctx->iv,
|
||||
&num);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ede_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
DES_EDE_KEY *dat = data(ctx);
|
||||
|
||||
if (dat->stream.cbc != NULL) {
|
||||
(*dat->stream.cbc) (in, out, inl, dat->ks.ks,
|
||||
ctx->iv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
DES_ede3_cbc_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
&dat->ks1, &dat->ks2, &dat->ks3,
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl)
|
||||
DES_ede3_cbc_encrypt(in, out, (long)inl,
|
||||
&dat->ks1, &dat->ks2, &dat->ks3,
|
||||
(DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ede_cfb64_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ede3_cfb64_encrypt(in, out, (long)EVP_MAXCHUNK,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, (DES_cblock *)ctx->iv,
|
||||
&num, EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl) {
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
DES_ede3_cfb64_encrypt(in, out, (long)inl,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, (DES_cblock *)ctx->iv,
|
||||
&num, EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although we have a CFB-r implementation for 3-DES, it doesn't pack the
|
||||
* right way, so wrap it here
|
||||
*/
|
||||
static int des_ede3_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
size_t n;
|
||||
unsigned char c[1];
|
||||
unsigned char d[1] = { 0 }; /* Appease Coverity */
|
||||
|
||||
if (!EVP_CIPHER_CTX_test_flags(ctx, EVP_CIPH_FLAG_LENGTH_BITS))
|
||||
inl *= 8;
|
||||
for (n = 0; n < inl; ++n) {
|
||||
c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
|
||||
DES_ede3_cfb_encrypt(c, d, 1, 1,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, (DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
out[n / 8] = (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8)))
|
||||
| ((d[0] & 0x80) >> (unsigned int)(n % 8));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ede3_cfb8_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
DES_ede3_cfb_encrypt(in, out, 8, (long)EVP_MAXCHUNK,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, (DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl)
|
||||
DES_ede3_cfb_encrypt(in, out, 8, (long)inl,
|
||||
&data(ctx)->ks1, &data(ctx)->ks2,
|
||||
&data(ctx)->ks3, (DES_cblock *)ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLOCK_CIPHER_defs(des_ede, DES_EDE_KEY, NID_des_ede, 8, 16, 8, 64,
|
||||
EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
des_ede_init_key, NULL, NULL, NULL, des3_ctrl)
|
||||
# define des_ede3_cfb64_cipher des_ede_cfb64_cipher
|
||||
# define des_ede3_ofb_cipher des_ede_ofb_cipher
|
||||
# define des_ede3_cbc_cipher des_ede_cbc_cipher
|
||||
# define des_ede3_ecb_cipher des_ede_ecb_cipher
|
||||
BLOCK_CIPHER_defs(des_ede3, DES_EDE_KEY, NID_des_ede3, 8, 24, 8, 64,
|
||||
EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
|
||||
|
||||
BLOCK_CIPHER_def_cfb(des_ede3, DES_EDE_KEY, NID_des_ede3, 24, 8, 1,
|
||||
EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
|
||||
|
||||
BLOCK_CIPHER_def_cfb(des_ede3, DES_EDE_KEY, NID_des_ede3, 24, 8, 8,
|
||||
EVP_CIPH_RAND_KEY | EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
des_ede3_init_key, NULL, NULL, NULL, des3_ctrl)
|
||||
|
||||
static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
DES_cblock *deskey = (DES_cblock *)key;
|
||||
DES_EDE_KEY *dat = data(ctx);
|
||||
|
||||
dat->stream.cbc = NULL;
|
||||
# if defined(SPARC_DES_CAPABLE)
|
||||
if (SPARC_DES_CAPABLE) {
|
||||
int mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
|
||||
if (mode == EVP_CIPH_CBC_MODE) {
|
||||
des_t4_key_expand(&deskey[0], &dat->ks1);
|
||||
des_t4_key_expand(&deskey[1], &dat->ks2);
|
||||
memcpy(&dat->ks3, &dat->ks1, sizeof(dat->ks1));
|
||||
dat->stream.cbc = enc ? des_t4_ede3_cbc_encrypt :
|
||||
des_t4_ede3_cbc_decrypt;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
DES_set_key_unchecked(&deskey[0], &dat->ks1);
|
||||
DES_set_key_unchecked(&deskey[1], &dat->ks2);
|
||||
memcpy(&dat->ks3, &dat->ks1, sizeof(dat->ks1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
DES_cblock *deskey = (DES_cblock *)key;
|
||||
DES_EDE_KEY *dat = data(ctx);
|
||||
|
||||
dat->stream.cbc = NULL;
|
||||
# if defined(SPARC_DES_CAPABLE)
|
||||
if (SPARC_DES_CAPABLE) {
|
||||
int mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
|
||||
if (mode == EVP_CIPH_CBC_MODE) {
|
||||
des_t4_key_expand(&deskey[0], &dat->ks1);
|
||||
des_t4_key_expand(&deskey[1], &dat->ks2);
|
||||
des_t4_key_expand(&deskey[2], &dat->ks3);
|
||||
dat->stream.cbc = enc ? des_t4_ede3_cbc_encrypt :
|
||||
des_t4_ede3_cbc_decrypt;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
DES_set_key_unchecked(&deskey[0], &dat->ks1);
|
||||
DES_set_key_unchecked(&deskey[1], &dat->ks2);
|
||||
DES_set_key_unchecked(&deskey[2], &dat->ks3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int des3_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
|
||||
{
|
||||
|
||||
DES_cblock *deskey = ptr;
|
||||
int kl;
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_RAND_KEY:
|
||||
kl = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
if (kl < 0 || RAND_priv_bytes(ptr, kl) <= 0)
|
||||
return 0;
|
||||
DES_set_odd_parity(deskey);
|
||||
if (kl >= 16)
|
||||
DES_set_odd_parity(deskey + 1);
|
||||
if (kl >= 24)
|
||||
DES_set_odd_parity(deskey + 2);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_des_ede(void)
|
||||
{
|
||||
return &des_ede_ecb;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_des_ede3(void)
|
||||
{
|
||||
return &des_ede3_ecb;
|
||||
}
|
||||
|
||||
|
||||
# include <openssl/sha.h>
|
||||
|
||||
static const unsigned char wrap_iv[8] = {
|
||||
0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05
|
||||
};
|
||||
|
||||
static int des_ede3_unwrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
unsigned char icv[8], iv[8], sha1tmp[SHA_DIGEST_LENGTH];
|
||||
int rv = -1;
|
||||
if (inl < 24)
|
||||
return -1;
|
||||
if (out == NULL)
|
||||
return inl - 16;
|
||||
memcpy(ctx->iv, wrap_iv, 8);
|
||||
/* Decrypt first block which will end up as icv */
|
||||
des_ede_cbc_cipher(ctx, icv, in, 8);
|
||||
/* Decrypt central blocks */
|
||||
/*
|
||||
* If decrypting in place move whole output along a block so the next
|
||||
* des_ede_cbc_cipher is in place.
|
||||
*/
|
||||
if (out == in) {
|
||||
memmove(out, out + 8, inl - 8);
|
||||
in -= 8;
|
||||
}
|
||||
des_ede_cbc_cipher(ctx, out, in + 8, inl - 16);
|
||||
/* Decrypt final block which will be IV */
|
||||
des_ede_cbc_cipher(ctx, iv, in + inl - 8, 8);
|
||||
/* Reverse order of everything */
|
||||
BUF_reverse(icv, NULL, 8);
|
||||
BUF_reverse(out, NULL, inl - 16);
|
||||
BUF_reverse(ctx->iv, iv, 8);
|
||||
/* Decrypt again using new IV */
|
||||
des_ede_cbc_cipher(ctx, out, out, inl - 16);
|
||||
des_ede_cbc_cipher(ctx, icv, icv, 8);
|
||||
if (ossl_sha1(out, inl - 16, sha1tmp) /* Work out hash of first portion */
|
||||
&& CRYPTO_memcmp(sha1tmp, icv, 8) == 0)
|
||||
rv = inl - 16;
|
||||
OPENSSL_cleanse(icv, 8);
|
||||
OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
|
||||
OPENSSL_cleanse(iv, 8);
|
||||
OPENSSL_cleanse(ctx->iv, 8);
|
||||
if (rv == -1)
|
||||
OPENSSL_cleanse(out, inl - 16);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int des_ede3_wrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
unsigned char sha1tmp[SHA_DIGEST_LENGTH];
|
||||
if (out == NULL)
|
||||
return inl + 16;
|
||||
/* Copy input to output buffer + 8 so we have space for IV */
|
||||
memmove(out + 8, in, inl);
|
||||
/* Work out ICV */
|
||||
if (!ossl_sha1(in, inl, sha1tmp))
|
||||
return -1;
|
||||
memcpy(out + inl + 8, sha1tmp, 8);
|
||||
OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
|
||||
/* Generate random IV */
|
||||
if (RAND_bytes(ctx->iv, 8) <= 0)
|
||||
return -1;
|
||||
memcpy(out, ctx->iv, 8);
|
||||
/* Encrypt everything after IV in place */
|
||||
des_ede_cbc_cipher(ctx, out + 8, out + 8, inl + 8);
|
||||
BUF_reverse(out, NULL, inl + 16);
|
||||
memcpy(ctx->iv, wrap_iv, 8);
|
||||
des_ede_cbc_cipher(ctx, out, out, inl + 16);
|
||||
return inl + 16;
|
||||
}
|
||||
|
||||
static int des_ede3_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
/*
|
||||
* Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK
|
||||
* is more than will ever be needed. Also input length must be a multiple
|
||||
* of 8 bits.
|
||||
*/
|
||||
if (inl >= EVP_MAXCHUNK || inl % 8)
|
||||
return -1;
|
||||
|
||||
if (ossl_is_partially_overlapping(out, in, inl)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
return des_ede3_wrap(ctx, out, in, inl);
|
||||
else
|
||||
return des_ede3_unwrap(ctx, out, in, inl);
|
||||
}
|
||||
|
||||
static const EVP_CIPHER des3_wrap = {
|
||||
NID_id_smime_alg_CMS3DESwrap,
|
||||
8, 24, 0,
|
||||
EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
|
||||
| EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
EVP_ORIG_GLOBAL,
|
||||
des_ede3_init_key, des_ede3_wrap_cipher,
|
||||
NULL,
|
||||
sizeof(DES_EDE_KEY),
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_des_ede3_wrap(void)
|
||||
{
|
||||
return &des3_wrap;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* IDEA low level APIs are deprecated for public use, but still ok for internal
|
||||
* use where we're using them to implement the higher level EVP interface, as is
|
||||
* the case here.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_IDEA
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/idea.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
/* Can't use IMPLEMENT_BLOCK_CIPHER because IDEA_ecb_encrypt is different */
|
||||
|
||||
typedef struct {
|
||||
IDEA_KEY_SCHEDULE ks;
|
||||
} EVP_IDEA_KEY;
|
||||
|
||||
static int idea_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
/*
|
||||
* NB IDEA_ecb_encrypt doesn't take an 'encrypt' argument so we treat it as a
|
||||
* special case
|
||||
*/
|
||||
|
||||
static int idea_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
BLOCK_CIPHER_ecb_loop()
|
||||
IDEA_ecb_encrypt(in + i, out + i, &EVP_C_DATA(EVP_IDEA_KEY, ctx)->ks);
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLOCK_CIPHER_func_cbc(idea, IDEA, EVP_IDEA_KEY, ks)
|
||||
BLOCK_CIPHER_func_ofb(idea, IDEA, 64, EVP_IDEA_KEY, ks)
|
||||
BLOCK_CIPHER_func_cfb(idea, IDEA, 64, EVP_IDEA_KEY, ks)
|
||||
|
||||
BLOCK_CIPHER_defs(idea, IDEA_KEY_SCHEDULE, NID_idea, 8, 16, 8, 64,
|
||||
0, idea_init_key, NULL,
|
||||
EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, NULL)
|
||||
|
||||
static int idea_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
if (!enc) {
|
||||
if (EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_OFB_MODE)
|
||||
enc = 1;
|
||||
else if (EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_CFB_MODE)
|
||||
enc = 1;
|
||||
}
|
||||
if (enc)
|
||||
IDEA_set_encrypt_key(key, &EVP_C_DATA(EVP_IDEA_KEY, ctx)->ks);
|
||||
else {
|
||||
IDEA_KEY_SCHEDULE tmp;
|
||||
|
||||
IDEA_set_encrypt_key(key, &tmp);
|
||||
IDEA_set_decrypt_key(&tmp, &EVP_C_DATA(EVP_IDEA_KEY, ctx)->ks);
|
||||
OPENSSL_cleanse((unsigned char *)&tmp, sizeof(IDEA_KEY_SCHEDULE));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
static int null_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int null_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl);
|
||||
static const EVP_CIPHER n_cipher = {
|
||||
NID_undef,
|
||||
1, 0, 0, 0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
null_init_key,
|
||||
null_cipher,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_enc_null(void)
|
||||
{
|
||||
return &n_cipher;
|
||||
}
|
||||
|
||||
static int null_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int null_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
if (in != out)
|
||||
memcpy(out, in, inl);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/*
|
||||
* Define some deprecated functions, so older programs don't crash and burn
|
||||
* too quickly. On Windows and VMS, these will never be used, since
|
||||
* functions and variables in shared libraries are selected by entry point
|
||||
* location, not by name.
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_NO_BF
|
||||
# undef EVP_bf_cfb
|
||||
const EVP_CIPHER *EVP_bf_cfb(void);
|
||||
const EVP_CIPHER *EVP_bf_cfb(void)
|
||||
{
|
||||
return EVP_bf_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_DES
|
||||
# undef EVP_des_cfb
|
||||
const EVP_CIPHER *EVP_des_cfb(void);
|
||||
const EVP_CIPHER *EVP_des_cfb(void)
|
||||
{
|
||||
return EVP_des_cfb64();
|
||||
}
|
||||
|
||||
# undef EVP_des_ede3_cfb
|
||||
const EVP_CIPHER *EVP_des_ede3_cfb(void);
|
||||
const EVP_CIPHER *EVP_des_ede3_cfb(void)
|
||||
{
|
||||
return EVP_des_ede3_cfb64();
|
||||
}
|
||||
|
||||
# undef EVP_des_ede_cfb
|
||||
const EVP_CIPHER *EVP_des_ede_cfb(void);
|
||||
const EVP_CIPHER *EVP_des_ede_cfb(void)
|
||||
{
|
||||
return EVP_des_ede_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_IDEA
|
||||
# undef EVP_idea_cfb
|
||||
const EVP_CIPHER *EVP_idea_cfb(void);
|
||||
const EVP_CIPHER *EVP_idea_cfb(void)
|
||||
{
|
||||
return EVP_idea_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RC2
|
||||
# undef EVP_rc2_cfb
|
||||
const EVP_CIPHER *EVP_rc2_cfb(void);
|
||||
const EVP_CIPHER *EVP_rc2_cfb(void)
|
||||
{
|
||||
return EVP_rc2_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_CAST
|
||||
# undef EVP_cast5_cfb
|
||||
const EVP_CIPHER *EVP_cast5_cfb(void);
|
||||
const EVP_CIPHER *EVP_cast5_cfb(void)
|
||||
{
|
||||
return EVP_cast5_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RC5
|
||||
# undef EVP_rc5_32_12_16_cfb
|
||||
const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
|
||||
const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void)
|
||||
{
|
||||
return EVP_rc5_32_12_16_cfb64();
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef EVP_aes_128_cfb
|
||||
const EVP_CIPHER *EVP_aes_128_cfb(void);
|
||||
const EVP_CIPHER *EVP_aes_128_cfb(void)
|
||||
{
|
||||
return EVP_aes_128_cfb128();
|
||||
}
|
||||
|
||||
#undef EVP_aes_192_cfb
|
||||
const EVP_CIPHER *EVP_aes_192_cfb(void);
|
||||
const EVP_CIPHER *EVP_aes_192_cfb(void)
|
||||
{
|
||||
return EVP_aes_192_cfb128();
|
||||
}
|
||||
|
||||
#undef EVP_aes_256_cfb
|
||||
const EVP_CIPHER *EVP_aes_256_cfb(void);
|
||||
const EVP_CIPHER *EVP_aes_256_cfb(void)
|
||||
{
|
||||
return EVP_aes_256_cfb128();
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* RC2 low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_RC2
|
||||
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/rc2.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
static int rc2_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int rc2_meth_to_magic(EVP_CIPHER_CTX *ctx);
|
||||
static int rc2_magic_to_meth(int i);
|
||||
static int rc2_set_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
|
||||
static int rc2_get_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
|
||||
static int rc2_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
|
||||
|
||||
typedef struct {
|
||||
int key_bits; /* effective key bits */
|
||||
RC2_KEY ks; /* key schedule */
|
||||
} EVP_RC2_KEY;
|
||||
|
||||
# define data(ctx) EVP_C_DATA(EVP_RC2_KEY,ctx)
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(rc2, ks, RC2, EVP_RC2_KEY, NID_rc2,
|
||||
8,
|
||||
RC2_KEY_LENGTH, 8, 64,
|
||||
EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
|
||||
rc2_init_key, NULL,
|
||||
rc2_set_asn1_type_and_iv, rc2_get_asn1_type_and_iv,
|
||||
rc2_ctrl)
|
||||
# define RC2_40_MAGIC 0xa0
|
||||
# define RC2_64_MAGIC 0x78
|
||||
# define RC2_128_MAGIC 0x3a
|
||||
static const EVP_CIPHER r2_64_cbc_cipher = {
|
||||
NID_rc2_64_cbc,
|
||||
8, 8 /* 64 bit */ , 8,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
rc2_init_key,
|
||||
rc2_cbc_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_RC2_KEY),
|
||||
rc2_set_asn1_type_and_iv,
|
||||
rc2_get_asn1_type_and_iv,
|
||||
rc2_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const EVP_CIPHER r2_40_cbc_cipher = {
|
||||
NID_rc2_40_cbc,
|
||||
8, 5 /* 40 bit */ , 8,
|
||||
EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
rc2_init_key,
|
||||
rc2_cbc_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_RC2_KEY),
|
||||
rc2_set_asn1_type_and_iv,
|
||||
rc2_get_asn1_type_and_iv,
|
||||
rc2_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_rc2_64_cbc(void)
|
||||
{
|
||||
return &r2_64_cbc_cipher;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_rc2_40_cbc(void)
|
||||
{
|
||||
return &r2_40_cbc_cipher;
|
||||
}
|
||||
|
||||
static int rc2_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
RC2_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_get_key_length(ctx),
|
||||
key, data(ctx)->key_bits);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rc2_meth_to_magic(EVP_CIPHER_CTX *e)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(e, EVP_CTRL_GET_RC2_KEY_BITS, 0, &i) <= 0)
|
||||
return 0;
|
||||
if (i == 128)
|
||||
return RC2_128_MAGIC;
|
||||
else if (i == 64)
|
||||
return RC2_64_MAGIC;
|
||||
else if (i == 40)
|
||||
return RC2_40_MAGIC;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rc2_magic_to_meth(int i)
|
||||
{
|
||||
if (i == RC2_128_MAGIC)
|
||||
return 128;
|
||||
else if (i == RC2_64_MAGIC)
|
||||
return 64;
|
||||
else if (i == RC2_40_MAGIC)
|
||||
return 40;
|
||||
else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int rc2_get_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
|
||||
{
|
||||
long num = 0;
|
||||
int i = 0;
|
||||
int key_bits;
|
||||
unsigned int l;
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH];
|
||||
|
||||
if (type != NULL) {
|
||||
l = EVP_CIPHER_CTX_get_iv_length(c);
|
||||
OPENSSL_assert(l <= sizeof(iv));
|
||||
i = ASN1_TYPE_get_int_octetstring(type, &num, iv, l);
|
||||
if (i != (int)l)
|
||||
return -1;
|
||||
key_bits = rc2_magic_to_meth((int)num);
|
||||
if (!key_bits)
|
||||
return -1;
|
||||
if (i > 0 && !EVP_CipherInit_ex(c, NULL, NULL, NULL, iv, -1))
|
||||
return -1;
|
||||
if (EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_RC2_KEY_BITS, key_bits,
|
||||
NULL) <= 0
|
||||
|| EVP_CIPHER_CTX_set_key_length(c, key_bits / 8) <= 0)
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int rc2_set_asn1_type_and_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
|
||||
{
|
||||
long num;
|
||||
int i = 0, j;
|
||||
|
||||
if (type != NULL) {
|
||||
num = rc2_meth_to_magic(c);
|
||||
j = EVP_CIPHER_CTX_get_iv_length(c);
|
||||
i = ASN1_TYPE_set_int_octetstring(type, num, c->oiv, j);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int rc2_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
|
||||
{
|
||||
switch (type) {
|
||||
case EVP_CTRL_INIT:
|
||||
data(c)->key_bits = EVP_CIPHER_CTX_get_key_length(c) * 8;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GET_RC2_KEY_BITS:
|
||||
*(int *)ptr = data(c)->key_bits;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_SET_RC2_KEY_BITS:
|
||||
if (arg > 0) {
|
||||
data(c)->key_bits = arg;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
# ifdef PBE_PRF_TEST
|
||||
case EVP_CTRL_PBE_PRF_NID:
|
||||
*(int *)ptr = NID_hmacWithMD5;
|
||||
return 1;
|
||||
# endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* RC4 low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include <openssl/rc4.h>
|
||||
|
||||
# include "crypto/evp.h"
|
||||
|
||||
typedef struct {
|
||||
RC4_KEY ks; /* working key */
|
||||
} EVP_RC4_KEY;
|
||||
|
||||
# define data(ctx) ((EVP_RC4_KEY *)EVP_CIPHER_CTX_get_cipher_data(ctx))
|
||||
|
||||
static int rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl);
|
||||
static const EVP_CIPHER r4_cipher = {
|
||||
NID_rc4,
|
||||
1, EVP_RC4_KEY_SIZE, 0,
|
||||
EVP_CIPH_VARIABLE_LENGTH,
|
||||
EVP_ORIG_GLOBAL,
|
||||
rc4_init_key,
|
||||
rc4_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_RC4_KEY),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const EVP_CIPHER r4_40_cipher = {
|
||||
NID_rc4_40,
|
||||
1, 5 /* 40 bit */ , 0,
|
||||
EVP_CIPH_VARIABLE_LENGTH,
|
||||
EVP_ORIG_GLOBAL,
|
||||
rc4_init_key,
|
||||
rc4_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_RC4_KEY),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_rc4(void)
|
||||
{
|
||||
return &r4_cipher;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_rc4_40(void)
|
||||
{
|
||||
return &r4_40_cipher;
|
||||
}
|
||||
|
||||
static int rc4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int keylen;
|
||||
|
||||
if ((keylen = EVP_CIPHER_CTX_get_key_length(ctx)) <= 0)
|
||||
return 0;
|
||||
RC4_set_key(&data(ctx)->ks, keylen, key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rc4_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
RC4(&data(ctx)->ks, inl, in, out);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD5 and RC4 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
|
||||
|
||||
# include <openssl/crypto.h>
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include <openssl/rc4.h>
|
||||
# include <openssl/md5.h>
|
||||
# include "crypto/evp.h"
|
||||
|
||||
typedef struct {
|
||||
RC4_KEY ks;
|
||||
MD5_CTX head, tail, md;
|
||||
size_t payload_length;
|
||||
} EVP_RC4_HMAC_MD5;
|
||||
|
||||
# define NO_PAYLOAD_LENGTH ((size_t)-1)
|
||||
|
||||
void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out,
|
||||
MD5_CTX *ctx, const void *inp, size_t blocks);
|
||||
|
||||
# define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
|
||||
|
||||
static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx,
|
||||
const unsigned char *inkey,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
EVP_RC4_HMAC_MD5 *key = data(ctx);
|
||||
const int keylen = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
|
||||
if (keylen <= 0)
|
||||
return 0;
|
||||
|
||||
RC4_set_key(&key->ks, keylen, inkey);
|
||||
|
||||
MD5_Init(&key->head); /* handy when benchmarking */
|
||||
key->tail = key->head;
|
||||
key->md = key->head;
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# if defined(RC4_ASM) && defined(MD5_ASM) && ( \
|
||||
defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(_M_X64) )
|
||||
# define STITCHED_CALL
|
||||
# endif
|
||||
|
||||
# if !defined(STITCHED_CALL)
|
||||
# define rc4_off 0
|
||||
# define md5_off 0
|
||||
# endif
|
||||
|
||||
static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_RC4_HMAC_MD5 *key = data(ctx);
|
||||
# if defined(STITCHED_CALL)
|
||||
size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from
|
||||
* rc4_md5-x86_64.pl */
|
||||
md5_off = MD5_CBLOCK - key->md.num, blocks;
|
||||
unsigned int l;
|
||||
# endif
|
||||
size_t plen = key->payload_length;
|
||||
|
||||
if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH))
|
||||
return 0;
|
||||
|
||||
if (EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (plen == NO_PAYLOAD_LENGTH)
|
||||
plen = len;
|
||||
# if defined(STITCHED_CALL)
|
||||
/* cipher has to "fall behind" */
|
||||
if (rc4_off > md5_off)
|
||||
md5_off += MD5_CBLOCK;
|
||||
|
||||
if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) &&
|
||||
(OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
|
||||
MD5_Update(&key->md, in, md5_off);
|
||||
RC4(&key->ks, rc4_off, in, out);
|
||||
|
||||
rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off,
|
||||
&key->md, in + md5_off, blocks);
|
||||
blocks *= MD5_CBLOCK;
|
||||
rc4_off += blocks;
|
||||
md5_off += blocks;
|
||||
key->md.Nh += blocks >> 29;
|
||||
key->md.Nl += blocks <<= 3;
|
||||
if (key->md.Nl < (unsigned int)blocks)
|
||||
key->md.Nh++;
|
||||
} else {
|
||||
rc4_off = 0;
|
||||
md5_off = 0;
|
||||
}
|
||||
# endif
|
||||
MD5_Update(&key->md, in + md5_off, plen - md5_off);
|
||||
|
||||
if (plen != len) { /* "TLS" mode of operation */
|
||||
if (in != out)
|
||||
memcpy(out + rc4_off, in + rc4_off, plen - rc4_off);
|
||||
|
||||
/* calculate HMAC and append it to payload */
|
||||
MD5_Final(out + plen, &key->md);
|
||||
key->md = key->tail;
|
||||
MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH);
|
||||
MD5_Final(out + plen, &key->md);
|
||||
/* encrypt HMAC at once */
|
||||
RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off);
|
||||
} else {
|
||||
RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off);
|
||||
}
|
||||
} else {
|
||||
unsigned char mac[MD5_DIGEST_LENGTH];
|
||||
# if defined(STITCHED_CALL)
|
||||
/* digest has to "fall behind" */
|
||||
if (md5_off > rc4_off)
|
||||
rc4_off += 2 * MD5_CBLOCK;
|
||||
else
|
||||
rc4_off += MD5_CBLOCK;
|
||||
|
||||
if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) &&
|
||||
(OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
|
||||
RC4(&key->ks, rc4_off, in, out);
|
||||
MD5_Update(&key->md, out, md5_off);
|
||||
|
||||
rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off,
|
||||
&key->md, out + md5_off, blocks);
|
||||
blocks *= MD5_CBLOCK;
|
||||
rc4_off += blocks;
|
||||
md5_off += blocks;
|
||||
l = (key->md.Nl + (blocks << 3)) & 0xffffffffU;
|
||||
if (l < key->md.Nl)
|
||||
key->md.Nh++;
|
||||
key->md.Nl = l;
|
||||
key->md.Nh += blocks >> 29;
|
||||
} else {
|
||||
md5_off = 0;
|
||||
rc4_off = 0;
|
||||
}
|
||||
# endif
|
||||
/* decrypt HMAC at once */
|
||||
RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off);
|
||||
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
|
||||
MD5_Update(&key->md, out + md5_off, plen - md5_off);
|
||||
|
||||
/* calculate HMAC and verify it */
|
||||
MD5_Final(mac, &key->md);
|
||||
key->md = key->tail;
|
||||
MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH);
|
||||
MD5_Final(mac, &key->md);
|
||||
|
||||
if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH))
|
||||
return 0;
|
||||
} else {
|
||||
MD5_Update(&key->md, out + md5_off, len - md5_off);
|
||||
}
|
||||
}
|
||||
|
||||
key->payload_length = NO_PAYLOAD_LENGTH;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
|
||||
void *ptr)
|
||||
{
|
||||
EVP_RC4_HMAC_MD5 *key = data(ctx);
|
||||
|
||||
switch (type) {
|
||||
case EVP_CTRL_AEAD_SET_MAC_KEY:
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char hmac_key[64];
|
||||
|
||||
memset(hmac_key, 0, sizeof(hmac_key));
|
||||
|
||||
if (arg > (int)sizeof(hmac_key)) {
|
||||
MD5_Init(&key->head);
|
||||
MD5_Update(&key->head, ptr, arg);
|
||||
MD5_Final(hmac_key, &key->head);
|
||||
} else {
|
||||
memcpy(hmac_key, ptr, arg);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36; /* ipad */
|
||||
MD5_Init(&key->head);
|
||||
MD5_Update(&key->head, hmac_key, sizeof(hmac_key));
|
||||
|
||||
for (i = 0; i < sizeof(hmac_key); i++)
|
||||
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
|
||||
MD5_Init(&key->tail);
|
||||
MD5_Update(&key->tail, hmac_key, sizeof(hmac_key));
|
||||
|
||||
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
case EVP_CTRL_AEAD_TLS1_AAD:
|
||||
{
|
||||
unsigned char *p = ptr;
|
||||
unsigned int len;
|
||||
|
||||
if (arg != EVP_AEAD_TLS1_AAD_LEN)
|
||||
return -1;
|
||||
|
||||
len = p[arg - 2] << 8 | p[arg - 1];
|
||||
|
||||
if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {
|
||||
if (len < MD5_DIGEST_LENGTH)
|
||||
return -1;
|
||||
len -= MD5_DIGEST_LENGTH;
|
||||
p[arg - 2] = len >> 8;
|
||||
p[arg - 1] = len;
|
||||
}
|
||||
key->payload_length = len;
|
||||
key->md = key->head;
|
||||
MD5_Update(&key->md, p, arg);
|
||||
|
||||
return MD5_DIGEST_LENGTH;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static EVP_CIPHER r4_hmac_md5_cipher = {
|
||||
# ifdef NID_rc4_hmac_md5
|
||||
NID_rc4_hmac_md5,
|
||||
# else
|
||||
NID_undef,
|
||||
# endif
|
||||
1, EVP_RC4_KEY_SIZE, 0,
|
||||
EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH |
|
||||
EVP_CIPH_FLAG_AEAD_CIPHER,
|
||||
EVP_ORIG_GLOBAL,
|
||||
rc4_hmac_md5_init_key,
|
||||
rc4_hmac_md5_cipher,
|
||||
NULL,
|
||||
sizeof(EVP_RC4_HMAC_MD5),
|
||||
NULL,
|
||||
NULL,
|
||||
rc4_hmac_md5_ctrl,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_rc4_hmac_md5(void)
|
||||
{
|
||||
return &r4_hmac_md5_cipher;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* RC5 low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_RC5
|
||||
|
||||
# include <openssl/evp.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/objects.h>
|
||||
# include "evp_local.h"
|
||||
# include <openssl/rc5.h>
|
||||
|
||||
static int r_32_12_16_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int rc5_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
|
||||
|
||||
typedef struct {
|
||||
int rounds; /* number of rounds */
|
||||
RC5_32_KEY ks; /* key schedule */
|
||||
} EVP_RC5_KEY;
|
||||
|
||||
# define data(ctx) EVP_C_DATA(EVP_RC5_KEY,ctx)
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(rc5_32_12_16, ks, RC5_32, EVP_RC5_KEY, NID_rc5,
|
||||
8, RC5_32_KEY_LENGTH, 8, 64,
|
||||
EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
|
||||
r_32_12_16_init_key, NULL, NULL, NULL, rc5_ctrl)
|
||||
|
||||
static int rc5_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
|
||||
{
|
||||
switch (type) {
|
||||
case EVP_CTRL_INIT:
|
||||
data(c)->rounds = RC5_12_ROUNDS;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_GET_RC5_ROUNDS:
|
||||
*(int *)ptr = data(c)->rounds;
|
||||
return 1;
|
||||
|
||||
case EVP_CTRL_SET_RC5_ROUNDS:
|
||||
switch (arg) {
|
||||
case RC5_8_ROUNDS:
|
||||
case RC5_12_ROUNDS:
|
||||
case RC5_16_ROUNDS:
|
||||
data(c)->rounds = arg;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int r_32_12_16_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
const int key_len = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
|
||||
if (key_len > 255 || key_len < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_BAD_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
return RC5_32_set_key(&data(ctx)->ks, key_len, key, data(ctx)->rounds);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* SEED low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <openssl/seed.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static int seed_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
|
||||
typedef struct {
|
||||
SEED_KEY_SCHEDULE ks;
|
||||
} EVP_SEED_KEY;
|
||||
|
||||
IMPLEMENT_BLOCK_CIPHER(seed, ks, SEED, EVP_SEED_KEY, NID_seed,
|
||||
16, 16, 16, 128, EVP_CIPH_FLAG_DEFAULT_ASN1,
|
||||
seed_init_key, 0, 0, 0, 0)
|
||||
|
||||
static int seed_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
SEED_set_key(key, &EVP_C_DATA(EVP_SEED_KEY, ctx)->ks);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 2017 Ribose Inc. All Rights Reserved.
|
||||
* Ported from Ribose contributions from Botan.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#ifndef OPENSSL_NO_SM4
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/modes.h>
|
||||
# include "crypto/sm4.h"
|
||||
# include "crypto/evp.h"
|
||||
# include "crypto/sm4_platform.h"
|
||||
# include "evp_local.h"
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
OSSL_UNION_ALIGN;
|
||||
SM4_KEY ks;
|
||||
} ks;
|
||||
block128_f block;
|
||||
union {
|
||||
ecb128_f ecb;
|
||||
cbc128_f cbc;
|
||||
ctr128_f ctr;
|
||||
} stream;
|
||||
} EVP_SM4_KEY;
|
||||
|
||||
# define BLOCK_CIPHER_generic(nid,blocksize,ivlen,nmode,mode,MODE,flags) \
|
||||
static const EVP_CIPHER sm4_##mode = { \
|
||||
nid##_##nmode,blocksize,128/8,ivlen, \
|
||||
flags|EVP_CIPH_##MODE##_MODE, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
sm4_init_key, \
|
||||
sm4_##mode##_cipher, \
|
||||
NULL, \
|
||||
sizeof(EVP_SM4_KEY), \
|
||||
NULL,NULL,NULL,NULL }; \
|
||||
const EVP_CIPHER *EVP_sm4_##mode(void) \
|
||||
{ return &sm4_##mode; }
|
||||
|
||||
#define DEFINE_BLOCK_CIPHERS(nid,flags) \
|
||||
BLOCK_CIPHER_generic(nid,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1) \
|
||||
BLOCK_CIPHER_generic(nid,1,16,ctr,ctr,CTR,flags)
|
||||
|
||||
static int sm4_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
int mode;
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
|
||||
mode = EVP_CIPHER_CTX_get_mode(ctx);
|
||||
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE)
|
||||
&& !enc) {
|
||||
#ifdef HWSM4_CAPABLE
|
||||
if (HWSM4_CAPABLE) {
|
||||
HWSM4_set_decrypt_key(key, &dat->ks.ks);
|
||||
dat->block = (block128_f) HWSM4_decrypt;
|
||||
dat->stream.cbc = NULL;
|
||||
# ifdef HWSM4_cbc_encrypt
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) HWSM4_cbc_encrypt;
|
||||
# endif
|
||||
# ifdef HWSM4_ecb_encrypt
|
||||
if (mode == EVP_CIPH_ECB_MODE)
|
||||
dat->stream.ecb = (ecb128_f) HWSM4_ecb_encrypt;
|
||||
# endif
|
||||
} else
|
||||
#endif
|
||||
#ifdef VPSM4_CAPABLE
|
||||
if (VPSM4_CAPABLE) {
|
||||
vpsm4_set_decrypt_key(key, &dat->ks.ks);
|
||||
dat->block = (block128_f) vpsm4_decrypt;
|
||||
dat->stream.cbc = NULL;
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) vpsm4_cbc_encrypt;
|
||||
else if (mode == EVP_CIPH_ECB_MODE)
|
||||
dat->stream.ecb = (ecb128_f) vpsm4_ecb_encrypt;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dat->block = (block128_f) ossl_sm4_decrypt;
|
||||
ossl_sm4_set_key(key, EVP_CIPHER_CTX_get_cipher_data(ctx));
|
||||
}
|
||||
} else
|
||||
#ifdef HWSM4_CAPABLE
|
||||
if (HWSM4_CAPABLE) {
|
||||
HWSM4_set_encrypt_key(key, &dat->ks.ks);
|
||||
dat->block = (block128_f) HWSM4_encrypt;
|
||||
dat->stream.cbc = NULL;
|
||||
# ifdef HWSM4_cbc_encrypt
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) HWSM4_cbc_encrypt;
|
||||
else
|
||||
# endif
|
||||
# ifdef HWSM4_ecb_encrypt
|
||||
if (mode == EVP_CIPH_ECB_MODE)
|
||||
dat->stream.ecb = (ecb128_f) HWSM4_ecb_encrypt;
|
||||
else
|
||||
# endif
|
||||
# ifdef HWSM4_ctr32_encrypt_blocks
|
||||
if (mode == EVP_CIPH_CTR_MODE)
|
||||
dat->stream.ctr = (ctr128_f) HWSM4_ctr32_encrypt_blocks;
|
||||
else
|
||||
# endif
|
||||
(void)0; /* terminate potentially open 'else' */
|
||||
} else
|
||||
#endif
|
||||
#ifdef VPSM4_CAPABLE
|
||||
if (VPSM4_CAPABLE) {
|
||||
vpsm4_set_encrypt_key(key, &dat->ks.ks);
|
||||
dat->block = (block128_f) vpsm4_encrypt;
|
||||
dat->stream.cbc = NULL;
|
||||
if (mode == EVP_CIPH_CBC_MODE)
|
||||
dat->stream.cbc = (cbc128_f) vpsm4_cbc_encrypt;
|
||||
else if (mode == EVP_CIPH_ECB_MODE)
|
||||
dat->stream.ecb = (ecb128_f) vpsm4_ecb_encrypt;
|
||||
else if (mode == EVP_CIPH_CTR_MODE)
|
||||
dat->stream.ctr = (ctr128_f) vpsm4_ctr32_encrypt_blocks;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dat->block = (block128_f) ossl_sm4_encrypt;
|
||||
ossl_sm4_set_key(key, EVP_CIPHER_CTX_get_cipher_data(ctx));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm4_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
|
||||
if (dat->stream.cbc)
|
||||
(*dat->stream.cbc) (in, out, len, &dat->ks.ks, ctx->iv,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
else if (EVP_CIPHER_CTX_is_encrypting(ctx))
|
||||
CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv,
|
||||
dat->block);
|
||||
else
|
||||
CRYPTO_cbc128_decrypt(in, out, len, &dat->ks,
|
||||
ctx->iv, dat->block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm4_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
|
||||
CRYPTO_cfb128_encrypt(in, out, len, &dat->ks,
|
||||
ctx->iv, &num,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx), dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm4_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
size_t bl = EVP_CIPHER_CTX_get_block_size(ctx);
|
||||
size_t i;
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
|
||||
if (len < bl)
|
||||
return 1;
|
||||
|
||||
if (dat->stream.ecb != NULL)
|
||||
(*dat->stream.ecb) (in, out, len, &dat->ks.ks,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
else
|
||||
for (i = 0, len -= bl; i <= len; i += bl)
|
||||
(*dat->block) (in + i, out + i, &dat->ks);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm4_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
int num = EVP_CIPHER_CTX_get_num(ctx);
|
||||
|
||||
CRYPTO_ofb128_encrypt(in, out, len, &dat->ks,
|
||||
ctx->iv, &num, dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sm4_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t len)
|
||||
{
|
||||
int n = EVP_CIPHER_CTX_get_num(ctx);
|
||||
unsigned int num;
|
||||
EVP_SM4_KEY *dat = EVP_C_DATA(EVP_SM4_KEY,ctx);
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
num = (unsigned int)n;
|
||||
|
||||
if (dat->stream.ctr)
|
||||
CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks,
|
||||
ctx->iv,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx),
|
||||
&num, dat->stream.ctr);
|
||||
else
|
||||
CRYPTO_ctr128_encrypt(in, out, len, &dat->ks,
|
||||
ctx->iv,
|
||||
EVP_CIPHER_CTX_buf_noconst(ctx), &num,
|
||||
dat->block);
|
||||
EVP_CIPHER_CTX_set_num(ctx, num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEFINE_BLOCK_CIPHERS(NID_sm4, 0)
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* DES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#ifndef OPENSSL_NO_DES
|
||||
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/objects.h>
|
||||
# include "crypto/evp.h"
|
||||
# include <openssl/des.h>
|
||||
# include "evp_local.h"
|
||||
|
||||
static int desx_cbc_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
static int desx_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl);
|
||||
|
||||
typedef struct {
|
||||
DES_key_schedule ks; /* key schedule */
|
||||
DES_cblock inw;
|
||||
DES_cblock outw;
|
||||
} DESX_CBC_KEY;
|
||||
|
||||
# define data(ctx) EVP_C_DATA(DESX_CBC_KEY,ctx)
|
||||
|
||||
static const EVP_CIPHER d_xcbc_cipher = {
|
||||
NID_desx_cbc,
|
||||
8, 24, 8,
|
||||
EVP_CIPH_CBC_MODE,
|
||||
EVP_ORIG_GLOBAL,
|
||||
desx_cbc_init_key,
|
||||
desx_cbc_cipher,
|
||||
NULL,
|
||||
sizeof(DESX_CBC_KEY),
|
||||
EVP_CIPHER_set_asn1_iv,
|
||||
EVP_CIPHER_get_asn1_iv,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const EVP_CIPHER *EVP_desx_cbc(void)
|
||||
{
|
||||
return &d_xcbc_cipher;
|
||||
}
|
||||
|
||||
static int desx_cbc_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
DES_cblock *deskey = (DES_cblock *)key;
|
||||
|
||||
DES_set_key_unchecked(deskey, &data(ctx)->ks);
|
||||
memcpy(&data(ctx)->inw[0], &key[8], 8);
|
||||
memcpy(&data(ctx)->outw[0], &key[16], 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int desx_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
while (inl >= EVP_MAXCHUNK) {
|
||||
DES_xcbc_encrypt(in, out, (long)EVP_MAXCHUNK, &data(ctx)->ks,
|
||||
(DES_cblock *)ctx->iv,
|
||||
&data(ctx)->inw, &data(ctx)->outw,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
inl -= EVP_MAXCHUNK;
|
||||
in += EVP_MAXCHUNK;
|
||||
out += EVP_MAXCHUNK;
|
||||
}
|
||||
if (inl)
|
||||
DES_xcbc_encrypt(in, out, (long)inl, &data(ctx)->ks,
|
||||
(DES_cblock *)ctx->iv,
|
||||
&data(ctx)->inw, &data(ctx)->outw,
|
||||
EVP_CIPHER_CTX_is_encrypting(ctx));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ec.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "crypto/ec.h"
|
||||
|
||||
/*
|
||||
* This file is meant to contain functions to provide EVP_PKEY support for EC
|
||||
* keys.
|
||||
*/
|
||||
|
||||
static ossl_inline
|
||||
int evp_pkey_ctx_getset_ecdh_param_checks(const EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
/* Uses the same return values as EVP_PKEY_CTX_ctrl */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* If key type not EC return error */
|
||||
if (evp_pkey_ctx_is_legacy(ctx)
|
||||
&& ctx->pmeth != NULL && ctx->pmeth->pkey_id != EVP_PKEY_EC)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx, int cofactor_mode)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Valid input values are:
|
||||
* * 0 for disable
|
||||
* * 1 for enable
|
||||
* * -1 for reset to default for associated priv key
|
||||
*/
|
||||
if (cofactor_mode < -1 || cofactor_mode > 1) {
|
||||
/* Uses the same return value of pkey_ec_ctrl() */
|
||||
return -2;
|
||||
}
|
||||
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE,
|
||||
&cofactor_mode);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_get_ecdh_cofactor_mode(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
int ret, mode;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE,
|
||||
&mode);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_get_params_strict(ctx, params);
|
||||
|
||||
switch (ret) {
|
||||
case -2:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
break;
|
||||
case 1:
|
||||
ret = mode;
|
||||
if (mode < 0 || mode > 1) {
|
||||
/*
|
||||
* The provider should return either 0 or 1, any other value is a
|
||||
* provider error.
|
||||
*/
|
||||
ret = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_ecdh_kdf_type(EVP_PKEY_CTX *ctx, int kdf)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_EC_KDF_TYPE, kdf, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_get_ecdh_kdf_type(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_EC_KDF_TYPE, -2, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_EC_KDF_MD, 0, (void *)(md));
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_get_ecdh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,
|
||||
EVP_PKEY_CTRL_GET_EC_KDF_MD, 0, (void *)(pmd));
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int outlen)
|
||||
{
|
||||
int ret;
|
||||
size_t len = outlen;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
if (outlen <= 0) {
|
||||
/*
|
||||
* This would ideally be -1 or 0, but we have to retain compatibility
|
||||
* with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if
|
||||
* in <= 0
|
||||
*/
|
||||
return -2;
|
||||
}
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
|
||||
&len);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
if (ret == -2)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_get_ecdh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen)
|
||||
{
|
||||
size_t len = UINT_MAX;
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
|
||||
&len);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_get_params_strict(ctx, params);
|
||||
|
||||
switch (ret) {
|
||||
case -2:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
break;
|
||||
case 1:
|
||||
if (len <= INT_MAX)
|
||||
*plen = (int)len;
|
||||
else
|
||||
ret = -1;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_set0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len)
|
||||
{
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM,
|
||||
/*
|
||||
* Cast away the const. This is read
|
||||
* only so should be safe
|
||||
*/
|
||||
(void *)ukm,
|
||||
(size_t)len);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_set_params_strict(ctx, params);
|
||||
|
||||
switch (ret) {
|
||||
case -2:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
break;
|
||||
case 1:
|
||||
OPENSSL_free(ukm);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
int EVP_PKEY_CTX_get0_ecdh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm)
|
||||
{
|
||||
size_t ukmlen;
|
||||
int ret;
|
||||
OSSL_PARAM params[2], *p = params;
|
||||
|
||||
ret = evp_pkey_ctx_getset_ecdh_param_checks(ctx);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM,
|
||||
(void **)pukm, 0);
|
||||
*p++ = OSSL_PARAM_construct_end();
|
||||
|
||||
ret = evp_pkey_ctx_get_params_strict(ctx, params);
|
||||
|
||||
switch (ret) {
|
||||
case -2:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
|
||||
break;
|
||||
case 1:
|
||||
ret = -1;
|
||||
ukmlen = params[0].return_size;
|
||||
if (ukmlen <= INT_MAX)
|
||||
ret = (int)ukmlen;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
* ASN1_OBJECT (which would be converted to text internally)?
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid)
|
||||
{
|
||||
int keytype = nid == EVP_PKEY_SM2 ? EVP_PKEY_SM2 : EVP_PKEY_EC;
|
||||
|
||||
return EVP_PKEY_CTX_ctrl(ctx, keytype, EVP_PKEY_OP_TYPE_GEN,
|
||||
EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID,
|
||||
nid, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
|
||||
* simply because that's easier.
|
||||
*/
|
||||
int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc)
|
||||
{
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN,
|
||||
EVP_PKEY_CTRL_EC_PARAM_ENC, param_enc, NULL);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/ec.h>
|
||||
#include "crypto/ec.h"
|
||||
#include "internal/nelem.h"
|
||||
|
||||
typedef struct ec_name2nid_st {
|
||||
const char *name;
|
||||
int nid;
|
||||
} EC_NAME2NID;
|
||||
|
||||
static const EC_NAME2NID curve_list[] = {
|
||||
/* prime field curves */
|
||||
/* secg curves */
|
||||
{"secp112r1", NID_secp112r1 },
|
||||
{"secp112r2", NID_secp112r2 },
|
||||
{"secp128r1", NID_secp128r1 },
|
||||
{"secp128r2", NID_secp128r2 },
|
||||
{"secp160k1", NID_secp160k1 },
|
||||
{"secp160r1", NID_secp160r1 },
|
||||
{"secp160r2", NID_secp160r2 },
|
||||
{"secp192k1", NID_secp192k1 },
|
||||
{"secp224k1", NID_secp224k1 },
|
||||
{"secp224r1", NID_secp224r1 },
|
||||
{"secp256k1", NID_secp256k1 },
|
||||
{"secp384r1", NID_secp384r1 },
|
||||
{"secp521r1", NID_secp521r1 },
|
||||
/* X9.62 curves */
|
||||
{"prime192v1", NID_X9_62_prime192v1 },
|
||||
{"prime192v2", NID_X9_62_prime192v2 },
|
||||
{"prime192v3", NID_X9_62_prime192v3 },
|
||||
{"prime239v1", NID_X9_62_prime239v1 },
|
||||
{"prime239v2", NID_X9_62_prime239v2 },
|
||||
{"prime239v3", NID_X9_62_prime239v3 },
|
||||
{"prime256v1", NID_X9_62_prime256v1 },
|
||||
/* characteristic two field curves */
|
||||
/* NIST/SECG curves */
|
||||
{"sect113r1", NID_sect113r1 },
|
||||
{"sect113r2", NID_sect113r2 },
|
||||
{"sect131r1", NID_sect131r1 },
|
||||
{"sect131r2", NID_sect131r2 },
|
||||
{"sect163k1", NID_sect163k1 },
|
||||
{"sect163r1", NID_sect163r1 },
|
||||
{"sect163r2", NID_sect163r2 },
|
||||
{"sect193r1", NID_sect193r1 },
|
||||
{"sect193r2", NID_sect193r2 },
|
||||
{"sect233k1", NID_sect233k1 },
|
||||
{"sect233r1", NID_sect233r1 },
|
||||
{"sect239k1", NID_sect239k1 },
|
||||
{"sect283k1", NID_sect283k1 },
|
||||
{"sect283r1", NID_sect283r1 },
|
||||
{"sect409k1", NID_sect409k1 },
|
||||
{"sect409r1", NID_sect409r1 },
|
||||
{"sect571k1", NID_sect571k1 },
|
||||
{"sect571r1", NID_sect571r1 },
|
||||
/* X9.62 curves */
|
||||
{"c2pnb163v1", NID_X9_62_c2pnb163v1 },
|
||||
{"c2pnb163v2", NID_X9_62_c2pnb163v2 },
|
||||
{"c2pnb163v3", NID_X9_62_c2pnb163v3 },
|
||||
{"c2pnb176v1", NID_X9_62_c2pnb176v1 },
|
||||
{"c2tnb191v1", NID_X9_62_c2tnb191v1 },
|
||||
{"c2tnb191v2", NID_X9_62_c2tnb191v2 },
|
||||
{"c2tnb191v3", NID_X9_62_c2tnb191v3 },
|
||||
{"c2pnb208w1", NID_X9_62_c2pnb208w1 },
|
||||
{"c2tnb239v1", NID_X9_62_c2tnb239v1 },
|
||||
{"c2tnb239v2", NID_X9_62_c2tnb239v2 },
|
||||
{"c2tnb239v3", NID_X9_62_c2tnb239v3 },
|
||||
{"c2pnb272w1", NID_X9_62_c2pnb272w1 },
|
||||
{"c2pnb304w1", NID_X9_62_c2pnb304w1 },
|
||||
{"c2tnb359v1", NID_X9_62_c2tnb359v1 },
|
||||
{"c2pnb368w1", NID_X9_62_c2pnb368w1 },
|
||||
{"c2tnb431r1", NID_X9_62_c2tnb431r1 },
|
||||
/*
|
||||
* the WAP/WTLS curves [unlike SECG, spec has its own OIDs for curves
|
||||
* from X9.62]
|
||||
*/
|
||||
{"wap-wsg-idm-ecid-wtls1", NID_wap_wsg_idm_ecid_wtls1 },
|
||||
{"wap-wsg-idm-ecid-wtls3", NID_wap_wsg_idm_ecid_wtls3 },
|
||||
{"wap-wsg-idm-ecid-wtls4", NID_wap_wsg_idm_ecid_wtls4 },
|
||||
{"wap-wsg-idm-ecid-wtls5", NID_wap_wsg_idm_ecid_wtls5 },
|
||||
{"wap-wsg-idm-ecid-wtls6", NID_wap_wsg_idm_ecid_wtls6 },
|
||||
{"wap-wsg-idm-ecid-wtls7", NID_wap_wsg_idm_ecid_wtls7 },
|
||||
{"wap-wsg-idm-ecid-wtls8", NID_wap_wsg_idm_ecid_wtls8 },
|
||||
{"wap-wsg-idm-ecid-wtls9", NID_wap_wsg_idm_ecid_wtls9 },
|
||||
{"wap-wsg-idm-ecid-wtls10", NID_wap_wsg_idm_ecid_wtls10 },
|
||||
{"wap-wsg-idm-ecid-wtls11", NID_wap_wsg_idm_ecid_wtls11 },
|
||||
{"wap-wsg-idm-ecid-wtls12", NID_wap_wsg_idm_ecid_wtls12 },
|
||||
/* IPSec curves */
|
||||
{"Oakley-EC2N-3", NID_ipsec3 },
|
||||
{"Oakley-EC2N-4", NID_ipsec4 },
|
||||
/* brainpool curves */
|
||||
{"brainpoolP160r1", NID_brainpoolP160r1 },
|
||||
{"brainpoolP160t1", NID_brainpoolP160t1 },
|
||||
{"brainpoolP192r1", NID_brainpoolP192r1 },
|
||||
{"brainpoolP192t1", NID_brainpoolP192t1 },
|
||||
{"brainpoolP224r1", NID_brainpoolP224r1 },
|
||||
{"brainpoolP224t1", NID_brainpoolP224t1 },
|
||||
{"brainpoolP256r1", NID_brainpoolP256r1 },
|
||||
{"brainpoolP256t1", NID_brainpoolP256t1 },
|
||||
{"brainpoolP320r1", NID_brainpoolP320r1 },
|
||||
{"brainpoolP320t1", NID_brainpoolP320t1 },
|
||||
{"brainpoolP384r1", NID_brainpoolP384r1 },
|
||||
{"brainpoolP384t1", NID_brainpoolP384t1 },
|
||||
{"brainpoolP512r1", NID_brainpoolP512r1 },
|
||||
{"brainpoolP512t1", NID_brainpoolP512t1 },
|
||||
/* SM2 curve */
|
||||
{"SM2", NID_sm2 },
|
||||
};
|
||||
|
||||
const char *OSSL_EC_curve_nid2name(int nid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (nid <= 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(curve_list); i++) {
|
||||
if (curve_list[i].nid == nid)
|
||||
return curve_list[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ossl_ec_curve_name2nid(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
int nid;
|
||||
|
||||
if (name != NULL) {
|
||||
if ((nid = ossl_ec_curve_nist2nid_int(name)) != NID_undef)
|
||||
return nid;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(curve_list); i++) {
|
||||
if (OPENSSL_strcasecmp(curve_list[i].name, name) == 0)
|
||||
return curve_list[i].nid;
|
||||
}
|
||||
}
|
||||
|
||||
return NID_undef;
|
||||
}
|
||||
|
||||
/* Functions to translate between common NIST curve names and NIDs */
|
||||
|
||||
static const EC_NAME2NID nist_curves[] = {
|
||||
{"B-163", NID_sect163r2},
|
||||
{"B-233", NID_sect233r1},
|
||||
{"B-283", NID_sect283r1},
|
||||
{"B-409", NID_sect409r1},
|
||||
{"B-571", NID_sect571r1},
|
||||
{"K-163", NID_sect163k1},
|
||||
{"K-233", NID_sect233k1},
|
||||
{"K-283", NID_sect283k1},
|
||||
{"K-409", NID_sect409k1},
|
||||
{"K-571", NID_sect571k1},
|
||||
{"P-192", NID_X9_62_prime192v1},
|
||||
{"P-224", NID_secp224r1},
|
||||
{"P-256", NID_X9_62_prime256v1},
|
||||
{"P-384", NID_secp384r1},
|
||||
{"P-521", NID_secp521r1}
|
||||
};
|
||||
|
||||
const char *ossl_ec_curve_nid2nist_int(int nid)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < OSSL_NELEM(nist_curves); i++) {
|
||||
if (nist_curves[i].nid == nid)
|
||||
return nist_curves[i].name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ossl_ec_curve_nist2nid_int(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < OSSL_NELEM(nist_curves); i++) {
|
||||
if (strcmp(nist_curves[i].name, name) == 0)
|
||||
return nist_curves[i].nid;
|
||||
}
|
||||
return NID_undef;
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static unsigned char conv_ascii2bin(unsigned char a,
|
||||
const unsigned char *table);
|
||||
static int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
|
||||
const unsigned char *f, int dlen);
|
||||
static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
|
||||
const unsigned char *f, int n, int eof);
|
||||
|
||||
#ifndef CHARSET_EBCDIC
|
||||
# define conv_bin2ascii(a, table) ((table)[(a)&0x3f])
|
||||
#else
|
||||
/*
|
||||
* We assume that PEM encoded files are EBCDIC files (i.e., printable text
|
||||
* files). Convert them here while decoding. When encoding, output is EBCDIC
|
||||
* (text) format again. (No need for conversion in the conv_bin2ascii macro,
|
||||
* as the underlying textstring data_bin2ascii[] is already EBCDIC)
|
||||
*/
|
||||
# define conv_bin2ascii(a, table) ((table)[(a)&0x3f])
|
||||
#endif
|
||||
|
||||
/*-
|
||||
* 64 char lines
|
||||
* pad input with 0
|
||||
* left over chars are set to =
|
||||
* 1 byte => xx==
|
||||
* 2 bytes => xxx=
|
||||
* 3 bytes => xxxx
|
||||
*/
|
||||
#define BIN_PER_LINE (64/4*3)
|
||||
#define CHUNKS_PER_LINE (64/4)
|
||||
#define CHAR_PER_LINE (64+1)
|
||||
|
||||
static const unsigned char data_bin2ascii[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/* SRP uses a different base64 alphabet */
|
||||
static const unsigned char srpdata_bin2ascii[65] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
|
||||
|
||||
|
||||
/*-
|
||||
* 0xF0 is a EOLN
|
||||
* 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
|
||||
* 0xF2 is EOF
|
||||
* 0xE0 is ignore at start of line.
|
||||
* 0xFF is error
|
||||
*/
|
||||
|
||||
#define B64_EOLN 0xF0
|
||||
#define B64_CR 0xF1
|
||||
#define B64_EOF 0xF2
|
||||
#define B64_WS 0xE0
|
||||
#define B64_ERROR 0xFF
|
||||
#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
|
||||
#define B64_BASE64(a) (!B64_NOT_BASE64(a))
|
||||
|
||||
static const unsigned char data_ascii2bin[128] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
|
||||
0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
static const unsigned char srpdata_ascii2bin[128] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x3E, 0x3F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
||||
0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
|
||||
0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
|
||||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
|
||||
0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
#ifndef CHARSET_EBCDIC
|
||||
static unsigned char conv_ascii2bin(unsigned char a, const unsigned char *table)
|
||||
{
|
||||
if (a & 0x80)
|
||||
return B64_ERROR;
|
||||
return table[a];
|
||||
}
|
||||
#else
|
||||
static unsigned char conv_ascii2bin(unsigned char a, const unsigned char *table)
|
||||
{
|
||||
a = os_toascii[a];
|
||||
if (a & 0x80)
|
||||
return B64_ERROR;
|
||||
return table[a];
|
||||
}
|
||||
#endif
|
||||
|
||||
EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
|
||||
{
|
||||
return OPENSSL_zalloc(sizeof(EVP_ENCODE_CTX));
|
||||
}
|
||||
|
||||
void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
|
||||
{
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
int EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX *dctx, const EVP_ENCODE_CTX *sctx)
|
||||
{
|
||||
memcpy(dctx, sctx, sizeof(EVP_ENCODE_CTX));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx)
|
||||
{
|
||||
return ctx->num;
|
||||
}
|
||||
|
||||
void evp_encode_ctx_set_flags(EVP_ENCODE_CTX *ctx, unsigned int flags)
|
||||
{
|
||||
ctx->flags = flags;
|
||||
}
|
||||
|
||||
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
|
||||
{
|
||||
ctx->length = 48;
|
||||
ctx->num = 0;
|
||||
ctx->line_num = 0;
|
||||
ctx->flags = 0;
|
||||
}
|
||||
|
||||
int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
|
||||
const unsigned char *in, int inl)
|
||||
{
|
||||
int i, j;
|
||||
size_t total = 0;
|
||||
|
||||
*outl = 0;
|
||||
if (inl <= 0)
|
||||
return 0;
|
||||
OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
|
||||
if (ctx->length - ctx->num > inl) {
|
||||
memcpy(&(ctx->enc_data[ctx->num]), in, inl);
|
||||
ctx->num += inl;
|
||||
return 1;
|
||||
}
|
||||
if (ctx->num != 0) {
|
||||
i = ctx->length - ctx->num;
|
||||
memcpy(&(ctx->enc_data[ctx->num]), in, i);
|
||||
in += i;
|
||||
inl -= i;
|
||||
j = evp_encodeblock_int(ctx, out, ctx->enc_data, ctx->length);
|
||||
ctx->num = 0;
|
||||
out += j;
|
||||
total = j;
|
||||
if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) {
|
||||
*(out++) = '\n';
|
||||
total++;
|
||||
}
|
||||
*out = '\0';
|
||||
}
|
||||
while (inl >= ctx->length && total <= INT_MAX) {
|
||||
j = evp_encodeblock_int(ctx, out, in, ctx->length);
|
||||
in += ctx->length;
|
||||
inl -= ctx->length;
|
||||
out += j;
|
||||
total += j;
|
||||
if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) {
|
||||
*(out++) = '\n';
|
||||
total++;
|
||||
}
|
||||
*out = '\0';
|
||||
}
|
||||
if (total > INT_MAX) {
|
||||
/* Too much output data! */
|
||||
*outl = 0;
|
||||
return 0;
|
||||
}
|
||||
if (inl != 0)
|
||||
memcpy(&(ctx->enc_data[0]), in, inl);
|
||||
ctx->num = inl;
|
||||
*outl = total;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (ctx->num != 0) {
|
||||
ret = evp_encodeblock_int(ctx, out, ctx->enc_data, ctx->num);
|
||||
if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)
|
||||
out[ret++] = '\n';
|
||||
out[ret] = '\0';
|
||||
ctx->num = 0;
|
||||
}
|
||||
*outl = ret;
|
||||
}
|
||||
|
||||
static int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
|
||||
const unsigned char *f, int dlen)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned long l;
|
||||
const unsigned char *table;
|
||||
|
||||
if (ctx != NULL && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
|
||||
table = srpdata_bin2ascii;
|
||||
else
|
||||
table = data_bin2ascii;
|
||||
|
||||
for (i = dlen; i > 0; i -= 3) {
|
||||
if (i >= 3) {
|
||||
l = (((unsigned long)f[0]) << 16L) |
|
||||
(((unsigned long)f[1]) << 8L) | f[2];
|
||||
*(t++) = conv_bin2ascii(l >> 18L, table);
|
||||
*(t++) = conv_bin2ascii(l >> 12L, table);
|
||||
*(t++) = conv_bin2ascii(l >> 6L, table);
|
||||
*(t++) = conv_bin2ascii(l, table);
|
||||
} else {
|
||||
l = ((unsigned long)f[0]) << 16L;
|
||||
if (i == 2)
|
||||
l |= ((unsigned long)f[1] << 8L);
|
||||
|
||||
*(t++) = conv_bin2ascii(l >> 18L, table);
|
||||
*(t++) = conv_bin2ascii(l >> 12L, table);
|
||||
*(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L, table);
|
||||
*(t++) = '=';
|
||||
}
|
||||
ret += 4;
|
||||
f += 3;
|
||||
}
|
||||
|
||||
*t = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
|
||||
{
|
||||
return evp_encodeblock_int(NULL, t, f, dlen);
|
||||
}
|
||||
|
||||
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
|
||||
{
|
||||
/* Only ctx->num and ctx->flags are used during decoding. */
|
||||
ctx->num = 0;
|
||||
ctx->length = 0;
|
||||
ctx->line_num = 0;
|
||||
ctx->flags = 0;
|
||||
}
|
||||
|
||||
/*-
|
||||
* -1 for error
|
||||
* 0 for last line
|
||||
* 1 for full line
|
||||
*
|
||||
* Note: even though EVP_DecodeUpdate attempts to detect and report end of
|
||||
* content, the context doesn't currently remember it and will accept more data
|
||||
* in the next call. Therefore, the caller is responsible for checking and
|
||||
* rejecting a 0 return value in the middle of content.
|
||||
*
|
||||
* Note: even though EVP_DecodeUpdate has historically tried to detect end of
|
||||
* content based on line length, this has never worked properly. Therefore,
|
||||
* we now return 0 when one of the following is true:
|
||||
* - Padding or B64_EOF was detected and the last block is complete.
|
||||
* - Input has zero-length.
|
||||
* -1 is returned if:
|
||||
* - Invalid characters are detected.
|
||||
* - There is extra trailing padding, or data after padding.
|
||||
* - B64_EOF is detected after an incomplete base64 block.
|
||||
*/
|
||||
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
|
||||
const unsigned char *in, int inl)
|
||||
{
|
||||
int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
|
||||
unsigned char *d;
|
||||
const unsigned char *table;
|
||||
|
||||
n = ctx->num;
|
||||
d = ctx->enc_data;
|
||||
|
||||
if (n > 0 && d[n - 1] == '=') {
|
||||
eof++;
|
||||
if (n > 1 && d[n - 2] == '=')
|
||||
eof++;
|
||||
}
|
||||
|
||||
/* Legacy behaviour: an empty input chunk signals end of input. */
|
||||
if (inl == 0) {
|
||||
rv = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
|
||||
table = srpdata_ascii2bin;
|
||||
else
|
||||
table = data_ascii2bin;
|
||||
|
||||
for (i = 0; i < inl; i++) {
|
||||
tmp = *(in++);
|
||||
v = conv_ascii2bin(tmp, table);
|
||||
if (v == B64_ERROR) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (tmp == '=') {
|
||||
eof++;
|
||||
} else if (eof > 0 && B64_BASE64(v)) {
|
||||
/* More data after padding. */
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (eof > 2) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (v == B64_EOF) {
|
||||
seof = 1;
|
||||
goto tail;
|
||||
}
|
||||
|
||||
/* Only save valid base64 characters. */
|
||||
if (B64_BASE64(v)) {
|
||||
if (n >= 64) {
|
||||
/*
|
||||
* We increment n once per loop, and empty the buffer as soon as
|
||||
* we reach 64 characters, so this can only happen if someone's
|
||||
* manually messed with the ctx. Refuse to write any more data.
|
||||
*/
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
|
||||
d[n++] = tmp;
|
||||
}
|
||||
|
||||
if (n == 64) {
|
||||
decoded_len = evp_decodeblock_int(ctx, out, d, n, eof);
|
||||
n = 0;
|
||||
if (decoded_len < 0 || (decoded_len == 0 && eof > 0)) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
ret += decoded_len;
|
||||
out += decoded_len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy behaviour: if the current line is a full base64-block (i.e., has
|
||||
* 0 mod 4 base64 characters), it is processed immediately. We keep this
|
||||
* behaviour as applications may not be calling EVP_DecodeFinal properly.
|
||||
*/
|
||||
tail:
|
||||
if (n > 0) {
|
||||
if ((n & 3) == 0) {
|
||||
decoded_len = evp_decodeblock_int(ctx, out, d, n, eof);
|
||||
n = 0;
|
||||
if (decoded_len < 0 || (decoded_len == 0 && eof > 0)) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
ret += decoded_len;
|
||||
} else if (seof) {
|
||||
/* EOF in the middle of a base64 block. */
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
rv = seof || (n == 0 && eof) ? 0 : 1;
|
||||
end:
|
||||
/* Legacy behaviour. This should probably rather be zeroed on error. */
|
||||
*outl = ret;
|
||||
ctx->num = n;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
|
||||
const unsigned char *f, int n,
|
||||
int eof)
|
||||
{
|
||||
int i, ret = 0, a, b, c, d;
|
||||
unsigned long l;
|
||||
const unsigned char *table;
|
||||
|
||||
if (eof < -1 || eof > 2)
|
||||
return -1;
|
||||
|
||||
if (ctx != NULL && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
|
||||
table = srpdata_ascii2bin;
|
||||
else
|
||||
table = data_ascii2bin;
|
||||
|
||||
/* trim whitespace from the start of the line. */
|
||||
while ((n > 0) && (conv_ascii2bin(*f, table) == B64_WS)) {
|
||||
f++;
|
||||
n--;
|
||||
}
|
||||
|
||||
/*
|
||||
* strip off stuff at the end of the line ascii2bin values B64_WS,
|
||||
* B64_EOLN, B64_EOLN and B64_EOF
|
||||
*/
|
||||
while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1], table))))
|
||||
n--;
|
||||
|
||||
if (n % 4 != 0)
|
||||
return -1;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* all 4-byte blocks except the last one do not have padding. */
|
||||
for (i = 0; i < n - 4; i += 4) {
|
||||
a = conv_ascii2bin(*(f++), table);
|
||||
b = conv_ascii2bin(*(f++), table);
|
||||
c = conv_ascii2bin(*(f++), table);
|
||||
d = conv_ascii2bin(*(f++), table);
|
||||
if ((a | b | c | d) & 0x80)
|
||||
return -1;
|
||||
l = ((((unsigned long)a) << 18L) |
|
||||
(((unsigned long)b) << 12L) |
|
||||
(((unsigned long)c) << 6L) | (((unsigned long)d)));
|
||||
*(t++) = (unsigned char)(l >> 16L) & 0xff;
|
||||
*(t++) = (unsigned char)(l >> 8L) & 0xff;
|
||||
*(t++) = (unsigned char)(l) & 0xff;
|
||||
ret += 3;
|
||||
}
|
||||
|
||||
/* process the last block that may have padding. */
|
||||
a = conv_ascii2bin(*(f++), table);
|
||||
b = conv_ascii2bin(*(f++), table);
|
||||
c = conv_ascii2bin(*(f++), table);
|
||||
d = conv_ascii2bin(*(f++), table);
|
||||
if ((a | b | c | d) & 0x80)
|
||||
return -1;
|
||||
l = ((((unsigned long)a) << 18L) |
|
||||
(((unsigned long)b) << 12L) |
|
||||
(((unsigned long)c) << 6L) | (((unsigned long)d)));
|
||||
|
||||
if (eof == -1)
|
||||
eof = (f[2] == '=') + (f[3] == '=');
|
||||
|
||||
switch (eof) {
|
||||
case 2:
|
||||
*(t++) = (unsigned char)(l >> 16L) & 0xff;
|
||||
break;
|
||||
case 1:
|
||||
*(t++) = (unsigned char)(l >> 16L) & 0xff;
|
||||
*(t++) = (unsigned char)(l >> 8L) & 0xff;
|
||||
break;
|
||||
case 0:
|
||||
*(t++) = (unsigned char)(l >> 16L) & 0xff;
|
||||
*(t++) = (unsigned char)(l >> 8L) & 0xff;
|
||||
*(t++) = (unsigned char)(l) & 0xff;
|
||||
break;
|
||||
}
|
||||
ret += 3 - eof;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
|
||||
{
|
||||
return evp_decodeblock_int(NULL, t, f, n, 0);
|
||||
}
|
||||
|
||||
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
|
||||
{
|
||||
int i;
|
||||
|
||||
*outl = 0;
|
||||
if (ctx->num != 0) {
|
||||
i = evp_decodeblock_int(ctx, out, ctx->enc_data, ctx->num, -1);
|
||||
if (i < 0)
|
||||
return -1;
|
||||
ctx->num = 0;
|
||||
*outl = i;
|
||||
return 1;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/trace.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
/* Algorithm configuration module. */
|
||||
|
||||
static int alg_module_init(CONF_IMODULE *md, const CONF *cnf)
|
||||
{
|
||||
int i;
|
||||
const char *oid_section;
|
||||
STACK_OF(CONF_VALUE) *sktmp;
|
||||
CONF_VALUE *oval;
|
||||
|
||||
OSSL_TRACE2(CONF, "Loading EVP module: name %s, value %s\n",
|
||||
CONF_imodule_get_name(md), CONF_imodule_get_value(md));
|
||||
|
||||
oid_section = CONF_imodule_get_value(md);
|
||||
if ((sktmp = NCONF_get_section(cnf, oid_section)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_ERROR_LOADING_SECTION);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
|
||||
oval = sk_CONF_VALUE_value(sktmp, i);
|
||||
if (strcmp(oval->name, "fips_mode") == 0) {
|
||||
int m;
|
||||
|
||||
/* Detailed error already reported. */
|
||||
if (!X509V3_get_value_bool(oval, &m))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* fips_mode is deprecated and should not be used in new
|
||||
* configurations.
|
||||
*/
|
||||
if (!evp_default_properties_enable_fips_int(
|
||||
NCONF_get0_libctx((CONF *)cnf), m > 0, 0)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else if (strcmp(oval->name, "default_properties") == 0) {
|
||||
if (!evp_set_default_properties_int(NCONF_get0_libctx((CONF *)cnf),
|
||||
oval->value, 0, 0)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION,
|
||||
"name=%s, value=%s", oval->name, oval->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_add_alg_module(void)
|
||||
{
|
||||
OSSL_TRACE(CONF, "Adding config module 'alg_section'\n");
|
||||
CONF_module_add("alg_section", alg_module_init, 0);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evperr.h>
|
||||
#include "crypto/evperr.h"
|
||||
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
|
||||
static const ERR_STRING_DATA EVP_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_AES_KEY_SETUP_FAILED),
|
||||
"aes key setup failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ARIA_KEY_SETUP_FAILED),
|
||||
"aria key setup failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BAD_ALGORITHM_NAME), "bad algorithm name"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BAD_DECRYPT), "bad decrypt"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BAD_KEY_LENGTH), "bad key length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BUFFER_TOO_SMALL), "buffer too small"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CACHE_CONSTANTS_FAILED),
|
||||
"cache constants failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CAMELLIA_KEY_SETUP_FAILED),
|
||||
"camellia key setup failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CANNOT_GET_PARAMETERS),
|
||||
"cannot get parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CANNOT_SET_PARAMETERS),
|
||||
"cannot set parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CIPHER_NOT_GCM_MODE),
|
||||
"cipher not gcm mode"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CIPHER_PARAMETER_ERROR),
|
||||
"cipher parameter error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COMMAND_NOT_SUPPORTED),
|
||||
"command not supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CONFLICTING_ALGORITHM_NAME),
|
||||
"conflicting algorithm name"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COPY_ERROR), "copy error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CTRL_NOT_IMPLEMENTED),
|
||||
"ctrl not implemented"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED),
|
||||
"ctrl operation not implemented"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH),
|
||||
"data not multiple of block length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "decode error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DEFAULT_QUERY_PARSE_ERROR),
|
||||
"default query parse error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES),
|
||||
"different key types"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS),
|
||||
"different parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ERROR_LOADING_SECTION),
|
||||
"error loading section"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_HMAC_KEY),
|
||||
"expecting an hmac key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY),
|
||||
"expecting an rsa key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DH_KEY), "expecting a dh key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DSA_KEY),
|
||||
"expecting a dsa key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_ECX_KEY),
|
||||
"expecting an ecx key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_EC_KEY), "expecting an ec key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_POLY1305_KEY),
|
||||
"expecting a poly1305 key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_SIPHASH_KEY),
|
||||
"expecting a siphash key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_FINAL_ERROR), "final error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GENERATE_ERROR), "generate error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GETTING_ALGORITHMIDENTIFIER_NOT_SUPPORTED),
|
||||
"getting AlgorithmIdentifier not supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_GET_RAW_KEY_FAILED), "get raw key failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ILLEGAL_SCRYPT_PARAMETERS),
|
||||
"illegal scrypt parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS),
|
||||
"inaccessible domain parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INACCESSIBLE_KEY), "inaccessible key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INITIALIZATION_ERROR),
|
||||
"initialization error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INPUT_NOT_INITIALIZED),
|
||||
"input not initialized"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_CUSTOM_LENGTH),
|
||||
"invalid custom length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_DIGEST), "invalid digest"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_IV_LENGTH), "invalid iv length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEY), "invalid key"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEY_LENGTH), "invalid key length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_LENGTH), "invalid length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_NULL_ALGORITHM),
|
||||
"invalid null algorithm"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_OPERATION), "invalid operation"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PROVIDER_FUNCTIONS),
|
||||
"invalid provider functions"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH),
|
||||
"invalid salt length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SECRET_LENGTH),
|
||||
"invalid secret length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SEED_LENGTH),
|
||||
"invalid seed length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_VALUE), "invalid value"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYMGMT_EXPORT_FAILURE),
|
||||
"keymgmt export failure"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEY_SETUP_FAILED), "key setup failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_LOCKING_NOT_SUPPORTED),
|
||||
"locking not supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MEMORY_LIMIT_EXCEEDED),
|
||||
"memory limit exceeded"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MESSAGE_DIGEST_IS_NULL),
|
||||
"message digest is null"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_METHOD_NOT_SUPPORTED),
|
||||
"method not supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MISSING_PARAMETERS), "missing parameters"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NOT_ABLE_TO_COPY_CTX),
|
||||
"not able to copy ctx"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NOT_XOF_OR_INVALID_LENGTH),
|
||||
"not XOF or invalid length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_CIPHER_SET), "no cipher set"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "no default digest"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DIGEST_SET), "no digest set"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_IMPORT_FUNCTION), "no import function"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEYMGMT_AVAILABLE),
|
||||
"no keymgmt available"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEYMGMT_PRESENT), "no keymgmt present"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEY_SET), "no key set"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_OPERATION_SET), "no operation set"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NULL_MAC_PKEY_CTX), "null mac pkey ctx"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ONLY_ONESHOT_SUPPORTED),
|
||||
"only oneshot supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_INITIALIZED),
|
||||
"operation not initialized"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
|
||||
"operation not supported for this keytype"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_SIGNATURE_TYPE),
|
||||
"operation not supported for this signature type"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OUTPUT_WOULD_OVERFLOW),
|
||||
"output would overflow"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PARAMETER_TOO_LARGE),
|
||||
"parameter too large"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PARTIALLY_OVERLAPPING),
|
||||
"partially overlapping buffers"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PBKDF2_ERROR), "pbkdf2 error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PIPELINE_NOT_SUPPORTED),
|
||||
"pipeline not supported"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED),
|
||||
"pkey application asn1 method already registered"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PRIVATE_KEY_DECODE_ERROR),
|
||||
"private key decode error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PRIVATE_KEY_ENCODE_ERROR),
|
||||
"private key encode error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PUBLIC_KEY_NOT_RSA), "public key not rsa"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SETTING_XOF_FAILED), "setting xof failed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SET_DEFAULT_PROPERTY_FAILURE),
|
||||
"set default property failure"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE),
|
||||
"signature type and key type incompatible"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_PIPES), "too many pipes"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_RECORDS), "too many records"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_ENABLE_LOCKING),
|
||||
"unable to enable locking"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE),
|
||||
"unable to get maximum request size"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH),
|
||||
"unable to get random strength"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_LOCK_CONTEXT),
|
||||
"unable to lock context"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_SET_CALLBACKS),
|
||||
"unable to set callbacks"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_BITS), "unknown bits"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_CIPHER), "unknown cipher"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_DIGEST), "unknown digest"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_KEY_TYPE), "unknown key type"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_MAX_SIZE), "unknown max size"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_OPTION), "unknown option"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_PBE_ALGORITHM),
|
||||
"unknown pbe algorithm"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_SECURITY_BITS),
|
||||
"unknown security bits"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM),
|
||||
"unsupported algorithm"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_CIPHER), "unsupported cipher"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_KEYLENGTH),
|
||||
"unsupported keylength"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION),
|
||||
"unsupported key derivation function"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_KEY_SIZE),
|
||||
"unsupported key size"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_KEY_TYPE),
|
||||
"unsupported key type"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS),
|
||||
"unsupported number of rounds"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_PRF), "unsupported prf"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM),
|
||||
"unsupported private key algorithm"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_SALT_TYPE),
|
||||
"unsupported salt type"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UPDATE_ERROR), "update error"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_WRAP_MODE_NOT_ALLOWED),
|
||||
"wrap mode not allowed"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_WRONG_FINAL_BLOCK_LENGTH),
|
||||
"wrong final block length"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE),
|
||||
"xts data unit is too large"},
|
||||
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_XTS_DUPLICATED_KEYS),
|
||||
"xts duplicated keys"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int ossl_err_load_EVP_strings(void)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
if (ERR_reason_error_string(EVP_str_reasons[0].error) == NULL)
|
||||
ERR_load_strings_const(EVP_str_reasons);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <openssl/types.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/thread_once.h"
|
||||
#include "internal/property.h"
|
||||
#include "internal/core.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/namemap.h"
|
||||
#include "crypto/decoder.h"
|
||||
#include "crypto/evp.h" /* evp_local.h needs it */
|
||||
#include "evp_local.h"
|
||||
|
||||
#define NAME_SEPARATOR ':'
|
||||
|
||||
/* Data to be passed through ossl_method_construct() */
|
||||
struct evp_method_data_st {
|
||||
OSSL_LIB_CTX *libctx;
|
||||
int operation_id; /* For get_evp_method_from_store() */
|
||||
int name_id; /* For get_evp_method_from_store() */
|
||||
const char *names; /* For get_evp_method_from_store() */
|
||||
const char *propquery; /* For get_evp_method_from_store() */
|
||||
|
||||
OSSL_METHOD_STORE *tmp_store; /* For get_tmp_evp_method_store() */
|
||||
|
||||
unsigned int flag_construct_error_occurred : 1;
|
||||
|
||||
void *(*method_from_algorithm)(int name_id, const OSSL_ALGORITHM *,
|
||||
OSSL_PROVIDER *);
|
||||
int (*refcnt_up_method)(void *method);
|
||||
void (*destruct_method)(void *method);
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic routines to fetch / create EVP methods with ossl_method_construct()
|
||||
*/
|
||||
static void *get_tmp_evp_method_store(void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
|
||||
if (methdata->tmp_store == NULL) {
|
||||
methdata->tmp_store = ossl_method_store_new(methdata->libctx);
|
||||
OSSL_TRACE1(QUERY, "Allocating a new tmp_store %p\n", (void *)methdata->tmp_store);
|
||||
} else {
|
||||
OSSL_TRACE1(QUERY, "Using the existing tmp_store %p\n", (void *)methdata->tmp_store);
|
||||
}
|
||||
return methdata->tmp_store;
|
||||
}
|
||||
|
||||
static void dealloc_tmp_evp_method_store(void *store)
|
||||
{
|
||||
OSSL_TRACE1(QUERY, "Deallocating the tmp_store %p\n", store);
|
||||
if (store != NULL)
|
||||
ossl_method_store_free(store);
|
||||
}
|
||||
|
||||
static OSSL_METHOD_STORE *get_evp_method_store(OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_EVP_METHOD_STORE_INDEX);
|
||||
}
|
||||
|
||||
static int reserve_evp_method_store(void *store, void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
|
||||
if (store == NULL
|
||||
&& (store = get_evp_method_store(methdata->libctx)) == NULL)
|
||||
return 0;
|
||||
|
||||
return ossl_method_lock_store(store);
|
||||
}
|
||||
|
||||
static int unreserve_evp_method_store(void *store, void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
|
||||
if (store == NULL
|
||||
&& (store = get_evp_method_store(methdata->libctx)) == NULL)
|
||||
return 0;
|
||||
|
||||
return ossl_method_unlock_store(store);
|
||||
}
|
||||
|
||||
/*
|
||||
* To identify the method in the EVP method store, we mix the name identity
|
||||
* with the operation identity, under the assumption that we don't have more
|
||||
* than 2^23 names or more than 2^8 operation types.
|
||||
*
|
||||
* The resulting identity is a 31-bit integer, composed like this:
|
||||
*
|
||||
* +---------23 bits--------+-8 bits-+
|
||||
* | name identity | op id |
|
||||
* +------------------------+--------+
|
||||
*
|
||||
* We limit this composite number to 31 bits, thus leaving the top uint32_t
|
||||
* bit always zero, to avoid negative sign extension when downshifting after
|
||||
* this number happens to be passed to an int (which happens as soon as it's
|
||||
* passed to ossl_method_store_cache_set(), and it's in that form that it
|
||||
* gets passed along to filter_on_operation_id(), defined further down.
|
||||
*/
|
||||
#define METHOD_ID_OPERATION_MASK 0x000000FF
|
||||
#define METHOD_ID_OPERATION_MAX ((1 << 8) - 1)
|
||||
#define METHOD_ID_NAME_MASK 0x7FFFFF00
|
||||
#define METHOD_ID_NAME_OFFSET 8
|
||||
#define METHOD_ID_NAME_MAX ((1 << 23) - 1)
|
||||
static uint32_t evp_method_id(int name_id, unsigned int operation_id)
|
||||
{
|
||||
if (!ossl_assert(name_id > 0 && name_id <= METHOD_ID_NAME_MAX)
|
||||
|| !ossl_assert(operation_id > 0
|
||||
&& operation_id <= METHOD_ID_OPERATION_MAX))
|
||||
return 0;
|
||||
return (((name_id << METHOD_ID_NAME_OFFSET) & METHOD_ID_NAME_MASK)
|
||||
| (operation_id & METHOD_ID_OPERATION_MASK));
|
||||
}
|
||||
|
||||
static void *get_evp_method_from_store(void *store, const OSSL_PROVIDER **prov,
|
||||
void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
void *method = NULL;
|
||||
int name_id;
|
||||
uint32_t meth_id;
|
||||
|
||||
/*
|
||||
* get_evp_method_from_store() is only called to try and get the method
|
||||
* that evp_generic_fetch() is asking for, and the operation id as well
|
||||
* as the name or name id are passed via methdata.
|
||||
*/
|
||||
if ((name_id = methdata->name_id) == 0 && methdata->names != NULL) {
|
||||
OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
|
||||
const char *names = methdata->names;
|
||||
const char *q = strchr(names, NAME_SEPARATOR);
|
||||
size_t l = (q == NULL ? strlen(names) : (size_t)(q - names));
|
||||
|
||||
if (namemap == 0)
|
||||
return NULL;
|
||||
name_id = ossl_namemap_name2num_n(namemap, names, l);
|
||||
}
|
||||
|
||||
if (name_id == 0
|
||||
|| (meth_id = evp_method_id(name_id, methdata->operation_id)) == 0)
|
||||
return NULL;
|
||||
|
||||
if (store == NULL
|
||||
&& (store = get_evp_method_store(methdata->libctx)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!ossl_method_store_fetch(store, meth_id, methdata->propquery, prov,
|
||||
&method))
|
||||
return NULL;
|
||||
return method;
|
||||
}
|
||||
|
||||
static int put_evp_method_in_store(void *store, void *method,
|
||||
const OSSL_PROVIDER *prov,
|
||||
const char *names, const char *propdef,
|
||||
void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
OSSL_NAMEMAP *namemap;
|
||||
int name_id;
|
||||
uint32_t meth_id;
|
||||
size_t l = 0;
|
||||
|
||||
/*
|
||||
* put_evp_method_in_store() is only called with an EVP method that was
|
||||
* successfully created by construct_method() below, which means that
|
||||
* all the names should already be stored in the namemap with the same
|
||||
* numeric identity, so just use the first to get that identity.
|
||||
*/
|
||||
if (names != NULL) {
|
||||
const char *q = strchr(names, NAME_SEPARATOR);
|
||||
|
||||
l = (q == NULL ? strlen(names) : (size_t)(q - names));
|
||||
}
|
||||
|
||||
if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
|
||||
|| (name_id = ossl_namemap_name2num_n(namemap, names, l)) == 0
|
||||
|| (meth_id = evp_method_id(name_id, methdata->operation_id)) == 0)
|
||||
return 0;
|
||||
|
||||
OSSL_TRACE1(QUERY, "put_evp_method_in_store: original store: %p\n", store);
|
||||
if (store == NULL
|
||||
&& (store = get_evp_method_store(methdata->libctx)) == NULL)
|
||||
return 0;
|
||||
|
||||
OSSL_TRACE5(QUERY,
|
||||
"put_evp_method_in_store: "
|
||||
"store: %p, names: %s, operation_id %d, method_id: %d, properties: %s\n",
|
||||
store, names, methdata->operation_id, meth_id, propdef ? propdef : "<null>");
|
||||
return ossl_method_store_add(store, prov, meth_id, propdef, method,
|
||||
methdata->refcnt_up_method,
|
||||
methdata->destruct_method);
|
||||
}
|
||||
|
||||
/*
|
||||
* The core fetching functionality passes the name of the implementation.
|
||||
* This function is responsible to getting an identity number for it.
|
||||
*/
|
||||
static void *construct_evp_method(const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov, void *data)
|
||||
{
|
||||
/*
|
||||
* This function is only called if get_evp_method_from_store() returned
|
||||
* NULL, so it's safe to say that of all the spots to create a new
|
||||
* namemap entry, this is it. Should the name already exist there, we
|
||||
* know that ossl_namemap_add_name() will return its corresponding
|
||||
* number.
|
||||
*/
|
||||
struct evp_method_data_st *methdata = data;
|
||||
OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
|
||||
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
|
||||
const char *names = algodef->algorithm_names;
|
||||
int name_id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
|
||||
void *method;
|
||||
|
||||
if (name_id == 0)
|
||||
return NULL;
|
||||
|
||||
method = methdata->method_from_algorithm(name_id, algodef, prov);
|
||||
|
||||
/*
|
||||
* Flag to indicate that there was actual construction errors. This
|
||||
* helps inner_evp_generic_fetch() determine what error it should
|
||||
* record on inaccessible algorithms.
|
||||
*/
|
||||
if (method == NULL)
|
||||
methdata->flag_construct_error_occurred = 1;
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
static void destruct_evp_method(void *method, void *data)
|
||||
{
|
||||
struct evp_method_data_st *methdata = data;
|
||||
|
||||
methdata->destruct_method(method);
|
||||
}
|
||||
|
||||
static void *
|
||||
inner_evp_generic_fetch(struct evp_method_data_st *methdata,
|
||||
OSSL_PROVIDER *prov, int operation_id,
|
||||
const char *name, ossl_unused const char *properties,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *))
|
||||
{
|
||||
OSSL_METHOD_STORE *store = get_evp_method_store(methdata->libctx);
|
||||
OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
|
||||
#ifdef FIPS_MODULE
|
||||
/*
|
||||
* The FIPS provider has its own internal library context where only it
|
||||
* is loaded. Consequently, property queries aren't relevant because
|
||||
* there is only one fetchable algorithm and it is assumed that the
|
||||
* FIPS-ness is handled by the using algorithm.
|
||||
*/
|
||||
const char *const propq = "";
|
||||
#else
|
||||
const char *const propq = properties != NULL ? properties : "";
|
||||
#endif /* FIPS_MODULE */
|
||||
uint32_t meth_id = 0;
|
||||
void *method = NULL;
|
||||
int unsupported, name_id;
|
||||
|
||||
if (store == NULL || namemap == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's ever an operation_id == 0 passed, we have an internal
|
||||
* programming error.
|
||||
*/
|
||||
if (!ossl_assert(operation_id > 0)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we haven't received a name id yet, try to get one for the name */
|
||||
name_id = name != NULL ? ossl_namemap_name2num(namemap, name) : 0;
|
||||
|
||||
/*
|
||||
* If we have a name id, calculate a method id with evp_method_id().
|
||||
*
|
||||
* evp_method_id returns 0 if we have too many operations (more than
|
||||
* about 2^8) or too many names (more than about 2^24). In that case,
|
||||
* we can't create any new method.
|
||||
* For all intents and purposes, this is an internal error.
|
||||
*/
|
||||
if (name_id != 0 && (meth_id = evp_method_id(name_id, operation_id)) == 0) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we haven't found the name yet, chances are that the algorithm to
|
||||
* be fetched is unsupported.
|
||||
*/
|
||||
unsupported = name_id == 0;
|
||||
|
||||
if (meth_id == 0
|
||||
|| !ossl_method_store_cache_get(store, prov, meth_id, propq, &method)) {
|
||||
OSSL_METHOD_CONSTRUCT_METHOD mcm = {
|
||||
get_tmp_evp_method_store,
|
||||
reserve_evp_method_store,
|
||||
unreserve_evp_method_store,
|
||||
get_evp_method_from_store,
|
||||
put_evp_method_in_store,
|
||||
construct_evp_method,
|
||||
destruct_evp_method
|
||||
};
|
||||
|
||||
methdata->operation_id = operation_id;
|
||||
methdata->name_id = name_id;
|
||||
methdata->names = name;
|
||||
methdata->propquery = propq;
|
||||
methdata->method_from_algorithm = new_method;
|
||||
methdata->refcnt_up_method = up_ref_method;
|
||||
methdata->destruct_method = free_method;
|
||||
methdata->flag_construct_error_occurred = 0;
|
||||
if ((method = ossl_method_construct(methdata->libctx, operation_id,
|
||||
&prov, 0 /* !force_cache */,
|
||||
&mcm, methdata)) != NULL) {
|
||||
/*
|
||||
* If construction did create a method for us, we know that
|
||||
* there is a correct name_id and meth_id, since those have
|
||||
* already been calculated in get_evp_method_from_store() and
|
||||
* put_evp_method_in_store() above.
|
||||
* Note that there is a corner case here, in which, if a user
|
||||
* passes a name of the form name1:name2:..., then the construction
|
||||
* will create a method against all names, but the lookup will fail
|
||||
* as ossl_namemap_name2num treats the name string as a single name
|
||||
* rather than introducing new features where in the EVP_<obj>_fetch
|
||||
* parses the string and queries for each, return an error.
|
||||
*/
|
||||
if (name_id == 0)
|
||||
name_id = ossl_namemap_name2num(namemap, name);
|
||||
if (name_id == 0) {
|
||||
ERR_raise_data(ERR_LIB_EVP, ERR_R_FETCH_FAILED,
|
||||
"Algorithm %s cannot be found", name);
|
||||
free_method(method);
|
||||
method = NULL;
|
||||
} else {
|
||||
meth_id = evp_method_id(name_id, operation_id);
|
||||
if (meth_id != 0)
|
||||
ossl_method_store_cache_set(store, prov, meth_id, propq,
|
||||
method, up_ref_method, free_method);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we never were in the constructor, the algorithm to be fetched
|
||||
* is unsupported.
|
||||
*/
|
||||
unsupported = !methdata->flag_construct_error_occurred;
|
||||
}
|
||||
|
||||
if ((name_id != 0 || name != NULL) && method == NULL) {
|
||||
int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED;
|
||||
|
||||
if (name == NULL)
|
||||
name = ossl_namemap_num2name(namemap, name_id, 0);
|
||||
ERR_raise_data(ERR_LIB_EVP, code,
|
||||
"%s, Algorithm (%s : %d), Properties (%s)",
|
||||
ossl_lib_ctx_get_descriptor(methdata->libctx),
|
||||
name == NULL ? "<null>" : name, name_id,
|
||||
properties == NULL ? "<null>" : properties);
|
||||
} else {
|
||||
OSSL_TRACE4(QUERY, "%s, Algorithm (%s : %d), Properties (%s)\n",
|
||||
ossl_lib_ctx_get_descriptor(methdata->libctx),
|
||||
name == NULL ? "<null>" : name, name_id,
|
||||
properties == NULL ? "<null>" : properties);
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id,
|
||||
const char *name, const char *properties,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *))
|
||||
{
|
||||
struct evp_method_data_st methdata;
|
||||
void *method;
|
||||
|
||||
methdata.libctx = libctx;
|
||||
methdata.tmp_store = NULL;
|
||||
method = inner_evp_generic_fetch(&methdata, NULL, operation_id,
|
||||
name, properties,
|
||||
new_method, up_ref_method, free_method);
|
||||
dealloc_tmp_evp_method_store(methdata.tmp_store);
|
||||
return method;
|
||||
}
|
||||
|
||||
/*
|
||||
* evp_generic_fetch_from_prov() is special, and only returns methods from
|
||||
* the given provider.
|
||||
* This is meant to be used when one method needs to fetch an associated
|
||||
* method.
|
||||
*/
|
||||
void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
|
||||
const char *name, const char *properties,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *))
|
||||
{
|
||||
struct evp_method_data_st methdata;
|
||||
void *method;
|
||||
|
||||
methdata.libctx = ossl_provider_libctx(prov);
|
||||
methdata.tmp_store = NULL;
|
||||
method = inner_evp_generic_fetch(&methdata, prov, operation_id,
|
||||
name, properties,
|
||||
new_method, up_ref_method, free_method);
|
||||
dealloc_tmp_evp_method_store(methdata.tmp_store);
|
||||
return method;
|
||||
}
|
||||
|
||||
int evp_method_store_cache_flush(OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
OSSL_METHOD_STORE *store = get_evp_method_store(libctx);
|
||||
|
||||
if (store != NULL)
|
||||
return ossl_method_store_cache_flush_all(store);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int evp_method_store_remove_all_provided(const OSSL_PROVIDER *prov)
|
||||
{
|
||||
OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
|
||||
OSSL_METHOD_STORE *store = get_evp_method_store(libctx);
|
||||
|
||||
if (store != NULL)
|
||||
return ossl_method_store_remove_all_provided(store, prov);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int evp_set_parsed_default_properties(OSSL_LIB_CTX *libctx,
|
||||
OSSL_PROPERTY_LIST *def_prop,
|
||||
int loadconfig,
|
||||
int mirrored)
|
||||
{
|
||||
OSSL_METHOD_STORE *store = get_evp_method_store(libctx);
|
||||
OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, loadconfig);
|
||||
|
||||
if (plp != NULL && store != NULL) {
|
||||
int ret;
|
||||
#ifndef FIPS_MODULE
|
||||
char *propstr = NULL;
|
||||
size_t strsz;
|
||||
|
||||
if (mirrored) {
|
||||
if (ossl_global_properties_no_mirrored(libctx))
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* These properties have been explicitly set on this libctx, so
|
||||
* don't allow any mirroring from a parent libctx.
|
||||
*/
|
||||
ossl_global_properties_stop_mirroring(libctx);
|
||||
}
|
||||
|
||||
strsz = ossl_property_list_to_string(libctx, def_prop, NULL, 0);
|
||||
if (strsz > 0)
|
||||
propstr = OPENSSL_malloc(strsz);
|
||||
if (propstr == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (ossl_property_list_to_string(libctx, def_prop, propstr,
|
||||
strsz) == 0) {
|
||||
OPENSSL_free(propstr);
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
ossl_provider_default_props_update(libctx, propstr);
|
||||
OPENSSL_free(propstr);
|
||||
#endif
|
||||
ossl_property_free(*plp);
|
||||
*plp = def_prop;
|
||||
|
||||
ret = ossl_method_store_cache_flush_all(store);
|
||||
#ifndef FIPS_MODULE
|
||||
ossl_decoder_cache_flush(libctx);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evp_set_default_properties_int(OSSL_LIB_CTX *libctx, const char *propq,
|
||||
int loadconfig, int mirrored)
|
||||
{
|
||||
OSSL_PROPERTY_LIST *pl = NULL;
|
||||
|
||||
if (propq != NULL && (pl = ossl_parse_query(libctx, propq, 1)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!evp_set_parsed_default_properties(libctx, pl, loadconfig, mirrored)) {
|
||||
ossl_property_free(pl);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_set_default_properties(OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
return evp_set_default_properties_int(libctx, propq, 1, 0);
|
||||
}
|
||||
|
||||
static int evp_default_properties_merge(OSSL_LIB_CTX *libctx, const char *propq,
|
||||
int loadconfig)
|
||||
{
|
||||
OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, loadconfig);
|
||||
OSSL_PROPERTY_LIST *pl1, *pl2;
|
||||
|
||||
if (propq == NULL)
|
||||
return 1;
|
||||
if (plp == NULL || *plp == NULL)
|
||||
return evp_set_default_properties_int(libctx, propq, 0, 0);
|
||||
if ((pl1 = ossl_parse_query(libctx, propq, 1)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
pl2 = ossl_property_merge(pl1, *plp);
|
||||
ossl_property_free(pl1);
|
||||
if (pl2 == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
|
||||
return 0;
|
||||
}
|
||||
if (!evp_set_parsed_default_properties(libctx, pl2, 0, 0)) {
|
||||
ossl_property_free(pl2);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int evp_default_property_is_enabled(OSSL_LIB_CTX *libctx,
|
||||
const char *prop_name)
|
||||
{
|
||||
OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, 1);
|
||||
|
||||
return plp != NULL && ossl_property_is_enabled(libctx, prop_name, *plp);
|
||||
}
|
||||
|
||||
int EVP_default_properties_is_fips_enabled(OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return evp_default_property_is_enabled(libctx, "fips");
|
||||
}
|
||||
|
||||
int evp_default_properties_enable_fips_int(OSSL_LIB_CTX *libctx, int enable,
|
||||
int loadconfig)
|
||||
{
|
||||
const char *query = (enable != 0) ? "fips=yes" : "-fips";
|
||||
|
||||
return evp_default_properties_merge(libctx, query, loadconfig);
|
||||
}
|
||||
|
||||
int EVP_default_properties_enable_fips(OSSL_LIB_CTX *libctx, int enable)
|
||||
{
|
||||
return evp_default_properties_enable_fips_int(libctx, enable, 1);
|
||||
}
|
||||
|
||||
char *evp_get_global_properties_str(OSSL_LIB_CTX *libctx, int loadconfig)
|
||||
{
|
||||
OSSL_PROPERTY_LIST **plp = ossl_ctx_global_properties(libctx, loadconfig);
|
||||
char *propstr = NULL;
|
||||
size_t sz;
|
||||
|
||||
if (plp == NULL)
|
||||
return OPENSSL_strdup("");
|
||||
|
||||
sz = ossl_property_list_to_string(libctx, *plp, NULL, 0);
|
||||
if (sz == 0) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
propstr = OPENSSL_malloc(sz);
|
||||
if (propstr == NULL)
|
||||
return NULL;
|
||||
if (ossl_property_list_to_string(libctx, *plp, propstr, sz) == 0) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
OPENSSL_free(propstr);
|
||||
return NULL;
|
||||
}
|
||||
return propstr;
|
||||
}
|
||||
|
||||
char *EVP_get1_default_properties(OSSL_LIB_CTX *libctx)
|
||||
{
|
||||
return evp_get_global_properties_str(libctx, ossl_lib_ctx_is_global_default(libctx));
|
||||
}
|
||||
|
||||
struct filter_data_st {
|
||||
int operation_id;
|
||||
void (*user_fn)(void *method, void *arg);
|
||||
void *user_arg;
|
||||
};
|
||||
|
||||
static void filter_on_operation_id(int id, void *method, void *arg)
|
||||
{
|
||||
struct filter_data_st *data = arg;
|
||||
|
||||
if ((id & METHOD_ID_OPERATION_MASK) == data->operation_id)
|
||||
data->user_fn(method, data->user_arg);
|
||||
}
|
||||
|
||||
void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
|
||||
void (*user_fn)(void *method, void *arg),
|
||||
void *user_arg,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *))
|
||||
{
|
||||
struct evp_method_data_st methdata;
|
||||
struct filter_data_st data;
|
||||
|
||||
methdata.libctx = libctx;
|
||||
methdata.tmp_store = NULL;
|
||||
(void)inner_evp_generic_fetch(&methdata, NULL, operation_id, NULL, NULL,
|
||||
new_method, up_ref_method, free_method);
|
||||
|
||||
data.operation_id = operation_id;
|
||||
data.user_fn = user_fn;
|
||||
data.user_arg = user_arg;
|
||||
if (methdata.tmp_store != NULL)
|
||||
ossl_method_store_do_all(methdata.tmp_store, &filter_on_operation_id,
|
||||
&data);
|
||||
ossl_method_store_do_all(get_evp_method_store(libctx),
|
||||
&filter_on_operation_id, &data);
|
||||
dealloc_tmp_evp_method_store(methdata.tmp_store);
|
||||
}
|
||||
|
||||
int evp_is_a(OSSL_PROVIDER *prov, int number,
|
||||
const char *legacy_name, const char *name)
|
||||
{
|
||||
/*
|
||||
* For a |prov| that is NULL, the library context will be NULL
|
||||
*/
|
||||
OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
|
||||
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
|
||||
|
||||
if (prov == NULL)
|
||||
number = ossl_namemap_name2num(namemap, legacy_name);
|
||||
return ossl_namemap_name2num(namemap, name) == number;
|
||||
}
|
||||
|
||||
int evp_names_do_all(OSSL_PROVIDER *prov, int number,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
|
||||
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
|
||||
|
||||
return ossl_namemap_doall_names(namemap, number, fn, data);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ui.h>
|
||||
|
||||
#ifndef BUFSIZ
|
||||
# define BUFSIZ 256
|
||||
#endif
|
||||
|
||||
/* should be init to zeros. */
|
||||
static char prompt_string[80];
|
||||
|
||||
void EVP_set_pw_prompt(const char *prompt)
|
||||
{
|
||||
if (prompt == NULL)
|
||||
prompt_string[0] = '\0';
|
||||
else {
|
||||
strncpy(prompt_string, prompt, 79);
|
||||
prompt_string[79] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char *EVP_get_pw_prompt(void)
|
||||
{
|
||||
if (prompt_string[0] == '\0')
|
||||
return NULL;
|
||||
else
|
||||
return prompt_string;
|
||||
}
|
||||
|
||||
/*
|
||||
* For historical reasons, the standard function for reading passwords is in
|
||||
* the DES library -- if someone ever wants to disable DES, this function
|
||||
* will fail
|
||||
*/
|
||||
int EVP_read_pw_string(char *buf, int len, const char *prompt, int verify)
|
||||
{
|
||||
return EVP_read_pw_string_min(buf, 0, len, prompt, verify);
|
||||
}
|
||||
|
||||
int EVP_read_pw_string_min(char *buf, int min, int len, const char *prompt,
|
||||
int verify)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[BUFSIZ];
|
||||
UI *ui;
|
||||
|
||||
if ((prompt == NULL) && (prompt_string[0] != '\0'))
|
||||
prompt = prompt_string;
|
||||
ui = UI_new();
|
||||
if (ui == NULL)
|
||||
return ret;
|
||||
if (UI_add_input_string(ui, prompt, 0, buf, min,
|
||||
(len >= BUFSIZ) ? BUFSIZ - 1 : len) < 0
|
||||
|| (verify
|
||||
&& UI_add_verify_string(ui, prompt, 0, buff, min,
|
||||
(len >= BUFSIZ) ? BUFSIZ - 1 : len,
|
||||
buf) < 0))
|
||||
goto end;
|
||||
ret = UI_process(ui);
|
||||
OPENSSL_cleanse(buff, BUFSIZ);
|
||||
end:
|
||||
UI_free(ui);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
|
||||
const unsigned char *salt, const unsigned char *data,
|
||||
int datal, int count, unsigned char *key,
|
||||
unsigned char *iv)
|
||||
{
|
||||
EVP_MD_CTX *c;
|
||||
unsigned char md_buf[EVP_MAX_MD_SIZE];
|
||||
int niv, nkey, addmd = 0;
|
||||
unsigned int mds = 0, i;
|
||||
int rv = 0;
|
||||
nkey = EVP_CIPHER_get_key_length(type);
|
||||
niv = EVP_CIPHER_get_iv_length(type);
|
||||
OPENSSL_assert(nkey <= EVP_MAX_KEY_LENGTH);
|
||||
OPENSSL_assert(niv >= 0 && niv <= EVP_MAX_IV_LENGTH);
|
||||
|
||||
if (data == NULL)
|
||||
return nkey;
|
||||
|
||||
c = EVP_MD_CTX_new();
|
||||
if (c == NULL)
|
||||
goto err;
|
||||
for (;;) {
|
||||
if (!EVP_DigestInit_ex(c, md, NULL))
|
||||
goto err;
|
||||
if (addmd++)
|
||||
if (!EVP_DigestUpdate(c, &(md_buf[0]), mds))
|
||||
goto err;
|
||||
if (!EVP_DigestUpdate(c, data, datal))
|
||||
goto err;
|
||||
if (salt != NULL)
|
||||
if (!EVP_DigestUpdate(c, salt, PKCS5_SALT_LEN))
|
||||
goto err;
|
||||
if (!EVP_DigestFinal_ex(c, &(md_buf[0]), &mds))
|
||||
goto err;
|
||||
|
||||
for (i = 1; i < (unsigned int)count; i++) {
|
||||
if (!EVP_DigestInit_ex(c, md, NULL))
|
||||
goto err;
|
||||
if (!EVP_DigestUpdate(c, &(md_buf[0]), mds))
|
||||
goto err;
|
||||
if (!EVP_DigestFinal_ex(c, &(md_buf[0]), &mds))
|
||||
goto err;
|
||||
}
|
||||
i = 0;
|
||||
if (nkey) {
|
||||
for (;;) {
|
||||
if (nkey == 0)
|
||||
break;
|
||||
if (i == mds)
|
||||
break;
|
||||
if (key != NULL)
|
||||
*(key++) = md_buf[i];
|
||||
nkey--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (niv && (i != mds)) {
|
||||
for (;;) {
|
||||
if (niv == 0)
|
||||
break;
|
||||
if (i == mds)
|
||||
break;
|
||||
if (iv != NULL)
|
||||
*(iv++) = md_buf[i];
|
||||
niv--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if ((nkey == 0) && (niv == 0))
|
||||
break;
|
||||
}
|
||||
rv = EVP_CIPHER_get_key_length(type);
|
||||
err:
|
||||
EVP_MD_CTX_free(c);
|
||||
OPENSSL_cleanse(md_buf, sizeof(md_buf));
|
||||
return rv;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include "internal/refcount.h"
|
||||
|
||||
#define EVP_CTRL_RET_UNSUPPORTED -1
|
||||
|
||||
|
||||
struct evp_md_ctx_st {
|
||||
const EVP_MD *reqdigest; /* The original requested digest */
|
||||
const EVP_MD *digest;
|
||||
ENGINE *engine; /* functional reference if 'digest' is
|
||||
* ENGINE-provided */
|
||||
unsigned long flags;
|
||||
void *md_data;
|
||||
/* Public key context for sign/verify */
|
||||
EVP_PKEY_CTX *pctx;
|
||||
/* Update function: usually copied from EVP_MD */
|
||||
int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
|
||||
|
||||
/*
|
||||
* Opaque ctx returned from a providers digest algorithm implementation
|
||||
* OSSL_FUNC_digest_newctx()
|
||||
*/
|
||||
void *algctx;
|
||||
EVP_MD *fetched_digest;
|
||||
} /* EVP_MD_CTX */ ;
|
||||
|
||||
struct evp_cipher_ctx_st {
|
||||
const EVP_CIPHER *cipher;
|
||||
ENGINE *engine; /* functional reference if 'cipher' is
|
||||
* ENGINE-provided */
|
||||
int encrypt; /* encrypt or decrypt */
|
||||
int buf_len; /* number we have left */
|
||||
unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */
|
||||
unsigned char buf[EVP_MAX_BLOCK_LENGTH]; /* saved partial block */
|
||||
int num; /* used by cfb/ofb/ctr mode */
|
||||
/* FIXME: Should this even exist? It appears unused */
|
||||
void *app_data; /* application stuff */
|
||||
int key_len; /* May change for variable length cipher */
|
||||
int iv_len; /* IV length */
|
||||
unsigned long flags; /* Various flags */
|
||||
void *cipher_data; /* per EVP data */
|
||||
int final_used;
|
||||
int block_mask;
|
||||
unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
|
||||
size_t numpipes;
|
||||
|
||||
/*
|
||||
* Opaque ctx returned from a providers cipher algorithm implementation
|
||||
* OSSL_FUNC_cipher_newctx()
|
||||
*/
|
||||
void *algctx;
|
||||
EVP_CIPHER *fetched_cipher;
|
||||
} /* EVP_CIPHER_CTX */ ;
|
||||
|
||||
struct evp_mac_ctx_st {
|
||||
EVP_MAC *meth; /* Method structure */
|
||||
/*
|
||||
* Opaque ctx returned from a providers MAC algorithm implementation
|
||||
* OSSL_FUNC_mac_newctx()
|
||||
*/
|
||||
void *algctx;
|
||||
} /* EVP_MAC_CTX */;
|
||||
|
||||
struct evp_kdf_ctx_st {
|
||||
EVP_KDF *meth; /* Method structure */
|
||||
/*
|
||||
* Opaque ctx returned from a providers KDF algorithm implementation
|
||||
* OSSL_FUNC_kdf_newctx()
|
||||
*/
|
||||
void *algctx;
|
||||
} /* EVP_KDF_CTX */ ;
|
||||
|
||||
struct evp_rand_ctx_st {
|
||||
EVP_RAND *meth; /* Method structure */
|
||||
/*
|
||||
* Opaque ctx returned from a providers rand algorithm implementation
|
||||
* OSSL_FUNC_rand_newctx()
|
||||
*/
|
||||
void *algctx;
|
||||
EVP_RAND_CTX *parent; /* Parent EVP_RAND or NULL if none */
|
||||
CRYPTO_REF_COUNT refcnt; /* Context reference count */
|
||||
CRYPTO_RWLOCK *refcnt_lock;
|
||||
} /* EVP_RAND_CTX */ ;
|
||||
|
||||
struct evp_keymgmt_st {
|
||||
int id; /* libcrypto internal */
|
||||
|
||||
int name_id;
|
||||
/* NID for the legacy alg if there is one */
|
||||
int legacy_alg;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
/* Constructor(s), destructor, information */
|
||||
OSSL_FUNC_keymgmt_new_fn *new;
|
||||
OSSL_FUNC_keymgmt_free_fn *free;
|
||||
OSSL_FUNC_keymgmt_get_params_fn *get_params;
|
||||
OSSL_FUNC_keymgmt_gettable_params_fn *gettable_params;
|
||||
OSSL_FUNC_keymgmt_set_params_fn *set_params;
|
||||
OSSL_FUNC_keymgmt_settable_params_fn *settable_params;
|
||||
|
||||
/* Generation, a complex constructor */
|
||||
OSSL_FUNC_keymgmt_gen_init_fn *gen_init;
|
||||
OSSL_FUNC_keymgmt_gen_set_template_fn *gen_set_template;
|
||||
OSSL_FUNC_keymgmt_gen_get_params_fn *gen_get_params;
|
||||
OSSL_FUNC_keymgmt_gen_gettable_params_fn *gen_gettable_params;
|
||||
OSSL_FUNC_keymgmt_gen_set_params_fn *gen_set_params;
|
||||
OSSL_FUNC_keymgmt_gen_settable_params_fn *gen_settable_params;
|
||||
OSSL_FUNC_keymgmt_gen_fn *gen;
|
||||
OSSL_FUNC_keymgmt_gen_cleanup_fn *gen_cleanup;
|
||||
|
||||
OSSL_FUNC_keymgmt_load_fn *load;
|
||||
|
||||
/* Key object checking */
|
||||
OSSL_FUNC_keymgmt_query_operation_name_fn *query_operation_name;
|
||||
OSSL_FUNC_keymgmt_has_fn *has;
|
||||
OSSL_FUNC_keymgmt_validate_fn *validate;
|
||||
OSSL_FUNC_keymgmt_match_fn *match;
|
||||
|
||||
/* Import and export routines */
|
||||
OSSL_FUNC_keymgmt_import_fn *import;
|
||||
OSSL_FUNC_keymgmt_import_types_fn *import_types;
|
||||
OSSL_FUNC_keymgmt_import_types_ex_fn *import_types_ex;
|
||||
OSSL_FUNC_keymgmt_export_fn *export;
|
||||
OSSL_FUNC_keymgmt_export_types_fn *export_types;
|
||||
OSSL_FUNC_keymgmt_export_types_ex_fn *export_types_ex;
|
||||
OSSL_FUNC_keymgmt_dup_fn *dup;
|
||||
} /* EVP_KEYMGMT */ ;
|
||||
|
||||
struct evp_keyexch_st {
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
OSSL_FUNC_keyexch_newctx_fn *newctx;
|
||||
OSSL_FUNC_keyexch_init_fn *init;
|
||||
OSSL_FUNC_keyexch_set_peer_fn *set_peer;
|
||||
OSSL_FUNC_keyexch_derive_fn *derive;
|
||||
OSSL_FUNC_keyexch_freectx_fn *freectx;
|
||||
OSSL_FUNC_keyexch_dupctx_fn *dupctx;
|
||||
OSSL_FUNC_keyexch_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_keyexch_settable_ctx_params_fn *settable_ctx_params;
|
||||
OSSL_FUNC_keyexch_get_ctx_params_fn *get_ctx_params;
|
||||
OSSL_FUNC_keyexch_gettable_ctx_params_fn *gettable_ctx_params;
|
||||
} /* EVP_KEYEXCH */;
|
||||
|
||||
struct evp_signature_st {
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
OSSL_FUNC_signature_newctx_fn *newctx;
|
||||
OSSL_FUNC_signature_sign_init_fn *sign_init;
|
||||
OSSL_FUNC_signature_sign_fn *sign;
|
||||
OSSL_FUNC_signature_sign_message_init_fn *sign_message_init;
|
||||
OSSL_FUNC_signature_sign_message_update_fn *sign_message_update;
|
||||
OSSL_FUNC_signature_sign_message_final_fn *sign_message_final;
|
||||
OSSL_FUNC_signature_verify_init_fn *verify_init;
|
||||
OSSL_FUNC_signature_verify_fn *verify;
|
||||
OSSL_FUNC_signature_verify_message_init_fn *verify_message_init;
|
||||
OSSL_FUNC_signature_verify_message_update_fn *verify_message_update;
|
||||
OSSL_FUNC_signature_verify_message_final_fn *verify_message_final;
|
||||
OSSL_FUNC_signature_verify_recover_init_fn *verify_recover_init;
|
||||
OSSL_FUNC_signature_verify_recover_fn *verify_recover;
|
||||
OSSL_FUNC_signature_digest_sign_init_fn *digest_sign_init;
|
||||
OSSL_FUNC_signature_digest_sign_update_fn *digest_sign_update;
|
||||
OSSL_FUNC_signature_digest_sign_final_fn *digest_sign_final;
|
||||
OSSL_FUNC_signature_digest_sign_fn *digest_sign;
|
||||
OSSL_FUNC_signature_digest_verify_init_fn *digest_verify_init;
|
||||
OSSL_FUNC_signature_digest_verify_update_fn *digest_verify_update;
|
||||
OSSL_FUNC_signature_digest_verify_final_fn *digest_verify_final;
|
||||
OSSL_FUNC_signature_digest_verify_fn *digest_verify;
|
||||
OSSL_FUNC_signature_freectx_fn *freectx;
|
||||
OSSL_FUNC_signature_dupctx_fn *dupctx;
|
||||
OSSL_FUNC_signature_get_ctx_params_fn *get_ctx_params;
|
||||
OSSL_FUNC_signature_gettable_ctx_params_fn *gettable_ctx_params;
|
||||
OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_signature_settable_ctx_params_fn *settable_ctx_params;
|
||||
OSSL_FUNC_signature_get_ctx_md_params_fn *get_ctx_md_params;
|
||||
OSSL_FUNC_signature_gettable_ctx_md_params_fn *gettable_ctx_md_params;
|
||||
OSSL_FUNC_signature_set_ctx_md_params_fn *set_ctx_md_params;
|
||||
OSSL_FUNC_signature_settable_ctx_md_params_fn *settable_ctx_md_params;
|
||||
|
||||
/* Signature object checking */
|
||||
OSSL_FUNC_signature_query_key_types_fn *query_key_types;
|
||||
} /* EVP_SIGNATURE */;
|
||||
|
||||
struct evp_skeymgmt_st {
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
/* Import and export routines */
|
||||
OSSL_FUNC_skeymgmt_imp_settable_params_fn *imp_params;
|
||||
OSSL_FUNC_skeymgmt_import_fn *import;
|
||||
OSSL_FUNC_skeymgmt_export_fn *export;
|
||||
|
||||
/* Key generation */
|
||||
OSSL_FUNC_skeymgmt_gen_settable_params_fn *gen_params;
|
||||
OSSL_FUNC_skeymgmt_generate_fn *generate;
|
||||
|
||||
/* Key identifier */
|
||||
OSSL_FUNC_skeymgmt_get_key_id_fn *get_key_id;
|
||||
|
||||
/* destructor */
|
||||
OSSL_FUNC_skeymgmt_free_fn *free;
|
||||
} /* EVP_SKEYMGMT */;
|
||||
|
||||
struct evp_asym_cipher_st {
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
OSSL_FUNC_asym_cipher_newctx_fn *newctx;
|
||||
OSSL_FUNC_asym_cipher_encrypt_init_fn *encrypt_init;
|
||||
OSSL_FUNC_asym_cipher_encrypt_fn *encrypt;
|
||||
OSSL_FUNC_asym_cipher_decrypt_init_fn *decrypt_init;
|
||||
OSSL_FUNC_asym_cipher_decrypt_fn *decrypt;
|
||||
OSSL_FUNC_asym_cipher_freectx_fn *freectx;
|
||||
OSSL_FUNC_asym_cipher_dupctx_fn *dupctx;
|
||||
OSSL_FUNC_asym_cipher_get_ctx_params_fn *get_ctx_params;
|
||||
OSSL_FUNC_asym_cipher_gettable_ctx_params_fn *gettable_ctx_params;
|
||||
OSSL_FUNC_asym_cipher_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_asym_cipher_settable_ctx_params_fn *settable_ctx_params;
|
||||
} /* EVP_ASYM_CIPHER */;
|
||||
|
||||
struct evp_kem_st {
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
OSSL_PROVIDER *prov;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
OSSL_FUNC_kem_newctx_fn *newctx;
|
||||
OSSL_FUNC_kem_encapsulate_init_fn *encapsulate_init;
|
||||
OSSL_FUNC_kem_encapsulate_fn *encapsulate;
|
||||
OSSL_FUNC_kem_decapsulate_init_fn *decapsulate_init;
|
||||
OSSL_FUNC_kem_decapsulate_fn *decapsulate;
|
||||
OSSL_FUNC_kem_freectx_fn *freectx;
|
||||
OSSL_FUNC_kem_dupctx_fn *dupctx;
|
||||
OSSL_FUNC_kem_get_ctx_params_fn *get_ctx_params;
|
||||
OSSL_FUNC_kem_gettable_ctx_params_fn *gettable_ctx_params;
|
||||
OSSL_FUNC_kem_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_kem_settable_ctx_params_fn *settable_ctx_params;
|
||||
OSSL_FUNC_kem_auth_encapsulate_init_fn *auth_encapsulate_init;
|
||||
OSSL_FUNC_kem_auth_decapsulate_init_fn *auth_decapsulate_init;
|
||||
} /* EVP_KEM */;
|
||||
|
||||
int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
|
||||
int passlen, ASN1_TYPE *param,
|
||||
const EVP_CIPHER *c, const EVP_MD *md,
|
||||
int en_de);
|
||||
int PKCS5_v2_PBKDF2_keyivgen_ex(EVP_CIPHER_CTX *ctx, const char *pass,
|
||||
int passlen, ASN1_TYPE *param,
|
||||
const EVP_CIPHER *c, const EVP_MD *md,
|
||||
int en_de, OSSL_LIB_CTX *libctx, const char *propq);
|
||||
|
||||
struct evp_Encode_Ctx_st {
|
||||
/* number saved in a partial encode/decode */
|
||||
int num;
|
||||
/*
|
||||
* The length is either the output line length (in input bytes) or the
|
||||
* shortest input line length that is ok. Once decoding begins, the
|
||||
* length is adjusted up each time a longer line is decoded
|
||||
*/
|
||||
int length;
|
||||
/* data to encode */
|
||||
unsigned char enc_data[80];
|
||||
/* number read on current line */
|
||||
int line_num;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
typedef struct evp_pbe_st EVP_PBE_CTL;
|
||||
DEFINE_STACK_OF(EVP_PBE_CTL)
|
||||
|
||||
int ossl_is_partially_overlapping(const void *ptr1, const void *ptr2, int len);
|
||||
|
||||
#include <openssl/types.h>
|
||||
#include <openssl/core.h>
|
||||
|
||||
void *evp_generic_fetch(OSSL_LIB_CTX *ctx, int operation_id,
|
||||
const char *name, const char *properties,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *));
|
||||
void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
|
||||
const char *name, const char *properties,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *));
|
||||
void evp_generic_do_all_prefetched(OSSL_LIB_CTX *libctx, int operation_id,
|
||||
void (*user_fn)(void *method, void *arg),
|
||||
void *user_arg);
|
||||
void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
|
||||
void (*user_fn)(void *method, void *arg),
|
||||
void *user_arg,
|
||||
void *(*new_method)(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov),
|
||||
int (*up_ref_method)(void *),
|
||||
void (*free_method)(void *));
|
||||
|
||||
/* Internal fetchers for method types that are to be combined with others */
|
||||
EVP_KEYMGMT *evp_keymgmt_fetch_by_number(OSSL_LIB_CTX *ctx, int name_id,
|
||||
const char *properties);
|
||||
EVP_SIGNATURE *evp_signature_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties);
|
||||
EVP_ASYM_CIPHER *evp_asym_cipher_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties);
|
||||
EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties);
|
||||
EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties);
|
||||
EVP_CIPHER *evp_cipher_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties);
|
||||
EVP_MD *evp_digest_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties);
|
||||
EVP_MAC *evp_mac_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties);
|
||||
|
||||
/* Internal structure constructors for fetched methods */
|
||||
EVP_MD *evp_md_new(void);
|
||||
EVP_CIPHER *evp_cipher_new(void);
|
||||
|
||||
int evp_cipher_get_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
|
||||
evp_cipher_aead_asn1_params *asn1_params);
|
||||
int evp_cipher_set_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
|
||||
evp_cipher_aead_asn1_params *asn1_params);
|
||||
|
||||
/* Helper functions to avoid duplicating code */
|
||||
|
||||
/*
|
||||
* These methods implement different ways to pass a params array to the
|
||||
* provider. They will return one of these values:
|
||||
*
|
||||
* -2 if the method doesn't come from a provider
|
||||
* (evp_do_param will return this to the called)
|
||||
* -1 if the provider doesn't offer the desired function
|
||||
* (evp_do_param will raise an error and return 0)
|
||||
* or the return value from the desired function
|
||||
* (evp_do_param will return it to the caller)
|
||||
*/
|
||||
int evp_do_ciph_getparams(const EVP_CIPHER *ciph, OSSL_PARAM params[]);
|
||||
int evp_do_ciph_ctx_getparams(const EVP_CIPHER *ciph, void *provctx,
|
||||
OSSL_PARAM params[]);
|
||||
int evp_do_ciph_ctx_setparams(const EVP_CIPHER *ciph, void *provctx,
|
||||
OSSL_PARAM params[]);
|
||||
int evp_do_md_getparams(const EVP_MD *md, OSSL_PARAM params[]);
|
||||
int evp_do_md_ctx_getparams(const EVP_MD *md, void *provctx,
|
||||
OSSL_PARAM params[]);
|
||||
int evp_do_md_ctx_setparams(const EVP_MD *md, void *provctx,
|
||||
OSSL_PARAM params[]);
|
||||
|
||||
OSSL_PARAM *evp_pkey_to_param(EVP_PKEY *pkey, size_t *sz);
|
||||
|
||||
#define M_check_autoarg(ctx, arg, arglen, err) \
|
||||
if (ctx->pmeth->flags & EVP_PKEY_FLAG_AUTOARGLEN) { \
|
||||
size_t pksize = (size_t)EVP_PKEY_get_size(ctx->pkey); \
|
||||
\
|
||||
if (pksize == 0) { \
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY); /*ckerr_ignore*/ \
|
||||
return 0; \
|
||||
} \
|
||||
if (arg == NULL) { \
|
||||
*arglen = pksize; \
|
||||
return 1; \
|
||||
} \
|
||||
if (*arglen < pksize) { \
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL); /*ckerr_ignore*/ \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx);
|
||||
void evp_cipher_free_int(EVP_CIPHER *md);
|
||||
void evp_md_free_int(EVP_MD *md);
|
||||
|
||||
/* OSSL_PROVIDER * is only used to get the library context */
|
||||
int evp_is_a(OSSL_PROVIDER *prov, int number,
|
||||
const char *legacy_name, const char *name);
|
||||
int evp_names_do_all(OSSL_PROVIDER *prov, int number,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data);
|
||||
int evp_cipher_cache_constants(EVP_CIPHER *cipher);
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
/* Password based encryption (PBE) functions */
|
||||
|
||||
/* Setup a cipher context from a PBE algorithm */
|
||||
|
||||
struct evp_pbe_st {
|
||||
int pbe_type;
|
||||
int pbe_nid;
|
||||
int cipher_nid;
|
||||
int md_nid;
|
||||
EVP_PBE_KEYGEN *keygen;
|
||||
EVP_PBE_KEYGEN_EX *keygen_ex;
|
||||
};
|
||||
|
||||
static STACK_OF(EVP_PBE_CTL) *pbe_algs;
|
||||
|
||||
static const EVP_PBE_CTL builtin_pbe[] = {
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndDES_CBC,
|
||||
NID_des_cbc, NID_md2, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndDES_CBC,
|
||||
NID_des_cbc, NID_md5, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndRC2_CBC,
|
||||
NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
|
||||
{EVP_PBE_TYPE_OUTER, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen,
|
||||
PKCS5_v2_PBKDF2_keyivgen_ex},
|
||||
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC4,
|
||||
NID_rc4, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC4,
|
||||
NID_rc4_40, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
|
||||
NID_des_ede3_cbc, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And2_Key_TripleDES_CBC,
|
||||
NID_des_ede_cbc, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC2_CBC,
|
||||
NID_rc2_cbc, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC2_CBC,
|
||||
NID_rc2_40_cbc, NID_sha1, PKCS12_PBE_keyivgen, &PKCS12_PBE_keyivgen_ex},
|
||||
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbes2, -1, -1, PKCS5_v2_PBE_keyivgen, &PKCS5_v2_PBE_keyivgen_ex},
|
||||
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithMD2AndRC2_CBC,
|
||||
NID_rc2_64_cbc, NID_md2, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithMD5AndRC2_CBC,
|
||||
NID_rc2_64_cbc, NID_md5, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
{EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndDES_CBC,
|
||||
NID_des_cbc, NID_sha1, PKCS5_PBE_keyivgen, PKCS5_PBE_keyivgen_ex},
|
||||
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA1, -1, NID_sha1, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_md5, -1, NID_md5, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_sha1, -1, NID_sha1, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithMD5, -1, NID_md5, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA224, -1, NID_sha224, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA256, -1, NID_sha256, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA384, -1, NID_sha384, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA512, -1, NID_sha512, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_id_HMACGostR3411_94, -1, NID_id_GostR3411_94, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_id_tc26_hmac_gost_3411_2012_256, -1,
|
||||
NID_id_GostR3411_2012_256, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_id_tc26_hmac_gost_3411_2012_512, -1,
|
||||
NID_id_GostR3411_2012_512, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_sha3_224, -1, NID_sha3_224, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_sha3_256, -1, NID_sha3_256, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_sha3_384, -1, NID_sha3_384, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmac_sha3_512, -1, NID_sha3_512, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA512_224, -1, NID_sha512_224, 0},
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSHA512_256, -1, NID_sha512_256, 0},
|
||||
#ifndef OPENSSL_NO_SM3
|
||||
{EVP_PBE_TYPE_PRF, NID_hmacWithSM3, -1, NID_sm3, 0},
|
||||
#endif
|
||||
{EVP_PBE_TYPE_KDF, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen, &PKCS5_v2_PBKDF2_keyivgen_ex},
|
||||
#ifndef OPENSSL_NO_SCRYPT
|
||||
{EVP_PBE_TYPE_KDF, NID_id_scrypt, -1, -1, PKCS5_v2_scrypt_keyivgen, &PKCS5_v2_scrypt_keyivgen_ex}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
int EVP_PBE_CipherInit_ex(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
const EVP_CIPHER *cipher = NULL;
|
||||
EVP_CIPHER *cipher_fetch = NULL;
|
||||
const EVP_MD *md = NULL;
|
||||
EVP_MD *md_fetch = NULL;
|
||||
int ret = 0, cipher_nid, md_nid;
|
||||
EVP_PBE_KEYGEN_EX *keygen_ex;
|
||||
EVP_PBE_KEYGEN *keygen;
|
||||
|
||||
if (!EVP_PBE_find_ex(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
|
||||
&cipher_nid, &md_nid, &keygen, &keygen_ex)) {
|
||||
char obj_tmp[80];
|
||||
|
||||
if (pbe_obj == NULL)
|
||||
OPENSSL_strlcpy(obj_tmp, "NULL", sizeof(obj_tmp));
|
||||
else
|
||||
i2t_ASN1_OBJECT(obj_tmp, sizeof(obj_tmp), pbe_obj);
|
||||
ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_PBE_ALGORITHM,
|
||||
"TYPE=%s", obj_tmp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pass == NULL)
|
||||
passlen = 0;
|
||||
else if (passlen == -1)
|
||||
passlen = strlen(pass);
|
||||
|
||||
if (cipher_nid != -1) {
|
||||
(void)ERR_set_mark();
|
||||
cipher = cipher_fetch = EVP_CIPHER_fetch(libctx, OBJ_nid2sn(cipher_nid), propq);
|
||||
/* Fallback to legacy method */
|
||||
if (cipher == NULL)
|
||||
cipher = EVP_get_cipherbynid(cipher_nid);
|
||||
if (cipher == NULL) {
|
||||
(void)ERR_clear_last_mark();
|
||||
ERR_raise_data(ERR_LIB_EVP, EVP_R_UNKNOWN_CIPHER,
|
||||
OBJ_nid2sn(cipher_nid));
|
||||
goto err;
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
}
|
||||
|
||||
if (md_nid != -1) {
|
||||
(void)ERR_set_mark();
|
||||
md = md_fetch = EVP_MD_fetch(libctx, OBJ_nid2sn(md_nid), propq);
|
||||
/* Fallback to legacy method */
|
||||
if (md == NULL)
|
||||
md = EVP_get_digestbynid(md_nid);
|
||||
|
||||
if (md == NULL) {
|
||||
(void)ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNKNOWN_DIGEST);
|
||||
goto err;
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
}
|
||||
|
||||
/* Try extended keygen with libctx/propq first, fall back to legacy keygen */
|
||||
if (keygen_ex != NULL)
|
||||
ret = keygen_ex(ctx, pass, passlen, param, cipher, md, en_de, libctx, propq);
|
||||
else
|
||||
ret = keygen(ctx, pass, passlen, param, cipher, md, en_de);
|
||||
|
||||
err:
|
||||
EVP_CIPHER_free(cipher_fetch);
|
||||
EVP_MD_free(md_fetch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
|
||||
{
|
||||
return EVP_PBE_CipherInit_ex(pbe_obj, pass, passlen, param, ctx, en_de, NULL, NULL);
|
||||
}
|
||||
|
||||
DECLARE_OBJ_BSEARCH_CMP_FN(EVP_PBE_CTL, EVP_PBE_CTL, pbe2);
|
||||
|
||||
static int pbe2_cmp(const EVP_PBE_CTL *pbe1, const EVP_PBE_CTL *pbe2)
|
||||
{
|
||||
int ret = pbe1->pbe_type - pbe2->pbe_type;
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return pbe1->pbe_nid - pbe2->pbe_nid;
|
||||
}
|
||||
|
||||
IMPLEMENT_OBJ_BSEARCH_CMP_FN(EVP_PBE_CTL, EVP_PBE_CTL, pbe2);
|
||||
|
||||
static int pbe_cmp(const EVP_PBE_CTL *const *a, const EVP_PBE_CTL *const *b)
|
||||
{
|
||||
int ret = (*a)->pbe_type - (*b)->pbe_type;
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return (*a)->pbe_nid - (*b)->pbe_nid;
|
||||
}
|
||||
|
||||
/* Add a PBE algorithm */
|
||||
|
||||
int EVP_PBE_alg_add_type(int pbe_type, int pbe_nid, int cipher_nid,
|
||||
int md_nid, EVP_PBE_KEYGEN *keygen)
|
||||
{
|
||||
EVP_PBE_CTL *pbe_tmp = NULL;
|
||||
|
||||
if (pbe_algs == NULL) {
|
||||
pbe_algs = sk_EVP_PBE_CTL_new(pbe_cmp);
|
||||
if (pbe_algs == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pbe_tmp = OPENSSL_zalloc(sizeof(*pbe_tmp))) == NULL)
|
||||
goto err;
|
||||
|
||||
pbe_tmp->pbe_type = pbe_type;
|
||||
pbe_tmp->pbe_nid = pbe_nid;
|
||||
pbe_tmp->cipher_nid = cipher_nid;
|
||||
pbe_tmp->md_nid = md_nid;
|
||||
pbe_tmp->keygen = keygen;
|
||||
|
||||
if (!sk_EVP_PBE_CTL_push(pbe_algs, pbe_tmp)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
|
||||
goto err;
|
||||
}
|
||||
return 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(pbe_tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
|
||||
EVP_PBE_KEYGEN *keygen)
|
||||
{
|
||||
int cipher_nid, md_nid;
|
||||
|
||||
if (cipher)
|
||||
cipher_nid = EVP_CIPHER_get_nid(cipher);
|
||||
else
|
||||
cipher_nid = -1;
|
||||
if (md)
|
||||
md_nid = EVP_MD_get_type(md);
|
||||
else
|
||||
md_nid = -1;
|
||||
|
||||
return EVP_PBE_alg_add_type(EVP_PBE_TYPE_OUTER, nid,
|
||||
cipher_nid, md_nid, keygen);
|
||||
}
|
||||
|
||||
int EVP_PBE_find_ex(int type, int pbe_nid, int *pcnid, int *pmnid,
|
||||
EVP_PBE_KEYGEN **pkeygen, EVP_PBE_KEYGEN_EX **pkeygen_ex)
|
||||
{
|
||||
EVP_PBE_CTL *pbetmp = NULL, pbelu;
|
||||
int i;
|
||||
if (pbe_nid == NID_undef)
|
||||
return 0;
|
||||
|
||||
pbelu.pbe_type = type;
|
||||
pbelu.pbe_nid = pbe_nid;
|
||||
|
||||
if (pbe_algs != NULL) {
|
||||
/* Ideally, this would be done under lock */
|
||||
sk_EVP_PBE_CTL_sort(pbe_algs);
|
||||
i = sk_EVP_PBE_CTL_find(pbe_algs, &pbelu);
|
||||
pbetmp = sk_EVP_PBE_CTL_value(pbe_algs, i);
|
||||
}
|
||||
if (pbetmp == NULL) {
|
||||
pbetmp = OBJ_bsearch_pbe2(&pbelu, builtin_pbe, OSSL_NELEM(builtin_pbe));
|
||||
}
|
||||
if (pbetmp == NULL)
|
||||
return 0;
|
||||
if (pcnid != NULL)
|
||||
*pcnid = pbetmp->cipher_nid;
|
||||
if (pmnid != NULL)
|
||||
*pmnid = pbetmp->md_nid;
|
||||
if (pkeygen != NULL)
|
||||
*pkeygen = pbetmp->keygen;
|
||||
if (pkeygen_ex != NULL)
|
||||
*pkeygen_ex = pbetmp->keygen_ex;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PBE_find(int type, int pbe_nid,
|
||||
int *pcnid, int *pmnid, EVP_PBE_KEYGEN **pkeygen)
|
||||
{
|
||||
return EVP_PBE_find_ex(type, pbe_nid, pcnid, pmnid, pkeygen, NULL);
|
||||
}
|
||||
|
||||
static void free_evp_pbe_ctl(EVP_PBE_CTL *pbe)
|
||||
{
|
||||
OPENSSL_free(pbe);
|
||||
}
|
||||
|
||||
void EVP_PBE_cleanup(void)
|
||||
{
|
||||
sk_EVP_PBE_CTL_pop_free(pbe_algs, free_evp_pbe_ctl);
|
||||
pbe_algs = NULL;
|
||||
}
|
||||
|
||||
int EVP_PBE_get(int *ptype, int *ppbe_nid, size_t num)
|
||||
{
|
||||
const EVP_PBE_CTL *tpbe;
|
||||
|
||||
if (num >= OSSL_NELEM(builtin_pbe))
|
||||
return 0;
|
||||
|
||||
tpbe = builtin_pbe + num;
|
||||
if (ptype)
|
||||
*ptype = tpbe->pbe_type;
|
||||
if (ppbe_nid)
|
||||
*ppbe_nid = tpbe->pbe_nid;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/encoder.h>
|
||||
#include <openssl/decoder.h>
|
||||
#include "internal/provider.h"
|
||||
#include "internal/sizes.h"
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "crypto/x509.h"
|
||||
|
||||
/* Extract a private key from a PKCS8 structure */
|
||||
|
||||
EVP_PKEY *evp_pkcs82pkey_legacy(const PKCS8_PRIV_KEY_INFO *p8, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
const ASN1_OBJECT *algoid;
|
||||
char obj_tmp[80];
|
||||
|
||||
if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8))
|
||||
return NULL;
|
||||
|
||||
if ((pkey = EVP_PKEY_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) {
|
||||
i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
|
||||
ERR_raise_data(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM,
|
||||
"TYPE=%s", obj_tmp);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pkey->ameth->priv_decode_ex != NULL) {
|
||||
if (!pkey->ameth->priv_decode_ex(pkey, p8, libctx, propq))
|
||||
goto error;
|
||||
} else if (pkey->ameth->priv_decode != NULL) {
|
||||
if (!pkey->ameth->priv_decode(pkey, p8)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PRIVATE_KEY_DECODE_ERROR);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
|
||||
error:
|
||||
EVP_PKEY_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY *EVP_PKCS82PKEY_ex(const PKCS8_PRIV_KEY_INFO *p8, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
const unsigned char *p8_data = NULL;
|
||||
unsigned char *encoded_data = NULL;
|
||||
int encoded_len;
|
||||
int selection;
|
||||
size_t len;
|
||||
OSSL_DECODER_CTX *dctx = NULL;
|
||||
const ASN1_OBJECT *algoid = NULL;
|
||||
char keytype[OSSL_MAX_NAME_SIZE];
|
||||
|
||||
if (p8 == NULL
|
||||
|| !PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8)
|
||||
|| !OBJ_obj2txt(keytype, sizeof(keytype), algoid, 0))
|
||||
return NULL;
|
||||
|
||||
if ((encoded_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &encoded_data)) <= 0
|
||||
|| encoded_data == NULL)
|
||||
return NULL;
|
||||
|
||||
p8_data = encoded_data;
|
||||
len = encoded_len;
|
||||
selection = EVP_PKEY_KEYPAIR | EVP_PKEY_KEY_PARAMETERS;
|
||||
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "PrivateKeyInfo",
|
||||
keytype, selection, libctx, propq);
|
||||
|
||||
if (dctx != NULL && OSSL_DECODER_CTX_get_num_decoders(dctx) == 0) {
|
||||
OSSL_DECODER_CTX_free(dctx);
|
||||
|
||||
/*
|
||||
* This could happen if OBJ_obj2txt() returned a text OID and the
|
||||
* decoder has not got that OID as an alias. We fall back to a NULL
|
||||
* keytype
|
||||
*/
|
||||
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "PrivateKeyInfo",
|
||||
NULL, selection, libctx, propq);
|
||||
}
|
||||
|
||||
if (dctx == NULL
|
||||
|| !OSSL_DECODER_from_data(dctx, &p8_data, &len))
|
||||
/* try legacy */
|
||||
pkey = evp_pkcs82pkey_legacy(p8, libctx, propq);
|
||||
|
||||
OPENSSL_clear_free(encoded_data, encoded_len);
|
||||
OSSL_DECODER_CTX_free(dctx);
|
||||
return pkey;
|
||||
}
|
||||
|
||||
EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8)
|
||||
{
|
||||
return EVP_PKCS82PKEY_ex(p8, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Turn a private key into a PKCS8 structure */
|
||||
|
||||
PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey)
|
||||
{
|
||||
PKCS8_PRIV_KEY_INFO *p8 = NULL;
|
||||
OSSL_ENCODER_CTX *ctx = NULL;
|
||||
|
||||
/*
|
||||
* The implementation for provider-native keys is to encode the
|
||||
* key to a DER encoded PKCS#8 structure, then convert it to a
|
||||
* PKCS8_PRIV_KEY_INFO with good old d2i functions.
|
||||
*/
|
||||
if (evp_pkey_is_provided(pkey)) {
|
||||
int selection = OSSL_KEYMGMT_SELECT_ALL;
|
||||
unsigned char *der = NULL;
|
||||
size_t derlen = 0;
|
||||
const unsigned char *pp;
|
||||
|
||||
if ((ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection,
|
||||
"DER", "PrivateKeyInfo",
|
||||
NULL)) == NULL
|
||||
|| !OSSL_ENCODER_to_data(ctx, &der, &derlen))
|
||||
goto error;
|
||||
|
||||
pp = der;
|
||||
p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &pp, (long)derlen);
|
||||
OPENSSL_free(der);
|
||||
if (p8 == NULL)
|
||||
goto error;
|
||||
} else {
|
||||
p8 = PKCS8_PRIV_KEY_INFO_new();
|
||||
if (p8 == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_ASN1_LIB);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pkey->ameth != NULL) {
|
||||
if (pkey->ameth->priv_encode != NULL) {
|
||||
if (!pkey->ameth->priv_encode(p8, pkey)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PRIVATE_KEY_ENCODE_ERROR);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
goto end;
|
||||
error:
|
||||
PKCS8_PRIV_KEY_INFO_free(p8);
|
||||
p8 = NULL;
|
||||
end:
|
||||
OSSL_ENCODER_CTX_free(ctx);
|
||||
return p8;
|
||||
|
||||
}
|
||||
|
||||
/* EVP_PKEY attribute functions */
|
||||
|
||||
int EVP_PKEY_get_attr_count(const EVP_PKEY *key)
|
||||
{
|
||||
return X509at_get_attr_count(key->attributes);
|
||||
}
|
||||
|
||||
int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, int lastpos)
|
||||
{
|
||||
return X509at_get_attr_by_NID(key->attributes, nid, lastpos);
|
||||
}
|
||||
|
||||
int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, const ASN1_OBJECT *obj,
|
||||
int lastpos)
|
||||
{
|
||||
return X509at_get_attr_by_OBJ(key->attributes, obj, lastpos);
|
||||
}
|
||||
|
||||
X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc)
|
||||
{
|
||||
return X509at_get_attr(key->attributes, loc);
|
||||
}
|
||||
|
||||
X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc)
|
||||
{
|
||||
return X509at_delete_attr(key->attributes, loc);
|
||||
}
|
||||
|
||||
int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr)
|
||||
{
|
||||
if (X509at_add1_attr(&key->attributes, attr))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
|
||||
const ASN1_OBJECT *obj, int type,
|
||||
const unsigned char *bytes, int len)
|
||||
{
|
||||
if (X509at_add1_attr_by_OBJ(&key->attributes, obj, type, bytes, len))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
|
||||
int nid, int type,
|
||||
const unsigned char *bytes, int len)
|
||||
{
|
||||
if (X509at_add1_attr_by_NID(&key->attributes, nid, type, bytes, len))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
|
||||
const char *attrname, int type,
|
||||
const unsigned char *bytes, int len)
|
||||
{
|
||||
if (X509at_add1_attr_by_txt(&key->attributes, attrname, type, bytes, len))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *EVP_PKEY_get0_type_name(const EVP_PKEY *key)
|
||||
{
|
||||
const EVP_PKEY_ASN1_METHOD *ameth;
|
||||
const char *name = NULL;
|
||||
|
||||
if (key->keymgmt != NULL)
|
||||
return EVP_KEYMGMT_get0_name(key->keymgmt);
|
||||
|
||||
/* Otherwise fallback to legacy */
|
||||
ameth = EVP_PKEY_get0_asn1(key);
|
||||
if (ameth != NULL)
|
||||
EVP_PKEY_asn1_get0_info(NULL, NULL,
|
||||
NULL, NULL, &name, ameth);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_PKEY_get0_provider(const EVP_PKEY *key)
|
||||
{
|
||||
if (evp_pkey_is_provided(key))
|
||||
return EVP_KEYMGMT_get0_provider(key->keymgmt);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/numbers.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
struct evp_rand_st {
|
||||
OSSL_PROVIDER *prov;
|
||||
int name_id;
|
||||
char *type_name;
|
||||
const char *description;
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
|
||||
const OSSL_DISPATCH *dispatch;
|
||||
OSSL_FUNC_rand_newctx_fn *newctx;
|
||||
OSSL_FUNC_rand_freectx_fn *freectx;
|
||||
OSSL_FUNC_rand_instantiate_fn *instantiate;
|
||||
OSSL_FUNC_rand_uninstantiate_fn *uninstantiate;
|
||||
OSSL_FUNC_rand_generate_fn *generate;
|
||||
OSSL_FUNC_rand_reseed_fn *reseed;
|
||||
OSSL_FUNC_rand_nonce_fn *nonce;
|
||||
OSSL_FUNC_rand_enable_locking_fn *enable_locking;
|
||||
OSSL_FUNC_rand_lock_fn *lock;
|
||||
OSSL_FUNC_rand_unlock_fn *unlock;
|
||||
OSSL_FUNC_rand_gettable_params_fn *gettable_params;
|
||||
OSSL_FUNC_rand_gettable_ctx_params_fn *gettable_ctx_params;
|
||||
OSSL_FUNC_rand_settable_ctx_params_fn *settable_ctx_params;
|
||||
OSSL_FUNC_rand_get_params_fn *get_params;
|
||||
OSSL_FUNC_rand_get_ctx_params_fn *get_ctx_params;
|
||||
OSSL_FUNC_rand_set_ctx_params_fn *set_ctx_params;
|
||||
OSSL_FUNC_rand_verify_zeroization_fn *verify_zeroization;
|
||||
OSSL_FUNC_rand_get_seed_fn *get_seed;
|
||||
OSSL_FUNC_rand_clear_seed_fn *clear_seed;
|
||||
} /* EVP_RAND */ ;
|
||||
|
||||
static int evp_rand_up_ref(void *vrand)
|
||||
{
|
||||
EVP_RAND *rand = (EVP_RAND *)vrand;
|
||||
int ref = 0;
|
||||
|
||||
if (rand != NULL)
|
||||
return CRYPTO_UP_REF(&rand->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void evp_rand_free(void *vrand)
|
||||
{
|
||||
EVP_RAND *rand = (EVP_RAND *)vrand;
|
||||
int ref = 0;
|
||||
|
||||
if (rand == NULL)
|
||||
return;
|
||||
CRYPTO_DOWN_REF(&rand->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
OPENSSL_free(rand->type_name);
|
||||
ossl_provider_free(rand->prov);
|
||||
CRYPTO_FREE_REF(&rand->refcnt);
|
||||
OPENSSL_free(rand);
|
||||
}
|
||||
|
||||
static void *evp_rand_new(void)
|
||||
{
|
||||
EVP_RAND *rand = OPENSSL_zalloc(sizeof(*rand));
|
||||
|
||||
if (rand == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_NEW_REF(&rand->refcnt, 1)) {
|
||||
OPENSSL_free(rand);
|
||||
return NULL;
|
||||
}
|
||||
return rand;
|
||||
}
|
||||
|
||||
/* Enable locking of the underlying DRBG/RAND if available */
|
||||
int EVP_RAND_enable_locking(EVP_RAND_CTX *rand)
|
||||
{
|
||||
if (rand->meth->enable_locking != NULL)
|
||||
return rand->meth->enable_locking(rand->algctx);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_LOCKING_NOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lock the underlying DRBG/RAND if available */
|
||||
static int evp_rand_lock(EVP_RAND_CTX *rand)
|
||||
{
|
||||
if (rand->meth->lock != NULL)
|
||||
return rand->meth->lock(rand->algctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Unlock the underlying DRBG/RAND if available */
|
||||
static void evp_rand_unlock(EVP_RAND_CTX *rand)
|
||||
{
|
||||
if (rand->meth->unlock != NULL)
|
||||
rand->meth->unlock(rand->algctx);
|
||||
}
|
||||
|
||||
static void *evp_rand_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_RAND *rand = NULL;
|
||||
int fnrandcnt = 0, fnctxcnt = 0, fnlockcnt = 0, fnenablelockcnt = 0;
|
||||
#ifdef FIPS_MODULE
|
||||
int fnzeroizecnt = 0;
|
||||
#endif
|
||||
|
||||
if ((rand = evp_rand_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return NULL;
|
||||
}
|
||||
rand->name_id = name_id;
|
||||
if ((rand->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
|
||||
evp_rand_free(rand);
|
||||
return NULL;
|
||||
}
|
||||
rand->description = algodef->algorithm_description;
|
||||
rand->dispatch = fns;
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_RAND_NEWCTX:
|
||||
if (rand->newctx != NULL)
|
||||
break;
|
||||
rand->newctx = OSSL_FUNC_rand_newctx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_FREECTX:
|
||||
if (rand->freectx != NULL)
|
||||
break;
|
||||
rand->freectx = OSSL_FUNC_rand_freectx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_INSTANTIATE:
|
||||
if (rand->instantiate != NULL)
|
||||
break;
|
||||
rand->instantiate = OSSL_FUNC_rand_instantiate(fns);
|
||||
fnrandcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_UNINSTANTIATE:
|
||||
if (rand->uninstantiate != NULL)
|
||||
break;
|
||||
rand->uninstantiate = OSSL_FUNC_rand_uninstantiate(fns);
|
||||
fnrandcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GENERATE:
|
||||
if (rand->generate != NULL)
|
||||
break;
|
||||
rand->generate = OSSL_FUNC_rand_generate(fns);
|
||||
fnrandcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_RESEED:
|
||||
if (rand->reseed != NULL)
|
||||
break;
|
||||
rand->reseed = OSSL_FUNC_rand_reseed(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_NONCE:
|
||||
if (rand->nonce != NULL)
|
||||
break;
|
||||
rand->nonce = OSSL_FUNC_rand_nonce(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_ENABLE_LOCKING:
|
||||
if (rand->enable_locking != NULL)
|
||||
break;
|
||||
rand->enable_locking = OSSL_FUNC_rand_enable_locking(fns);
|
||||
fnenablelockcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_LOCK:
|
||||
if (rand->lock != NULL)
|
||||
break;
|
||||
rand->lock = OSSL_FUNC_rand_lock(fns);
|
||||
fnlockcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_UNLOCK:
|
||||
if (rand->unlock != NULL)
|
||||
break;
|
||||
rand->unlock = OSSL_FUNC_rand_unlock(fns);
|
||||
fnlockcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GETTABLE_PARAMS:
|
||||
if (rand->gettable_params != NULL)
|
||||
break;
|
||||
rand->gettable_params =
|
||||
OSSL_FUNC_rand_gettable_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS:
|
||||
if (rand->gettable_ctx_params != NULL)
|
||||
break;
|
||||
rand->gettable_ctx_params =
|
||||
OSSL_FUNC_rand_gettable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_SETTABLE_CTX_PARAMS:
|
||||
if (rand->settable_ctx_params != NULL)
|
||||
break;
|
||||
rand->settable_ctx_params =
|
||||
OSSL_FUNC_rand_settable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GET_PARAMS:
|
||||
if (rand->get_params != NULL)
|
||||
break;
|
||||
rand->get_params = OSSL_FUNC_rand_get_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GET_CTX_PARAMS:
|
||||
if (rand->get_ctx_params != NULL)
|
||||
break;
|
||||
rand->get_ctx_params = OSSL_FUNC_rand_get_ctx_params(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_RAND_SET_CTX_PARAMS:
|
||||
if (rand->set_ctx_params != NULL)
|
||||
break;
|
||||
rand->set_ctx_params = OSSL_FUNC_rand_set_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_VERIFY_ZEROIZATION:
|
||||
if (rand->verify_zeroization != NULL)
|
||||
break;
|
||||
rand->verify_zeroization = OSSL_FUNC_rand_verify_zeroization(fns);
|
||||
#ifdef FIPS_MODULE
|
||||
fnzeroizecnt++;
|
||||
#endif
|
||||
break;
|
||||
case OSSL_FUNC_RAND_GET_SEED:
|
||||
if (rand->get_seed != NULL)
|
||||
break;
|
||||
rand->get_seed = OSSL_FUNC_rand_get_seed(fns);
|
||||
break;
|
||||
case OSSL_FUNC_RAND_CLEAR_SEED:
|
||||
if (rand->clear_seed != NULL)
|
||||
break;
|
||||
rand->clear_seed = OSSL_FUNC_rand_clear_seed(fns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a complete set of "rand" functions and a complete set of context
|
||||
* management functions. In FIPS mode, we also require the zeroization
|
||||
* verification function.
|
||||
*
|
||||
* In addition, if locking can be enabled, we need a complete set of
|
||||
* locking functions.
|
||||
*/
|
||||
if (fnrandcnt != 3
|
||||
|| fnctxcnt != 3
|
||||
|| (fnenablelockcnt != 0 && fnenablelockcnt != 1)
|
||||
|| (fnlockcnt != 0 && fnlockcnt != 2)
|
||||
#ifdef FIPS_MODULE
|
||||
|| fnzeroizecnt != 1
|
||||
#endif
|
||||
) {
|
||||
evp_rand_free(rand);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (prov != NULL && !ossl_provider_up_ref(prov)) {
|
||||
evp_rand_free(rand);
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
rand->prov = prov;
|
||||
|
||||
return rand;
|
||||
}
|
||||
|
||||
EVP_RAND *EVP_RAND_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(libctx, OSSL_OP_RAND, algorithm, properties,
|
||||
evp_rand_from_algorithm, evp_rand_up_ref,
|
||||
evp_rand_free);
|
||||
}
|
||||
|
||||
int EVP_RAND_up_ref(EVP_RAND *rand)
|
||||
{
|
||||
return evp_rand_up_ref(rand);
|
||||
}
|
||||
|
||||
void EVP_RAND_free(EVP_RAND *rand)
|
||||
{
|
||||
evp_rand_free(rand);
|
||||
}
|
||||
|
||||
int evp_rand_get_number(const EVP_RAND *rand)
|
||||
{
|
||||
return rand->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_RAND_get0_name(const EVP_RAND *rand)
|
||||
{
|
||||
return rand->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_RAND_get0_description(const EVP_RAND *rand)
|
||||
{
|
||||
return rand->description;
|
||||
}
|
||||
|
||||
int EVP_RAND_is_a(const EVP_RAND *rand, const char *name)
|
||||
{
|
||||
return rand != NULL && evp_is_a(rand->prov, rand->name_id, NULL, name);
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_RAND_get0_provider(const EVP_RAND *rand)
|
||||
{
|
||||
return rand->prov;
|
||||
}
|
||||
|
||||
int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[])
|
||||
{
|
||||
if (rand->get_params != NULL)
|
||||
return rand->get_params(params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_RAND_CTX_up_ref(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
return CRYPTO_UP_REF(&ctx->refcnt, &ref);
|
||||
}
|
||||
|
||||
EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent)
|
||||
{
|
||||
EVP_RAND_CTX *ctx;
|
||||
void *parent_ctx = NULL;
|
||||
const OSSL_DISPATCH *parent_dispatch = NULL;
|
||||
|
||||
if (rand == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = OPENSSL_zalloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
if (!CRYPTO_NEW_REF(&ctx->refcnt, 1)) {
|
||||
OPENSSL_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
if (parent != NULL) {
|
||||
if (!EVP_RAND_CTX_up_ref(parent)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
CRYPTO_FREE_REF(&ctx->refcnt);
|
||||
OPENSSL_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
parent_ctx = parent->algctx;
|
||||
parent_dispatch = parent->meth->dispatch;
|
||||
}
|
||||
if ((ctx->algctx = rand->newctx(ossl_provider_ctx(rand->prov), parent_ctx,
|
||||
parent_dispatch)) == NULL
|
||||
|| !EVP_RAND_up_ref(rand)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
rand->freectx(ctx->algctx);
|
||||
CRYPTO_FREE_REF(&ctx->refcnt);
|
||||
OPENSSL_free(ctx);
|
||||
EVP_RAND_CTX_free(parent);
|
||||
return NULL;
|
||||
}
|
||||
ctx->meth = rand;
|
||||
ctx->parent = parent;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void EVP_RAND_CTX_free(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
int ref = 0;
|
||||
EVP_RAND_CTX *parent;
|
||||
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&ctx->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
parent = ctx->parent;
|
||||
ctx->meth->freectx(ctx->algctx);
|
||||
ctx->algctx = NULL;
|
||||
EVP_RAND_free(ctx->meth);
|
||||
CRYPTO_FREE_REF(&ctx->refcnt);
|
||||
OPENSSL_free(ctx);
|
||||
EVP_RAND_CTX_free(parent);
|
||||
}
|
||||
|
||||
EVP_RAND *EVP_RAND_CTX_get0_rand(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
return ctx->meth;
|
||||
}
|
||||
|
||||
static int evp_rand_get_ctx_params_locked(EVP_RAND_CTX *ctx,
|
||||
OSSL_PARAM params[])
|
||||
{
|
||||
return ctx->meth->get_ctx_params(ctx->algctx, params);
|
||||
}
|
||||
|
||||
int EVP_RAND_CTX_get_params(EVP_RAND_CTX *ctx, OSSL_PARAM params[])
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_get_ctx_params_locked(ctx, params);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int evp_rand_set_ctx_params_locked(EVP_RAND_CTX *ctx,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->set_ctx_params != NULL)
|
||||
return ctx->meth->set_ctx_params(ctx->algctx, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_RAND_CTX_set_params(EVP_RAND_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_set_ctx_params_locked(ctx, params);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_RAND_gettable_params(const EVP_RAND *rand)
|
||||
{
|
||||
if (rand->gettable_params == NULL)
|
||||
return NULL;
|
||||
return rand->gettable_params(ossl_provider_ctx(EVP_RAND_get0_provider(rand)));
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_RAND_gettable_ctx_params(const EVP_RAND *rand)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (rand->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
provctx = ossl_provider_ctx(EVP_RAND_get0_provider(rand));
|
||||
return rand->gettable_ctx_params(NULL, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_RAND_settable_ctx_params(const EVP_RAND *rand)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (rand->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
provctx = ossl_provider_ctx(EVP_RAND_get0_provider(rand));
|
||||
return rand->settable_ctx_params(NULL, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_RAND_CTX_gettable_params(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (ctx->meth->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
provctx = ossl_provider_ctx(EVP_RAND_get0_provider(ctx->meth));
|
||||
return ctx->meth->gettable_ctx_params(ctx->algctx, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_RAND_CTX_settable_params(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (ctx->meth->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
provctx = ossl_provider_ctx(EVP_RAND_get0_provider(ctx->meth));
|
||||
return ctx->meth->settable_ctx_params(ctx->algctx, provctx);
|
||||
}
|
||||
|
||||
void EVP_RAND_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_RAND *rand, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_RAND,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
evp_rand_from_algorithm, evp_rand_up_ref,
|
||||
evp_rand_free);
|
||||
}
|
||||
|
||||
int EVP_RAND_names_do_all(const EVP_RAND *rand,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (rand->prov != NULL)
|
||||
return evp_names_do_all(rand->prov, rand->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int evp_rand_instantiate_locked
|
||||
(EVP_RAND_CTX *ctx, unsigned int strength, int prediction_resistance,
|
||||
const unsigned char *pstr, size_t pstr_len, const OSSL_PARAM params[])
|
||||
{
|
||||
return ctx->meth->instantiate(ctx->algctx, strength, prediction_resistance,
|
||||
pstr, pstr_len, params);
|
||||
}
|
||||
|
||||
int EVP_RAND_instantiate(EVP_RAND_CTX *ctx, unsigned int strength,
|
||||
int prediction_resistance,
|
||||
const unsigned char *pstr, size_t pstr_len,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_instantiate_locked(ctx, strength, prediction_resistance,
|
||||
pstr, pstr_len, params);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int evp_rand_uninstantiate_locked(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
return ctx->meth->uninstantiate(ctx->algctx);
|
||||
}
|
||||
|
||||
int EVP_RAND_uninstantiate(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_uninstantiate_locked(ctx);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int evp_rand_generate_locked(EVP_RAND_CTX *ctx, unsigned char *out,
|
||||
size_t outlen, unsigned int strength,
|
||||
int prediction_resistance,
|
||||
const unsigned char *addin,
|
||||
size_t addin_len)
|
||||
{
|
||||
size_t chunk, max_request = 0;
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
|
||||
params[0] = OSSL_PARAM_construct_size_t(OSSL_RAND_PARAM_MAX_REQUEST,
|
||||
&max_request);
|
||||
if (!evp_rand_get_ctx_params_locked(ctx, params)
|
||||
|| max_request == 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE);
|
||||
return 0;
|
||||
}
|
||||
for (; outlen > 0; outlen -= chunk, out += chunk) {
|
||||
chunk = outlen > max_request ? max_request : outlen;
|
||||
if (!ctx->meth->generate(ctx->algctx, out, chunk, strength,
|
||||
prediction_resistance, addin, addin_len)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_GENERATE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Prediction resistance is only relevant the first time around,
|
||||
* subsequently, the DRBG has already been properly reseeded.
|
||||
*/
|
||||
prediction_resistance = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_RAND_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen,
|
||||
unsigned int strength, int prediction_resistance,
|
||||
const unsigned char *addin, size_t addin_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_generate_locked(ctx, out, outlen, strength,
|
||||
prediction_resistance, addin, addin_len);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int evp_rand_reseed_locked(EVP_RAND_CTX *ctx, int prediction_resistance,
|
||||
const unsigned char *ent, size_t ent_len,
|
||||
const unsigned char *addin, size_t addin_len)
|
||||
{
|
||||
if (ctx->meth->reseed != NULL)
|
||||
return ctx->meth->reseed(ctx->algctx, prediction_resistance,
|
||||
ent, ent_len, addin, addin_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_RAND_reseed(EVP_RAND_CTX *ctx, int prediction_resistance,
|
||||
const unsigned char *ent, size_t ent_len,
|
||||
const unsigned char *addin, size_t addin_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_reseed_locked(ctx, prediction_resistance,
|
||||
ent, ent_len, addin, addin_len);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int evp_rand_strength_locked(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
unsigned int strength = 0;
|
||||
|
||||
params[0] = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, &strength);
|
||||
if (!evp_rand_get_ctx_params_locked(ctx, params))
|
||||
return 0;
|
||||
return strength;
|
||||
}
|
||||
|
||||
unsigned int EVP_RAND_get_strength(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_strength_locked(ctx);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int evp_rand_nonce_locked(EVP_RAND_CTX *ctx, unsigned char *out,
|
||||
size_t outlen)
|
||||
{
|
||||
unsigned int str = evp_rand_strength_locked(ctx);
|
||||
|
||||
if (ctx->meth->nonce == NULL)
|
||||
return 0;
|
||||
if (ctx->meth->nonce(ctx->algctx, out, str, outlen, outlen))
|
||||
return 1;
|
||||
return evp_rand_generate_locked(ctx, out, outlen, str, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int EVP_RAND_nonce(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_nonce_locked(ctx, out, outlen);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
int EVP_RAND_get_state(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
int state;
|
||||
|
||||
params[0] = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STATE, &state);
|
||||
if (!EVP_RAND_CTX_get_params(ctx, params))
|
||||
state = EVP_RAND_STATE_ERROR;
|
||||
return state;
|
||||
}
|
||||
|
||||
static int evp_rand_verify_zeroization_locked(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
if (ctx->meth->verify_zeroization != NULL)
|
||||
return ctx->meth->verify_zeroization(ctx->algctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_RAND_verify_zeroization(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_verify_zeroization_locked(ctx);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
int evp_rand_can_seed(EVP_RAND_CTX *ctx)
|
||||
{
|
||||
return ctx->meth->get_seed != NULL;
|
||||
}
|
||||
|
||||
static size_t evp_rand_get_seed_locked(EVP_RAND_CTX *ctx,
|
||||
unsigned char **buffer,
|
||||
int entropy,
|
||||
size_t min_len, size_t max_len,
|
||||
int prediction_resistance,
|
||||
const unsigned char *adin,
|
||||
size_t adin_len)
|
||||
{
|
||||
if (ctx->meth->get_seed != NULL)
|
||||
return ctx->meth->get_seed(ctx->algctx, buffer,
|
||||
entropy, min_len, max_len,
|
||||
prediction_resistance,
|
||||
adin, adin_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t evp_rand_get_seed(EVP_RAND_CTX *ctx,
|
||||
unsigned char **buffer,
|
||||
int entropy, size_t min_len, size_t max_len,
|
||||
int prediction_resistance,
|
||||
const unsigned char *adin, size_t adin_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!evp_rand_lock(ctx))
|
||||
return 0;
|
||||
res = evp_rand_get_seed_locked(ctx,
|
||||
buffer,
|
||||
entropy, min_len, max_len,
|
||||
prediction_resistance,
|
||||
adin, adin_len);
|
||||
evp_rand_unlock(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void evp_rand_clear_seed_locked(EVP_RAND_CTX *ctx,
|
||||
unsigned char *buffer, size_t b_len)
|
||||
{
|
||||
if (ctx->meth->clear_seed != NULL)
|
||||
ctx->meth->clear_seed(ctx->algctx, buffer, b_len);
|
||||
}
|
||||
|
||||
void evp_rand_clear_seed(EVP_RAND_CTX *ctx,
|
||||
unsigned char *buffer, size_t b_len)
|
||||
{
|
||||
if (!evp_rand_lock(ctx))
|
||||
return;
|
||||
evp_rand_clear_seed_locked(ctx, buffer, b_len);
|
||||
evp_rand_unlock(ctx);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* Internal EVP utility functions */
|
||||
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/asn1.h> /* evp_local.h needs it */
|
||||
#include <openssl/safestack.h> /* evp_local.h needs it */
|
||||
#include "crypto/evp.h" /* evp_local.h needs it */
|
||||
#include "evp_local.h"
|
||||
|
||||
/*
|
||||
* EVP_CTRL_RET_UNSUPPORTED = -1 is the returned value from any ctrl function
|
||||
* where the control command isn't supported, and an alternative code path
|
||||
* may be chosen.
|
||||
* Since these functions are used to implement ctrl functionality, we
|
||||
* use the same value, and other callers will have to compensate.
|
||||
*/
|
||||
#define PARAM_CHECK(obj, func, errfunc) \
|
||||
if (obj == NULL) \
|
||||
return 0; \
|
||||
if (obj->prov == NULL) \
|
||||
return EVP_CTRL_RET_UNSUPPORTED; \
|
||||
if (obj->func == NULL) { \
|
||||
errfunc(); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define PARAM_FUNC(name, func, type, err) \
|
||||
int name (const type *obj, OSSL_PARAM params[]) \
|
||||
{ \
|
||||
PARAM_CHECK(obj, func, err) \
|
||||
return obj->func(params); \
|
||||
}
|
||||
|
||||
#define PARAM_CTX_FUNC(name, func, type, err) \
|
||||
int name (const type *obj, void *algctx, OSSL_PARAM params[]) \
|
||||
{ \
|
||||
PARAM_CHECK(obj, func, err) \
|
||||
return obj->func(algctx, params); \
|
||||
}
|
||||
|
||||
#define PARAM_FUNCTIONS(type, \
|
||||
getname, getfunc, \
|
||||
getctxname, getctxfunc, \
|
||||
setctxname, setctxfunc) \
|
||||
PARAM_FUNC(getname, getfunc, type, geterr) \
|
||||
PARAM_CTX_FUNC(getctxname, getctxfunc, type, geterr) \
|
||||
PARAM_CTX_FUNC(setctxname, setctxfunc, type, seterr)
|
||||
|
||||
/*
|
||||
* These error functions are a workaround for the error scripts, which
|
||||
* currently require that XXXerr method appears inside a function (not a macro).
|
||||
*/
|
||||
static void geterr(void)
|
||||
{
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_CANNOT_GET_PARAMETERS);
|
||||
}
|
||||
|
||||
static void seterr(void)
|
||||
{
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_CANNOT_SET_PARAMETERS);
|
||||
}
|
||||
|
||||
PARAM_FUNCTIONS(EVP_CIPHER,
|
||||
evp_do_ciph_getparams, get_params,
|
||||
evp_do_ciph_ctx_getparams, get_ctx_params,
|
||||
evp_do_ciph_ctx_setparams, set_ctx_params)
|
||||
|
||||
PARAM_FUNCTIONS(EVP_MD,
|
||||
evp_do_md_getparams, get_params,
|
||||
evp_do_md_ctx_getparams, get_ctx_params,
|
||||
evp_do_md_ctx_setparams, set_ctx_params)
|
||||
@@ -0,0 +1,612 @@
|
||||
/*
|
||||
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/refcount.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "internal/numbers.h" /* includes SIZE_MAX */
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static void evp_keyexch_free(void *data)
|
||||
{
|
||||
EVP_KEYEXCH_free(data);
|
||||
}
|
||||
|
||||
static int evp_keyexch_up_ref(void *data)
|
||||
{
|
||||
return EVP_KEYEXCH_up_ref(data);
|
||||
}
|
||||
|
||||
static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
|
||||
{
|
||||
EVP_KEYEXCH *exchange = OPENSSL_zalloc(sizeof(EVP_KEYEXCH));
|
||||
|
||||
if (exchange == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_NEW_REF(&exchange->refcnt, 1)
|
||||
|| !ossl_provider_up_ref(prov)) {
|
||||
CRYPTO_FREE_REF(&exchange->refcnt);
|
||||
OPENSSL_free(exchange);
|
||||
return NULL;
|
||||
}
|
||||
exchange->prov = prov;
|
||||
|
||||
return exchange;
|
||||
}
|
||||
|
||||
static void *evp_keyexch_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_KEYEXCH *exchange = NULL;
|
||||
int fncnt = 0, sparamfncnt = 0, gparamfncnt = 0;
|
||||
|
||||
if ((exchange = evp_keyexch_new(prov)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
exchange->name_id = name_id;
|
||||
if ((exchange->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
|
||||
goto err;
|
||||
exchange->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_KEYEXCH_NEWCTX:
|
||||
if (exchange->newctx != NULL)
|
||||
break;
|
||||
exchange->newctx = OSSL_FUNC_keyexch_newctx(fns);
|
||||
fncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_INIT:
|
||||
if (exchange->init != NULL)
|
||||
break;
|
||||
exchange->init = OSSL_FUNC_keyexch_init(fns);
|
||||
fncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_SET_PEER:
|
||||
if (exchange->set_peer != NULL)
|
||||
break;
|
||||
exchange->set_peer = OSSL_FUNC_keyexch_set_peer(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_DERIVE:
|
||||
if (exchange->derive != NULL)
|
||||
break;
|
||||
exchange->derive = OSSL_FUNC_keyexch_derive(fns);
|
||||
fncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_FREECTX:
|
||||
if (exchange->freectx != NULL)
|
||||
break;
|
||||
exchange->freectx = OSSL_FUNC_keyexch_freectx(fns);
|
||||
fncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_DUPCTX:
|
||||
if (exchange->dupctx != NULL)
|
||||
break;
|
||||
exchange->dupctx = OSSL_FUNC_keyexch_dupctx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS:
|
||||
if (exchange->get_ctx_params != NULL)
|
||||
break;
|
||||
exchange->get_ctx_params = OSSL_FUNC_keyexch_get_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS:
|
||||
if (exchange->gettable_ctx_params != NULL)
|
||||
break;
|
||||
exchange->gettable_ctx_params
|
||||
= OSSL_FUNC_keyexch_gettable_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS:
|
||||
if (exchange->set_ctx_params != NULL)
|
||||
break;
|
||||
exchange->set_ctx_params = OSSL_FUNC_keyexch_set_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS:
|
||||
if (exchange->settable_ctx_params != NULL)
|
||||
break;
|
||||
exchange->settable_ctx_params
|
||||
= OSSL_FUNC_keyexch_settable_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fncnt != 4
|
||||
|| (gparamfncnt != 0 && gparamfncnt != 2)
|
||||
|| (sparamfncnt != 0 && sparamfncnt != 2)) {
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a complete set of "exchange" functions: init, derive, newctx,
|
||||
* and freectx. The set_ctx_params and settable_ctx_params functions are
|
||||
* optional, but if one of them is present then the other one must also
|
||||
* be present. Same goes for get_ctx_params and gettable_ctx_params.
|
||||
* The dupctx and set_peer functions are optional.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return exchange;
|
||||
|
||||
err:
|
||||
EVP_KEYEXCH_free(exchange);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (exchange == NULL)
|
||||
return;
|
||||
CRYPTO_DOWN_REF(&exchange->refcnt, &i);
|
||||
if (i > 0)
|
||||
return;
|
||||
OPENSSL_free(exchange->type_name);
|
||||
ossl_provider_free(exchange->prov);
|
||||
CRYPTO_FREE_REF(&exchange->refcnt);
|
||||
OPENSSL_free(exchange);
|
||||
}
|
||||
|
||||
int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&exchange->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_PROVIDER *EVP_KEYEXCH_get0_provider(const EVP_KEYEXCH *exchange)
|
||||
{
|
||||
return exchange->prov;
|
||||
}
|
||||
|
||||
EVP_KEYEXCH *EVP_KEYEXCH_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties,
|
||||
evp_keyexch_from_algorithm,
|
||||
evp_keyexch_up_ref,
|
||||
evp_keyexch_free);
|
||||
}
|
||||
|
||||
EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov, OSSL_OP_KEYEXCH,
|
||||
algorithm, properties,
|
||||
evp_keyexch_from_algorithm,
|
||||
evp_keyexch_up_ref,
|
||||
evp_keyexch_free);
|
||||
}
|
||||
|
||||
int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return EVP_PKEY_derive_init_ex(ctx, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
int ret;
|
||||
void *provkey = NULL;
|
||||
EVP_KEYEXCH *exchange = NULL;
|
||||
EVP_KEYMGMT *tmp_keymgmt = NULL;
|
||||
const OSSL_PROVIDER *tmp_prov = NULL;
|
||||
const char *supported_exch = NULL;
|
||||
int iter;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return -2;
|
||||
}
|
||||
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = EVP_PKEY_OP_DERIVE;
|
||||
|
||||
ERR_set_mark();
|
||||
|
||||
if (evp_pkey_ctx_is_legacy(ctx))
|
||||
goto legacy;
|
||||
|
||||
/*
|
||||
* Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create
|
||||
* a blank one.
|
||||
*/
|
||||
if (ctx->pkey == NULL) {
|
||||
EVP_PKEY *pkey = EVP_PKEY_new();
|
||||
|
||||
if (pkey == NULL
|
||||
|| !EVP_PKEY_set_type_by_keymgmt(pkey, ctx->keymgmt)
|
||||
|| (pkey->keydata = evp_keymgmt_newdata(ctx->keymgmt)) == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
EVP_PKEY_free(pkey);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ctx->pkey = pkey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to derive the supported exch from |ctx->keymgmt|.
|
||||
*/
|
||||
if (!ossl_assert(ctx->pkey->keymgmt == NULL
|
||||
|| ctx->pkey->keymgmt == ctx->keymgmt)) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
supported_exch = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
|
||||
OSSL_OP_KEYEXCH);
|
||||
if (supported_exch == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We perform two iterations:
|
||||
*
|
||||
* 1. Do the normal exchange fetch, using the fetching data given by
|
||||
* the EVP_PKEY_CTX.
|
||||
* 2. Do the provider specific exchange fetch, from the same provider
|
||||
* as |ctx->keymgmt|
|
||||
*
|
||||
* We then try to fetch the keymgmt from the same provider as the
|
||||
* exchange, and try to export |ctx->pkey| to that keymgmt (when
|
||||
* this keymgmt happens to be the same as |ctx->keymgmt|, the export
|
||||
* is a no-op, but we call it anyway to not complicate the code even
|
||||
* more).
|
||||
* If the export call succeeds (returns a non-NULL provider key pointer),
|
||||
* we're done and can perform the operation itself. If not, we perform
|
||||
* the second iteration, or jump to legacy.
|
||||
*/
|
||||
for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
|
||||
EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
|
||||
|
||||
/*
|
||||
* If we're on the second iteration, free the results from the first.
|
||||
* They are NULL on the first iteration, so no need to check what
|
||||
* iteration we're on.
|
||||
*/
|
||||
EVP_KEYEXCH_free(exchange);
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
|
||||
switch (iter) {
|
||||
case 1:
|
||||
exchange =
|
||||
EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
|
||||
if (exchange != NULL)
|
||||
tmp_prov = EVP_KEYEXCH_get0_provider(exchange);
|
||||
break;
|
||||
case 2:
|
||||
tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
|
||||
exchange =
|
||||
evp_keyexch_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
supported_exch, ctx->propquery);
|
||||
if (exchange == NULL)
|
||||
goto legacy;
|
||||
break;
|
||||
}
|
||||
if (exchange == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure that the key is provided, either natively, or as a cached
|
||||
* export. We start by fetching the keymgmt with the same name as
|
||||
* |ctx->keymgmt|, but from the provider of the exchange method, using
|
||||
* the same property query as when fetching the exchange method.
|
||||
* With the keymgmt we found (if we did), we try to export |ctx->pkey|
|
||||
* to it (evp_pkey_export_to_provider() is smart enough to only actually
|
||||
* export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt)
|
||||
*/
|
||||
tmp_keymgmt_tofree = tmp_keymgmt =
|
||||
evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
EVP_KEYMGMT_get0_name(ctx->keymgmt),
|
||||
ctx->propquery);
|
||||
if (tmp_keymgmt != NULL)
|
||||
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
||||
&tmp_keymgmt, ctx->propquery);
|
||||
if (tmp_keymgmt == NULL)
|
||||
EVP_KEYMGMT_free(tmp_keymgmt_tofree);
|
||||
}
|
||||
|
||||
if (provkey == NULL) {
|
||||
EVP_KEYEXCH_free(exchange);
|
||||
goto legacy;
|
||||
}
|
||||
|
||||
ERR_pop_to_mark();
|
||||
|
||||
/* No more legacy from here down to legacy: */
|
||||
|
||||
/* A Coverity false positive with up_ref/down_ref and free */
|
||||
/* coverity[use_after_free] */
|
||||
ctx->op.kex.exchange = exchange;
|
||||
/* A Coverity false positive with up_ref/down_ref and free */
|
||||
/* coverity[deref_arg] */
|
||||
ctx->op.kex.algctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
|
||||
if (ctx->op.kex.algctx == NULL) {
|
||||
/* The provider key can stay in the cache */
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ret = exchange->init(ctx->op.kex.algctx, provkey, params);
|
||||
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return ret ? 1 : 0;
|
||||
err:
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return 0;
|
||||
|
||||
legacy:
|
||||
/*
|
||||
* If we don't have the full support we need with provided methods,
|
||||
* let's go see if legacy does.
|
||||
*/
|
||||
ERR_pop_to_mark();
|
||||
|
||||
#ifdef FIPS_MODULE
|
||||
return 0;
|
||||
#else
|
||||
if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ctx->pmeth->derive_init == NULL)
|
||||
return 1;
|
||||
ret = ctx->pmeth->derive_init(ctx);
|
||||
if (ret <= 0)
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int EVP_PKEY_derive_set_peer_ex(EVP_PKEY_CTX *ctx, EVP_PKEY *peer,
|
||||
int validate_peer)
|
||||
{
|
||||
int ret = 0, check;
|
||||
void *provkey = NULL;
|
||||
EVP_PKEY_CTX *check_ctx = NULL;
|
||||
EVP_KEYMGMT *tmp_keymgmt = NULL, *tmp_keymgmt_tofree = NULL;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.algctx == NULL)
|
||||
goto legacy;
|
||||
|
||||
if (ctx->op.kex.exchange->set_peer == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (validate_peer) {
|
||||
check_ctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, peer, ctx->propquery);
|
||||
if (check_ctx == NULL)
|
||||
return -1;
|
||||
check = EVP_PKEY_public_check(check_ctx);
|
||||
EVP_PKEY_CTX_free(check_ctx);
|
||||
if (check <= 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the |peer| is provided, either natively, or as a cached
|
||||
* export. We start by fetching the keymgmt with the same name as
|
||||
* |ctx->keymgmt|, but from the provider of the exchange method, using
|
||||
* the same property query as when fetching the exchange method.
|
||||
* With the keymgmt we found (if we did), we try to export |peer|
|
||||
* to it (evp_pkey_export_to_provider() is smart enough to only actually
|
||||
* export it if |tmp_keymgmt| is different from |peer|'s keymgmt)
|
||||
*/
|
||||
tmp_keymgmt_tofree = tmp_keymgmt =
|
||||
evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)
|
||||
EVP_KEYEXCH_get0_provider(ctx->op.kex.exchange),
|
||||
EVP_KEYMGMT_get0_name(ctx->keymgmt),
|
||||
ctx->propquery);
|
||||
if (tmp_keymgmt != NULL)
|
||||
/* A Coverity issue with up_ref/down_ref and free */
|
||||
/* coverity[pass_freed_arg] */
|
||||
provkey = evp_pkey_export_to_provider(peer, ctx->libctx,
|
||||
&tmp_keymgmt, ctx->propquery);
|
||||
EVP_KEYMGMT_free(tmp_keymgmt_tofree);
|
||||
|
||||
/*
|
||||
* If making the key provided wasn't possible, legacy may be able to pick
|
||||
* it up
|
||||
*/
|
||||
if (provkey == NULL)
|
||||
goto legacy;
|
||||
ret = ctx->op.kex.exchange->set_peer(ctx->op.kex.algctx, provkey);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
goto common;
|
||||
|
||||
legacy:
|
||||
#ifdef FIPS_MODULE
|
||||
return ret;
|
||||
#else
|
||||
if (ctx->pmeth == NULL
|
||||
|| !(ctx->pmeth->derive != NULL
|
||||
|| ctx->pmeth->encrypt != NULL
|
||||
|| ctx->pmeth->decrypt != NULL)
|
||||
|| ctx->pmeth->ctrl == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
if (ctx->operation != EVP_PKEY_OP_DERIVE
|
||||
&& ctx->operation != EVP_PKEY_OP_ENCRYPT
|
||||
&& ctx->operation != EVP_PKEY_OP_DECRYPT) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 2)
|
||||
return 1;
|
||||
|
||||
if (ctx->pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->pkey->type != peer->type) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For clarity. The error is if parameters in peer are
|
||||
* present (!missing) but don't match. EVP_PKEY_parameters_eq may return
|
||||
* 1 (match), 0 (don't match) and -2 (comparison is not defined). -1
|
||||
* (different key types) is impossible here because it is checked earlier.
|
||||
* -2 is OK for us here, as well as 1, so we can check for 0 only.
|
||||
*/
|
||||
if (!EVP_PKEY_missing_parameters(peer) &&
|
||||
!EVP_PKEY_parameters_eq(ctx->pkey, peer)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_PARAMETERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
common:
|
||||
if (!EVP_PKEY_up_ref(peer))
|
||||
return -1;
|
||||
|
||||
EVP_PKEY_free(ctx->peerkey);
|
||||
ctx->peerkey = peer;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
|
||||
{
|
||||
return EVP_PKEY_derive_set_peer_ex(ctx, peer, 1);
|
||||
}
|
||||
|
||||
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ctx == NULL || pkeylen == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.kex.algctx == NULL)
|
||||
goto legacy;
|
||||
|
||||
ret = ctx->op.kex.exchange->derive(ctx->op.kex.algctx, key, pkeylen,
|
||||
key != NULL ? *pkeylen : 0);
|
||||
|
||||
return ret;
|
||||
legacy:
|
||||
if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
M_check_autoarg(ctx, key, pkeylen, EVP_F_EVP_PKEY_DERIVE)
|
||||
return ctx->pmeth->derive(ctx, key, pkeylen);
|
||||
}
|
||||
|
||||
int evp_keyexch_get_number(const EVP_KEYEXCH *keyexch)
|
||||
{
|
||||
return keyexch->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_KEYEXCH_get0_name(const EVP_KEYEXCH *keyexch)
|
||||
{
|
||||
return keyexch->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_KEYEXCH_get0_description(const EVP_KEYEXCH *keyexch)
|
||||
{
|
||||
return keyexch->description;
|
||||
}
|
||||
|
||||
int EVP_KEYEXCH_is_a(const EVP_KEYEXCH *keyexch, const char *name)
|
||||
{
|
||||
return keyexch != NULL
|
||||
&& evp_is_a(keyexch->prov, keyexch->name_id, NULL, name);
|
||||
}
|
||||
|
||||
void EVP_KEYEXCH_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_KEYEXCH *keyexch, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_KEYEXCH,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
evp_keyexch_from_algorithm,
|
||||
evp_keyexch_up_ref,
|
||||
evp_keyexch_free);
|
||||
}
|
||||
|
||||
int EVP_KEYEXCH_names_do_all(const EVP_KEYEXCH *keyexch,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (keyexch->prov != NULL)
|
||||
return evp_names_do_all(keyexch->prov, keyexch->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYEXCH_gettable_ctx_params(const EVP_KEYEXCH *keyexch)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (keyexch == NULL || keyexch->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(keyexch));
|
||||
return keyexch->gettable_ctx_params(NULL, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYEXCH_settable_ctx_params(const EVP_KEYEXCH *keyexch)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (keyexch == NULL || keyexch->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
provctx = ossl_provider_ctx(EVP_KEYEXCH_get0_provider(keyexch));
|
||||
return keyexch->settable_ctx_params(NULL, provctx);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright (c) 2018-2019, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/numbers.h"
|
||||
#include "internal/provider.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
EVP_KDF_CTX *EVP_KDF_CTX_new(EVP_KDF *kdf)
|
||||
{
|
||||
EVP_KDF_CTX *ctx = NULL;
|
||||
|
||||
if (kdf == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx = OPENSSL_zalloc(sizeof(EVP_KDF_CTX));
|
||||
if (ctx == NULL
|
||||
|| (ctx->algctx = kdf->newctx(ossl_provider_ctx(kdf->prov))) == NULL
|
||||
|| !EVP_KDF_up_ref(kdf)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
if (ctx != NULL)
|
||||
kdf->freectx(ctx->algctx);
|
||||
OPENSSL_free(ctx);
|
||||
ctx = NULL;
|
||||
} else {
|
||||
ctx->meth = kdf;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void EVP_KDF_CTX_free(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
ctx->meth->freectx(ctx->algctx);
|
||||
ctx->algctx = NULL;
|
||||
EVP_KDF_free(ctx->meth);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
EVP_KDF_CTX *EVP_KDF_CTX_dup(const EVP_KDF_CTX *src)
|
||||
{
|
||||
EVP_KDF_CTX *dst;
|
||||
|
||||
if (src == NULL || src->algctx == NULL || src->meth->dupctx == NULL)
|
||||
return NULL;
|
||||
|
||||
dst = OPENSSL_malloc(sizeof(*dst));
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
if (!EVP_KDF_up_ref(dst->meth)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
OPENSSL_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst->algctx = src->meth->dupctx(src->algctx);
|
||||
if (dst->algctx == NULL) {
|
||||
EVP_KDF_CTX_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int evp_kdf_get_number(const EVP_KDF *kdf)
|
||||
{
|
||||
return kdf->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_KDF_get0_name(const EVP_KDF *kdf)
|
||||
{
|
||||
return kdf->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_KDF_get0_description(const EVP_KDF *kdf)
|
||||
{
|
||||
return kdf->description;
|
||||
}
|
||||
|
||||
int EVP_KDF_is_a(const EVP_KDF *kdf, const char *name)
|
||||
{
|
||||
return kdf != NULL && evp_is_a(kdf->prov, kdf->name_id, NULL, name);
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_KDF_get0_provider(const EVP_KDF *kdf)
|
||||
{
|
||||
return kdf->prov;
|
||||
}
|
||||
|
||||
const EVP_KDF *EVP_KDF_CTX_kdf(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
return ctx->meth;
|
||||
}
|
||||
|
||||
void EVP_KDF_CTX_reset(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
if (ctx->meth->reset != NULL)
|
||||
ctx->meth->reset(ctx->algctx);
|
||||
}
|
||||
|
||||
size_t EVP_KDF_CTX_get_kdf_size(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
size_t s = 0;
|
||||
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
*params = OSSL_PARAM_construct_size_t(OSSL_KDF_PARAM_SIZE, &s);
|
||||
if (ctx->meth->get_ctx_params != NULL
|
||||
&& ctx->meth->get_ctx_params(ctx->algctx, params))
|
||||
return s;
|
||||
if (ctx->meth->get_params != NULL
|
||||
&& ctx->meth->get_params(params))
|
||||
return s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_KDF_derive(EVP_KDF_CTX *ctx, unsigned char *key, size_t keylen,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
return ctx->meth->derive(ctx->algctx, key, keylen, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* The {get,set}_params functions return 1 if there is no corresponding
|
||||
* function in the implementation. This is the same as if there was one,
|
||||
* but it didn't recognise any of the given params, i.e. nothing in the
|
||||
* bag of parameters was useful.
|
||||
*/
|
||||
int EVP_KDF_get_params(EVP_KDF *kdf, OSSL_PARAM params[])
|
||||
{
|
||||
if (kdf->get_params != NULL)
|
||||
return kdf->get_params(params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_KDF_CTX_get_params(EVP_KDF_CTX *ctx, OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->get_ctx_params != NULL)
|
||||
return ctx->meth->get_ctx_params(ctx->algctx, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_KDF_CTX_set_params(EVP_KDF_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->set_ctx_params != NULL)
|
||||
return ctx->meth->set_ctx_params(ctx->algctx, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_KDF_names_do_all(const EVP_KDF *kdf,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (kdf->prov != NULL)
|
||||
return evp_names_do_all(kdf->prov, kdf->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static int evp_kdf_up_ref(void *vkdf)
|
||||
{
|
||||
EVP_KDF *kdf = (EVP_KDF *)vkdf;
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&kdf->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void evp_kdf_free(void *vkdf)
|
||||
{
|
||||
EVP_KDF *kdf = (EVP_KDF *)vkdf;
|
||||
int ref = 0;
|
||||
|
||||
if (kdf == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&kdf->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
OPENSSL_free(kdf->type_name);
|
||||
ossl_provider_free(kdf->prov);
|
||||
CRYPTO_FREE_REF(&kdf->refcnt);
|
||||
OPENSSL_free(kdf);
|
||||
}
|
||||
|
||||
static void *evp_kdf_new(void)
|
||||
{
|
||||
EVP_KDF *kdf = NULL;
|
||||
|
||||
if ((kdf = OPENSSL_zalloc(sizeof(*kdf))) == NULL
|
||||
|| !CRYPTO_NEW_REF(&kdf->refcnt, 1)) {
|
||||
OPENSSL_free(kdf);
|
||||
return NULL;
|
||||
}
|
||||
return kdf;
|
||||
}
|
||||
|
||||
static void *evp_kdf_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_KDF *kdf = NULL;
|
||||
int fnkdfcnt = 0, fnctxcnt = 0;
|
||||
|
||||
if ((kdf = evp_kdf_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return NULL;
|
||||
}
|
||||
kdf->name_id = name_id;
|
||||
if ((kdf->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
|
||||
goto err;
|
||||
|
||||
kdf->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_KDF_NEWCTX:
|
||||
if (kdf->newctx != NULL)
|
||||
break;
|
||||
kdf->newctx = OSSL_FUNC_kdf_newctx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KDF_DUPCTX:
|
||||
if (kdf->dupctx != NULL)
|
||||
break;
|
||||
kdf->dupctx = OSSL_FUNC_kdf_dupctx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_FREECTX:
|
||||
if (kdf->freectx != NULL)
|
||||
break;
|
||||
kdf->freectx = OSSL_FUNC_kdf_freectx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KDF_RESET:
|
||||
if (kdf->reset != NULL)
|
||||
break;
|
||||
kdf->reset = OSSL_FUNC_kdf_reset(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_DERIVE:
|
||||
if (kdf->derive != NULL)
|
||||
break;
|
||||
kdf->derive = OSSL_FUNC_kdf_derive(fns);
|
||||
fnkdfcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KDF_GETTABLE_PARAMS:
|
||||
if (kdf->gettable_params != NULL)
|
||||
break;
|
||||
kdf->gettable_params =
|
||||
OSSL_FUNC_kdf_gettable_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS:
|
||||
if (kdf->gettable_ctx_params != NULL)
|
||||
break;
|
||||
kdf->gettable_ctx_params =
|
||||
OSSL_FUNC_kdf_gettable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS:
|
||||
if (kdf->settable_ctx_params != NULL)
|
||||
break;
|
||||
kdf->settable_ctx_params =
|
||||
OSSL_FUNC_kdf_settable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_GET_PARAMS:
|
||||
if (kdf->get_params != NULL)
|
||||
break;
|
||||
kdf->get_params = OSSL_FUNC_kdf_get_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_GET_CTX_PARAMS:
|
||||
if (kdf->get_ctx_params != NULL)
|
||||
break;
|
||||
kdf->get_ctx_params = OSSL_FUNC_kdf_get_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KDF_SET_CTX_PARAMS:
|
||||
if (kdf->set_ctx_params != NULL)
|
||||
break;
|
||||
kdf->set_ctx_params = OSSL_FUNC_kdf_set_ctx_params(fns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fnkdfcnt != 1 || fnctxcnt != 2) {
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a derive function, and a complete set of context management
|
||||
* functions.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
goto err;
|
||||
}
|
||||
if (prov != NULL && !ossl_provider_up_ref(prov))
|
||||
goto err;
|
||||
|
||||
kdf->prov = prov;
|
||||
|
||||
return kdf;
|
||||
|
||||
err:
|
||||
evp_kdf_free(kdf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_KDF *EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(libctx, OSSL_OP_KDF, algorithm, properties,
|
||||
evp_kdf_from_algorithm, evp_kdf_up_ref,
|
||||
evp_kdf_free);
|
||||
}
|
||||
|
||||
int EVP_KDF_up_ref(EVP_KDF *kdf)
|
||||
{
|
||||
return evp_kdf_up_ref(kdf);
|
||||
}
|
||||
|
||||
void EVP_KDF_free(EVP_KDF *kdf)
|
||||
{
|
||||
evp_kdf_free(kdf);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KDF_gettable_params(const EVP_KDF *kdf)
|
||||
{
|
||||
if (kdf->gettable_params == NULL)
|
||||
return NULL;
|
||||
return kdf->gettable_params(ossl_provider_ctx(EVP_KDF_get0_provider(kdf)));
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KDF_gettable_ctx_params(const EVP_KDF *kdf)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (kdf->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_KDF_get0_provider(kdf));
|
||||
return kdf->gettable_ctx_params(NULL, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KDF_settable_ctx_params(const EVP_KDF *kdf)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (kdf->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_KDF_get0_provider(kdf));
|
||||
return kdf->settable_ctx_params(NULL, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KDF_CTX_gettable_params(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (ctx->meth->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_KDF_get0_provider(ctx->meth));
|
||||
return ctx->meth->gettable_ctx_params(ctx->algctx, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KDF_CTX_settable_params(EVP_KDF_CTX *ctx)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (ctx->meth->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_KDF_get0_provider(ctx->meth));
|
||||
return ctx->meth->settable_ctx_params(ctx->algctx, alg);
|
||||
}
|
||||
|
||||
void EVP_KDF_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_KDF *kdf, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_KDF,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
evp_kdf_from_algorithm, evp_kdf_up_ref, evp_kdf_free);
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static void evp_kem_free(void *data)
|
||||
{
|
||||
EVP_KEM_free(data);
|
||||
}
|
||||
|
||||
static int evp_kem_up_ref(void *data)
|
||||
{
|
||||
return EVP_KEM_up_ref(data);
|
||||
}
|
||||
|
||||
static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
|
||||
const OSSL_PARAM params[], EVP_PKEY *authkey)
|
||||
{
|
||||
int ret = 0;
|
||||
EVP_KEM *kem = NULL;
|
||||
EVP_KEYMGMT *tmp_keymgmt = NULL;
|
||||
const OSSL_PROVIDER *tmp_prov = NULL;
|
||||
void *provkey = NULL, *provauthkey = NULL;
|
||||
const char *supported_kem = NULL;
|
||||
int iter;
|
||||
|
||||
if (ctx == NULL || ctx->keytype == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = operation;
|
||||
|
||||
if (ctx->pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
goto err;
|
||||
}
|
||||
if (authkey != NULL && authkey->type != ctx->pkey->type) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Try to derive the supported kem from |ctx->keymgmt|.
|
||||
*/
|
||||
if (!ossl_assert(ctx->pkey->keymgmt == NULL
|
||||
|| ctx->pkey->keymgmt == ctx->keymgmt)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
supported_kem = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
|
||||
OSSL_OP_KEM);
|
||||
if (supported_kem == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we cleared out old ops, we shouldn't need to worry about
|
||||
* checking if kem is already there.
|
||||
* We perform two iterations:
|
||||
*
|
||||
* 1. Do the normal kem fetch, using the fetching data given by
|
||||
* the EVP_PKEY_CTX.
|
||||
* 2. Do the provider specific kem fetch, from the same provider
|
||||
* as |ctx->keymgmt|
|
||||
*
|
||||
* We then try to fetch the keymgmt from the same provider as the
|
||||
* kem, and try to export |ctx->pkey| to that keymgmt (when this
|
||||
* keymgmt happens to be the same as |ctx->keymgmt|, the export is
|
||||
* a no-op, but we call it anyway to not complicate the code even
|
||||
* more).
|
||||
* If the export call succeeds (returns a non-NULL provider key pointer),
|
||||
* we're done and can perform the operation itself. If not, we perform
|
||||
* the second iteration, or jump to legacy.
|
||||
*/
|
||||
for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
|
||||
EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
|
||||
|
||||
/*
|
||||
* If we're on the second iteration, free the results from the first.
|
||||
* They are NULL on the first iteration, so no need to check what
|
||||
* iteration we're on.
|
||||
*/
|
||||
EVP_KEM_free(kem);
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
|
||||
switch (iter) {
|
||||
case 1:
|
||||
kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
|
||||
if (kem != NULL)
|
||||
tmp_prov = EVP_KEM_get0_provider(kem);
|
||||
break;
|
||||
case 2:
|
||||
tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
|
||||
kem = evp_kem_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
supported_kem, ctx->propquery);
|
||||
|
||||
if (kem == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP,
|
||||
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (kem == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure that the key is provided, either natively, or as a cached
|
||||
* export. We start by fetching the keymgmt with the same name as
|
||||
* |ctx->pkey|, but from the provider of the kem method, using the
|
||||
* same property query as when fetching the kem method.
|
||||
* With the keymgmt we found (if we did), we try to export |ctx->pkey|
|
||||
* to it (evp_pkey_export_to_provider() is smart enough to only actually
|
||||
* export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt)
|
||||
*/
|
||||
tmp_keymgmt_tofree = tmp_keymgmt =
|
||||
evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
EVP_KEYMGMT_get0_name(ctx->keymgmt),
|
||||
ctx->propquery);
|
||||
if (tmp_keymgmt != NULL) {
|
||||
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
||||
&tmp_keymgmt, ctx->propquery);
|
||||
if (provkey != NULL && authkey != NULL) {
|
||||
provauthkey = evp_pkey_export_to_provider(authkey, ctx->libctx,
|
||||
&tmp_keymgmt,
|
||||
ctx->propquery);
|
||||
if (provauthkey == NULL) {
|
||||
EVP_KEM_free(kem);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmp_keymgmt == NULL)
|
||||
EVP_KEYMGMT_free(tmp_keymgmt_tofree);
|
||||
}
|
||||
|
||||
if (provkey == NULL) {
|
||||
EVP_KEM_free(kem);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ctx->op.encap.kem = kem;
|
||||
ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov));
|
||||
if (ctx->op.encap.algctx == NULL) {
|
||||
/* The provider key can stay in the cache */
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case EVP_PKEY_OP_ENCAPSULATE:
|
||||
if (provauthkey != NULL && kem->auth_encapsulate_init != NULL) {
|
||||
ret = kem->auth_encapsulate_init(ctx->op.encap.algctx, provkey,
|
||||
provauthkey, params);
|
||||
} else if (provauthkey == NULL && kem->encapsulate_init != NULL) {
|
||||
ret = kem->encapsulate_init(ctx->op.encap.algctx, provkey, params);
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case EVP_PKEY_OP_DECAPSULATE:
|
||||
if (provauthkey != NULL && kem->auth_decapsulate_init != NULL) {
|
||||
ret = kem->auth_decapsulate_init(ctx->op.encap.algctx, provkey,
|
||||
provauthkey, params);
|
||||
} else if (provauthkey == NULL && kem->encapsulate_init != NULL) {
|
||||
ret = kem->decapsulate_init(ctx->op.encap.algctx, provkey, params);
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
tmp_keymgmt = NULL;
|
||||
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
err:
|
||||
if (ret <= 0) {
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
}
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_PKEY_auth_encapsulate_init(EVP_PKEY_CTX *ctx, EVP_PKEY *authpriv,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (authpriv == NULL)
|
||||
return 0;
|
||||
return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE, params, authpriv);
|
||||
}
|
||||
|
||||
int EVP_PKEY_encapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
return evp_kem_init(ctx, EVP_PKEY_OP_ENCAPSULATE, params, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *out, size_t *outlen,
|
||||
unsigned char *secret, size_t *secretlen)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
if (ctx->operation != EVP_PKEY_OP_ENCAPSULATE) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.encap.algctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (out != NULL && secret == NULL)
|
||||
return 0;
|
||||
|
||||
return ctx->op.encap.kem->encapsulate(ctx->op.encap.algctx,
|
||||
out, outlen, secret, secretlen);
|
||||
}
|
||||
|
||||
int EVP_PKEY_decapsulate_init(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE, params, NULL);
|
||||
}
|
||||
|
||||
int EVP_PKEY_auth_decapsulate_init(EVP_PKEY_CTX *ctx, EVP_PKEY *authpub,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (authpub == NULL)
|
||||
return 0;
|
||||
return evp_kem_init(ctx, EVP_PKEY_OP_DECAPSULATE, params, authpub);
|
||||
}
|
||||
|
||||
int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *secret, size_t *secretlen,
|
||||
const unsigned char *in, size_t inlen)
|
||||
{
|
||||
if (ctx == NULL
|
||||
|| (in == NULL || inlen == 0)
|
||||
|| (secret == NULL && secretlen == NULL))
|
||||
return 0;
|
||||
|
||||
if (ctx->operation != EVP_PKEY_OP_DECAPSULATE) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.encap.algctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
return ctx->op.encap.kem->decapsulate(ctx->op.encap.algctx,
|
||||
secret, secretlen, in, inlen);
|
||||
}
|
||||
|
||||
static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
|
||||
{
|
||||
EVP_KEM *kem = OPENSSL_zalloc(sizeof(EVP_KEM));
|
||||
|
||||
if (kem == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_NEW_REF(&kem->refcnt, 1)
|
||||
|| !ossl_provider_up_ref(prov)) {
|
||||
CRYPTO_FREE_REF(&kem->refcnt);
|
||||
OPENSSL_free(kem);
|
||||
return NULL;
|
||||
}
|
||||
kem->prov = prov;
|
||||
|
||||
return kem;
|
||||
}
|
||||
|
||||
static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_KEM *kem = NULL;
|
||||
int ctxfncnt = 0, encfncnt = 0, decfncnt = 0;
|
||||
int gparamfncnt = 0, sparamfncnt = 0;
|
||||
|
||||
if ((kem = evp_kem_new(prov)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kem->name_id = name_id;
|
||||
if ((kem->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
|
||||
goto err;
|
||||
kem->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_KEM_NEWCTX:
|
||||
if (kem->newctx != NULL)
|
||||
break;
|
||||
kem->newctx = OSSL_FUNC_kem_newctx(fns);
|
||||
ctxfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_ENCAPSULATE_INIT:
|
||||
if (kem->encapsulate_init != NULL)
|
||||
break;
|
||||
kem->encapsulate_init = OSSL_FUNC_kem_encapsulate_init(fns);
|
||||
encfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT:
|
||||
if (kem->auth_encapsulate_init != NULL)
|
||||
break;
|
||||
kem->auth_encapsulate_init = OSSL_FUNC_kem_auth_encapsulate_init(fns);
|
||||
encfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_ENCAPSULATE:
|
||||
if (kem->encapsulate != NULL)
|
||||
break;
|
||||
kem->encapsulate = OSSL_FUNC_kem_encapsulate(fns);
|
||||
encfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_DECAPSULATE_INIT:
|
||||
if (kem->decapsulate_init != NULL)
|
||||
break;
|
||||
kem->decapsulate_init = OSSL_FUNC_kem_decapsulate_init(fns);
|
||||
decfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT:
|
||||
if (kem->auth_decapsulate_init != NULL)
|
||||
break;
|
||||
kem->auth_decapsulate_init = OSSL_FUNC_kem_auth_decapsulate_init(fns);
|
||||
decfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_DECAPSULATE:
|
||||
if (kem->decapsulate != NULL)
|
||||
break;
|
||||
kem->decapsulate = OSSL_FUNC_kem_decapsulate(fns);
|
||||
decfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_FREECTX:
|
||||
if (kem->freectx != NULL)
|
||||
break;
|
||||
kem->freectx = OSSL_FUNC_kem_freectx(fns);
|
||||
ctxfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_DUPCTX:
|
||||
if (kem->dupctx != NULL)
|
||||
break;
|
||||
kem->dupctx = OSSL_FUNC_kem_dupctx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEM_GET_CTX_PARAMS:
|
||||
if (kem->get_ctx_params != NULL)
|
||||
break;
|
||||
kem->get_ctx_params
|
||||
= OSSL_FUNC_kem_get_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS:
|
||||
if (kem->gettable_ctx_params != NULL)
|
||||
break;
|
||||
kem->gettable_ctx_params
|
||||
= OSSL_FUNC_kem_gettable_ctx_params(fns);
|
||||
gparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_SET_CTX_PARAMS:
|
||||
if (kem->set_ctx_params != NULL)
|
||||
break;
|
||||
kem->set_ctx_params
|
||||
= OSSL_FUNC_kem_set_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
case OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS:
|
||||
if (kem->settable_ctx_params != NULL)
|
||||
break;
|
||||
kem->settable_ctx_params
|
||||
= OSSL_FUNC_kem_settable_ctx_params(fns);
|
||||
sparamfncnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ctxfncnt != 2
|
||||
|| (encfncnt != 0 && encfncnt != 2 && encfncnt != 3)
|
||||
|| (decfncnt != 0 && decfncnt != 2 && decfncnt != 3)
|
||||
|| (encfncnt != decfncnt)
|
||||
|| (gparamfncnt != 0 && gparamfncnt != 2)
|
||||
|| (sparamfncnt != 0 && sparamfncnt != 2)) {
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a set of context functions (newctx and freectx) as well as a pair
|
||||
* (or triplet) of "kem" functions:
|
||||
* (encapsulate_init, (and/or auth_encapsulate_init), encapsulate) or
|
||||
* (decapsulate_init, (and/or auth_decapsulate_init), decapsulate).
|
||||
* set_ctx_params and settable_ctx_params are optional, but if one of
|
||||
* them is present then the other one must also be present. The same
|
||||
* applies to get_ctx_params and gettable_ctx_params.
|
||||
* The dupctx function is optional.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return kem;
|
||||
err:
|
||||
EVP_KEM_free(kem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EVP_KEM_free(EVP_KEM *kem)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (kem == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&kem->refcnt, &i);
|
||||
if (i > 0)
|
||||
return;
|
||||
OPENSSL_free(kem->type_name);
|
||||
ossl_provider_free(kem->prov);
|
||||
CRYPTO_FREE_REF(&kem->refcnt);
|
||||
OPENSSL_free(kem);
|
||||
}
|
||||
|
||||
int EVP_KEM_up_ref(EVP_KEM *kem)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&kem->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_PROVIDER *EVP_KEM_get0_provider(const EVP_KEM *kem)
|
||||
{
|
||||
return kem->prov;
|
||||
}
|
||||
|
||||
EVP_KEM *EVP_KEM_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_KEM, algorithm, properties,
|
||||
evp_kem_from_algorithm,
|
||||
evp_kem_up_ref,
|
||||
evp_kem_free);
|
||||
}
|
||||
|
||||
EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov, OSSL_OP_KEM, algorithm, properties,
|
||||
evp_kem_from_algorithm,
|
||||
evp_kem_up_ref,
|
||||
evp_kem_free);
|
||||
}
|
||||
|
||||
int EVP_KEM_is_a(const EVP_KEM *kem, const char *name)
|
||||
{
|
||||
return kem != NULL && evp_is_a(kem->prov, kem->name_id, NULL, name);
|
||||
}
|
||||
|
||||
int evp_kem_get_number(const EVP_KEM *kem)
|
||||
{
|
||||
return kem->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_KEM_get0_name(const EVP_KEM *kem)
|
||||
{
|
||||
return kem->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_KEM_get0_description(const EVP_KEM *kem)
|
||||
{
|
||||
return kem->description;
|
||||
}
|
||||
|
||||
void EVP_KEM_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_KEM *kem, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_KEM, (void (*)(void *, void *))fn, arg,
|
||||
evp_kem_from_algorithm,
|
||||
evp_kem_up_ref,
|
||||
evp_kem_free);
|
||||
}
|
||||
|
||||
int EVP_KEM_names_do_all(const EVP_KEM *kem,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (kem->prov != NULL)
|
||||
return evp_names_do_all(kem->prov, kem->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEM_gettable_ctx_params(const EVP_KEM *kem)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (kem == NULL || kem->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
|
||||
return kem->gettable_ctx_params(NULL, provctx);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEM_settable_ctx_params(const EVP_KEM *kem)
|
||||
{
|
||||
void *provctx;
|
||||
|
||||
if (kem == NULL || kem->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_KEM_get0_provider(kem));
|
||||
return kem->settable_ctx_params(NULL, provctx);
|
||||
}
|
||||
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
* Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/core_names.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/core.h"
|
||||
#include "internal/provider.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
/*
|
||||
* match_type() checks if two EVP_KEYMGMT are matching key types. This
|
||||
* function assumes that the caller has made all the necessary NULL checks.
|
||||
*/
|
||||
static int match_type(const EVP_KEYMGMT *keymgmt1, const EVP_KEYMGMT *keymgmt2)
|
||||
{
|
||||
const char *name2 = EVP_KEYMGMT_get0_name(keymgmt2);
|
||||
|
||||
return EVP_KEYMGMT_is_a(keymgmt1, name2);
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_try_import(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
struct evp_keymgmt_util_try_import_data_st *data = arg;
|
||||
int delete_on_error = 0;
|
||||
|
||||
/* Just in time creation of keydata */
|
||||
if (data->keydata == NULL) {
|
||||
if ((data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return 0;
|
||||
}
|
||||
delete_on_error = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's fine if there was no data to transfer, we just end up with an
|
||||
* empty destination key.
|
||||
*/
|
||||
if (params[0].key == NULL)
|
||||
return 1;
|
||||
|
||||
if (evp_keymgmt_import(data->keymgmt, data->keydata, data->selection,
|
||||
params))
|
||||
return 1;
|
||||
if (delete_on_error) {
|
||||
evp_keymgmt_freedata(data->keymgmt, data->keydata);
|
||||
data->keydata = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_assign_pkey(EVP_PKEY *pkey, EVP_KEYMGMT *keymgmt,
|
||||
void *keydata)
|
||||
{
|
||||
if (pkey == NULL || keymgmt == NULL || keydata == NULL
|
||||
|| !EVP_PKEY_set_type_by_keymgmt(pkey, keymgmt)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
pkey->keydata = keydata;
|
||||
evp_keymgmt_util_cache_keyinfo(pkey);
|
||||
return 1;
|
||||
}
|
||||
|
||||
EVP_PKEY *evp_keymgmt_util_make_pkey(EVP_KEYMGMT *keymgmt, void *keydata)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
|
||||
if (keymgmt == NULL
|
||||
|| keydata == NULL
|
||||
|| (pkey = EVP_PKEY_new()) == NULL
|
||||
|| !evp_keymgmt_util_assign_pkey(pkey, keymgmt, keydata)) {
|
||||
EVP_PKEY_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
return pkey;
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection,
|
||||
OSSL_CALLBACK *export_cb, void *export_cbarg)
|
||||
{
|
||||
if (pk == NULL || export_cb == NULL)
|
||||
return 0;
|
||||
return evp_keymgmt_export(pk->keymgmt, pk->keydata, selection,
|
||||
export_cb, export_cbarg);
|
||||
}
|
||||
|
||||
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
|
||||
int selection)
|
||||
{
|
||||
struct evp_keymgmt_util_try_import_data_st import_data;
|
||||
OP_CACHE_ELEM *op;
|
||||
|
||||
/* Export to where? */
|
||||
if (keymgmt == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we have an unassigned key, give up */
|
||||
if (pk->keydata == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If |keymgmt| matches the "origin" |keymgmt|, there is no more to do.
|
||||
* The "origin" is determined by the |keymgmt| pointers being identical
|
||||
* or when the provider and the name ID match. The latter case handles the
|
||||
* situation where the fetch cache is flushed and a "new" key manager is
|
||||
* created.
|
||||
*/
|
||||
if (pk->keymgmt == keymgmt
|
||||
|| (pk->keymgmt->name_id == keymgmt->name_id
|
||||
&& pk->keymgmt->prov == keymgmt->prov))
|
||||
return pk->keydata;
|
||||
|
||||
if (!CRYPTO_THREAD_read_lock(pk->lock))
|
||||
return NULL;
|
||||
/*
|
||||
* If the provider native "origin" hasn't changed since last time, we
|
||||
* try to find our keymgmt in the operation cache. If it has changed
|
||||
* and our keymgmt isn't found, we will clear the cache further down.
|
||||
*/
|
||||
if (pk->dirty_cnt == pk->dirty_cnt_copy) {
|
||||
/* If this key is already exported to |keymgmt|, no more to do */
|
||||
op = evp_keymgmt_util_find_operation_cache(pk, keymgmt, selection);
|
||||
if (op != NULL && op->keymgmt != NULL) {
|
||||
void *ret = op->keydata;
|
||||
|
||||
CRYPTO_THREAD_unlock(pk->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
CRYPTO_THREAD_unlock(pk->lock);
|
||||
|
||||
/* If the "origin" |keymgmt| doesn't support exporting, give up */
|
||||
if (pk->keymgmt->export == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Make sure that the type of the keymgmt to export to matches the type
|
||||
* of the "origin"
|
||||
*/
|
||||
if (!ossl_assert(match_type(pk->keymgmt, keymgmt)))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We look at the already cached provider keys, and import from the
|
||||
* first that supports it (i.e. use its export function), and export
|
||||
* the imported data to the new provider.
|
||||
*/
|
||||
|
||||
/* Setup for the export callback */
|
||||
import_data.keydata = NULL; /* evp_keymgmt_util_try_import will create it */
|
||||
import_data.keymgmt = keymgmt;
|
||||
import_data.selection = selection;
|
||||
|
||||
/*
|
||||
* The export function calls the callback (evp_keymgmt_util_try_import),
|
||||
* which does the import for us. If successful, we're done.
|
||||
*/
|
||||
if (!evp_keymgmt_util_export(pk, selection,
|
||||
&evp_keymgmt_util_try_import, &import_data))
|
||||
/* If there was an error, bail out */
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_THREAD_write_lock(pk->lock)) {
|
||||
evp_keymgmt_freedata(keymgmt, import_data.keydata);
|
||||
return NULL;
|
||||
}
|
||||
/* Check to make sure some other thread didn't get there first */
|
||||
op = evp_keymgmt_util_find_operation_cache(pk, keymgmt, selection);
|
||||
if (op != NULL && op->keydata != NULL) {
|
||||
void *ret = op->keydata;
|
||||
|
||||
CRYPTO_THREAD_unlock(pk->lock);
|
||||
|
||||
/*
|
||||
* Another thread seemms to have already exported this so we abandon
|
||||
* all the work we just did.
|
||||
*/
|
||||
evp_keymgmt_freedata(keymgmt, import_data.keydata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the dirty counter changed since last time, then clear the
|
||||
* operation cache. In that case, we know that |i| is zero.
|
||||
*/
|
||||
if (pk->dirty_cnt != pk->dirty_cnt_copy)
|
||||
evp_keymgmt_util_clear_operation_cache(pk);
|
||||
|
||||
/* Add the new export to the operation cache */
|
||||
if (!evp_keymgmt_util_cache_keydata(pk, keymgmt, import_data.keydata,
|
||||
selection)) {
|
||||
CRYPTO_THREAD_unlock(pk->lock);
|
||||
evp_keymgmt_freedata(keymgmt, import_data.keydata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Synchronize the dirty count */
|
||||
pk->dirty_cnt_copy = pk->dirty_cnt;
|
||||
|
||||
CRYPTO_THREAD_unlock(pk->lock);
|
||||
|
||||
return import_data.keydata;
|
||||
}
|
||||
|
||||
static void op_cache_free(OP_CACHE_ELEM *e)
|
||||
{
|
||||
evp_keymgmt_freedata(e->keymgmt, e->keydata);
|
||||
EVP_KEYMGMT_free(e->keymgmt);
|
||||
OPENSSL_free(e);
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk)
|
||||
{
|
||||
if (pk != NULL) {
|
||||
sk_OP_CACHE_ELEM_pop_free(pk->operation_cache, op_cache_free);
|
||||
pk->operation_cache = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk,
|
||||
EVP_KEYMGMT *keymgmt,
|
||||
int selection)
|
||||
{
|
||||
int i, end = sk_OP_CACHE_ELEM_num(pk->operation_cache);
|
||||
OP_CACHE_ELEM *p;
|
||||
|
||||
/*
|
||||
* A comparison and sk_P_CACHE_ELEM_find() are avoided to not cause
|
||||
* problems when we've only a read lock.
|
||||
* A keymgmt is a match if the |keymgmt| pointers are identical or if the
|
||||
* provider and the name ID match
|
||||
*/
|
||||
for (i = 0; i < end; i++) {
|
||||
p = sk_OP_CACHE_ELEM_value(pk->operation_cache, i);
|
||||
if ((p->selection & selection) == selection
|
||||
&& (keymgmt == p->keymgmt
|
||||
|| (keymgmt->name_id == p->keymgmt->name_id
|
||||
&& keymgmt->prov == p->keymgmt->prov)))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
|
||||
void *keydata, int selection)
|
||||
{
|
||||
OP_CACHE_ELEM *p = NULL;
|
||||
|
||||
if (keydata != NULL) {
|
||||
if (pk->operation_cache == NULL) {
|
||||
pk->operation_cache = sk_OP_CACHE_ELEM_new_null();
|
||||
if (pk->operation_cache == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = OPENSSL_malloc(sizeof(*p));
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
p->keydata = keydata;
|
||||
p->keymgmt = keymgmt;
|
||||
p->selection = selection;
|
||||
|
||||
if (!EVP_KEYMGMT_up_ref(keymgmt)) {
|
||||
OPENSSL_free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sk_OP_CACHE_ELEM_push(pk->operation_cache, p)) {
|
||||
EVP_KEYMGMT_free(keymgmt);
|
||||
OPENSSL_free(p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk)
|
||||
{
|
||||
/*
|
||||
* Cache information about the provider "origin" key.
|
||||
*
|
||||
* This services functions like EVP_PKEY_get_size, EVP_PKEY_get_bits, etc
|
||||
*/
|
||||
if (pk->keydata != NULL) {
|
||||
int bits = 0;
|
||||
int security_bits = 0;
|
||||
int size = 0;
|
||||
OSSL_PARAM params[4];
|
||||
|
||||
params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits);
|
||||
params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS,
|
||||
&security_bits);
|
||||
params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size);
|
||||
params[3] = OSSL_PARAM_construct_end();
|
||||
if (evp_keymgmt_get_params(pk->keymgmt, pk->keydata, params)) {
|
||||
pk->cache.size = size;
|
||||
pk->cache.bits = bits;
|
||||
pk->cache.security_bits = security_bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
|
||||
int selection, const OSSL_PARAM params[])
|
||||
{
|
||||
void *keydata = NULL;
|
||||
|
||||
if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL
|
||||
|| !evp_keymgmt_import(keymgmt, keydata, selection, params)
|
||||
|| !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) {
|
||||
evp_keymgmt_freedata(keymgmt, keydata);
|
||||
keydata = NULL;
|
||||
}
|
||||
return keydata;
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_has(EVP_PKEY *pk, int selection)
|
||||
{
|
||||
/* Check if key is even assigned */
|
||||
if (pk->keymgmt == NULL)
|
||||
return 0;
|
||||
|
||||
return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection);
|
||||
}
|
||||
|
||||
/*
|
||||
* evp_keymgmt_util_match() doesn't just look at the provider side "origin",
|
||||
* but also in the operation cache to see if there's any common keymgmt that
|
||||
* supplies OP_keymgmt_match.
|
||||
*
|
||||
* evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_eq()
|
||||
* and EVP_PKEY_parameters_eq() return, i.e.:
|
||||
*
|
||||
* 1 same key
|
||||
* 0 not same key
|
||||
* -1 not same key type
|
||||
* -2 unsupported operation
|
||||
*/
|
||||
int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
|
||||
{
|
||||
EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
|
||||
void *keydata1 = NULL, *keydata2 = NULL;
|
||||
|
||||
if (pk1 == NULL || pk2 == NULL) {
|
||||
if (pk1 == NULL && pk2 == NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
keymgmt1 = pk1->keymgmt;
|
||||
keydata1 = pk1->keydata;
|
||||
keymgmt2 = pk2->keymgmt;
|
||||
keydata2 = pk2->keydata;
|
||||
|
||||
if (keymgmt1 != keymgmt2) {
|
||||
/*
|
||||
* The condition for a successful cross export is that the
|
||||
* keydata to be exported is NULL (typed, but otherwise empty
|
||||
* EVP_PKEY), or that it was possible to export it with
|
||||
* evp_keymgmt_util_export_to_provider().
|
||||
*
|
||||
* We use |ok| to determine if it's ok to cross export one way,
|
||||
* but also to determine if we should attempt a cross export
|
||||
* the other way. There's no point doing it both ways.
|
||||
*/
|
||||
int ok = 0;
|
||||
|
||||
/* Complex case, where the keymgmt differ */
|
||||
if (keymgmt1 != NULL
|
||||
&& keymgmt2 != NULL
|
||||
&& !match_type(keymgmt1, keymgmt2)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
||||
return -1; /* Not the same type */
|
||||
}
|
||||
|
||||
/*
|
||||
* The key types are determined to match, so we try cross export,
|
||||
* but only to keymgmt's that supply a matching function.
|
||||
*/
|
||||
if (keymgmt2 != NULL
|
||||
&& keymgmt2->match != NULL) {
|
||||
void *tmp_keydata = NULL;
|
||||
|
||||
ok = 1;
|
||||
if (keydata1 != NULL) {
|
||||
tmp_keydata =
|
||||
evp_keymgmt_util_export_to_provider(pk1, keymgmt2,
|
||||
selection);
|
||||
ok = (tmp_keydata != NULL);
|
||||
}
|
||||
if (ok) {
|
||||
keymgmt1 = keymgmt2;
|
||||
keydata1 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we've successfully cross exported one way, there's no point
|
||||
* doing it the other way, hence the |!ok| check.
|
||||
*/
|
||||
if (!ok
|
||||
&& keymgmt1 != NULL
|
||||
&& keymgmt1->match != NULL) {
|
||||
void *tmp_keydata = NULL;
|
||||
|
||||
ok = 1;
|
||||
if (keydata2 != NULL) {
|
||||
tmp_keydata =
|
||||
evp_keymgmt_util_export_to_provider(pk2, keymgmt1,
|
||||
selection);
|
||||
ok = (tmp_keydata != NULL);
|
||||
}
|
||||
if (ok) {
|
||||
keymgmt2 = keymgmt1;
|
||||
keydata2 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we still don't have matching keymgmt implementations, we give up */
|
||||
if (keymgmt1 != keymgmt2)
|
||||
return -2;
|
||||
|
||||
/* If both keydata are NULL, then they're the same key */
|
||||
if (keydata1 == NULL && keydata2 == NULL)
|
||||
return 1;
|
||||
/* If only one of the keydata is NULL, then they're different keys */
|
||||
if (keydata1 == NULL || keydata2 == NULL)
|
||||
return 0;
|
||||
/* If both keydata are non-NULL, we let the backend decide */
|
||||
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
|
||||
}
|
||||
|
||||
int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
|
||||
{
|
||||
/* Save copies of pointers we want to play with without affecting |to| */
|
||||
EVP_KEYMGMT *to_keymgmt = to->keymgmt;
|
||||
void *to_keydata = to->keydata, *alloc_keydata = NULL;
|
||||
|
||||
/* An unassigned key can't be copied */
|
||||
if (from == NULL || from->keydata == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If |to| is unassigned, ensure it gets the same KEYMGMT as |from|,
|
||||
* Note that the final setting of KEYMGMT is done further down, with
|
||||
* EVP_PKEY_set_type_by_keymgmt(); we don't want to do that prematurely.
|
||||
*/
|
||||
if (to_keymgmt == NULL)
|
||||
to_keymgmt = from->keymgmt;
|
||||
|
||||
if (to_keymgmt == from->keymgmt && to_keymgmt->dup != NULL
|
||||
&& to_keydata == NULL) {
|
||||
to_keydata = alloc_keydata = evp_keymgmt_dup(to_keymgmt,
|
||||
from->keydata,
|
||||
selection);
|
||||
if (to_keydata == NULL)
|
||||
return 0;
|
||||
} else if (match_type(to_keymgmt, from->keymgmt)) {
|
||||
struct evp_keymgmt_util_try_import_data_st import_data;
|
||||
|
||||
import_data.keymgmt = to_keymgmt;
|
||||
import_data.keydata = to_keydata;
|
||||
import_data.selection = selection;
|
||||
|
||||
if (!evp_keymgmt_util_export(from, selection,
|
||||
&evp_keymgmt_util_try_import,
|
||||
&import_data))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In case to_keydata was previously unallocated,
|
||||
* evp_keymgmt_util_try_import() may have created it for us.
|
||||
*/
|
||||
if (to_keydata == NULL)
|
||||
to_keydata = alloc_keydata = import_data.keydata;
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only need to set the |to| type when its |keymgmt| isn't set.
|
||||
* We can then just set its |keydata| to what we have, which might
|
||||
* be exactly what it had when entering this function.
|
||||
* This is a bit different from using evp_keymgmt_util_assign_pkey(),
|
||||
* which isn't as careful with |to|'s original |keymgmt|, since it's
|
||||
* meant to forcibly reassign an EVP_PKEY no matter what, which is
|
||||
* why we don't use that one here.
|
||||
*/
|
||||
if (to->keymgmt == NULL
|
||||
&& !EVP_PKEY_set_type_by_keymgmt(to, to_keymgmt)) {
|
||||
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
|
||||
return 0;
|
||||
}
|
||||
to->keydata = to_keydata;
|
||||
evp_keymgmt_util_cache_keyinfo(to);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
|
||||
void *genctx, OSSL_CALLBACK *cb, void *cbarg)
|
||||
{
|
||||
void *keydata = NULL;
|
||||
|
||||
if ((keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg)) == NULL
|
||||
|| !evp_keymgmt_util_assign_pkey(target, keymgmt, keydata)) {
|
||||
evp_keymgmt_freedata(keymgmt, keydata);
|
||||
keydata = NULL;
|
||||
}
|
||||
|
||||
return keydata;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the same numbers as EVP_PKEY_get_default_digest_name()
|
||||
* When the string from the EVP_KEYMGMT implementation is "", we use
|
||||
* SN_undef, since that corresponds to what EVP_PKEY_get_default_nid()
|
||||
* returns for no digest.
|
||||
*/
|
||||
int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt,
|
||||
void *keydata,
|
||||
char *mdname, size_t mdname_sz)
|
||||
{
|
||||
OSSL_PARAM params[3];
|
||||
char mddefault[100] = "";
|
||||
char mdmandatory[100] = "";
|
||||
char *result = NULL;
|
||||
int rv = -2;
|
||||
|
||||
params[0] =
|
||||
OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST,
|
||||
mddefault, sizeof(mddefault));
|
||||
params[1] =
|
||||
OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST,
|
||||
mdmandatory,
|
||||
sizeof(mdmandatory));
|
||||
params[2] = OSSL_PARAM_construct_end();
|
||||
|
||||
if (!evp_keymgmt_get_params(keymgmt, keydata, params))
|
||||
return 0;
|
||||
|
||||
if (OSSL_PARAM_modified(params + 1)) {
|
||||
if (params[1].return_size <= 1) /* Only a NUL byte */
|
||||
result = SN_undef;
|
||||
else
|
||||
result = mdmandatory;
|
||||
rv = 2;
|
||||
} else if (OSSL_PARAM_modified(params)) {
|
||||
if (params[0].return_size <= 1) /* Only a NUL byte */
|
||||
result = SN_undef;
|
||||
else
|
||||
result = mddefault;
|
||||
rv = 1;
|
||||
}
|
||||
if (rv > 0)
|
||||
OPENSSL_strlcpy(mdname, result, mdname_sz);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* If |keymgmt| has the method function |query_operation_name|, use it to get
|
||||
* the name of a supported operation identity. Otherwise, return the keytype,
|
||||
* assuming that it works as a default operation name.
|
||||
*/
|
||||
const char *evp_keymgmt_util_query_operation_name(EVP_KEYMGMT *keymgmt,
|
||||
int op_id)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
if (keymgmt != NULL) {
|
||||
if (keymgmt->query_operation_name != NULL)
|
||||
name = keymgmt->query_operation_name(op_id);
|
||||
if (name == NULL)
|
||||
name = EVP_KEYMGMT_get0_name(keymgmt);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/provider.h"
|
||||
#include "internal/refcount.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static void evp_keymgmt_free(void *data)
|
||||
{
|
||||
EVP_KEYMGMT_free(data);
|
||||
}
|
||||
|
||||
static int evp_keymgmt_up_ref(void *data)
|
||||
{
|
||||
return EVP_KEYMGMT_up_ref(data);
|
||||
}
|
||||
|
||||
static void *keymgmt_new(void)
|
||||
{
|
||||
EVP_KEYMGMT *keymgmt = NULL;
|
||||
|
||||
if ((keymgmt = OPENSSL_zalloc(sizeof(*keymgmt))) == NULL)
|
||||
return NULL;
|
||||
if (!CRYPTO_NEW_REF(&keymgmt->refcnt, 1)) {
|
||||
EVP_KEYMGMT_free(keymgmt);
|
||||
return NULL;
|
||||
}
|
||||
return keymgmt;
|
||||
}
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
static void help_get_legacy_alg_type_from_keymgmt(const char *keytype,
|
||||
void *arg)
|
||||
{
|
||||
int *type = arg;
|
||||
|
||||
if (*type == NID_undef)
|
||||
*type = evp_pkey_name2type(keytype);
|
||||
}
|
||||
|
||||
static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
int type = NID_undef;
|
||||
|
||||
EVP_KEYMGMT_names_do_all(keymgmt, help_get_legacy_alg_type_from_keymgmt,
|
||||
&type);
|
||||
return type;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *keymgmt_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_KEYMGMT *keymgmt = NULL;
|
||||
int setparamfncnt = 0, getparamfncnt = 0;
|
||||
int setgenparamfncnt = 0;
|
||||
int importfncnt = 0, exportfncnt = 0;
|
||||
int importtypesfncnt = 0, exporttypesfncnt = 0;
|
||||
int getgenparamfncnt = 0;
|
||||
|
||||
if ((keymgmt = keymgmt_new()) == NULL)
|
||||
return NULL;
|
||||
|
||||
keymgmt->name_id = name_id;
|
||||
if ((keymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
|
||||
EVP_KEYMGMT_free(keymgmt);
|
||||
return NULL;
|
||||
}
|
||||
keymgmt->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_KEYMGMT_NEW:
|
||||
if (keymgmt->new == NULL)
|
||||
keymgmt->new = OSSL_FUNC_keymgmt_new(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_INIT:
|
||||
if (keymgmt->gen_init == NULL)
|
||||
keymgmt->gen_init = OSSL_FUNC_keymgmt_gen_init(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE:
|
||||
if (keymgmt->gen_set_template == NULL)
|
||||
keymgmt->gen_set_template =
|
||||
OSSL_FUNC_keymgmt_gen_set_template(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS:
|
||||
if (keymgmt->gen_set_params == NULL) {
|
||||
setgenparamfncnt++;
|
||||
keymgmt->gen_set_params =
|
||||
OSSL_FUNC_keymgmt_gen_set_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS:
|
||||
if (keymgmt->gen_settable_params == NULL) {
|
||||
setgenparamfncnt++;
|
||||
keymgmt->gen_settable_params =
|
||||
OSSL_FUNC_keymgmt_gen_settable_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_GET_PARAMS:
|
||||
if (keymgmt->gen_get_params == NULL) {
|
||||
getgenparamfncnt++;
|
||||
keymgmt->gen_get_params =
|
||||
OSSL_FUNC_keymgmt_gen_get_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_GETTABLE_PARAMS:
|
||||
if (keymgmt->gen_gettable_params == NULL) {
|
||||
getgenparamfncnt++;
|
||||
keymgmt->gen_gettable_params =
|
||||
OSSL_FUNC_keymgmt_gen_gettable_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN:
|
||||
if (keymgmt->gen == NULL)
|
||||
keymgmt->gen = OSSL_FUNC_keymgmt_gen(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GEN_CLEANUP:
|
||||
if (keymgmt->gen_cleanup == NULL)
|
||||
keymgmt->gen_cleanup = OSSL_FUNC_keymgmt_gen_cleanup(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_FREE:
|
||||
if (keymgmt->free == NULL)
|
||||
keymgmt->free = OSSL_FUNC_keymgmt_free(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_LOAD:
|
||||
if (keymgmt->load == NULL)
|
||||
keymgmt->load = OSSL_FUNC_keymgmt_load(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GET_PARAMS:
|
||||
if (keymgmt->get_params == NULL) {
|
||||
getparamfncnt++;
|
||||
keymgmt->get_params = OSSL_FUNC_keymgmt_get_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS:
|
||||
if (keymgmt->gettable_params == NULL) {
|
||||
getparamfncnt++;
|
||||
keymgmt->gettable_params =
|
||||
OSSL_FUNC_keymgmt_gettable_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_SET_PARAMS:
|
||||
if (keymgmt->set_params == NULL) {
|
||||
setparamfncnt++;
|
||||
keymgmt->set_params = OSSL_FUNC_keymgmt_set_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS:
|
||||
if (keymgmt->settable_params == NULL) {
|
||||
setparamfncnt++;
|
||||
keymgmt->settable_params =
|
||||
OSSL_FUNC_keymgmt_settable_params(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME:
|
||||
if (keymgmt->query_operation_name == NULL)
|
||||
keymgmt->query_operation_name =
|
||||
OSSL_FUNC_keymgmt_query_operation_name(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_HAS:
|
||||
if (keymgmt->has == NULL)
|
||||
keymgmt->has = OSSL_FUNC_keymgmt_has(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_DUP:
|
||||
if (keymgmt->dup == NULL)
|
||||
keymgmt->dup = OSSL_FUNC_keymgmt_dup(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_VALIDATE:
|
||||
if (keymgmt->validate == NULL)
|
||||
keymgmt->validate = OSSL_FUNC_keymgmt_validate(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_MATCH:
|
||||
if (keymgmt->match == NULL)
|
||||
keymgmt->match = OSSL_FUNC_keymgmt_match(fns);
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_IMPORT:
|
||||
if (keymgmt->import == NULL) {
|
||||
importfncnt++;
|
||||
keymgmt->import = OSSL_FUNC_keymgmt_import(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_IMPORT_TYPES:
|
||||
if (keymgmt->import_types == NULL) {
|
||||
if (importtypesfncnt == 0)
|
||||
importfncnt++;
|
||||
importtypesfncnt++;
|
||||
keymgmt->import_types = OSSL_FUNC_keymgmt_import_types(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_IMPORT_TYPES_EX:
|
||||
if (keymgmt->import_types_ex == NULL) {
|
||||
if (importtypesfncnt == 0)
|
||||
importfncnt++;
|
||||
importtypesfncnt++;
|
||||
keymgmt->import_types_ex = OSSL_FUNC_keymgmt_import_types_ex(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_EXPORT:
|
||||
if (keymgmt->export == NULL) {
|
||||
exportfncnt++;
|
||||
keymgmt->export = OSSL_FUNC_keymgmt_export(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_EXPORT_TYPES:
|
||||
if (keymgmt->export_types == NULL) {
|
||||
if (exporttypesfncnt == 0)
|
||||
exportfncnt++;
|
||||
exporttypesfncnt++;
|
||||
keymgmt->export_types = OSSL_FUNC_keymgmt_export_types(fns);
|
||||
}
|
||||
break;
|
||||
case OSSL_FUNC_KEYMGMT_EXPORT_TYPES_EX:
|
||||
if (keymgmt->export_types_ex == NULL) {
|
||||
if (exporttypesfncnt == 0)
|
||||
exportfncnt++;
|
||||
exporttypesfncnt++;
|
||||
keymgmt->export_types_ex = OSSL_FUNC_keymgmt_export_types_ex(fns);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Try to check that the method is sensible.
|
||||
* At least one constructor and the destructor are MANDATORY
|
||||
* The functions 'has' is MANDATORY
|
||||
* It makes no sense being able to free stuff if you can't create it.
|
||||
* It makes no sense providing OSSL_PARAM descriptors for import and
|
||||
* export if you can't import or export.
|
||||
*/
|
||||
if (keymgmt->free == NULL
|
||||
|| (keymgmt->new == NULL
|
||||
&& keymgmt->gen == NULL
|
||||
&& keymgmt->load == NULL)
|
||||
|| keymgmt->has == NULL
|
||||
|| (getparamfncnt != 0 && getparamfncnt != 2)
|
||||
|| (setparamfncnt != 0 && setparamfncnt != 2)
|
||||
|| (setgenparamfncnt != 0 && setgenparamfncnt != 2)
|
||||
|| (getgenparamfncnt != 0 && getgenparamfncnt != 2)
|
||||
|| (importfncnt != 0 && importfncnt != 2)
|
||||
|| (exportfncnt != 0 && exportfncnt != 2)
|
||||
|| (keymgmt->gen != NULL
|
||||
&& (keymgmt->gen_init == NULL
|
||||
|| keymgmt->gen_cleanup == NULL))) {
|
||||
EVP_KEYMGMT_free(keymgmt);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
return NULL;
|
||||
}
|
||||
keymgmt->prov = prov;
|
||||
if (prov != NULL)
|
||||
ossl_provider_up_ref(prov);
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
keymgmt->legacy_alg = get_legacy_alg_type_from_keymgmt(keymgmt);
|
||||
#endif
|
||||
|
||||
return keymgmt;
|
||||
}
|
||||
|
||||
EVP_KEYMGMT *evp_keymgmt_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov, OSSL_OP_KEYMGMT,
|
||||
name, properties,
|
||||
keymgmt_from_algorithm,
|
||||
evp_keymgmt_up_ref,
|
||||
evp_keymgmt_free);
|
||||
}
|
||||
|
||||
EVP_KEYMGMT *EVP_KEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_KEYMGMT, algorithm, properties,
|
||||
keymgmt_from_algorithm,
|
||||
evp_keymgmt_up_ref,
|
||||
evp_keymgmt_free);
|
||||
}
|
||||
|
||||
int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&keymgmt->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
if (keymgmt == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
OPENSSL_free(keymgmt->type_name);
|
||||
ossl_provider_free(keymgmt->prov);
|
||||
CRYPTO_FREE_REF(&keymgmt->refcnt);
|
||||
OPENSSL_free(keymgmt);
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_KEYMGMT_get0_provider(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt->prov;
|
||||
}
|
||||
|
||||
int evp_keymgmt_get_number(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt->name_id;
|
||||
}
|
||||
|
||||
int evp_keymgmt_get_legacy_alg(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt->legacy_alg;
|
||||
}
|
||||
|
||||
const char *EVP_KEYMGMT_get0_description(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt->description;
|
||||
}
|
||||
|
||||
const char *EVP_KEYMGMT_get0_name(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt->type_name;
|
||||
}
|
||||
|
||||
int EVP_KEYMGMT_is_a(const EVP_KEYMGMT *keymgmt, const char *name)
|
||||
{
|
||||
return keymgmt != NULL
|
||||
&& evp_is_a(keymgmt->prov, keymgmt->name_id, NULL, name);
|
||||
}
|
||||
|
||||
void EVP_KEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_KEYMGMT *keymgmt, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_KEYMGMT,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
keymgmt_from_algorithm,
|
||||
evp_keymgmt_up_ref,
|
||||
evp_keymgmt_free);
|
||||
}
|
||||
|
||||
int EVP_KEYMGMT_names_do_all(const EVP_KEYMGMT *keymgmt,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (keymgmt->prov != NULL)
|
||||
return evp_names_do_all(keymgmt->prov, keymgmt->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal API that interfaces with the method function pointers
|
||||
*/
|
||||
void *evp_keymgmt_newdata(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
/*
|
||||
* 'new' is currently mandatory on its own, but when new
|
||||
* constructors appear, it won't be quite as mandatory,
|
||||
* so we have a check for future cases.
|
||||
*/
|
||||
if (keymgmt->new == NULL)
|
||||
return NULL;
|
||||
return keymgmt->new(provctx);
|
||||
}
|
||||
|
||||
void evp_keymgmt_freedata(const EVP_KEYMGMT *keymgmt, void *keydata)
|
||||
{
|
||||
/* This is mandatory, no need to check for its presence */
|
||||
keymgmt->free(keydata);
|
||||
}
|
||||
|
||||
void *evp_keymgmt_gen_init(const EVP_KEYMGMT *keymgmt, int selection,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->gen_init == NULL)
|
||||
return NULL;
|
||||
return keymgmt->gen_init(provctx, selection, params);
|
||||
}
|
||||
|
||||
int evp_keymgmt_gen_set_template(const EVP_KEYMGMT *keymgmt, void *genctx,
|
||||
void *templ)
|
||||
{
|
||||
/*
|
||||
* It's arguable if we actually should return success in this case, as
|
||||
* it allows the caller to set a template key, which is then ignored.
|
||||
* However, this is how the legacy methods (EVP_PKEY_METHOD) operate,
|
||||
* so we do this in the interest of backward compatibility.
|
||||
*/
|
||||
if (keymgmt->gen_set_template == NULL)
|
||||
return 1;
|
||||
return keymgmt->gen_set_template(genctx, templ);
|
||||
}
|
||||
|
||||
int evp_keymgmt_gen_set_params(const EVP_KEYMGMT *keymgmt, void *genctx,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (keymgmt->gen_set_params == NULL)
|
||||
return 0;
|
||||
return keymgmt->gen_set_params(genctx, params);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYMGMT_gen_settable_params(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->gen_settable_params == NULL)
|
||||
return NULL;
|
||||
return keymgmt->gen_settable_params(NULL, provctx);
|
||||
}
|
||||
|
||||
int evp_keymgmt_gen_get_params(const EVP_KEYMGMT *keymgmt, void *genctx,
|
||||
OSSL_PARAM params[])
|
||||
{
|
||||
if (keymgmt->gen_get_params == NULL)
|
||||
return 0;
|
||||
return keymgmt->gen_get_params(genctx, params);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYMGMT_gen_gettable_params(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->gen_gettable_params == NULL)
|
||||
return NULL;
|
||||
return keymgmt->gen_gettable_params(NULL, provctx);
|
||||
}
|
||||
|
||||
void *evp_keymgmt_gen(const EVP_KEYMGMT *keymgmt, void *genctx,
|
||||
OSSL_CALLBACK *cb, void *cbarg)
|
||||
{
|
||||
if (keymgmt->gen == NULL)
|
||||
return NULL;
|
||||
return keymgmt->gen(genctx, cb, cbarg);
|
||||
}
|
||||
|
||||
void evp_keymgmt_gen_cleanup(const EVP_KEYMGMT *keymgmt, void *genctx)
|
||||
{
|
||||
if (keymgmt->gen_cleanup != NULL)
|
||||
keymgmt->gen_cleanup(genctx);
|
||||
}
|
||||
|
||||
int evp_keymgmt_has_load(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
return keymgmt != NULL && keymgmt->load != NULL;
|
||||
}
|
||||
|
||||
void *evp_keymgmt_load(const EVP_KEYMGMT *keymgmt,
|
||||
const void *objref, size_t objref_sz)
|
||||
{
|
||||
if (evp_keymgmt_has_load(keymgmt))
|
||||
return keymgmt->load(objref, objref_sz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int evp_keymgmt_get_params(const EVP_KEYMGMT *keymgmt, void *keydata,
|
||||
OSSL_PARAM params[])
|
||||
{
|
||||
if (keymgmt->get_params == NULL)
|
||||
return 1;
|
||||
return keymgmt->get_params(keydata, params);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYMGMT_gettable_params(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->gettable_params == NULL)
|
||||
return NULL;
|
||||
return keymgmt->gettable_params(provctx);
|
||||
}
|
||||
|
||||
int evp_keymgmt_set_params(const EVP_KEYMGMT *keymgmt, void *keydata,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (keymgmt->set_params == NULL)
|
||||
return 1;
|
||||
return keymgmt->set_params(keydata, params);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_KEYMGMT_settable_params(const EVP_KEYMGMT *keymgmt)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->settable_params == NULL)
|
||||
return NULL;
|
||||
return keymgmt->settable_params(provctx);
|
||||
}
|
||||
|
||||
int evp_keymgmt_has(const EVP_KEYMGMT *keymgmt, void *keydata, int selection)
|
||||
{
|
||||
/* This is mandatory, no need to check for its presence */
|
||||
return keymgmt->has(keydata, selection);
|
||||
}
|
||||
|
||||
int evp_keymgmt_validate(const EVP_KEYMGMT *keymgmt, void *keydata,
|
||||
int selection, int checktype)
|
||||
{
|
||||
/* We assume valid if the implementation doesn't have a function */
|
||||
if (keymgmt->validate == NULL)
|
||||
return 1;
|
||||
return keymgmt->validate(keydata, selection, checktype);
|
||||
}
|
||||
|
||||
int evp_keymgmt_match(const EVP_KEYMGMT *keymgmt,
|
||||
const void *keydata1, const void *keydata2,
|
||||
int selection)
|
||||
{
|
||||
/* We assume no match if the implementation doesn't have a function */
|
||||
if (keymgmt->match == NULL)
|
||||
return 0;
|
||||
return keymgmt->match(keydata1, keydata2, selection);
|
||||
}
|
||||
|
||||
int evp_keymgmt_import(const EVP_KEYMGMT *keymgmt, void *keydata,
|
||||
int selection, const OSSL_PARAM params[])
|
||||
{
|
||||
if (keymgmt->import == NULL)
|
||||
return 0;
|
||||
return keymgmt->import(keydata, selection, params);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *evp_keymgmt_import_types(const EVP_KEYMGMT *keymgmt,
|
||||
int selection)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->import_types_ex != NULL)
|
||||
return keymgmt->import_types_ex(provctx, selection);
|
||||
if (keymgmt->import_types == NULL)
|
||||
return NULL;
|
||||
return keymgmt->import_types(selection);
|
||||
}
|
||||
|
||||
int evp_keymgmt_export(const EVP_KEYMGMT *keymgmt, void *keydata,
|
||||
int selection, OSSL_CALLBACK *param_cb, void *cbarg)
|
||||
{
|
||||
if (keymgmt->export == NULL)
|
||||
return 0;
|
||||
return keymgmt->export(keydata, selection, param_cb, cbarg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *evp_keymgmt_export_types(const EVP_KEYMGMT *keymgmt,
|
||||
int selection)
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_KEYMGMT_get0_provider(keymgmt));
|
||||
|
||||
if (keymgmt->export_types_ex != NULL)
|
||||
return keymgmt->export_types_ex(provctx, selection);
|
||||
if (keymgmt->export_types == NULL)
|
||||
return NULL;
|
||||
return keymgmt->export_types(selection);
|
||||
}
|
||||
|
||||
void *evp_keymgmt_dup(const EVP_KEYMGMT *keymgmt, const void *keydata_from,
|
||||
int selection)
|
||||
{
|
||||
/* We assume no dup if the implementation doesn't have a function */
|
||||
if (keymgmt->dup == NULL)
|
||||
return NULL;
|
||||
return keymgmt->dup(keydata_from, selection);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "crypto/evp.h"
|
||||
#include "prov/blake2.h" /* diverse BLAKE2 macros */
|
||||
#include "legacy_meth.h"
|
||||
|
||||
/*
|
||||
* Local hack to adapt the BLAKE2 init functions to what the
|
||||
* legacy function signatures demand.
|
||||
*/
|
||||
static int blake2s_init(BLAKE2S_CTX *C)
|
||||
{
|
||||
BLAKE2S_PARAM P;
|
||||
|
||||
ossl_blake2s_param_init(&P);
|
||||
return ossl_blake2s_init(C, &P);
|
||||
}
|
||||
static int blake2b_init(BLAKE2B_CTX *C)
|
||||
{
|
||||
BLAKE2B_PARAM P;
|
||||
|
||||
ossl_blake2b_param_init(&P);
|
||||
return ossl_blake2b_init(C, &P);
|
||||
}
|
||||
#define blake2s_update ossl_blake2s_update
|
||||
#define blake2b_update ossl_blake2b_update
|
||||
#define blake2s_final ossl_blake2s_final
|
||||
#define blake2b_final ossl_blake2b_final
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH_LC(blake2s_int, blake2s)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH_LC(blake2b_int, blake2b)
|
||||
|
||||
static const EVP_MD blake2b_md = {
|
||||
NID_blake2b512,
|
||||
0,
|
||||
BLAKE2B_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(blake2b_int_init, blake2b_int_update,
|
||||
blake2b_int_final, NULL, BLAKE2B_BLOCKBYTES),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_blake2b512(void)
|
||||
{
|
||||
return &blake2b_md;
|
||||
}
|
||||
|
||||
static const EVP_MD blake2s_md = {
|
||||
NID_blake2s256,
|
||||
0,
|
||||
BLAKE2S_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(blake2s_int_init, blake2s_int_update,
|
||||
blake2s_int_final, NULL, BLAKE2S_BLOCKBYTES),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_blake2s256(void)
|
||||
{
|
||||
return &blake2s_md;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD2 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/md2.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(md2, MD2)
|
||||
|
||||
static const EVP_MD md2_md = {
|
||||
NID_md2,
|
||||
NID_md2WithRSAEncryption,
|
||||
MD2_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(md2_init, md2_update, md2_final, NULL, MD2_BLOCK)
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_md2(void)
|
||||
{
|
||||
return &md2_md;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD4 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/md4.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(md4, MD4)
|
||||
|
||||
static const EVP_MD md4_md = {
|
||||
NID_md4,
|
||||
NID_md4WithRSAEncryption,
|
||||
MD4_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(md4_init, md4_update, md4_final, NULL, MD4_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_md4(void)
|
||||
{
|
||||
return &md4_md;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD5 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(md5, MD5)
|
||||
|
||||
static const EVP_MD md5_md = {
|
||||
NID_md5,
|
||||
NID_md5WithRSAEncryption,
|
||||
MD5_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(md5_init, md5_update, md5_final, NULL, MD5_CBLOCK)
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_md5(void)
|
||||
{
|
||||
return &md5_md;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD5 and SHA-1 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use. The prov/md5_sha1.h include requires this, but this must
|
||||
* be the first include loaded.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "crypto/evp.h"
|
||||
#include "prov/md5_sha1.h" /* diverse MD5_SHA1 macros */
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH_LC(md5_sha1_int, ossl_md5_sha1)
|
||||
static int md5_sha1_int_ctrl(EVP_MD_CTX *ctx, int cmd, int mslen, void *ms)
|
||||
{
|
||||
return ossl_md5_sha1_ctrl(EVP_MD_CTX_get0_md_data(ctx), cmd, mslen, ms);
|
||||
}
|
||||
|
||||
static const EVP_MD md5_sha1_md = {
|
||||
NID_md5_sha1,
|
||||
NID_md5_sha1,
|
||||
MD5_SHA1_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(md5_sha1_int_init, md5_sha1_int_update,
|
||||
md5_sha1_int_final, md5_sha1_int_ctrl,
|
||||
MD5_SHA1_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_md5_sha1(void)
|
||||
{
|
||||
return &md5_sha1_md;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* MDC2 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/mdc2.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(mdc2, MDC2)
|
||||
|
||||
static const EVP_MD mdc2_md = {
|
||||
NID_mdc2,
|
||||
NID_mdc2WithRSA,
|
||||
MDC2_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(mdc2_init, mdc2_update, mdc2_final, NULL,
|
||||
MDC2_BLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_mdc2(void)
|
||||
{
|
||||
return &mdc2_md;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#define IMPLEMENT_LEGACY_EVP_MD_METH(nm, fn) \
|
||||
static int nm##_init(EVP_MD_CTX *ctx) \
|
||||
{ \
|
||||
return fn##_Init(EVP_MD_CTX_get0_md_data(ctx)); \
|
||||
} \
|
||||
static int nm##_update(EVP_MD_CTX *ctx, const void *data, size_t count) \
|
||||
{ \
|
||||
return fn##_Update(EVP_MD_CTX_get0_md_data(ctx), data, count); \
|
||||
} \
|
||||
static int nm##_final(EVP_MD_CTX *ctx, unsigned char *md) \
|
||||
{ \
|
||||
return fn##_Final(md, EVP_MD_CTX_get0_md_data(ctx)); \
|
||||
}
|
||||
|
||||
#define IMPLEMENT_LEGACY_EVP_MD_METH_LC(nm, fn) \
|
||||
static int nm##_init(EVP_MD_CTX *ctx) \
|
||||
{ \
|
||||
return fn##_init(EVP_MD_CTX_get0_md_data(ctx)); \
|
||||
} \
|
||||
static int nm##_update(EVP_MD_CTX *ctx, const void *data, size_t count) \
|
||||
{ \
|
||||
return fn##_update(EVP_MD_CTX_get0_md_data(ctx), data, count); \
|
||||
} \
|
||||
static int nm##_final(EVP_MD_CTX *ctx, unsigned char *md) \
|
||||
{ \
|
||||
return fn##_final(md, EVP_MD_CTX_get0_md_data(ctx)); \
|
||||
}
|
||||
|
||||
|
||||
#define LEGACY_EVP_MD_METH_TABLE(init, update, final, ctrl, blksz) \
|
||||
init, update, final, NULL, NULL, blksz, 0, ctrl
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* RIPEMD160 low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/ripemd.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(ripe, RIPEMD160)
|
||||
|
||||
static const EVP_MD ripemd160_md = {
|
||||
NID_ripemd160,
|
||||
NID_ripemd160WithRSA,
|
||||
RIPEMD160_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(ripe_init, ripe_update, ripe_final, NULL,
|
||||
RIPEMD160_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_ripemd160(void)
|
||||
{
|
||||
return &ripemd160_md;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* All SHA low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/sha.h> /* diverse SHA macros */
|
||||
#include "internal/sha3.h" /* KECCAK1600_WIDTH */
|
||||
#include "crypto/evp.h"
|
||||
/* Used by legacy methods */
|
||||
#include "crypto/sha.h"
|
||||
#include "legacy_meth.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
/*-
|
||||
* LEGACY methods for SHA.
|
||||
* These only remain to support engines that can get these methods.
|
||||
* Hardware support for SHA3 has been removed from these legacy cases.
|
||||
*/
|
||||
#define IMPLEMENT_LEGACY_EVP_MD_METH_SHA3(nm, fn, tag) \
|
||||
static int nm##_init(EVP_MD_CTX *ctx) \
|
||||
{ \
|
||||
return fn##_init(EVP_MD_CTX_get0_md_data(ctx), tag, ctx->digest->md_size * 8); \
|
||||
} \
|
||||
static int nm##_update(EVP_MD_CTX *ctx, const void *data, size_t count) \
|
||||
{ \
|
||||
return fn##_update(EVP_MD_CTX_get0_md_data(ctx), data, count); \
|
||||
} \
|
||||
static int nm##_final(EVP_MD_CTX *ctx, unsigned char *md) \
|
||||
{ \
|
||||
KECCAK1600_CTX *kctx = EVP_MD_CTX_get0_md_data(ctx); \
|
||||
return fn##_final(kctx, md, kctx->md_size); \
|
||||
}
|
||||
#define IMPLEMENT_LEGACY_EVP_MD_METH_SHAKE(nm, fn, tag) \
|
||||
static int nm##_init(EVP_MD_CTX *ctx) \
|
||||
{ \
|
||||
return fn##_init(EVP_MD_CTX_get0_md_data(ctx), tag, ctx->digest->md_size * 8); \
|
||||
} \
|
||||
|
||||
#define sha512_224_Init sha512_224_init
|
||||
#define sha512_256_Init sha512_256_init
|
||||
|
||||
#define sha512_224_Update SHA512_Update
|
||||
#define sha512_224_Final SHA512_Final
|
||||
#define sha512_256_Update SHA512_Update
|
||||
#define sha512_256_Final SHA512_Final
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha1, SHA1)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha224, SHA224)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha256, SHA256)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha384, SHA384)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha512, SHA512)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha512_224_int, sha512_224)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(sha512_256_int, sha512_256)
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH_SHA3(sha3_int, ossl_sha3, '\x06')
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH_SHAKE(shake, ossl_sha3, '\x1f')
|
||||
|
||||
static int sha1_int_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
|
||||
{
|
||||
return ossl_sha1_ctrl(ctx != NULL ? EVP_MD_CTX_get0_md_data(ctx) : NULL,
|
||||
cmd, p1, p2);
|
||||
}
|
||||
|
||||
static int shake_ctrl(EVP_MD_CTX *evp_ctx, int cmd, int p1, void *p2)
|
||||
{
|
||||
KECCAK1600_CTX *ctx;
|
||||
|
||||
if (evp_ctx == NULL)
|
||||
return 0;
|
||||
ctx = evp_ctx->md_data;
|
||||
|
||||
switch (cmd) {
|
||||
case EVP_MD_CTRL_XOF_LEN:
|
||||
ctx->md_size = p1;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const EVP_MD sha1_md = {
|
||||
NID_sha1,
|
||||
NID_sha1WithRSAEncryption,
|
||||
SHA_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha1_init, sha1_update, sha1_final, sha1_int_ctrl,
|
||||
SHA_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha1(void)
|
||||
{
|
||||
return &sha1_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha224_md = {
|
||||
NID_sha224,
|
||||
NID_sha224WithRSAEncryption,
|
||||
SHA224_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha224_init, sha224_update, sha224_final, NULL,
|
||||
SHA256_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha224(void)
|
||||
{
|
||||
return &sha224_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha256_md = {
|
||||
NID_sha256,
|
||||
NID_sha256WithRSAEncryption,
|
||||
SHA256_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha256_init, sha256_update, sha256_final, NULL,
|
||||
SHA256_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha256(void)
|
||||
{
|
||||
return &sha256_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha512_224_md = {
|
||||
NID_sha512_224,
|
||||
NID_sha512_224WithRSAEncryption,
|
||||
SHA224_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha512_224_int_init, sha512_224_int_update,
|
||||
sha512_224_int_final, NULL, SHA512_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha512_224(void)
|
||||
{
|
||||
return &sha512_224_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha512_256_md = {
|
||||
NID_sha512_256,
|
||||
NID_sha512_256WithRSAEncryption,
|
||||
SHA256_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha512_256_int_init, sha512_256_int_update,
|
||||
sha512_256_int_final, NULL, SHA512_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha512_256(void)
|
||||
{
|
||||
return &sha512_256_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha384_md = {
|
||||
NID_sha384,
|
||||
NID_sha384WithRSAEncryption,
|
||||
SHA384_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha384_init, sha384_update, sha384_final, NULL,
|
||||
SHA512_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha384(void)
|
||||
{
|
||||
return &sha384_md;
|
||||
}
|
||||
|
||||
static const EVP_MD sha512_md = {
|
||||
NID_sha512,
|
||||
NID_sha512WithRSAEncryption,
|
||||
SHA512_DIGEST_LENGTH,
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(sha512_init, sha512_update, sha512_final, NULL,
|
||||
SHA512_CBLOCK),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_sha512(void)
|
||||
{
|
||||
return &sha512_md;
|
||||
}
|
||||
|
||||
#define EVP_MD_SHA3(bitlen) \
|
||||
const EVP_MD *EVP_sha3_##bitlen(void) \
|
||||
{ \
|
||||
static const EVP_MD sha3_##bitlen##_md = { \
|
||||
NID_sha3_##bitlen, \
|
||||
NID_RSA_SHA3_##bitlen, \
|
||||
bitlen / 8, \
|
||||
EVP_MD_FLAG_DIGALGID_ABSENT, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
LEGACY_EVP_MD_METH_TABLE(sha3_int_init, sha3_int_update, \
|
||||
sha3_int_final, NULL, \
|
||||
(KECCAK1600_WIDTH - bitlen * 2) / 8), \
|
||||
}; \
|
||||
return &sha3_##bitlen##_md; \
|
||||
}
|
||||
#define EVP_MD_SHAKE(bitlen) \
|
||||
const EVP_MD *EVP_shake##bitlen(void) \
|
||||
{ \
|
||||
static const EVP_MD shake##bitlen##_md = { \
|
||||
NID_shake##bitlen, \
|
||||
0, \
|
||||
bitlen / 8, \
|
||||
EVP_MD_FLAG_XOF, \
|
||||
EVP_ORIG_GLOBAL, \
|
||||
LEGACY_EVP_MD_METH_TABLE(shake_init, sha3_int_update, sha3_int_final, \
|
||||
shake_ctrl, (KECCAK1600_WIDTH - bitlen * 2) / 8), \
|
||||
}; \
|
||||
return &shake##bitlen##_md; \
|
||||
}
|
||||
|
||||
EVP_MD_SHA3(224)
|
||||
EVP_MD_SHA3(256)
|
||||
EVP_MD_SHA3(384)
|
||||
EVP_MD_SHA3(512)
|
||||
|
||||
EVP_MD_SHAKE(128)
|
||||
EVP_MD_SHAKE(256)
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Whirlpool low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/whrlpool.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "legacy_meth.h"
|
||||
|
||||
IMPLEMENT_LEGACY_EVP_MD_METH(wp, WHIRLPOOL)
|
||||
|
||||
static const EVP_MD whirlpool_md = {
|
||||
NID_whirlpool,
|
||||
0,
|
||||
WHIRLPOOL_DIGEST_LENGTH,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
LEGACY_EVP_MD_METH_TABLE(wp_init, wp_update, wp_final, NULL,
|
||||
WHIRLPOOL_BBLOCK / 8),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_whirlpool(void)
|
||||
{
|
||||
return &whirlpool_md;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
static int init(EVP_MD_CTX *ctx)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int update(EVP_MD_CTX *ctx, const void *data, size_t count)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int final(EVP_MD_CTX *ctx, unsigned char *md)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const EVP_MD null_md = {
|
||||
NID_undef,
|
||||
NID_undef,
|
||||
0,
|
||||
0,
|
||||
EVP_ORIG_GLOBAL,
|
||||
init,
|
||||
update,
|
||||
final,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
sizeof(EVP_MD *),
|
||||
};
|
||||
|
||||
const EVP_MD *EVP_md_null(void)
|
||||
{
|
||||
return &null_md;
|
||||
}
|
||||
@@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Copyright 2006-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/numbers.h" /* includes SIZE_MAX */
|
||||
#include "evp_local.h"
|
||||
|
||||
static int update(EVP_MD_CTX *ctx, const void *data, size_t datalen)
|
||||
{
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_ONLY_ONESHOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get the "NULL" md then the name comes back as "UNDEF". We want to use
|
||||
* NULL for this.
|
||||
*/
|
||||
static const char *canon_mdname(const char *mdname)
|
||||
{
|
||||
if (mdname != NULL && strcmp(mdname, "UNDEF") == 0)
|
||||
return NULL;
|
||||
|
||||
return mdname;
|
||||
}
|
||||
|
||||
static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, const char *mdname,
|
||||
OSSL_LIB_CTX *libctx, const char *props,
|
||||
ENGINE *e, EVP_PKEY *pkey, int ver,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
EVP_PKEY_CTX *locpctx = NULL;
|
||||
EVP_SIGNATURE *signature = NULL;
|
||||
EVP_KEYMGMT *tmp_keymgmt = NULL;
|
||||
const OSSL_PROVIDER *tmp_prov = NULL;
|
||||
const char *supported_sig = NULL;
|
||||
char locmdname[80] = ""; /* 80 chars should be enough */
|
||||
void *provkey = NULL;
|
||||
int ret, iter, reinit = 1;
|
||||
|
||||
if (!evp_md_ctx_free_algctx(ctx))
|
||||
return 0;
|
||||
|
||||
if (ctx->pctx == NULL) {
|
||||
reinit = 0;
|
||||
if (e == NULL)
|
||||
ctx->pctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, props);
|
||||
else
|
||||
ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
|
||||
}
|
||||
if (ctx->pctx == NULL)
|
||||
return 0;
|
||||
|
||||
EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_FINALISED);
|
||||
|
||||
locpctx = ctx->pctx;
|
||||
ERR_set_mark();
|
||||
|
||||
if (evp_pkey_ctx_is_legacy(locpctx))
|
||||
goto legacy;
|
||||
|
||||
/* do not reinitialize if pkey is set or operation is different */
|
||||
if (reinit
|
||||
&& (pkey != NULL
|
||||
|| locpctx->operation != (ver ? EVP_PKEY_OP_VERIFYCTX
|
||||
: EVP_PKEY_OP_SIGNCTX)
|
||||
|| (signature = locpctx->op.sig.signature) == NULL
|
||||
|| locpctx->op.sig.algctx == NULL))
|
||||
reinit = 0;
|
||||
|
||||
if (props == NULL)
|
||||
props = locpctx->propquery;
|
||||
|
||||
if (locpctx->pkey == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!reinit) {
|
||||
evp_pkey_ctx_free_old_ops(locpctx);
|
||||
} else {
|
||||
if (mdname == NULL && type == NULL)
|
||||
mdname = canon_mdname(EVP_MD_get0_name(ctx->reqdigest));
|
||||
goto reinitialize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to derive the supported signature from |locpctx->keymgmt|.
|
||||
*/
|
||||
if (!ossl_assert(locpctx->pkey->keymgmt == NULL
|
||||
|| locpctx->pkey->keymgmt == locpctx->keymgmt)) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
supported_sig = evp_keymgmt_util_query_operation_name(locpctx->keymgmt,
|
||||
OSSL_OP_SIGNATURE);
|
||||
if (supported_sig == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We perform two iterations:
|
||||
*
|
||||
* 1. Do the normal signature fetch, using the fetching data given by
|
||||
* the EVP_PKEY_CTX.
|
||||
* 2. Do the provider specific signature fetch, from the same provider
|
||||
* as |ctx->keymgmt|
|
||||
*
|
||||
* We then try to fetch the keymgmt from the same provider as the
|
||||
* signature, and try to export |ctx->pkey| to that keymgmt (when
|
||||
* this keymgmt happens to be the same as |ctx->keymgmt|, the export
|
||||
* is a no-op, but we call it anyway to not complicate the code even
|
||||
* more).
|
||||
* If the export call succeeds (returns a non-NULL provider key pointer),
|
||||
* we're done and can perform the operation itself. If not, we perform
|
||||
* the second iteration, or jump to legacy.
|
||||
*/
|
||||
for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
|
||||
EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
|
||||
|
||||
/*
|
||||
* If we're on the second iteration, free the results from the first.
|
||||
* They are NULL on the first iteration, so no need to check what
|
||||
* iteration we're on.
|
||||
*/
|
||||
EVP_SIGNATURE_free(signature);
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
|
||||
switch (iter) {
|
||||
case 1:
|
||||
signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
|
||||
locpctx->propquery);
|
||||
if (signature != NULL)
|
||||
tmp_prov = EVP_SIGNATURE_get0_provider(signature);
|
||||
break;
|
||||
case 2:
|
||||
tmp_prov = EVP_KEYMGMT_get0_provider(locpctx->keymgmt);
|
||||
signature =
|
||||
evp_signature_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
supported_sig, locpctx->propquery);
|
||||
if (signature == NULL)
|
||||
goto legacy;
|
||||
break;
|
||||
}
|
||||
if (signature == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ensure that the key is provided, either natively, or as a cached
|
||||
* export. We start by fetching the keymgmt with the same name as
|
||||
* |locpctx->pkey|, but from the provider of the signature method, using
|
||||
* the same property query as when fetching the signature method.
|
||||
* With the keymgmt we found (if we did), we try to export |locpctx->pkey|
|
||||
* to it (evp_pkey_export_to_provider() is smart enough to only actually
|
||||
|
||||
* export it if |tmp_keymgmt| is different from |locpctx->pkey|'s keymgmt)
|
||||
*/
|
||||
tmp_keymgmt_tofree = tmp_keymgmt =
|
||||
evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
|
||||
EVP_KEYMGMT_get0_name(locpctx->keymgmt),
|
||||
locpctx->propquery);
|
||||
if (tmp_keymgmt != NULL)
|
||||
provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx,
|
||||
&tmp_keymgmt, locpctx->propquery);
|
||||
if (tmp_keymgmt == NULL)
|
||||
EVP_KEYMGMT_free(tmp_keymgmt_tofree);
|
||||
}
|
||||
|
||||
if (provkey == NULL) {
|
||||
EVP_SIGNATURE_free(signature);
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ERR_pop_to_mark();
|
||||
|
||||
/* No more legacy from here down to legacy: */
|
||||
|
||||
locpctx->op.sig.signature = signature;
|
||||
locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX
|
||||
: EVP_PKEY_OP_SIGNCTX;
|
||||
locpctx->op.sig.algctx
|
||||
= signature->newctx(ossl_provider_ctx(signature->prov), props);
|
||||
if (locpctx->op.sig.algctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
reinitialize:
|
||||
if (pctx != NULL)
|
||||
*pctx = locpctx;
|
||||
|
||||
if (type != NULL) {
|
||||
ctx->reqdigest = type;
|
||||
if (mdname == NULL)
|
||||
mdname = canon_mdname(EVP_MD_get0_name(type));
|
||||
} else {
|
||||
if (mdname == NULL && !reinit) {
|
||||
if (evp_keymgmt_util_get_deflt_digest_name(tmp_keymgmt, provkey,
|
||||
locmdname,
|
||||
sizeof(locmdname)) > 0) {
|
||||
mdname = canon_mdname(locmdname);
|
||||
}
|
||||
}
|
||||
|
||||
if (mdname != NULL) {
|
||||
/*
|
||||
* We're about to get a new digest so clear anything associated with
|
||||
* an old digest.
|
||||
*/
|
||||
evp_md_ctx_clear_digest(ctx, 1, 0);
|
||||
|
||||
/* legacy code support for engines */
|
||||
ERR_set_mark();
|
||||
/*
|
||||
* This might be requested by a later call to EVP_MD_CTX_get0_md().
|
||||
* In that case the "explicit fetch" rules apply for that
|
||||
* function (as per man pages), i.e. the ref count is not updated
|
||||
* so the EVP_MD should not be used beyond the lifetime of the
|
||||
* EVP_MD_CTX.
|
||||
*/
|
||||
ctx->fetched_digest = EVP_MD_fetch(locpctx->libctx, mdname, props);
|
||||
if (ctx->fetched_digest != NULL) {
|
||||
ctx->digest = ctx->reqdigest = ctx->fetched_digest;
|
||||
} else {
|
||||
/* legacy engine support : remove the mark when this is deleted */
|
||||
ctx->reqdigest = ctx->digest = EVP_get_digestbyname(mdname);
|
||||
if (ctx->digest == NULL) {
|
||||
(void)ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
}
|
||||
}
|
||||
|
||||
if (ver) {
|
||||
if (signature->digest_verify_init == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ret = signature->digest_verify_init(locpctx->op.sig.algctx,
|
||||
mdname, provkey, params);
|
||||
} else {
|
||||
if (signature->digest_sign_init == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ret = signature->digest_sign_init(locpctx->op.sig.algctx,
|
||||
mdname, provkey, params);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the operation was not a success and no digest was found, an error
|
||||
* needs to be raised.
|
||||
*/
|
||||
if (ret > 0 || mdname != NULL)
|
||||
goto end;
|
||||
if (type == NULL) /* This check is redundant but clarifies matters */
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_DEFAULT_DIGEST);
|
||||
|
||||
err:
|
||||
evp_pkey_ctx_free_old_ops(locpctx);
|
||||
locpctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return 0;
|
||||
|
||||
legacy:
|
||||
/*
|
||||
* If we don't have the full support we need with provided methods,
|
||||
* let's go see if legacy does.
|
||||
*/
|
||||
ERR_pop_to_mark();
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
tmp_keymgmt = NULL;
|
||||
|
||||
if (type == NULL && mdname != NULL)
|
||||
type = evp_get_digestbyname_ex(locpctx->libctx, mdname);
|
||||
|
||||
if (ctx->pctx->pmeth == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)) {
|
||||
|
||||
if (type == NULL) {
|
||||
int def_nid;
|
||||
if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
|
||||
type = EVP_get_digestbynid(def_nid);
|
||||
}
|
||||
|
||||
if (type == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_DEFAULT_DIGEST);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ver) {
|
||||
if (ctx->pctx->pmeth->verifyctx_init) {
|
||||
if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <= 0)
|
||||
return 0;
|
||||
ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
|
||||
} else if (ctx->pctx->pmeth->digestverify != 0) {
|
||||
ctx->pctx->operation = EVP_PKEY_OP_VERIFY;
|
||||
ctx->update = update;
|
||||
} else if (EVP_PKEY_verify_init(ctx->pctx) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (ctx->pctx->pmeth->signctx_init) {
|
||||
if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0)
|
||||
return 0;
|
||||
ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
|
||||
} else if (ctx->pctx->pmeth->digestsign != 0) {
|
||||
ctx->pctx->operation = EVP_PKEY_OP_SIGN;
|
||||
ctx->update = update;
|
||||
} else if (EVP_PKEY_sign_init(ctx->pctx) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
|
||||
return 0;
|
||||
if (pctx)
|
||||
*pctx = ctx->pctx;
|
||||
if (ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)
|
||||
return 1;
|
||||
if (!EVP_DigestInit_ex(ctx, type, e))
|
||||
return 0;
|
||||
/*
|
||||
* This indicates the current algorithm requires
|
||||
* special treatment before hashing the tbs-message.
|
||||
*/
|
||||
ctx->pctx->flag_call_digest_custom = 0;
|
||||
if (ctx->pctx->pmeth->digest_custom != NULL)
|
||||
ctx->pctx->flag_call_digest_custom = 1;
|
||||
|
||||
ret = 1;
|
||||
end:
|
||||
if (ret > 0)
|
||||
ret = evp_pkey_ctx_use_cached_data(locpctx);
|
||||
|
||||
EVP_KEYMGMT_free(tmp_keymgmt);
|
||||
return ret > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int EVP_DigestSignInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const char *mdname, OSSL_LIB_CTX *libctx,
|
||||
const char *props, EVP_PKEY *pkey,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
return do_sigver_init(ctx, pctx, NULL, mdname, libctx, props, NULL, pkey, 0,
|
||||
params);
|
||||
}
|
||||
|
||||
int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
|
||||
{
|
||||
return do_sigver_init(ctx, pctx, type, NULL, NULL, NULL, e, pkey, 0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int EVP_DigestVerifyInit_ex(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const char *mdname, OSSL_LIB_CTX *libctx,
|
||||
const char *props, EVP_PKEY *pkey,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
return do_sigver_init(ctx, pctx, NULL, mdname, libctx, props, NULL, pkey, 1,
|
||||
params);
|
||||
}
|
||||
|
||||
int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
|
||||
{
|
||||
return do_sigver_init(ctx, pctx, type, NULL, NULL, NULL, e, pkey, 1,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = ctx->pctx;
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx == NULL
|
||||
|| pctx->operation != EVP_PKEY_OP_SIGNCTX
|
||||
|| pctx->op.sig.algctx == NULL
|
||||
|| pctx->op.sig.signature == NULL)
|
||||
goto legacy;
|
||||
|
||||
if (pctx->op.sig.signature->digest_sign_update == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pctx->op.sig.signature->digest_sign_update(pctx->op.sig.algctx,
|
||||
data, dsize);
|
||||
|
||||
legacy:
|
||||
if (pctx != NULL) {
|
||||
/* do_sigver_init() checked that |digest_custom| is non-NULL */
|
||||
if (pctx->flag_call_digest_custom
|
||||
&& !ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx))
|
||||
return 0;
|
||||
pctx->flag_call_digest_custom = 0;
|
||||
}
|
||||
|
||||
return EVP_DigestUpdate(ctx, data, dsize);
|
||||
}
|
||||
|
||||
int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = ctx->pctx;
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx == NULL
|
||||
|| pctx->operation != EVP_PKEY_OP_VERIFYCTX
|
||||
|| pctx->op.sig.algctx == NULL
|
||||
|| pctx->op.sig.signature == NULL)
|
||||
goto legacy;
|
||||
|
||||
if (pctx->op.sig.signature->digest_verify_update == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pctx->op.sig.signature->digest_verify_update(pctx->op.sig.algctx,
|
||||
data, dsize);
|
||||
|
||||
legacy:
|
||||
if (pctx != NULL) {
|
||||
/* do_sigver_init() checked that |digest_custom| is non-NULL */
|
||||
if (pctx->flag_call_digest_custom
|
||||
&& !ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx))
|
||||
return 0;
|
||||
pctx->flag_call_digest_custom = 0;
|
||||
}
|
||||
|
||||
return EVP_DigestUpdate(ctx, data, dsize);
|
||||
}
|
||||
|
||||
int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
size_t *siglen)
|
||||
{
|
||||
int sctx = 0;
|
||||
int r = 0;
|
||||
EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx;
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx == NULL
|
||||
|| pctx->operation != EVP_PKEY_OP_SIGNCTX
|
||||
|| pctx->op.sig.algctx == NULL
|
||||
|| pctx->op.sig.signature == NULL)
|
||||
goto legacy;
|
||||
|
||||
if (sigret != NULL && (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) == 0) {
|
||||
/* try dup */
|
||||
dctx = EVP_PKEY_CTX_dup(pctx);
|
||||
if (dctx != NULL)
|
||||
pctx = dctx;
|
||||
}
|
||||
r = pctx->op.sig.signature->digest_sign_final(pctx->op.sig.algctx,
|
||||
sigret, siglen,
|
||||
sigret == NULL ? 0 : *siglen);
|
||||
if (dctx == NULL && sigret != NULL)
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
else
|
||||
EVP_PKEY_CTX_free(dctx);
|
||||
return r;
|
||||
|
||||
legacy:
|
||||
if (pctx == NULL || pctx->pmeth == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do_sigver_init() checked that |digest_custom| is non-NULL */
|
||||
if (pctx->flag_call_digest_custom
|
||||
&& !ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx))
|
||||
return 0;
|
||||
pctx->flag_call_digest_custom = 0;
|
||||
|
||||
if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) {
|
||||
if (sigret == NULL)
|
||||
return pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) != 0) {
|
||||
r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
} else {
|
||||
dctx = EVP_PKEY_CTX_dup(pctx);
|
||||
if (dctx == NULL)
|
||||
return 0;
|
||||
r = dctx->pmeth->signctx(dctx, sigret, siglen, ctx);
|
||||
EVP_PKEY_CTX_free(dctx);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if (pctx->pmeth->signctx != NULL)
|
||||
sctx = 1;
|
||||
else
|
||||
sctx = 0;
|
||||
if (sigret != NULL) {
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
unsigned int mdlen = 0;
|
||||
|
||||
if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
|
||||
if (sctx)
|
||||
r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
|
||||
else
|
||||
r = EVP_DigestFinal_ex(ctx, md, &mdlen);
|
||||
} else {
|
||||
EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
|
||||
|
||||
if (tmp_ctx == NULL)
|
||||
return 0;
|
||||
if (!EVP_MD_CTX_copy_ex(tmp_ctx, ctx)) {
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
return 0;
|
||||
}
|
||||
if (sctx)
|
||||
r = tmp_ctx->pctx->pmeth->signctx(tmp_ctx->pctx,
|
||||
sigret, siglen, tmp_ctx);
|
||||
else
|
||||
r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen);
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
}
|
||||
if (sctx || !r)
|
||||
return r;
|
||||
if (EVP_PKEY_sign(pctx, sigret, siglen, md, mdlen) <= 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (sctx) {
|
||||
if (pctx->pmeth->signctx(pctx, sigret, siglen, ctx) <= 0)
|
||||
return 0;
|
||||
} else {
|
||||
int s = EVP_MD_get_size(ctx->digest);
|
||||
|
||||
if (s <= 0 || EVP_PKEY_sign(pctx, sigret, siglen, NULL, s) <= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen,
|
||||
const unsigned char *tbs, size_t tbslen)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = ctx->pctx;
|
||||
|
||||
if (pctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx->operation == EVP_PKEY_OP_SIGNCTX
|
||||
&& pctx->op.sig.algctx != NULL
|
||||
&& pctx->op.sig.signature != NULL) {
|
||||
if (pctx->op.sig.signature->digest_sign != NULL) {
|
||||
if (sigret != NULL)
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
return pctx->op.sig.signature->digest_sign(pctx->op.sig.algctx,
|
||||
sigret, siglen,
|
||||
sigret == NULL ? 0 : *siglen,
|
||||
tbs, tbslen);
|
||||
}
|
||||
} else {
|
||||
/* legacy */
|
||||
if (pctx->pmeth != NULL && pctx->pmeth->digestsign != NULL)
|
||||
return pctx->pmeth->digestsign(ctx, sigret, siglen, tbs, tbslen);
|
||||
}
|
||||
|
||||
if (sigret != NULL && EVP_DigestSignUpdate(ctx, tbs, tbslen) <= 0)
|
||||
return 0;
|
||||
return EVP_DigestSignFinal(ctx, sigret, siglen);
|
||||
}
|
||||
|
||||
int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
|
||||
size_t siglen)
|
||||
{
|
||||
int vctx = 0;
|
||||
unsigned int mdlen = 0;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
int r = 0;
|
||||
EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx;
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx == NULL
|
||||
|| pctx->operation != EVP_PKEY_OP_VERIFYCTX
|
||||
|| pctx->op.sig.algctx == NULL
|
||||
|| pctx->op.sig.signature == NULL)
|
||||
goto legacy;
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) == 0) {
|
||||
/* try dup */
|
||||
dctx = EVP_PKEY_CTX_dup(pctx);
|
||||
if (dctx != NULL)
|
||||
pctx = dctx;
|
||||
}
|
||||
r = pctx->op.sig.signature->digest_verify_final(pctx->op.sig.algctx,
|
||||
sig, siglen);
|
||||
if (dctx == NULL)
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
else
|
||||
EVP_PKEY_CTX_free(dctx);
|
||||
return r;
|
||||
|
||||
legacy:
|
||||
if (pctx == NULL || pctx->pmeth == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do_sigver_init() checked that |digest_custom| is non-NULL */
|
||||
if (pctx->flag_call_digest_custom
|
||||
&& !ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx))
|
||||
return 0;
|
||||
pctx->flag_call_digest_custom = 0;
|
||||
|
||||
if (pctx->pmeth->verifyctx != NULL)
|
||||
vctx = 1;
|
||||
else
|
||||
vctx = 0;
|
||||
if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
|
||||
if (vctx) {
|
||||
r = pctx->pmeth->verifyctx(pctx, sig, siglen, ctx);
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
} else
|
||||
r = EVP_DigestFinal_ex(ctx, md, &mdlen);
|
||||
} else {
|
||||
EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
|
||||
if (tmp_ctx == NULL)
|
||||
return -1;
|
||||
if (!EVP_MD_CTX_copy_ex(tmp_ctx, ctx)) {
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
return -1;
|
||||
}
|
||||
if (vctx)
|
||||
r = tmp_ctx->pctx->pmeth->verifyctx(tmp_ctx->pctx,
|
||||
sig, siglen, tmp_ctx);
|
||||
else
|
||||
r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen);
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
}
|
||||
if (vctx || !r)
|
||||
return r;
|
||||
return EVP_PKEY_verify(pctx, sig, siglen, md, mdlen);
|
||||
}
|
||||
|
||||
int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
|
||||
size_t siglen, const unsigned char *tbs, size_t tbslen)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx = ctx->pctx;
|
||||
|
||||
if (pctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pctx->operation == EVP_PKEY_OP_VERIFYCTX
|
||||
&& pctx->op.sig.algctx != NULL
|
||||
&& pctx->op.sig.signature != NULL) {
|
||||
if (pctx->op.sig.signature->digest_verify != NULL) {
|
||||
ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
|
||||
return pctx->op.sig.signature->digest_verify(pctx->op.sig.algctx,
|
||||
sigret, siglen,
|
||||
tbs, tbslen);
|
||||
}
|
||||
} else {
|
||||
/* legacy */
|
||||
if (pctx->pmeth != NULL && pctx->pmeth->digestverify != NULL)
|
||||
return pctx->pmeth->digestverify(ctx, sigret, siglen, tbs, tbslen);
|
||||
}
|
||||
if (EVP_DigestVerifyUpdate(ctx, tbs, tbslen) <= 0)
|
||||
return -1;
|
||||
return EVP_DigestVerifyFinal(ctx, sigret, siglen);
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 2018-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/types.h>
|
||||
#include "internal/nelem.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "internal/provider.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
EVP_MAC_CTX *EVP_MAC_CTX_new(EVP_MAC *mac)
|
||||
{
|
||||
EVP_MAC_CTX *ctx = OPENSSL_zalloc(sizeof(EVP_MAC_CTX));
|
||||
|
||||
if (ctx != NULL) {
|
||||
ctx->meth = mac;
|
||||
if ((ctx->algctx = mac->newctx(ossl_provider_ctx(mac->prov))) == NULL
|
||||
|| !EVP_MAC_up_ref(mac)) {
|
||||
mac->freectx(ctx->algctx);
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
OPENSSL_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
ctx->meth->freectx(ctx->algctx);
|
||||
ctx->algctx = NULL;
|
||||
/* refcnt-- */
|
||||
EVP_MAC_free(ctx->meth);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
EVP_MAC_CTX *EVP_MAC_CTX_dup(const EVP_MAC_CTX *src)
|
||||
{
|
||||
EVP_MAC_CTX *dst;
|
||||
|
||||
if (src->algctx == NULL)
|
||||
return NULL;
|
||||
|
||||
dst = OPENSSL_malloc(sizeof(*dst));
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
|
||||
*dst = *src;
|
||||
if (!EVP_MAC_up_ref(dst->meth)) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
OPENSSL_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst->algctx = src->meth->dupctx(src->algctx);
|
||||
if (dst->algctx == NULL) {
|
||||
EVP_MAC_CTX_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
EVP_MAC *EVP_MAC_CTX_get0_mac(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
return ctx->meth;
|
||||
}
|
||||
|
||||
static size_t get_size_t_ctx_param(EVP_MAC_CTX *ctx, const char *name)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
if (ctx->algctx != NULL) {
|
||||
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
|
||||
params[0] = OSSL_PARAM_construct_size_t(name, &sz);
|
||||
if (ctx->meth->get_ctx_params != NULL) {
|
||||
if (ctx->meth->get_ctx_params(ctx->algctx, params))
|
||||
return sz;
|
||||
} else if (ctx->meth->get_params != NULL) {
|
||||
if (ctx->meth->get_params(params))
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the MAC hasn't been initialized yet, or there is no size to get,
|
||||
* we return zero
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t EVP_MAC_CTX_get_mac_size(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
return get_size_t_ctx_param(ctx, OSSL_MAC_PARAM_SIZE);
|
||||
}
|
||||
|
||||
size_t EVP_MAC_CTX_get_block_size(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
return get_size_t_ctx_param(ctx, OSSL_MAC_PARAM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
int EVP_MAC_init(EVP_MAC_CTX *ctx, const unsigned char *key, size_t keylen,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->init == NULL) {
|
||||
ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
return ctx->meth->init(ctx->algctx, key, keylen, params);
|
||||
}
|
||||
|
||||
int EVP_MAC_init_SKEY(EVP_MAC_CTX *ctx, EVP_SKEY *skey, const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->init_skey == NULL
|
||||
|| skey->skeymgmt->prov != ctx->meth->prov
|
||||
|| ctx->meth->init_skey == NULL) {
|
||||
ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
return ctx->meth->init_skey(ctx->algctx, skey->keydata, params);
|
||||
}
|
||||
|
||||
int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen)
|
||||
{
|
||||
return ctx->meth->update(ctx->algctx, data, datalen);
|
||||
}
|
||||
|
||||
static int evp_mac_final(EVP_MAC_CTX *ctx, int xof,
|
||||
unsigned char *out, size_t *outl, size_t outsize)
|
||||
{
|
||||
size_t l;
|
||||
int res;
|
||||
OSSL_PARAM params[2];
|
||||
size_t macsize;
|
||||
|
||||
if (ctx == NULL || ctx->meth == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM);
|
||||
return 0;
|
||||
}
|
||||
if (ctx->meth->final == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
macsize = EVP_MAC_CTX_get_mac_size(ctx);
|
||||
if (out == NULL) {
|
||||
if (outl == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
*outl = macsize;
|
||||
return 1;
|
||||
}
|
||||
if (outsize < macsize) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
if (xof) {
|
||||
params[0] = OSSL_PARAM_construct_int(OSSL_MAC_PARAM_XOF, &xof);
|
||||
params[1] = OSSL_PARAM_construct_end();
|
||||
|
||||
if (EVP_MAC_CTX_set_params(ctx, params) <= 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_SETTING_XOF_FAILED);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
res = ctx->meth->final(ctx->algctx, out, &l, outsize);
|
||||
if (outl != NULL)
|
||||
*outl = l;
|
||||
return res;
|
||||
}
|
||||
|
||||
int EVP_MAC_final(EVP_MAC_CTX *ctx,
|
||||
unsigned char *out, size_t *outl, size_t outsize)
|
||||
{
|
||||
return evp_mac_final(ctx, 0, out, outl, outsize);
|
||||
}
|
||||
|
||||
int EVP_MAC_finalXOF(EVP_MAC_CTX *ctx, unsigned char *out, size_t outsize)
|
||||
{
|
||||
return evp_mac_final(ctx, 1, out, NULL, outsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* The {get,set}_params functions return 1 if there is no corresponding
|
||||
* function in the implementation. This is the same as if there was one,
|
||||
* but it didn't recognise any of the given params, i.e. nothing in the
|
||||
* bag of parameters was useful.
|
||||
*/
|
||||
int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[])
|
||||
{
|
||||
if (mac->get_params != NULL)
|
||||
return mac->get_params(params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_MAC_CTX_get_params(EVP_MAC_CTX *ctx, OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->get_ctx_params != NULL)
|
||||
return ctx->meth->get_ctx_params(ctx->algctx, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_MAC_CTX_set_params(EVP_MAC_CTX *ctx, const OSSL_PARAM params[])
|
||||
{
|
||||
if (ctx->meth->set_ctx_params != NULL)
|
||||
return ctx->meth->set_ctx_params(ctx->algctx, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int evp_mac_get_number(const EVP_MAC *mac)
|
||||
{
|
||||
return mac->name_id;
|
||||
}
|
||||
|
||||
const char *EVP_MAC_get0_name(const EVP_MAC *mac)
|
||||
{
|
||||
return mac->type_name;
|
||||
}
|
||||
|
||||
const char *EVP_MAC_get0_description(const EVP_MAC *mac)
|
||||
{
|
||||
return mac->description;
|
||||
}
|
||||
|
||||
int EVP_MAC_is_a(const EVP_MAC *mac, const char *name)
|
||||
{
|
||||
return mac != NULL && evp_is_a(mac->prov, mac->name_id, NULL, name);
|
||||
}
|
||||
|
||||
int EVP_MAC_names_do_all(const EVP_MAC *mac,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (mac->prov != NULL)
|
||||
return evp_names_do_all(mac->prov, mac->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char *EVP_Q_mac(OSSL_LIB_CTX *libctx,
|
||||
const char *name, const char *propq,
|
||||
const char *subalg, const OSSL_PARAM *params,
|
||||
const void *key, size_t keylen,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char *out, size_t outsize, size_t *outlen)
|
||||
{
|
||||
EVP_MAC *mac = EVP_MAC_fetch(libctx, name, propq);
|
||||
OSSL_PARAM subalg_param[] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
EVP_MAC_CTX *ctx = NULL;
|
||||
size_t len = 0;
|
||||
unsigned char *res = NULL;
|
||||
|
||||
if (outlen != NULL)
|
||||
*outlen = 0;
|
||||
if (mac == NULL)
|
||||
return NULL;
|
||||
if (subalg != NULL) {
|
||||
const OSSL_PARAM *defined_params = EVP_MAC_settable_ctx_params(mac);
|
||||
const char *param_name = OSSL_MAC_PARAM_DIGEST;
|
||||
|
||||
/*
|
||||
* The underlying algorithm may be a cipher or a digest.
|
||||
* We don't know which it is, but we can ask the MAC what it
|
||||
* should be and bet on that.
|
||||
*/
|
||||
if (OSSL_PARAM_locate_const(defined_params, param_name) == NULL) {
|
||||
param_name = OSSL_MAC_PARAM_CIPHER;
|
||||
if (OSSL_PARAM_locate_const(defined_params, param_name) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
subalg_param[0] =
|
||||
OSSL_PARAM_construct_utf8_string(param_name, (char *)subalg, 0);
|
||||
}
|
||||
/* Single-shot - on NULL key input, set dummy key value for EVP_MAC_Init. */
|
||||
if (key == NULL && keylen == 0)
|
||||
key = data;
|
||||
if ((ctx = EVP_MAC_CTX_new(mac)) != NULL
|
||||
&& EVP_MAC_CTX_set_params(ctx, subalg_param)
|
||||
&& EVP_MAC_CTX_set_params(ctx, params)
|
||||
&& EVP_MAC_init(ctx, key, keylen, params)
|
||||
&& EVP_MAC_update(ctx, data, datalen)
|
||||
&& EVP_MAC_final(ctx, out, &len, outsize)) {
|
||||
if (out == NULL) {
|
||||
out = OPENSSL_malloc(len);
|
||||
if (out != NULL && !EVP_MAC_final(ctx, out, NULL, len)) {
|
||||
OPENSSL_free(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
res = out;
|
||||
if (res != NULL && outlen != NULL)
|
||||
*outlen = len;
|
||||
}
|
||||
|
||||
err:
|
||||
EVP_MAC_CTX_free(ctx);
|
||||
EVP_MAC_free(mac);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include "internal/provider.h"
|
||||
#include "internal/core.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static int evp_mac_up_ref(void *vmac)
|
||||
{
|
||||
EVP_MAC *mac = vmac;
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&mac->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void evp_mac_free(void *vmac)
|
||||
{
|
||||
EVP_MAC *mac = vmac;
|
||||
int ref = 0;
|
||||
|
||||
if (mac == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&mac->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
OPENSSL_free(mac->type_name);
|
||||
ossl_provider_free(mac->prov);
|
||||
CRYPTO_FREE_REF(&mac->refcnt);
|
||||
OPENSSL_free(mac);
|
||||
}
|
||||
|
||||
static void *evp_mac_new(void)
|
||||
{
|
||||
EVP_MAC *mac = NULL;
|
||||
|
||||
if ((mac = OPENSSL_zalloc(sizeof(*mac))) == NULL
|
||||
|| !CRYPTO_NEW_REF(&mac->refcnt, 1)) {
|
||||
evp_mac_free(mac);
|
||||
return NULL;
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
static void *evp_mac_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_MAC *mac = NULL;
|
||||
int fnmaccnt = 0, fnctxcnt = 0, mac_init_found = 0;
|
||||
|
||||
if ((mac = evp_mac_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
mac->name_id = name_id;
|
||||
|
||||
if ((mac->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
|
||||
goto err;
|
||||
|
||||
mac->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_MAC_NEWCTX:
|
||||
if (mac->newctx != NULL)
|
||||
break;
|
||||
mac->newctx = OSSL_FUNC_mac_newctx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_MAC_DUPCTX:
|
||||
if (mac->dupctx != NULL)
|
||||
break;
|
||||
mac->dupctx = OSSL_FUNC_mac_dupctx(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_FREECTX:
|
||||
if (mac->freectx != NULL)
|
||||
break;
|
||||
mac->freectx = OSSL_FUNC_mac_freectx(fns);
|
||||
fnctxcnt++;
|
||||
break;
|
||||
case OSSL_FUNC_MAC_INIT:
|
||||
if (mac->init != NULL)
|
||||
break;
|
||||
mac->init = OSSL_FUNC_mac_init(fns);
|
||||
mac_init_found = 1;
|
||||
break;
|
||||
case OSSL_FUNC_MAC_UPDATE:
|
||||
if (mac->update != NULL)
|
||||
break;
|
||||
mac->update = OSSL_FUNC_mac_update(fns);
|
||||
fnmaccnt++;
|
||||
break;
|
||||
case OSSL_FUNC_MAC_FINAL:
|
||||
if (mac->final != NULL)
|
||||
break;
|
||||
mac->final = OSSL_FUNC_mac_final(fns);
|
||||
fnmaccnt++;
|
||||
break;
|
||||
case OSSL_FUNC_MAC_GETTABLE_PARAMS:
|
||||
if (mac->gettable_params != NULL)
|
||||
break;
|
||||
mac->gettable_params =
|
||||
OSSL_FUNC_mac_gettable_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS:
|
||||
if (mac->gettable_ctx_params != NULL)
|
||||
break;
|
||||
mac->gettable_ctx_params =
|
||||
OSSL_FUNC_mac_gettable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS:
|
||||
if (mac->settable_ctx_params != NULL)
|
||||
break;
|
||||
mac->settable_ctx_params =
|
||||
OSSL_FUNC_mac_settable_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_GET_PARAMS:
|
||||
if (mac->get_params != NULL)
|
||||
break;
|
||||
mac->get_params = OSSL_FUNC_mac_get_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_GET_CTX_PARAMS:
|
||||
if (mac->get_ctx_params != NULL)
|
||||
break;
|
||||
mac->get_ctx_params = OSSL_FUNC_mac_get_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_SET_CTX_PARAMS:
|
||||
if (mac->set_ctx_params != NULL)
|
||||
break;
|
||||
mac->set_ctx_params = OSSL_FUNC_mac_set_ctx_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_MAC_INIT_SKEY:
|
||||
if (mac->init_skey != NULL)
|
||||
break;
|
||||
mac->init_skey = OSSL_FUNC_mac_init_skey(fns);
|
||||
mac_init_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fnmaccnt += mac_init_found;
|
||||
if (fnmaccnt != 3
|
||||
|| fnctxcnt != 2) {
|
||||
/*
|
||||
* In order to be a consistent set of functions we must have at least
|
||||
* a complete set of "mac" functions, and a complete set of context
|
||||
* management functions, as well as the size function.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (prov != NULL && !ossl_provider_up_ref(prov))
|
||||
goto err;
|
||||
|
||||
mac->prov = prov;
|
||||
|
||||
return mac;
|
||||
|
||||
err:
|
||||
evp_mac_free(mac);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_MAC *EVP_MAC_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(libctx, OSSL_OP_MAC, algorithm, properties,
|
||||
evp_mac_from_algorithm, evp_mac_up_ref,
|
||||
evp_mac_free);
|
||||
}
|
||||
|
||||
int EVP_MAC_up_ref(EVP_MAC *mac)
|
||||
{
|
||||
return evp_mac_up_ref(mac);
|
||||
}
|
||||
|
||||
void EVP_MAC_free(EVP_MAC *mac)
|
||||
{
|
||||
evp_mac_free(mac);
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_MAC_get0_provider(const EVP_MAC *mac)
|
||||
{
|
||||
return mac->prov;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_MAC_gettable_params(const EVP_MAC *mac)
|
||||
{
|
||||
if (mac->gettable_params == NULL)
|
||||
return NULL;
|
||||
return mac->gettable_params(ossl_provider_ctx(EVP_MAC_get0_provider(mac)));
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_MAC_gettable_ctx_params(const EVP_MAC *mac)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (mac->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_MAC_get0_provider(mac));
|
||||
return mac->gettable_ctx_params(NULL, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_MAC_settable_ctx_params(const EVP_MAC *mac)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (mac->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_MAC_get0_provider(mac));
|
||||
return mac->settable_ctx_params(NULL, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_MAC_CTX_gettable_params(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (ctx->meth->gettable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_MAC_get0_provider(ctx->meth));
|
||||
return ctx->meth->gettable_ctx_params(ctx->algctx, alg);
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_MAC_CTX_settable_params(EVP_MAC_CTX *ctx)
|
||||
{
|
||||
void *alg;
|
||||
|
||||
if (ctx->meth->settable_ctx_params == NULL)
|
||||
return NULL;
|
||||
alg = ossl_provider_ctx(EVP_MAC_get0_provider(ctx->meth));
|
||||
return ctx->meth->settable_ctx_params(ctx->algctx, alg);
|
||||
}
|
||||
|
||||
void EVP_MAC_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_MAC *mac, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_MAC,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
evp_mac_from_algorithm, evp_mac_up_ref, evp_mac_free);
|
||||
}
|
||||
|
||||
EVP_MAC *evp_mac_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov, OSSL_OP_MAC,
|
||||
algorithm, properties,
|
||||
evp_mac_from_algorithm,
|
||||
evp_mac_up_ref,
|
||||
evp_mac_free);
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/namemap.h"
|
||||
#include "crypto/objects.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
int EVP_add_cipher(const EVP_CIPHER *c)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
|
||||
r = OBJ_NAME_add(OBJ_nid2sn(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
|
||||
(const char *)c);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
r = OBJ_NAME_add(OBJ_nid2ln(c->nid), OBJ_NAME_TYPE_CIPHER_METH,
|
||||
(const char *)c);
|
||||
return r;
|
||||
}
|
||||
|
||||
int EVP_add_digest(const EVP_MD *md)
|
||||
{
|
||||
int r;
|
||||
const char *name;
|
||||
|
||||
name = OBJ_nid2sn(md->type);
|
||||
r = OBJ_NAME_add(name, OBJ_NAME_TYPE_MD_METH, (const char *)md);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
r = OBJ_NAME_add(OBJ_nid2ln(md->type), OBJ_NAME_TYPE_MD_METH,
|
||||
(const char *)md);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (md->pkey_type && md->type != md->pkey_type) {
|
||||
r = OBJ_NAME_add(OBJ_nid2sn(md->pkey_type),
|
||||
OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
r = OBJ_NAME_add(OBJ_nid2ln(md->pkey_type),
|
||||
OBJ_NAME_TYPE_MD_METH | OBJ_NAME_ALIAS, name);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void cipher_from_name(const char *name, void *data)
|
||||
{
|
||||
const EVP_CIPHER **cipher = data;
|
||||
|
||||
if (*cipher != NULL)
|
||||
return;
|
||||
|
||||
*cipher = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *EVP_get_cipherbyname(const char *name)
|
||||
{
|
||||
return evp_get_cipherbyname_ex(NULL, name);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *evp_get_cipherbyname_ex(OSSL_LIB_CTX *libctx,
|
||||
const char *name)
|
||||
{
|
||||
const EVP_CIPHER *cp;
|
||||
OSSL_NAMEMAP *namemap;
|
||||
int id;
|
||||
int do_retry = 1;
|
||||
|
||||
if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL))
|
||||
return NULL;
|
||||
|
||||
cp = (const EVP_CIPHER *)OBJ_NAME_get(name, OBJ_NAME_TYPE_CIPHER_METH);
|
||||
|
||||
if (cp != NULL)
|
||||
return cp;
|
||||
|
||||
/*
|
||||
* It's not in the method database, but it might be there under a different
|
||||
* name. So we check for aliases in the EVP namemap and try all of those
|
||||
* in turn.
|
||||
*/
|
||||
|
||||
namemap = ossl_namemap_stored(libctx);
|
||||
retry:
|
||||
id = ossl_namemap_name2num(namemap, name);
|
||||
if (id == 0) {
|
||||
EVP_CIPHER *fetched_cipher;
|
||||
|
||||
/* Try to fetch it because the name might not be known yet. */
|
||||
if (!do_retry)
|
||||
return NULL;
|
||||
do_retry = 0;
|
||||
ERR_set_mark();
|
||||
fetched_cipher = EVP_CIPHER_fetch(libctx, name, NULL);
|
||||
EVP_CIPHER_free(fetched_cipher);
|
||||
ERR_pop_to_mark();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!ossl_namemap_doall_names(namemap, id, cipher_from_name, &cp))
|
||||
return NULL;
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
static void digest_from_name(const char *name, void *data)
|
||||
{
|
||||
const EVP_MD **md = data;
|
||||
|
||||
if (*md != NULL)
|
||||
return;
|
||||
|
||||
*md = (const EVP_MD *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH);
|
||||
}
|
||||
|
||||
const EVP_MD *EVP_get_digestbyname(const char *name)
|
||||
{
|
||||
return evp_get_digestbyname_ex(NULL, name);
|
||||
}
|
||||
|
||||
const EVP_MD *evp_get_digestbyname_ex(OSSL_LIB_CTX *libctx, const char *name)
|
||||
{
|
||||
const EVP_MD *dp;
|
||||
OSSL_NAMEMAP *namemap;
|
||||
int id;
|
||||
int do_retry = 1;
|
||||
|
||||
if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL))
|
||||
return NULL;
|
||||
|
||||
dp = (const EVP_MD *)OBJ_NAME_get(name, OBJ_NAME_TYPE_MD_METH);
|
||||
|
||||
if (dp != NULL)
|
||||
return dp;
|
||||
|
||||
/*
|
||||
* It's not in the method database, but it might be there under a different
|
||||
* name. So we check for aliases in the EVP namemap and try all of those
|
||||
* in turn.
|
||||
*/
|
||||
|
||||
namemap = ossl_namemap_stored(libctx);
|
||||
retry:
|
||||
id = ossl_namemap_name2num(namemap, name);
|
||||
if (id == 0) {
|
||||
EVP_MD *fetched_md;
|
||||
|
||||
/* Try to fetch it because the name might not be known yet. */
|
||||
if (!do_retry)
|
||||
return NULL;
|
||||
do_retry = 0;
|
||||
ERR_set_mark();
|
||||
fetched_md = EVP_MD_fetch(libctx, name, NULL);
|
||||
EVP_MD_free(fetched_md);
|
||||
ERR_pop_to_mark();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!ossl_namemap_doall_names(namemap, id, digest_from_name, &dp))
|
||||
return NULL;
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
void evp_cleanup_int(void)
|
||||
{
|
||||
OBJ_NAME_cleanup(OBJ_NAME_TYPE_KDF_METH);
|
||||
OBJ_NAME_cleanup(OBJ_NAME_TYPE_CIPHER_METH);
|
||||
OBJ_NAME_cleanup(OBJ_NAME_TYPE_MD_METH);
|
||||
/*
|
||||
* The above calls will only clean out the contents of the name hash
|
||||
* table, but not the hash table itself. The following line does that
|
||||
* part. -- Richard Levitte
|
||||
*/
|
||||
OBJ_NAME_cleanup(-1);
|
||||
|
||||
EVP_PBE_cleanup();
|
||||
OBJ_sigid_free();
|
||||
|
||||
evp_app_cleanup_int();
|
||||
}
|
||||
|
||||
struct doall_cipher {
|
||||
void *arg;
|
||||
void (*fn) (const EVP_CIPHER *ciph,
|
||||
const char *from, const char *to, void *arg);
|
||||
};
|
||||
|
||||
static void do_all_cipher_fn(const OBJ_NAME *nm, void *arg)
|
||||
{
|
||||
struct doall_cipher *dc = arg;
|
||||
if (nm->alias)
|
||||
dc->fn(NULL, nm->name, nm->data, dc->arg);
|
||||
else
|
||||
dc->fn((const EVP_CIPHER *)nm->data, nm->name, NULL, dc->arg);
|
||||
}
|
||||
|
||||
void EVP_CIPHER_do_all(void (*fn) (const EVP_CIPHER *ciph,
|
||||
const char *from, const char *to, void *x),
|
||||
void *arg)
|
||||
{
|
||||
struct doall_cipher dc;
|
||||
|
||||
/* Ignore errors */
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
|
||||
|
||||
dc.fn = fn;
|
||||
dc.arg = arg;
|
||||
OBJ_NAME_do_all(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
|
||||
}
|
||||
|
||||
void EVP_CIPHER_do_all_sorted(void (*fn) (const EVP_CIPHER *ciph,
|
||||
const char *from, const char *to,
|
||||
void *x), void *arg)
|
||||
{
|
||||
struct doall_cipher dc;
|
||||
|
||||
/* Ignore errors */
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL);
|
||||
|
||||
dc.fn = fn;
|
||||
dc.arg = arg;
|
||||
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc);
|
||||
}
|
||||
|
||||
struct doall_md {
|
||||
void *arg;
|
||||
void (*fn) (const EVP_MD *ciph,
|
||||
const char *from, const char *to, void *arg);
|
||||
};
|
||||
|
||||
static void do_all_md_fn(const OBJ_NAME *nm, void *arg)
|
||||
{
|
||||
struct doall_md *dc = arg;
|
||||
if (nm->alias)
|
||||
dc->fn(NULL, nm->name, nm->data, dc->arg);
|
||||
else
|
||||
dc->fn((const EVP_MD *)nm->data, nm->name, NULL, dc->arg);
|
||||
}
|
||||
|
||||
void EVP_MD_do_all(void (*fn) (const EVP_MD *md,
|
||||
const char *from, const char *to, void *x),
|
||||
void *arg)
|
||||
{
|
||||
struct doall_md dc;
|
||||
|
||||
/* Ignore errors */
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
|
||||
|
||||
dc.fn = fn;
|
||||
dc.arg = arg;
|
||||
OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
|
||||
}
|
||||
|
||||
void EVP_MD_do_all_sorted(void (*fn) (const EVP_MD *md,
|
||||
const char *from, const char *to,
|
||||
void *x), void *arg)
|
||||
{
|
||||
struct doall_md dc;
|
||||
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
|
||||
|
||||
dc.fn = fn;
|
||||
dc.arg = arg;
|
||||
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/kdf.h>
|
||||
|
||||
/*
|
||||
* Doesn't do anything now: Builtin PBE algorithms in static table.
|
||||
*/
|
||||
|
||||
void PKCS5_PBE_add(void)
|
||||
{
|
||||
}
|
||||
|
||||
int PKCS5_PBE_keyivgen_ex(EVP_CIPHER_CTX *cctx, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, const EVP_CIPHER *cipher,
|
||||
const EVP_MD *md, int en_de, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
unsigned char md_tmp[EVP_MAX_MD_SIZE];
|
||||
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
|
||||
int ivl, kl;
|
||||
PBEPARAM *pbe = NULL;
|
||||
int saltlen, iter;
|
||||
unsigned char *salt;
|
||||
int mdsize;
|
||||
int rv = 0;
|
||||
EVP_KDF *kdf;
|
||||
EVP_KDF_CTX *kctx = NULL;
|
||||
OSSL_PARAM params[5], *p = params;
|
||||
const char *mdname = EVP_MD_name(md);
|
||||
|
||||
/* Extract useful info from parameter */
|
||||
if (param == NULL || param->type != V_ASN1_SEQUENCE ||
|
||||
param->value.sequence == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), param);
|
||||
if (pbe == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl = EVP_CIPHER_get_iv_length(cipher);
|
||||
if (ivl < 0 || ivl > 16) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH);
|
||||
goto err;
|
||||
}
|
||||
kl = EVP_CIPHER_get_key_length(cipher);
|
||||
if (kl < 0 || kl > (int)sizeof(md_tmp)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pbe->iter == NULL)
|
||||
iter = 1;
|
||||
else
|
||||
iter = ASN1_INTEGER_get(pbe->iter);
|
||||
salt = pbe->salt->data;
|
||||
saltlen = pbe->salt->length;
|
||||
|
||||
if (pass == NULL)
|
||||
passlen = 0;
|
||||
else if (passlen == -1)
|
||||
passlen = strlen(pass);
|
||||
|
||||
mdsize = EVP_MD_get_size(md);
|
||||
if (mdsize <= 0)
|
||||
goto err;
|
||||
|
||||
kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_PBKDF1, propq);
|
||||
kctx = EVP_KDF_CTX_new(kdf);
|
||||
EVP_KDF_free(kdf);
|
||||
if (kctx == NULL)
|
||||
goto err;
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
|
||||
(char *)pass, (size_t)passlen);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
salt, saltlen);
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_ITER, &iter);
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
(char *)mdname, 0);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
if (EVP_KDF_derive(kctx, md_tmp, mdsize, params) != 1)
|
||||
goto err;
|
||||
memcpy(key, md_tmp, kl);
|
||||
memcpy(iv, md_tmp + (16 - ivl), ivl);
|
||||
if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, iv, en_de))
|
||||
goto err;
|
||||
OPENSSL_cleanse(md_tmp, EVP_MAX_MD_SIZE);
|
||||
OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
|
||||
OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
|
||||
rv = 1;
|
||||
err:
|
||||
EVP_KDF_CTX_free(kctx);
|
||||
PBEPARAM_free(pbe);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *cctx, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, const EVP_CIPHER *cipher,
|
||||
const EVP_MD *md, int en_de)
|
||||
{
|
||||
return PKCS5_PBE_keyivgen_ex(cctx, pass, passlen, param, cipher, md, en_de,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/trace.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
int ossl_pkcs5_pbkdf2_hmac_ex(const char *pass, int passlen,
|
||||
const unsigned char *salt, int saltlen, int iter,
|
||||
const EVP_MD *digest, int keylen, unsigned char *out,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
const char *empty = "";
|
||||
int rv = 1, mode = 1;
|
||||
EVP_KDF *kdf;
|
||||
EVP_KDF_CTX *kctx;
|
||||
const char *mdname = EVP_MD_get0_name(digest);
|
||||
OSSL_PARAM params[6], *p = params;
|
||||
|
||||
/* Keep documented behaviour. */
|
||||
if (pass == NULL) {
|
||||
pass = empty;
|
||||
passlen = 0;
|
||||
} else if (passlen == -1) {
|
||||
passlen = strlen(pass);
|
||||
}
|
||||
if (salt == NULL && saltlen == 0)
|
||||
salt = (unsigned char *)empty;
|
||||
|
||||
kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_PBKDF2, propq);
|
||||
if (kdf == NULL)
|
||||
return 0;
|
||||
kctx = EVP_KDF_CTX_new(kdf);
|
||||
EVP_KDF_free(kdf);
|
||||
if (kctx == NULL)
|
||||
return 0;
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
|
||||
(char *)pass, (size_t)passlen);
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &mode);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
(unsigned char *)salt, saltlen);
|
||||
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_ITER, &iter);
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
(char *)mdname, 0);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
if (EVP_KDF_derive(kctx, out, keylen, params) != 1)
|
||||
rv = 0;
|
||||
|
||||
EVP_KDF_CTX_free(kctx);
|
||||
|
||||
OSSL_TRACE_BEGIN(PKCS5V2) {
|
||||
BIO_printf(trc_out, "Password:\n");
|
||||
BIO_hex_string(trc_out,
|
||||
0, passlen, pass, passlen);
|
||||
BIO_printf(trc_out, "\n");
|
||||
BIO_printf(trc_out, "Salt:\n");
|
||||
BIO_hex_string(trc_out,
|
||||
0, saltlen, salt, saltlen);
|
||||
BIO_printf(trc_out, "\n");
|
||||
BIO_printf(trc_out, "Iteration count %d\n", iter);
|
||||
BIO_printf(trc_out, "Key:\n");
|
||||
BIO_hex_string(trc_out,
|
||||
0, keylen, out, keylen);
|
||||
BIO_printf(trc_out, "\n");
|
||||
} OSSL_TRACE_END(PKCS5V2);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const unsigned char *salt,
|
||||
int saltlen, int iter, const EVP_MD *digest, int keylen,
|
||||
unsigned char *out)
|
||||
{
|
||||
return ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, iter, digest,
|
||||
keylen, out, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
|
||||
const unsigned char *salt, int saltlen, int iter,
|
||||
int keylen, unsigned char *out)
|
||||
{
|
||||
EVP_MD *digest;
|
||||
int r = 0;
|
||||
|
||||
if ((digest = EVP_MD_fetch(NULL, SN_sha1, NULL)) != NULL)
|
||||
r = ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, iter,
|
||||
digest, keylen, out, NULL, NULL);
|
||||
EVP_MD_free(digest);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the key derivation function itself. This is a bit evil because it has
|
||||
* to check the ASN1 parameters are valid: and there are quite a few of
|
||||
* them...
|
||||
*/
|
||||
|
||||
int PKCS5_v2_PBE_keyivgen_ex(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, const EVP_CIPHER *c,
|
||||
const EVP_MD *md, int en_de,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
PBE2PARAM *pbe2 = NULL;
|
||||
char ciph_name[80];
|
||||
const EVP_CIPHER *cipher = NULL;
|
||||
EVP_CIPHER *cipher_fetch = NULL;
|
||||
EVP_PBE_KEYGEN_EX *kdf;
|
||||
|
||||
int rv = 0;
|
||||
|
||||
pbe2 = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBE2PARAM), param);
|
||||
if (pbe2 == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* See if we recognise the key derivation function */
|
||||
if (!EVP_PBE_find_ex(EVP_PBE_TYPE_KDF, OBJ_obj2nid(pbe2->keyfunc->algorithm),
|
||||
NULL, NULL, NULL, &kdf)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* lets see if we recognise the encryption algorithm.
|
||||
*/
|
||||
if (OBJ_obj2txt(ciph_name, sizeof(ciph_name), pbe2->encryption->algorithm, 0) <= 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_CIPHER);
|
||||
goto err;
|
||||
}
|
||||
|
||||
(void)ERR_set_mark();
|
||||
cipher = cipher_fetch = EVP_CIPHER_fetch(libctx, ciph_name, propq);
|
||||
/* Fallback to legacy method */
|
||||
if (cipher == NULL)
|
||||
cipher = EVP_get_cipherbyname(ciph_name);
|
||||
|
||||
if (cipher == NULL) {
|
||||
(void)ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_CIPHER);
|
||||
goto err;
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
|
||||
/* Fixup cipher based on AlgorithmIdentifier */
|
||||
if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de))
|
||||
goto err;
|
||||
if (EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) <= 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_CIPHER_PARAMETER_ERROR);
|
||||
goto err;
|
||||
}
|
||||
rv = kdf(ctx, pass, passlen, pbe2->keyfunc->parameter, NULL, NULL, en_de, libctx, propq);
|
||||
err:
|
||||
EVP_CIPHER_free(cipher_fetch);
|
||||
PBE2PARAM_free(pbe2);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
|
||||
ASN1_TYPE *param, const EVP_CIPHER *c,
|
||||
const EVP_MD *md, int en_de)
|
||||
{
|
||||
return PKCS5_v2_PBE_keyivgen_ex(ctx, pass, passlen, param, c, md, en_de, NULL, NULL);
|
||||
}
|
||||
|
||||
int PKCS5_v2_PBKDF2_keyivgen_ex(EVP_CIPHER_CTX *ctx, const char *pass,
|
||||
int passlen, ASN1_TYPE *param,
|
||||
const EVP_CIPHER *c, const EVP_MD *md, int en_de,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
|
||||
int saltlen, iter, t;
|
||||
int rv = 0;
|
||||
unsigned int keylen = 0;
|
||||
int prf_nid, hmac_md_nid;
|
||||
PBKDF2PARAM *kdf = NULL;
|
||||
const EVP_MD *prfmd = NULL;
|
||||
EVP_MD *prfmd_fetch = NULL;
|
||||
|
||||
if (EVP_CIPHER_CTX_get0_cipher(ctx) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
|
||||
goto err;
|
||||
}
|
||||
keylen = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
OPENSSL_assert(keylen <= sizeof(key));
|
||||
|
||||
/* Decode parameter */
|
||||
|
||||
kdf = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), param);
|
||||
|
||||
if (kdf == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
t = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
if (t < 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH);
|
||||
goto err;
|
||||
}
|
||||
keylen = t;
|
||||
|
||||
/* Now check the parameters of the kdf */
|
||||
|
||||
if (kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEYLENGTH);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (kdf->prf)
|
||||
prf_nid = OBJ_obj2nid(kdf->prf->algorithm);
|
||||
else
|
||||
prf_nid = NID_hmacWithSHA1;
|
||||
|
||||
if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRF);
|
||||
goto err;
|
||||
}
|
||||
|
||||
(void)ERR_set_mark();
|
||||
prfmd = prfmd_fetch = EVP_MD_fetch(libctx, OBJ_nid2sn(hmac_md_nid), propq);
|
||||
if (prfmd == NULL)
|
||||
prfmd = EVP_get_digestbynid(hmac_md_nid);
|
||||
if (prfmd == NULL) {
|
||||
(void)ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRF);
|
||||
goto err;
|
||||
}
|
||||
(void)ERR_pop_to_mark();
|
||||
|
||||
if (kdf->salt->type != V_ASN1_OCTET_STRING) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_SALT_TYPE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* it seems that its all OK */
|
||||
salt = kdf->salt->value.octet_string->data;
|
||||
saltlen = kdf->salt->value.octet_string->length;
|
||||
iter = ASN1_INTEGER_get(kdf->iter);
|
||||
if (!ossl_pkcs5_pbkdf2_hmac_ex(pass, passlen, salt, saltlen, iter, prfmd,
|
||||
keylen, key, libctx, propq))
|
||||
goto err;
|
||||
rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
|
||||
err:
|
||||
OPENSSL_cleanse(key, keylen);
|
||||
PBKDF2PARAM_free(kdf);
|
||||
EVP_MD_free(prfmd_fetch);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
|
||||
int passlen, ASN1_TYPE *param,
|
||||
const EVP_CIPHER *c, const EVP_MD *md, int en_de)
|
||||
{
|
||||
return PKCS5_v2_PBKDF2_keyivgen_ex(ctx, pass, passlen, param, c, md, en_de,
|
||||
NULL, NULL);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use the deprecated RSA low level calls */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
int EVP_PKEY_decrypt_old(unsigned char *key, const unsigned char *ek, int ekl,
|
||||
EVP_PKEY *priv)
|
||||
{
|
||||
int ret = -1;
|
||||
RSA *rsa = NULL;
|
||||
|
||||
if (EVP_PKEY_get_id(priv) != EVP_PKEY_RSA) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PUBLIC_KEY_NOT_RSA);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rsa = evp_pkey_get0_RSA_int(priv);
|
||||
if (rsa == NULL)
|
||||
goto err;
|
||||
|
||||
ret =
|
||||
RSA_private_decrypt(ekl, ek, key, rsa, RSA_PKCS1_PADDING);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use the deprecated RSA low level calls */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
int EVP_PKEY_encrypt_old(unsigned char *ek, const unsigned char *key,
|
||||
int key_len, EVP_PKEY *pubk)
|
||||
{
|
||||
int ret = 0;
|
||||
RSA *rsa = NULL;
|
||||
|
||||
if (EVP_PKEY_get_id(pubk) != EVP_PKEY_RSA) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PUBLIC_KEY_NOT_RSA);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rsa = evp_pkey_get0_RSA_int(pubk);
|
||||
if (rsa == NULL)
|
||||
goto err;
|
||||
|
||||
ret =
|
||||
RSA_public_encrypt(key_len, key, ek, rsa, RSA_PKCS1_PADDING);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Legacy EVP_PKEY assign/set/get APIs are deprecated for public use, but
|
||||
* still ok for internal use, particularly in providers.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/types.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ec.h>
|
||||
#include "crypto/types.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!RSA_up_ref(key))
|
||||
return 0;
|
||||
|
||||
ret = EVP_PKEY_assign_RSA(pkey, key);
|
||||
|
||||
if (!ret)
|
||||
RSA_free(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RSA *evp_pkey_get0_RSA_int(const EVP_PKEY *pkey)
|
||||
{
|
||||
if (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_RSA_PSS) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_EXPECTING_AN_RSA_KEY);
|
||||
return NULL;
|
||||
}
|
||||
return evp_pkey_get_legacy((EVP_PKEY *)pkey);
|
||||
}
|
||||
|
||||
const RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey)
|
||||
{
|
||||
return evp_pkey_get0_RSA_int(pkey);
|
||||
}
|
||||
|
||||
RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey)
|
||||
{
|
||||
RSA *ret = evp_pkey_get0_RSA_int(pkey);
|
||||
|
||||
if (ret != NULL && !RSA_up_ref(ret))
|
||||
ret = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key)
|
||||
{
|
||||
if (!EC_KEY_up_ref(key))
|
||||
return 0;
|
||||
if (!EVP_PKEY_assign_EC_KEY(pkey, key)) {
|
||||
EC_KEY_free(key);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
EC_KEY *evp_pkey_get0_EC_KEY_int(const EVP_PKEY *pkey)
|
||||
{
|
||||
if (EVP_PKEY_get_base_id(pkey) != EVP_PKEY_EC) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_EXPECTING_A_EC_KEY);
|
||||
return NULL;
|
||||
}
|
||||
return evp_pkey_get_legacy((EVP_PKEY *)pkey);
|
||||
}
|
||||
|
||||
const EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey)
|
||||
{
|
||||
return evp_pkey_get0_EC_KEY_int(pkey);
|
||||
}
|
||||
|
||||
EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey)
|
||||
{
|
||||
EC_KEY *ret = evp_pkey_get0_EC_KEY_int(pkey);
|
||||
|
||||
if (ret != NULL && !EC_KEY_up_ref(ret))
|
||||
ret = NULL;
|
||||
return ret;
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
|
||||
const unsigned char *ek, int ekl, const unsigned char *iv,
|
||||
EVP_PKEY *priv)
|
||||
{
|
||||
unsigned char *key = NULL;
|
||||
size_t keylen = 0;
|
||||
int ret = 0;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
|
||||
if (type) {
|
||||
EVP_CIPHER_CTX_reset(ctx);
|
||||
if (!EVP_DecryptInit_ex(ctx, type, NULL, NULL, NULL))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (priv == NULL)
|
||||
return 1;
|
||||
|
||||
if ((pctx = EVP_PKEY_CTX_new(priv, NULL)) == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_decrypt_init(pctx) <= 0
|
||||
|| EVP_PKEY_decrypt(pctx, NULL, &keylen, ek, ekl) <= 0)
|
||||
goto err;
|
||||
|
||||
if ((key = OPENSSL_malloc(keylen)) == NULL)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_decrypt(pctx, key, &keylen, ek, ekl) <= 0)
|
||||
goto err;
|
||||
|
||||
if (EVP_CIPHER_CTX_set_key_length(ctx, keylen) <= 0
|
||||
|| !EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
err:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
OPENSSL_clear_free(key, keylen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = EVP_DecryptFinal_ex(ctx, out, outl);
|
||||
if (i)
|
||||
i = EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL);
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/provider.h"
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
|
||||
unsigned char **ek, int *ekl, unsigned char *iv,
|
||||
EVP_PKEY **pubk, int npubk)
|
||||
{
|
||||
unsigned char key[EVP_MAX_KEY_LENGTH];
|
||||
const OSSL_PROVIDER *prov;
|
||||
OSSL_LIB_CTX *libctx = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
const EVP_CIPHER *cipher;
|
||||
int i, len;
|
||||
int rv = 0;
|
||||
|
||||
if (type != NULL) {
|
||||
EVP_CIPHER_CTX_reset(ctx);
|
||||
if (!EVP_EncryptInit_ex(ctx, type, NULL, NULL, NULL))
|
||||
return 0;
|
||||
}
|
||||
if ((cipher = EVP_CIPHER_CTX_get0_cipher(ctx)) != NULL
|
||||
&& (prov = EVP_CIPHER_get0_provider(cipher)) != NULL)
|
||||
libctx = ossl_provider_libctx(prov);
|
||||
if ((npubk <= 0) || !pubk)
|
||||
return 1;
|
||||
|
||||
if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
|
||||
return 0;
|
||||
|
||||
len = EVP_CIPHER_CTX_get_iv_length(ctx);
|
||||
if (len < 0 || RAND_priv_bytes_ex(libctx, iv, len, 0) <= 0)
|
||||
goto err;
|
||||
|
||||
len = EVP_CIPHER_CTX_get_key_length(ctx);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
if (!EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < npubk; i++) {
|
||||
size_t keylen = len;
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_from_pkey(libctx, pubk[i], NULL);
|
||||
if (pctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt_init(pctx) <= 0
|
||||
|| EVP_PKEY_encrypt(pctx, ek[i], &keylen, key, keylen) <= 0)
|
||||
goto err;
|
||||
ekl[i] = (int)keylen;
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
}
|
||||
pctx = NULL;
|
||||
rv = npubk;
|
||||
err:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
OPENSSL_cleanse(key, sizeof(key));
|
||||
return rv;
|
||||
}
|
||||
|
||||
int EVP_SealFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
|
||||
{
|
||||
int i;
|
||||
i = EVP_EncryptFinal_ex(ctx, out, outl);
|
||||
if (i)
|
||||
i = EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, NULL);
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
int EVP_SignFinal_ex(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
unsigned int *siglen, EVP_PKEY *pkey, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
unsigned char m[EVP_MAX_MD_SIZE];
|
||||
unsigned int m_len = 0;
|
||||
int i = 0;
|
||||
size_t sltmp;
|
||||
EVP_PKEY_CTX *pkctx = NULL;
|
||||
|
||||
*siglen = 0;
|
||||
if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) {
|
||||
if (!EVP_DigestFinal_ex(ctx, m, &m_len))
|
||||
goto err;
|
||||
} else {
|
||||
int rv = 0;
|
||||
EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
|
||||
|
||||
if (tmp_ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return 0;
|
||||
}
|
||||
rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx);
|
||||
if (rv)
|
||||
rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len);
|
||||
else
|
||||
rv = EVP_DigestFinal_ex(ctx, m, &m_len);
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
if (!rv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sltmp = (size_t)EVP_PKEY_get_size(pkey);
|
||||
i = 0;
|
||||
pkctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
|
||||
if (pkctx == NULL)
|
||||
goto err;
|
||||
if (EVP_PKEY_sign_init(pkctx) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_get0_md(ctx)) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_sign(pkctx, sigret, &sltmp, m, m_len) <= 0)
|
||||
goto err;
|
||||
*siglen = sltmp;
|
||||
i = 1;
|
||||
err:
|
||||
EVP_PKEY_CTX_free(pkctx);
|
||||
return i;
|
||||
}
|
||||
|
||||
int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
unsigned int *siglen, EVP_PKEY *pkey)
|
||||
{
|
||||
return EVP_SignFinal_ex(ctx, sigret, siglen, pkey, NULL, NULL);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/evp.h"
|
||||
|
||||
int EVP_VerifyFinal_ex(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
||||
unsigned int siglen, EVP_PKEY *pkey, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
unsigned char m[EVP_MAX_MD_SIZE];
|
||||
unsigned int m_len = 0;
|
||||
int i = 0;
|
||||
EVP_PKEY_CTX *pkctx = NULL;
|
||||
|
||||
if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) {
|
||||
if (!EVP_DigestFinal_ex(ctx, m, &m_len))
|
||||
goto err;
|
||||
} else {
|
||||
int rv = 0;
|
||||
EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
|
||||
|
||||
if (tmp_ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return 0;
|
||||
}
|
||||
rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx);
|
||||
if (rv)
|
||||
rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len);
|
||||
else
|
||||
rv = EVP_DigestFinal_ex(ctx, m, &m_len);
|
||||
EVP_MD_CTX_free(tmp_ctx);
|
||||
if (!rv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = -1;
|
||||
pkctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
|
||||
if (pkctx == NULL)
|
||||
goto err;
|
||||
if (EVP_PKEY_verify_init(pkctx) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_get0_md(ctx)) <= 0)
|
||||
goto err;
|
||||
i = EVP_PKEY_verify(pkctx, sigbuf, siglen, m, m_len);
|
||||
err:
|
||||
EVP_PKEY_CTX_free(pkctx);
|
||||
return i;
|
||||
}
|
||||
|
||||
int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
||||
unsigned int siglen, EVP_PKEY *pkey)
|
||||
{
|
||||
return EVP_VerifyFinal_ex(ctx, sigbuf, siglen, pkey, NULL, NULL);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include "internal/numbers.h"
|
||||
|
||||
#ifndef OPENSSL_NO_SCRYPT
|
||||
|
||||
/*
|
||||
* Maximum permitted memory allow this to be overridden with Configuration
|
||||
* option: e.g. -DSCRYPT_MAX_MEM=0 for maximum possible.
|
||||
*/
|
||||
|
||||
#ifdef SCRYPT_MAX_MEM
|
||||
# if SCRYPT_MAX_MEM == 0
|
||||
# undef SCRYPT_MAX_MEM
|
||||
/*
|
||||
* Although we could theoretically allocate SIZE_MAX memory that would leave
|
||||
* no memory available for anything else so set limit as half that.
|
||||
*/
|
||||
# define SCRYPT_MAX_MEM (SIZE_MAX/2)
|
||||
# endif
|
||||
#else
|
||||
/* Default memory limit: 32 MB */
|
||||
# define SCRYPT_MAX_MEM (1024 * 1024 * 32)
|
||||
#endif
|
||||
|
||||
int EVP_PBE_scrypt_ex(const char *pass, size_t passlen,
|
||||
const unsigned char *salt, size_t saltlen,
|
||||
uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
|
||||
unsigned char *key, size_t keylen,
|
||||
OSSL_LIB_CTX *ctx, const char *propq)
|
||||
{
|
||||
const char *empty = "";
|
||||
int rv = 1;
|
||||
EVP_KDF *kdf;
|
||||
EVP_KDF_CTX *kctx;
|
||||
OSSL_PARAM params[7], *z = params;
|
||||
|
||||
if (r > UINT32_MAX || p > UINT32_MAX) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_PARAMETER_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Maintain existing behaviour. */
|
||||
if (pass == NULL) {
|
||||
pass = empty;
|
||||
passlen = 0;
|
||||
}
|
||||
if (salt == NULL) {
|
||||
salt = (const unsigned char *)empty;
|
||||
saltlen = 0;
|
||||
}
|
||||
if (maxmem == 0)
|
||||
maxmem = SCRYPT_MAX_MEM;
|
||||
|
||||
/* Use OSSL_LIB_CTX_set0_default() if you need a library context */
|
||||
kdf = EVP_KDF_fetch(ctx, OSSL_KDF_NAME_SCRYPT, propq);
|
||||
kctx = EVP_KDF_CTX_new(kdf);
|
||||
EVP_KDF_free(kdf);
|
||||
if (kctx == NULL)
|
||||
return 0;
|
||||
|
||||
*z++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
|
||||
(unsigned char *)pass,
|
||||
passlen);
|
||||
*z++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
(unsigned char *)salt, saltlen);
|
||||
*z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_N, &N);
|
||||
*z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_R, &r);
|
||||
*z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_P, &p);
|
||||
*z++ = OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_SCRYPT_MAXMEM, &maxmem);
|
||||
*z = OSSL_PARAM_construct_end();
|
||||
if (EVP_KDF_derive(kctx, key, keylen, params) != 1)
|
||||
rv = 0;
|
||||
|
||||
EVP_KDF_CTX_free(kctx);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int EVP_PBE_scrypt(const char *pass, size_t passlen,
|
||||
const unsigned char *salt, size_t saltlen,
|
||||
uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
|
||||
unsigned char *key, size_t keylen)
|
||||
{
|
||||
return EVP_PBE_scrypt_ex(pass, passlen, salt, saltlen, N, r, p, maxmem,
|
||||
key, keylen, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/bn.h"
|
||||
#ifndef FIPS_MODULE
|
||||
# include "crypto/asn1.h"
|
||||
#endif
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 1 True
|
||||
* 0 False
|
||||
* -1 Unsupported (use legacy path)
|
||||
*/
|
||||
static int try_provided_check(EVP_PKEY_CTX *ctx, int selection, int checktype)
|
||||
{
|
||||
EVP_KEYMGMT *keymgmt;
|
||||
void *keydata;
|
||||
|
||||
if (evp_pkey_ctx_is_legacy(ctx))
|
||||
return -1;
|
||||
|
||||
keymgmt = ctx->keymgmt;
|
||||
keydata = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
||||
&keymgmt, ctx->propquery);
|
||||
if (keydata == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return evp_keymgmt_validate(keymgmt, keydata, selection, checktype);
|
||||
}
|
||||
|
||||
static int evp_pkey_public_check_combined(EVP_PKEY_CTX *ctx, int checktype)
|
||||
{
|
||||
EVP_PKEY *pkey = ctx->pkey;
|
||||
int ok;
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ok = try_provided_check(ctx, OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
|
||||
checktype)) != -1)
|
||||
return ok;
|
||||
|
||||
if (pkey->type == EVP_PKEY_NONE)
|
||||
goto not_supported;
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
/* legacy */
|
||||
/* call customized public key check function first */
|
||||
if (ctx->pmeth->public_check != NULL)
|
||||
return ctx->pmeth->public_check(pkey);
|
||||
|
||||
/* use default public key check function in ameth */
|
||||
if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL)
|
||||
goto not_supported;
|
||||
|
||||
return pkey->ameth->pkey_public_check(pkey);
|
||||
#endif
|
||||
not_supported:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_public_check_combined(ctx, OSSL_KEYMGMT_VALIDATE_FULL_CHECK);
|
||||
}
|
||||
|
||||
int EVP_PKEY_public_check_quick(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_public_check_combined(ctx, OSSL_KEYMGMT_VALIDATE_QUICK_CHECK);
|
||||
}
|
||||
|
||||
static int evp_pkey_param_check_combined(EVP_PKEY_CTX *ctx, int checktype)
|
||||
{
|
||||
EVP_PKEY *pkey = ctx->pkey;
|
||||
int ok;
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ok = try_provided_check(ctx,
|
||||
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS,
|
||||
checktype)) != -1)
|
||||
return ok;
|
||||
|
||||
if (pkey->type == EVP_PKEY_NONE)
|
||||
goto not_supported;
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
/* legacy */
|
||||
/* call customized param check function first */
|
||||
if (ctx->pmeth->param_check != NULL)
|
||||
return ctx->pmeth->param_check(pkey);
|
||||
|
||||
/* use default param check function in ameth */
|
||||
if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL)
|
||||
goto not_supported;
|
||||
|
||||
return pkey->ameth->pkey_param_check(pkey);
|
||||
#endif
|
||||
not_supported:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_param_check_combined(ctx, OSSL_KEYMGMT_VALIDATE_FULL_CHECK);
|
||||
}
|
||||
|
||||
int EVP_PKEY_param_check_quick(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return evp_pkey_param_check_combined(ctx, OSSL_KEYMGMT_VALIDATE_QUICK_CHECK);
|
||||
}
|
||||
|
||||
int EVP_PKEY_private_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
EVP_PKEY *pkey = ctx->pkey;
|
||||
int ok;
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ok = try_provided_check(ctx, OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
|
||||
OSSL_KEYMGMT_VALIDATE_FULL_CHECK)) != -1)
|
||||
return ok;
|
||||
|
||||
/* not supported for legacy keys */
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int EVP_PKEY_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return EVP_PKEY_pairwise_check(ctx);
|
||||
}
|
||||
|
||||
int EVP_PKEY_pairwise_check(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
EVP_PKEY *pkey = ctx->pkey;
|
||||
int ok;
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ok = try_provided_check(ctx, OSSL_KEYMGMT_SELECT_KEYPAIR,
|
||||
OSSL_KEYMGMT_VALIDATE_FULL_CHECK)) != -1)
|
||||
return ok;
|
||||
|
||||
if (pkey->type == EVP_PKEY_NONE)
|
||||
goto not_supported;
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
/* legacy */
|
||||
/* call customized check function first */
|
||||
if (ctx->pmeth->check != NULL)
|
||||
return ctx->pmeth->check(pkey);
|
||||
|
||||
/* use default check function in ameth */
|
||||
if (pkey->ameth == NULL || pkey->ameth->pkey_check == NULL)
|
||||
goto not_supported;
|
||||
|
||||
return pkey->ameth->pkey_check(pkey);
|
||||
#endif
|
||||
not_supported:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/core.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/core.h"
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/bn.h"
|
||||
#ifndef FIPS_MODULE
|
||||
# include "crypto/asn1.h"
|
||||
#endif
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
static int gen_init(EVP_PKEY_CTX *ctx, int operation)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ctx == NULL)
|
||||
goto not_supported;
|
||||
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = operation;
|
||||
|
||||
if (ctx->keymgmt == NULL || ctx->keymgmt->gen_init == NULL)
|
||||
goto legacy;
|
||||
|
||||
switch (operation) {
|
||||
case EVP_PKEY_OP_PARAMGEN:
|
||||
ctx->op.keymgmt.genctx =
|
||||
evp_keymgmt_gen_init(ctx->keymgmt,
|
||||
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, NULL);
|
||||
break;
|
||||
case EVP_PKEY_OP_KEYGEN:
|
||||
ctx->op.keymgmt.genctx =
|
||||
evp_keymgmt_gen_init(ctx->keymgmt, OSSL_KEYMGMT_SELECT_KEYPAIR,
|
||||
NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->op.keymgmt.genctx == NULL)
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
else
|
||||
ret = 1;
|
||||
goto end;
|
||||
|
||||
legacy:
|
||||
#ifdef FIPS_MODULE
|
||||
goto not_supported;
|
||||
#else
|
||||
if (ctx->pmeth == NULL
|
||||
|| (operation == EVP_PKEY_OP_PARAMGEN
|
||||
&& ctx->pmeth->paramgen == NULL)
|
||||
|| (operation == EVP_PKEY_OP_KEYGEN
|
||||
&& ctx->pmeth->keygen == NULL))
|
||||
goto not_supported;
|
||||
|
||||
ret = 1;
|
||||
switch (operation) {
|
||||
case EVP_PKEY_OP_PARAMGEN:
|
||||
if (ctx->pmeth->paramgen_init != NULL)
|
||||
ret = ctx->pmeth->paramgen_init(ctx);
|
||||
break;
|
||||
case EVP_PKEY_OP_KEYGEN:
|
||||
if (ctx->pmeth->keygen_init != NULL)
|
||||
ret = ctx->pmeth->keygen_init(ctx);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
if (ret <= 0 && ctx != NULL) {
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
}
|
||||
return ret;
|
||||
|
||||
not_supported:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return gen_init(ctx, EVP_PKEY_OP_PARAMGEN);
|
||||
}
|
||||
|
||||
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return gen_init(ctx, EVP_PKEY_OP_KEYGEN);
|
||||
}
|
||||
|
||||
static int ossl_callback_to_pkey_gencb(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx = arg;
|
||||
const OSSL_PARAM *param = NULL;
|
||||
int p = -1, n = -1;
|
||||
|
||||
if (ctx->pkey_gencb == NULL)
|
||||
return 1; /* No callback? That's fine */
|
||||
|
||||
if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_POTENTIAL))
|
||||
== NULL
|
||||
|| !OSSL_PARAM_get_int(param, &p))
|
||||
return 0;
|
||||
if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_ITERATION))
|
||||
== NULL
|
||||
|| !OSSL_PARAM_get_int(param, &n))
|
||||
return 0;
|
||||
|
||||
ctx->keygen_info[0] = p;
|
||||
ctx->keygen_info[1] = n;
|
||||
|
||||
return ctx->pkey_gencb(ctx);
|
||||
}
|
||||
|
||||
int EVP_PKEY_generate(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
||||
{
|
||||
int ret = 0;
|
||||
EVP_PKEY *allocated_pkey = NULL;
|
||||
/* Legacy compatible keygen callback info, only used with provider impls */
|
||||
int gentmp[2];
|
||||
|
||||
if (ppkey == NULL)
|
||||
return -1;
|
||||
|
||||
if (ctx == NULL)
|
||||
goto not_supported;
|
||||
|
||||
if ((ctx->operation & EVP_PKEY_OP_TYPE_GEN) == 0)
|
||||
goto not_initialized;
|
||||
|
||||
if (*ppkey == NULL)
|
||||
*ppkey = allocated_pkey = EVP_PKEY_new();
|
||||
|
||||
if (*ppkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->op.keymgmt.genctx == NULL)
|
||||
goto legacy;
|
||||
|
||||
/*
|
||||
* Assigning gentmp to ctx->keygen_info is something our legacy
|
||||
* implementations do. Because the provider implementations aren't
|
||||
* allowed to reach into our EVP_PKEY_CTX, we need to provide similar
|
||||
* space for backward compatibility. It's ok that we attach a local
|
||||
* variable, as it should only be useful in the calls down from here.
|
||||
* This is cleared as soon as it isn't useful any more, i.e. directly
|
||||
* after the evp_keymgmt_util_gen() call.
|
||||
*/
|
||||
ctx->keygen_info = gentmp;
|
||||
ctx->keygen_info_count = 2;
|
||||
|
||||
ret = 1;
|
||||
if (ctx->pkey != NULL) {
|
||||
EVP_KEYMGMT *tmp_keymgmt = ctx->keymgmt;
|
||||
void *keydata =
|
||||
evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
|
||||
&tmp_keymgmt, ctx->propquery);
|
||||
|
||||
if (tmp_keymgmt == NULL)
|
||||
goto not_supported;
|
||||
/*
|
||||
* It's ok if keydata is NULL here. The backend is expected to deal
|
||||
* with that as it sees fit.
|
||||
*/
|
||||
ret = evp_keymgmt_gen_set_template(ctx->keymgmt,
|
||||
ctx->op.keymgmt.genctx, keydata);
|
||||
}
|
||||
|
||||
/*
|
||||
* the returned value from evp_keymgmt_util_gen() is cached in *ppkey,
|
||||
* so we do not need to save it, just check it.
|
||||
*/
|
||||
ret = ret
|
||||
&& (evp_keymgmt_util_gen(*ppkey, ctx->keymgmt, ctx->op.keymgmt.genctx,
|
||||
ossl_callback_to_pkey_gencb, ctx)
|
||||
!= NULL);
|
||||
|
||||
ctx->keygen_info = NULL;
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
/* In case |*ppkey| was originally a legacy key */
|
||||
if (ret)
|
||||
evp_pkey_free_legacy(*ppkey);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Because we still have legacy keys
|
||||
*/
|
||||
(*ppkey)->type = ctx->legacy_keytype;
|
||||
|
||||
goto end;
|
||||
|
||||
legacy:
|
||||
#ifdef FIPS_MODULE
|
||||
goto not_supported;
|
||||
#else
|
||||
/*
|
||||
* If we get here then we're using legacy paramgen/keygen. In that case
|
||||
* the pkey in ctx (if there is one) had better not be provided (because the
|
||||
* legacy methods may not know how to handle it). However we can only get
|
||||
* here if ctx->op.keymgmt.genctx == NULL, but that should never be the case
|
||||
* if ctx->pkey is provided because we don't allow this when we initialise
|
||||
* the ctx.
|
||||
*/
|
||||
if (ctx->pkey != NULL && !ossl_assert(!evp_pkey_is_provided(ctx->pkey)))
|
||||
goto not_accessible;
|
||||
|
||||
switch (ctx->operation) {
|
||||
case EVP_PKEY_OP_PARAMGEN:
|
||||
ret = ctx->pmeth->paramgen(ctx, *ppkey);
|
||||
break;
|
||||
case EVP_PKEY_OP_KEYGEN:
|
||||
ret = ctx->pmeth->keygen(ctx, *ppkey);
|
||||
break;
|
||||
default:
|
||||
goto not_supported;
|
||||
}
|
||||
#endif
|
||||
|
||||
end:
|
||||
if (ret <= 0) {
|
||||
if (allocated_pkey != NULL)
|
||||
*ppkey = NULL;
|
||||
EVP_PKEY_free(allocated_pkey);
|
||||
}
|
||||
return ret;
|
||||
|
||||
not_supported:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
ret = -2;
|
||||
goto end;
|
||||
not_initialized:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
ret = -1;
|
||||
goto end;
|
||||
#ifndef FIPS_MODULE
|
||||
not_accessible:
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS);
|
||||
ret = -1;
|
||||
goto end;
|
||||
#endif
|
||||
}
|
||||
|
||||
int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
||||
{
|
||||
if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
return EVP_PKEY_generate(ctx, ppkey);
|
||||
}
|
||||
|
||||
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
|
||||
{
|
||||
if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED);
|
||||
return -1;
|
||||
}
|
||||
return EVP_PKEY_generate(ctx, ppkey);
|
||||
}
|
||||
|
||||
void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb)
|
||||
{
|
||||
ctx->pkey_gencb = cb;
|
||||
}
|
||||
|
||||
EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return ctx->pkey_gencb;
|
||||
}
|
||||
|
||||
/*
|
||||
* "translation callback" to call EVP_PKEY_CTX callbacks using BN_GENCB style
|
||||
* callbacks.
|
||||
*/
|
||||
|
||||
static int trans_cb(int a, int b, BN_GENCB *gcb)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx = BN_GENCB_get_arg(gcb);
|
||||
ctx->keygen_info[0] = a;
|
||||
ctx->keygen_info[1] = b;
|
||||
return ctx->pkey_gencb(ctx);
|
||||
}
|
||||
|
||||
void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
BN_GENCB_set(cb, trans_cb, ctx);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
return ctx->keygen_info_count;
|
||||
if (idx < 0 || idx > ctx->keygen_info_count)
|
||||
return 0;
|
||||
return ctx->keygen_info[idx];
|
||||
}
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
|
||||
EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
|
||||
const unsigned char *key, int keylen)
|
||||
{
|
||||
EVP_PKEY_CTX *mac_ctx = NULL;
|
||||
EVP_PKEY *mac_key = NULL;
|
||||
mac_ctx = EVP_PKEY_CTX_new_id(type, e);
|
||||
if (!mac_ctx)
|
||||
return NULL;
|
||||
if (EVP_PKEY_keygen_init(mac_ctx) <= 0)
|
||||
goto merr;
|
||||
if (EVP_PKEY_CTX_set_mac_key(mac_ctx, key, keylen) <= 0)
|
||||
goto merr;
|
||||
if (EVP_PKEY_keygen(mac_ctx, &mac_key) <= 0)
|
||||
goto merr;
|
||||
merr:
|
||||
EVP_PKEY_CTX_free(mac_ctx);
|
||||
return mac_key;
|
||||
}
|
||||
|
||||
#endif /* FIPS_MODULE */
|
||||
|
||||
/*- All methods below can also be used in FIPS_MODULE */
|
||||
|
||||
static int fromdata_init(EVP_PKEY_CTX *ctx, int operation)
|
||||
{
|
||||
if (ctx == NULL || ctx->keytype == NULL)
|
||||
goto not_supported;
|
||||
|
||||
evp_pkey_ctx_free_old_ops(ctx);
|
||||
if (ctx->keymgmt == NULL)
|
||||
goto not_supported;
|
||||
|
||||
ctx->operation = operation;
|
||||
return 1;
|
||||
|
||||
not_supported:
|
||||
if (ctx != NULL)
|
||||
ctx->operation = EVP_PKEY_OP_UNDEFINED;
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int EVP_PKEY_fromdata_init(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return fromdata_init(ctx, EVP_PKEY_OP_FROMDATA);
|
||||
}
|
||||
|
||||
int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, int selection,
|
||||
OSSL_PARAM params[])
|
||||
{
|
||||
void *keydata = NULL;
|
||||
EVP_PKEY *allocated_pkey = NULL;
|
||||
|
||||
if (ctx == NULL || (ctx->operation & EVP_PKEY_OP_FROMDATA) == 0) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ppkey == NULL)
|
||||
return -1;
|
||||
|
||||
if (*ppkey == NULL)
|
||||
allocated_pkey = *ppkey = EVP_PKEY_new();
|
||||
|
||||
if (*ppkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
|
||||
return -1;
|
||||
}
|
||||
|
||||
keydata = evp_keymgmt_util_fromdata(*ppkey, ctx->keymgmt, selection, params);
|
||||
if (keydata == NULL) {
|
||||
if (allocated_pkey != NULL) {
|
||||
*ppkey = NULL;
|
||||
EVP_PKEY_free(allocated_pkey);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* keydata is cached in *ppkey, so we need not bother with it further */
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_PKEY_fromdata_settable(EVP_PKEY_CTX *ctx, int selection)
|
||||
{
|
||||
/* We call fromdata_init to get ctx->keymgmt populated */
|
||||
if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED) == 1)
|
||||
return evp_keymgmt_import_types(ctx->keymgmt, selection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static OSSL_CALLBACK ossl_pkey_todata_cb;
|
||||
|
||||
static int ossl_pkey_todata_cb(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
OSSL_PARAM **ret = arg;
|
||||
|
||||
*ret = OSSL_PARAM_dup(params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_todata(const EVP_PKEY *pkey, int selection, OSSL_PARAM **params)
|
||||
{
|
||||
if (params == NULL)
|
||||
return 0;
|
||||
return EVP_PKEY_export(pkey, selection, ossl_pkey_todata_cb, params);
|
||||
}
|
||||
|
||||
#ifndef FIPS_MODULE
|
||||
struct fake_import_data_st {
|
||||
OSSL_CALLBACK *export_cb;
|
||||
void *export_cbarg;
|
||||
};
|
||||
|
||||
static OSSL_FUNC_keymgmt_import_fn pkey_fake_import;
|
||||
static int pkey_fake_import(void *fake_keydata, int ignored_selection,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
struct fake_import_data_st *data = fake_keydata;
|
||||
|
||||
return data->export_cb(params, data->export_cbarg);
|
||||
}
|
||||
#endif
|
||||
|
||||
int EVP_PKEY_export(const EVP_PKEY *pkey, int selection,
|
||||
OSSL_CALLBACK *export_cb, void *export_cbarg)
|
||||
{
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
#ifndef FIPS_MODULE
|
||||
if (evp_pkey_is_legacy(pkey)) {
|
||||
struct fake_import_data_st data;
|
||||
|
||||
data.export_cb = export_cb;
|
||||
data.export_cbarg = export_cbarg;
|
||||
|
||||
/*
|
||||
* We don't need to care about libctx or propq here, as we're only
|
||||
* interested in the resulting OSSL_PARAM array.
|
||||
*/
|
||||
return pkey->ameth->export_to(pkey, &data, pkey_fake_import,
|
||||
NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
return evp_keymgmt_util_export(pkey, selection, export_cb, export_cbarg);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/params.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core_names.h>
|
||||
|
||||
#include "internal/common.h"
|
||||
#include "internal/provider.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
int EVP_SKEY_export(const EVP_SKEY *skey, int selection,
|
||||
OSSL_CALLBACK *export_cb, void *export_cbarg)
|
||||
{
|
||||
if (skey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return evp_skeymgmt_export(skey->skeymgmt, skey->keydata, selection, export_cb, export_cbarg);
|
||||
}
|
||||
|
||||
static EVP_SKEY *evp_skey_alloc(EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
EVP_SKEY *skey;
|
||||
|
||||
if (!ossl_assert(skeymgmt != NULL))
|
||||
return NULL;
|
||||
|
||||
if ((skey = OPENSSL_zalloc(sizeof(*skey))) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CRYPTO_NEW_REF(&skey->references, 1))
|
||||
goto err;
|
||||
|
||||
skey->lock = CRYPTO_THREAD_lock_new();
|
||||
if (skey->lock == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_CRYPTO_LIB);
|
||||
goto err;
|
||||
}
|
||||
skey->skeymgmt = skeymgmt;
|
||||
return skey;
|
||||
|
||||
err:
|
||||
CRYPTO_FREE_REF(&skey->references);
|
||||
CRYPTO_THREAD_lock_free(skey->lock);
|
||||
OPENSSL_free(skey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static EVP_SKEY *evp_skey_alloc_fetch(OSSL_LIB_CTX *libctx,
|
||||
const char *skeymgmtname,
|
||||
const char *propquery)
|
||||
{
|
||||
EVP_SKEYMGMT *skeymgmt;
|
||||
EVP_SKEY *skey;
|
||||
|
||||
skeymgmt = EVP_SKEYMGMT_fetch(libctx, skeymgmtname, propquery);
|
||||
if (skeymgmt == NULL) {
|
||||
/*
|
||||
* if the specific key_type is unknown, attempt to use the generic
|
||||
* key management
|
||||
*/
|
||||
skeymgmt = EVP_SKEYMGMT_fetch(libctx, OSSL_SKEY_TYPE_GENERIC, propquery);
|
||||
if (skeymgmt == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
skey = evp_skey_alloc(skeymgmt);
|
||||
if (skey == NULL)
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
|
||||
return skey;
|
||||
}
|
||||
|
||||
EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery,
|
||||
int selection, const OSSL_PARAM *params)
|
||||
{
|
||||
EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
|
||||
|
||||
if (skey == NULL)
|
||||
return NULL;
|
||||
|
||||
skey->keydata = evp_skeymgmt_import(skey->skeymgmt, selection, params);
|
||||
if (skey->keydata == NULL)
|
||||
goto err;
|
||||
|
||||
return skey;
|
||||
|
||||
err:
|
||||
EVP_SKEY_free(skey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
|
||||
const char *propquery, const OSSL_PARAM *params)
|
||||
{
|
||||
EVP_SKEY *skey = evp_skey_alloc_fetch(libctx, skeymgmtname, propquery);
|
||||
|
||||
if (skey == NULL)
|
||||
return NULL;
|
||||
|
||||
skey->keydata = evp_skeymgmt_generate(skey->skeymgmt, params);
|
||||
if (skey->keydata == NULL)
|
||||
goto err;
|
||||
|
||||
return skey;
|
||||
|
||||
err:
|
||||
EVP_SKEY_free(skey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct raw_key_details_st {
|
||||
const void **key;
|
||||
size_t *len;
|
||||
};
|
||||
|
||||
static int get_secret_key(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
const OSSL_PARAM *p = NULL;
|
||||
struct raw_key_details_st *raw_key = arg;
|
||||
|
||||
if ((p = OSSL_PARAM_locate_const(params, OSSL_SKEY_PARAM_RAW_BYTES)) != NULL)
|
||||
return OSSL_PARAM_get_octet_string_ptr(p, raw_key->key, raw_key->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_SKEY_get0_raw_key(const EVP_SKEY *skey, const unsigned char **key,
|
||||
size_t *len)
|
||||
{
|
||||
struct raw_key_details_st raw_key;
|
||||
|
||||
if (skey == NULL || key == NULL || len == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
raw_key.key = (const void **)key;
|
||||
raw_key.len = len;
|
||||
|
||||
return evp_skeymgmt_export(skey->skeymgmt, skey->keydata,
|
||||
OSSL_SKEYMGMT_SELECT_SECRET_KEY,
|
||||
get_secret_key, &raw_key);
|
||||
}
|
||||
|
||||
EVP_SKEY *EVP_SKEY_import_raw_key(OSSL_LIB_CTX *libctx, const char *skeymgmtname,
|
||||
unsigned char *key, size_t keylen,
|
||||
const char *propquery)
|
||||
{
|
||||
OSSL_PARAM params[2];
|
||||
|
||||
params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
|
||||
(void *)key, keylen);
|
||||
params[1] = OSSL_PARAM_construct_end();
|
||||
|
||||
return EVP_SKEY_import(libctx, skeymgmtname, propquery,
|
||||
OSSL_SKEYMGMT_SELECT_SECRET_KEY, params);
|
||||
}
|
||||
|
||||
int EVP_SKEY_up_ref(EVP_SKEY *skey)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (CRYPTO_UP_REF(&skey->references, &i) <= 0)
|
||||
return 0;
|
||||
|
||||
REF_PRINT_COUNT("EVP_SKEY", i, skey);
|
||||
REF_ASSERT_ISNT(i < 2);
|
||||
return i > 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
void EVP_SKEY_free(EVP_SKEY *skey)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (skey == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&skey->references, &i);
|
||||
REF_PRINT_COUNT("EVP_SKEY", i, skey);
|
||||
if (i > 0)
|
||||
return;
|
||||
REF_ASSERT_ISNT(i < 0);
|
||||
evp_skeymgmt_freedata(skey->skeymgmt, skey->keydata);
|
||||
|
||||
EVP_SKEYMGMT_free(skey->skeymgmt);
|
||||
|
||||
CRYPTO_THREAD_lock_free(skey->lock);
|
||||
CRYPTO_FREE_REF(&skey->references);
|
||||
OPENSSL_free(skey);
|
||||
}
|
||||
|
||||
const char *EVP_SKEY_get0_key_id(const EVP_SKEY *skey)
|
||||
{
|
||||
if (skey == NULL)
|
||||
return NULL;
|
||||
|
||||
if (skey->skeymgmt->get_key_id)
|
||||
return skey->skeymgmt->get_key_id(skey->keydata);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey)
|
||||
{
|
||||
if (skey == NULL)
|
||||
return NULL;
|
||||
|
||||
return skey->skeymgmt->type_name;
|
||||
|
||||
}
|
||||
|
||||
const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey)
|
||||
{
|
||||
if (skey == NULL)
|
||||
return NULL;
|
||||
|
||||
return ossl_provider_name(skey->skeymgmt->prov);
|
||||
}
|
||||
|
||||
int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name)
|
||||
{
|
||||
if (skey == NULL)
|
||||
return 0;
|
||||
|
||||
return EVP_SKEYMGMT_is_a(skey->skeymgmt, name);
|
||||
}
|
||||
|
||||
struct transfer_cb_ctx {
|
||||
int selection;
|
||||
EVP_SKEYMGMT *skeymgmt;
|
||||
void *keydata;
|
||||
};
|
||||
|
||||
static int transfer_cb(const OSSL_PARAM params[], void *arg)
|
||||
{
|
||||
struct transfer_cb_ctx *ctx = arg;
|
||||
|
||||
ctx->keydata = evp_skeymgmt_import(ctx->skeymgmt, ctx->selection, params);
|
||||
return 1;
|
||||
}
|
||||
|
||||
EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx,
|
||||
OSSL_PROVIDER *prov, const char *propquery)
|
||||
{
|
||||
struct transfer_cb_ctx ctx = { 0 };
|
||||
EVP_SKEYMGMT *skeymgmt = NULL;
|
||||
EVP_SKEY *ret = NULL;
|
||||
|
||||
if (skey == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (prov != NULL) {
|
||||
if (skey->skeymgmt->prov == prov)
|
||||
skeymgmt = skey->skeymgmt;
|
||||
else
|
||||
skeymgmt = evp_skeymgmt_fetch_from_prov(prov, skey->skeymgmt->type_name,
|
||||
propquery);
|
||||
} else {
|
||||
/* If no provider, get the default skeymgmt */
|
||||
skeymgmt = EVP_SKEYMGMT_fetch(libctx, skey->skeymgmt->type_name,
|
||||
propquery);
|
||||
}
|
||||
if (skeymgmt == NULL) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_FETCH_FAILED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Short-circuit if destination provider is the same as origin */
|
||||
if (skey->skeymgmt->name_id == skeymgmt->name_id
|
||||
&& skey->skeymgmt->prov == skeymgmt->prov) {
|
||||
if (!EVP_SKEY_up_ref(skey))
|
||||
goto err;
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
return skey;
|
||||
}
|
||||
|
||||
ctx.selection = OSSL_SKEYMGMT_SELECT_ALL;
|
||||
ctx.skeymgmt = skeymgmt;
|
||||
|
||||
if (!EVP_SKEY_export(skey, ctx.selection, transfer_cb, &ctx))
|
||||
goto err;
|
||||
|
||||
if (ctx.keydata == NULL)
|
||||
goto err;
|
||||
|
||||
ret = evp_skey_alloc(skeymgmt);
|
||||
if (ret == NULL)
|
||||
goto err;
|
||||
|
||||
ret->keydata = ctx.keydata;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
EVP_SKEY_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include "internal/core.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/refcount.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "evp_local.h"
|
||||
|
||||
void *evp_skeymgmt_generate(const EVP_SKEYMGMT *skeymgmt, const OSSL_PARAM params[])
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
|
||||
|
||||
return (skeymgmt->generate != NULL) ? skeymgmt->generate(provctx, params) : NULL;
|
||||
}
|
||||
|
||||
void *evp_skeymgmt_import(const EVP_SKEYMGMT *skeymgmt, int selection, const OSSL_PARAM params[])
|
||||
{
|
||||
void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
|
||||
|
||||
/* This is mandatory, no need to check for its presence */
|
||||
return skeymgmt->import(provctx, selection, params);
|
||||
}
|
||||
|
||||
int evp_skeymgmt_export(const EVP_SKEYMGMT *skeymgmt, void *keydata,
|
||||
int selection, OSSL_CALLBACK *param_cb, void *cbarg)
|
||||
{
|
||||
/* This is mandatory, no need to check for its presence */
|
||||
return skeymgmt->export(keydata, selection, param_cb, cbarg);
|
||||
}
|
||||
|
||||
void evp_skeymgmt_freedata(const EVP_SKEYMGMT *skeymgmt, void *keydata)
|
||||
{
|
||||
/* This is mandatory, no need to check for its presence */
|
||||
skeymgmt->free(keydata);
|
||||
}
|
||||
|
||||
static void *skeymgmt_new(void)
|
||||
{
|
||||
EVP_SKEYMGMT *skeymgmt = NULL;
|
||||
|
||||
if ((skeymgmt = OPENSSL_zalloc(sizeof(*skeymgmt))) == NULL)
|
||||
return NULL;
|
||||
if (!CRYPTO_NEW_REF(&skeymgmt->refcnt, 1)) {
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
return NULL;
|
||||
}
|
||||
return skeymgmt;
|
||||
}
|
||||
|
||||
static void *skeymgmt_from_algorithm(int name_id,
|
||||
const OSSL_ALGORITHM *algodef,
|
||||
OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *fns = algodef->implementation;
|
||||
EVP_SKEYMGMT *skeymgmt = NULL;
|
||||
|
||||
if ((skeymgmt = skeymgmt_new()) == NULL)
|
||||
return NULL;
|
||||
|
||||
skeymgmt->name_id = name_id;
|
||||
if ((skeymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
return NULL;
|
||||
}
|
||||
skeymgmt->description = algodef->algorithm_description;
|
||||
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_SKEYMGMT_FREE:
|
||||
if (skeymgmt->free == NULL)
|
||||
skeymgmt->free = OSSL_FUNC_skeymgmt_free(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_IMPORT:
|
||||
if (skeymgmt->import == NULL)
|
||||
skeymgmt->import = OSSL_FUNC_skeymgmt_import(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_EXPORT:
|
||||
if (skeymgmt->export == NULL)
|
||||
skeymgmt->export = OSSL_FUNC_skeymgmt_export(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_GENERATE:
|
||||
if (skeymgmt->generate == NULL)
|
||||
skeymgmt->generate = OSSL_FUNC_skeymgmt_generate(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_GET_KEY_ID:
|
||||
if (skeymgmt->get_key_id == NULL)
|
||||
skeymgmt->get_key_id = OSSL_FUNC_skeymgmt_get_key_id(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_IMP_SETTABLE_PARAMS:
|
||||
if (skeymgmt->imp_params == NULL)
|
||||
skeymgmt->imp_params = OSSL_FUNC_skeymgmt_imp_settable_params(fns);
|
||||
break;
|
||||
case OSSL_FUNC_SKEYMGMT_GEN_SETTABLE_PARAMS:
|
||||
if (skeymgmt->gen_params == NULL)
|
||||
skeymgmt->gen_params = OSSL_FUNC_skeymgmt_gen_settable_params(fns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that the provider is sensible */
|
||||
if (skeymgmt->free == NULL
|
||||
|| skeymgmt->import == NULL
|
||||
|| skeymgmt->export == NULL) {
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ossl_provider_up_ref(prov)) {
|
||||
EVP_SKEYMGMT_free(skeymgmt);
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
skeymgmt->prov = prov;
|
||||
|
||||
return skeymgmt;
|
||||
}
|
||||
|
||||
EVP_SKEYMGMT *evp_skeymgmt_fetch_from_prov(OSSL_PROVIDER *prov,
|
||||
const char *name,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch_from_prov(prov,
|
||||
OSSL_OP_SKEYMGMT,
|
||||
name, properties,
|
||||
skeymgmt_from_algorithm,
|
||||
(int (*)(void *))EVP_SKEYMGMT_up_ref,
|
||||
(void (*)(void *))EVP_SKEYMGMT_free);
|
||||
}
|
||||
|
||||
EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties)
|
||||
{
|
||||
return evp_generic_fetch(ctx, OSSL_OP_SKEYMGMT, algorithm, properties,
|
||||
skeymgmt_from_algorithm,
|
||||
(int (*)(void *))EVP_SKEYMGMT_up_ref,
|
||||
(void (*)(void *))EVP_SKEYMGMT_free);
|
||||
}
|
||||
|
||||
int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&skeymgmt->refcnt, &ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_SKEYMGMT_free(EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
if (skeymgmt == NULL)
|
||||
return;
|
||||
|
||||
CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref);
|
||||
if (ref > 0)
|
||||
return;
|
||||
OPENSSL_free(skeymgmt->type_name);
|
||||
ossl_provider_free(skeymgmt->prov);
|
||||
CRYPTO_FREE_REF(&skeymgmt->refcnt);
|
||||
OPENSSL_free(skeymgmt);
|
||||
}
|
||||
|
||||
const OSSL_PROVIDER *EVP_SKEYMGMT_get0_provider(const EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
return (skeymgmt != NULL) ? skeymgmt->prov : NULL;
|
||||
}
|
||||
|
||||
const char *EVP_SKEYMGMT_get0_description(const EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
return (skeymgmt != NULL) ? skeymgmt->description : NULL;
|
||||
}
|
||||
|
||||
const char *EVP_SKEYMGMT_get0_name(const EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
return (skeymgmt != NULL) ? skeymgmt->type_name : NULL;
|
||||
}
|
||||
|
||||
int EVP_SKEYMGMT_is_a(const EVP_SKEYMGMT *skeymgmt, const char *name)
|
||||
{
|
||||
return skeymgmt != NULL
|
||||
&& evp_is_a(skeymgmt->prov, skeymgmt->name_id, NULL, name);
|
||||
}
|
||||
|
||||
void EVP_SKEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
void (*fn)(EVP_SKEYMGMT *skeymgmt, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
evp_generic_do_all(libctx, OSSL_OP_KEYMGMT,
|
||||
(void (*)(void *, void *))fn, arg,
|
||||
skeymgmt_from_algorithm,
|
||||
(int (*)(void *))EVP_SKEYMGMT_up_ref,
|
||||
(void (*)(void *))EVP_SKEYMGMT_free);
|
||||
}
|
||||
|
||||
int EVP_SKEYMGMT_names_do_all(const EVP_SKEYMGMT *skeymgmt,
|
||||
void (*fn)(const char *name, void *data),
|
||||
void *data)
|
||||
{
|
||||
if (skeymgmt == NULL)
|
||||
return 0;
|
||||
|
||||
if (skeymgmt->prov != NULL)
|
||||
return evp_names_do_all(skeymgmt->prov, skeymgmt->name_id, fn, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_SKEYMGMT_get0_gen_settable_params(const EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
void *provctx = NULL;
|
||||
|
||||
if (skeymgmt == NULL)
|
||||
return 0;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
|
||||
|
||||
return (skeymgmt->gen_params != NULL) ? skeymgmt->gen_params(provctx) : NULL;
|
||||
}
|
||||
|
||||
const OSSL_PARAM *EVP_SKEYMGMT_get0_imp_settable_params(const EVP_SKEYMGMT *skeymgmt)
|
||||
{
|
||||
void *provctx = NULL;
|
||||
|
||||
if (skeymgmt == NULL)
|
||||
return 0;
|
||||
|
||||
provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt));
|
||||
|
||||
return (skeymgmt->imp_params != NULL) ? skeymgmt->imp_params(provctx) : NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user