chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,321 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006,2007 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/err.h>
#include "../pqdsa/internal.h"
#include "../delocate.h"
#include "../digest/internal.h"
#include "internal.h"
enum evp_sign_verify_t {
evp_sign,
evp_verify,
};
DEFINE_LOCAL_DATA(struct evp_md_pctx_ops, EVP_MD_pctx_ops) {
out->free = EVP_PKEY_CTX_free;
out->dup = EVP_PKEY_CTX_dup;
}
static int uses_prehash(EVP_MD_CTX *ctx, enum evp_sign_verify_t op) {
// Pre-hash modes of ML-DSA that uses an external mu calculation differs from
// other signing algorithms, so we specifically check for NIDs of type NID_MLDSAXX.
if (ctx->pctx->pkey->type == EVP_PKEY_PQDSA &&
ctx->pctx->pkey->pkey.pqdsa_key != NULL) {
int nid = ctx->pctx->pkey->pkey.pqdsa_key->pqdsa->nid;
if (nid == NID_MLDSA44 || nid == NID_MLDSA65 || nid == NID_MLDSA87) {
return 0;
}
}
return (op == evp_sign) ? (ctx->pctx->pmeth->sign != NULL)
: (ctx->pctx->pmeth->verify != NULL);
}
static int hmac_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
HMAC_PKEY_CTX *hctx = ctx->pctx->data;
// HMAC_Update returns 1 on success and 0 on failure.
return HMAC_Update(&hctx->ctx, data, count);
}
static int HMAC_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *out_sig,
size_t *out_sig_len) {
unsigned int mdlen;
if (*out_sig_len < EVP_MD_CTX_size(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
HMAC_PKEY_CTX *hctx = ctx->pctx->data;
if (!HMAC_Final(&hctx->ctx, out_sig, &mdlen)) {
return 0;
}
*out_sig_len = (size_t)mdlen;
return 1;
}
static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
enum evp_sign_verify_t op) {
if (ctx->pctx == NULL) {
ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
}
if (ctx->pctx == NULL) {
return 0;
}
ctx->pctx_ops = EVP_MD_pctx_ops();
if (op == evp_verify) {
if (!EVP_PKEY_verify_init(ctx->pctx)) {
return 0;
}
} else {
if (pkey->type == EVP_PKEY_HMAC) {
// |ctx->update| gets repurposed as a hook to call |HMAC_Update|.
// |ctx->update| is normally copied from |ctx->digest->update|, but
// |EVP_PKEY_HMAC| has its own definition. We suppress the automatic
// setting of |mctx->update| and the rest of its initialization here.
ctx->pctx->operation = EVP_PKEY_OP_SIGN;
ctx->flags |= EVP_MD_CTX_HMAC;
ctx->update = hmac_update;
} else {
if (!EVP_PKEY_sign_init(ctx->pctx)) {
return 0;
}
}
}
if (type != NULL && !EVP_PKEY_CTX_set_signature_md(ctx->pctx, type)) {
return 0;
}
if (uses_prehash(ctx, op) || used_for_hmac(ctx)) {
if (type == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST);
return 0;
}
if (!EVP_DigestInit_ex(ctx, type, e)) {
return 0;
}
}
if (pctx) {
*pctx = ctx->pctx;
}
return 1;
}
int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
ENGINE *e, EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
return do_sigver_init(ctx, pctx, type, e, pkey, evp_sign);
}
int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
return do_sigver_init(ctx, pctx, type, e, pkey, evp_verify);
}
int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
SET_DIT_AUTO_RESET;
if (!uses_prehash(ctx, evp_sign) && !used_for_hmac(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return EVP_DigestUpdate(ctx, data, len);
}
int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
SET_DIT_AUTO_RESET;
if (!uses_prehash(ctx, evp_verify) || used_for_hmac(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return EVP_DigestUpdate(ctx, data, len);
}
int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
size_t *out_sig_len) {
SET_DIT_AUTO_RESET;
if (!uses_prehash(ctx, evp_sign) && !used_for_hmac(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (out_sig) {
EVP_MD_CTX tmp_ctx;
int ret = 0;
uint8_t md[EVP_MAX_MD_SIZE];
unsigned int mdlen;
// We have to avoid the underlying SHA services updating the indicator
// state, so we lock the state here.
FIPS_service_indicator_lock_state();
EVP_MD_CTX_init(&tmp_ctx);
if (EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
if (used_for_hmac(ctx)) {
ret = HMAC_DigestFinal_ex(&tmp_ctx, out_sig, out_sig_len);
} else {
ret = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
}
}
EVP_MD_CTX_cleanup(&tmp_ctx);
FIPS_service_indicator_unlock_state();
if (ret > 0) {
EVP_DigestSign_verify_service_indicator(ctx);
}
return ret;
} else {
// This only determines the size of the signature. This case of
// |EVP_DigestSignFinal| should not return an approval check because no
// crypto is being done.
if (used_for_hmac(ctx)) {
// This is only defined in |EVP_PKEY_HMAC|.
*out_sig_len = EVP_MD_CTX_size(ctx);
return 1;
} else {
size_t s = EVP_MD_size(ctx->digest);
return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s);
}
}
}
int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len) {
SET_DIT_AUTO_RESET;
if (!uses_prehash(ctx, evp_verify) || used_for_hmac(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
// We have to avoid the underlying SHA services updating the indicator
// state, so we lock the state here.
FIPS_service_indicator_lock_state();
EVP_MD_CTX tmp_ctx;
int ret;
uint8_t md[EVP_MAX_MD_SIZE];
unsigned int mdlen;
EVP_MD_CTX_init(&tmp_ctx);
ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) &&
EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
EVP_MD_CTX_cleanup(&tmp_ctx);
FIPS_service_indicator_unlock_state();
if (ret > 0) {
EVP_DigestVerify_verify_service_indicator(ctx);
}
return ret;
}
int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len,
const uint8_t *data, size_t data_len) {
GUARD_PTR(ctx->pctx);
// We have to avoid the underlying |EVP_DigestSignFinal| services updating
// the indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
SET_DIT_AUTO_RESET;
int ret = 0;
if (uses_prehash(ctx, evp_sign) || used_for_hmac(ctx)) {
// If |out_sig| is NULL, the caller is only querying the maximum output
// length. |data| should only be incorporated in the final call.
if (out_sig != NULL && !EVP_DigestSignUpdate(ctx, data, data_len)) {
goto end;
}
ret = EVP_DigestSignFinal(ctx, out_sig, out_sig_len);
goto end;
}
if (ctx->pctx->pmeth->sign_message == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
// This is executed when |uses_prehash| is not true, which is the case for
// Ed25519 and ML-DSA when in pure mode.
ret = ctx->pctx->pmeth->sign_message(ctx->pctx, out_sig, out_sig_len, data,
data_len);
end:
FIPS_service_indicator_unlock_state();
if (ret > 0 && out_sig != NULL) {
// Indicator should only be set if we performed crypto, don't set if we only
// performed a size check.
EVP_DigestSign_verify_service_indicator(ctx);
}
return ret;
}
int EVP_DigestVerify(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
const uint8_t *data, size_t len) {
GUARD_PTR(ctx->pctx);
// We have to avoid the underlying |EVP_DigestSignFinal| services updating
// the indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
SET_DIT_AUTO_RESET;
int ret = 0;
if (uses_prehash(ctx, evp_verify) && !used_for_hmac(ctx)) {
ret = EVP_DigestVerifyUpdate(ctx, data, len) &&
EVP_DigestVerifyFinal(ctx, sig, sig_len);
goto end;
}
if (ctx->pctx->pmeth->verify_message == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
// This is executed when |uses_prehash| is not true, which is the case for
// Ed25519 and ML-DSA when in pure mode.
ret = ctx->pctx->pmeth->verify_message(ctx->pctx, sig, sig_len, data, len);
end:
FIPS_service_indicator_unlock_state();
if (ret > 0) {
EVP_DigestVerify_verify_service_indicator(ctx);
}
return ret;
}
void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx) {
SET_DIT_AUTO_RESET;
// |pctx| could be null, so we have to deal with the cleanup job here.
if (!(ctx->flags & EVP_MD_CTX_FLAG_KEEP_PKEY_CTX)) {
EVP_PKEY_CTX_free(ctx->pctx);
}
ctx->pctx = pctx;
ctx->pctx_ops = EVP_MD_pctx_ops();
if (pctx != NULL) {
// make sure |pctx| is not freed when destroying |EVP_MD_CTX|
ctx->flags |= EVP_MD_CTX_FLAG_KEEP_PKEY_CTX;
} else {
// if |pctx| is null, we remove the flag.
ctx->flags &= ~EVP_MD_CTX_FLAG_KEEP_PKEY_CTX;
}
}
EVP_PKEY_CTX *EVP_MD_CTX_get_pkey_ctx(const EVP_MD_CTX *ctx) {
SET_DIT_AUTO_RESET;
if(ctx == NULL) {
return NULL;
}
return ctx->pctx;
}
EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx) {
return EVP_MD_CTX_get_pkey_ctx(ctx);
}

View File

@@ -0,0 +1,985 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <assert.h>
#include <string.h>
#include <openssl/curve25519.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rsa.h>
#include <openssl/thread.h>
#include "../../evp_extra/internal.h"
#include "../../pem/internal.h"
#include "../../console/internal.h"
#include "../../internal.h"
#include "../pqdsa/internal.h"
#include "internal.h"
// Node depends on |EVP_R_NOT_XOF_OR_INVALID_LENGTH|.
//
// TODO(davidben): Fix Node to not touch the error queue itself and remove this.
OPENSSL_DECLARE_ERROR_REASON(EVP, NOT_XOF_OR_INVALID_LENGTH)
// The HPKE module uses the EVP error namespace, but it lives in another
// directory.
OPENSSL_DECLARE_ERROR_REASON(EVP, EMPTY_PSK)
EVP_PKEY *EVP_PKEY_new(void) {
EVP_PKEY *ret;
ret = OPENSSL_zalloc(sizeof(EVP_PKEY));
if (ret == NULL) {
return NULL;
}
ret->type = EVP_PKEY_NONE;
ret->references = 1;
return ret;
}
static void free_it(EVP_PKEY *pkey) {
if (pkey->ameth && pkey->ameth->pkey_free) {
pkey->ameth->pkey_free(pkey);
}
pkey->pkey.ptr = NULL;
pkey->type = EVP_PKEY_NONE;
pkey->ameth = NULL;
}
void EVP_PKEY_free(EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey == NULL) {
return;
}
if (!CRYPTO_refcount_dec_and_test_zero(&pkey->references)) {
return;
}
free_it(pkey);
OPENSSL_free(pkey);
}
int EVP_PKEY_up_ref(EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
CRYPTO_refcount_inc(&pkey->references);
return 1;
}
int EVP_PKEY_is_opaque(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->ameth && pkey->ameth->pkey_opaque) {
return pkey->ameth->pkey_opaque(pkey);
}
return 0;
}
int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
SET_DIT_AUTO_RESET;
if (a->type != b->type) {
return -1;
}
if (a->ameth) {
int ret;
// Compare parameters if the algorithm has them
if (a->ameth->param_cmp) {
ret = a->ameth->param_cmp(a, b);
if (ret <= 0) {
return ret;
}
}
if (a->ameth->pub_cmp) {
return a->ameth->pub_cmp(a, b);
}
}
return -2;
}
char *EVP_get_pw_prompt(void) {
return (char*)"Enter PEM passphrase:";
}
int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify) {
return EVP_read_pw_string_min(buf, 0, length, prompt, verify);
}
int EVP_read_pw_string_min(char *buf, int min_length, int length,
const char *prompt, int verify) {
int ret = -1;
char verify_buf[1024];
if (!buf || min_length < 0 || min_length >= length) {
return -1;
}
if (prompt == NULL) {
prompt = EVP_get_pw_prompt();
}
// Proactively zeroize |buf| and verify_buf
OPENSSL_cleanse(buf, length);
OPENSSL_cleanse(verify_buf, sizeof(verify_buf));
// acquire write lock
openssl_console_acquire_mutex();
if (!openssl_console_open()) {
goto err;
}
// Write initial password prompt
if (!openssl_console_write(prompt)) {
goto err;
}
// Read password with echo disabled. Returns 0 on success.
// While |buf| and |length| are user-provided and can be arbitrarily large,
// passwords exceeding 1024 characters will be rejected with AWS-LC. OpenSSL
// handles this by silently truncating |length| before reading the password.
ret = openssl_console_read(buf, min_length, length, 0);
if (ret != 0) {
OPENSSL_cleanse(buf, length);
OPENSSL_PUT_ERROR(PEM, PEM_R_PROBLEMS_GETTING_PASSWORD);
goto err;
}
if (verify) {
openssl_console_write("Verifying - ");
openssl_console_write(prompt);
ret = openssl_console_read(verify_buf, min_length, sizeof(verify_buf), 0);
if (ret == 0) {
if (strncmp(buf, verify_buf, length) != 0) {
openssl_console_write("Verify failure\n");
ret = -1;
}
} else {
OPENSSL_PUT_ERROR(PEM, PEM_R_PROBLEMS_GETTING_PASSWORD);
goto err;
}
}
openssl_console_close();
err:
openssl_console_release_mutex();
OPENSSL_cleanse(verify_buf, sizeof(verify_buf));
return ret;
}
int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
SET_DIT_AUTO_RESET;
if (to->type == EVP_PKEY_NONE) {
evp_pkey_set_method(to, from->ameth);
} else if (to->type != from->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
return 0;
}
if (EVP_PKEY_missing_parameters(from)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
// Once set, parameters may not change.
if (!EVP_PKEY_missing_parameters(to)) {
if (EVP_PKEY_cmp_parameters(to, from) == 1) {
return 1;
}
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS);
return 0;
}
if (from->ameth && from->ameth->param_copy) {
return from->ameth->param_copy(to, from);
}
// TODO(https://crbug.com/boringssl/536): If the algorithm takes no
// parameters, copying them should vacuously succeed.
return 0;
}
int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->ameth && pkey->ameth->param_missing) {
return pkey->ameth->param_missing(pkey);
}
return 0;
}
int EVP_PKEY_size(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey && pkey->ameth && pkey->ameth->pkey_size) {
return pkey->ameth->pkey_size(pkey);
}
return 0;
}
int EVP_PKEY_bits(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey && pkey->ameth && pkey->ameth->pkey_bits) {
return pkey->ameth->pkey_bits(pkey);
}
return 0;
}
int EVP_PKEY_id(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
return pkey->type;
}
int EVP_PKEY_pqdsa_get_type(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->type != EVP_PKEY_PQDSA) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_PQDSA_KEY);
return 0;
}
if (!pkey->pkey.pqdsa_key || !pkey->pkey.pqdsa_key->pqdsa) {
return 0;
}
return pkey->pkey.pqdsa_key->pqdsa->nid;
}
int EVP_MD_get_pkey_type(const EVP_MD *md) {
if (md) {
int sig_nid = 0;
if (OBJ_find_sigid_by_algs(&sig_nid, md->type, NID_rsaEncryption)) {
return sig_nid;
}
}
return 0;
}
int EVP_MD_pkey_type(const EVP_MD *md){
return EVP_MD_get_pkey_type(md);
}
const char *EVP_MD_get0_name(const EVP_MD *md) {
if (md != NULL) {
return OBJ_nid2sn(EVP_MD_nid(md));
}
return NULL;
}
const char *EVP_MD_name(const EVP_MD *md) {
return EVP_MD_get0_name(md);
}
// evp_pkey_asn1_find returns the ASN.1 method table for the given |nid|, which
// should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is
// unknown.
static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) {
const EVP_PKEY_ASN1_METHOD *const *methods = AWSLC_non_fips_pkey_evp_asn1_methods();
for (size_t i = 0; i < ASN1_EVP_PKEY_METHODS; i++) {
if (methods[i]->pkey_id == nid) {
return methods[i];
}
}
return NULL;
}
void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method) {
free_it(pkey);
pkey->ameth = method;
pkey->type = pkey->ameth->pkey_id;
}
static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) {
if (pkey && pkey->pkey.ptr) {
// This isn't strictly necessary, but historically |EVP_PKEY_set_type| would
// clear |pkey| even if |evp_pkey_asn1_find| failed, so we preserve that
// behavior.
free_it(pkey);
}
const EVP_PKEY_ASN1_METHOD *ameth = NULL;
if (str != NULL) {
ameth = EVP_PKEY_asn1_find_str(NULL, str, len);
} else {
ameth = evp_pkey_asn1_find(type);
}
if (ameth == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
ERR_add_error_dataf("algorithm %d", type);
return 0;
}
if (pkey) {
evp_pkey_set_method(pkey, ameth);
}
return 1;
}
int EVP_PKEY_type(int nid) {
// In OpenSSL, this was used to map between type aliases. BoringSSL supports
// no type aliases, so this function is just the identity.
return nid;
}
EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *engine, const uint8_t *mac_key,
size_t mac_key_len) {
SET_DIT_AUTO_RESET;
// Only |EVP_PKEY_HMAC| is supported as of now.
if (type != EVP_PKEY_HMAC) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return NULL;
}
// NULL |mac_key| will result in a complete zero-key being used, but in that
// case, the length must be zero.
if (mac_key == NULL && mac_key_len > 0) {
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
return NULL;
}
HMAC_KEY *key = HMAC_KEY_new();
if(key == NULL) {
goto err;
}
key->key = OPENSSL_memdup(mac_key, mac_key_len);
if (key->key == NULL && mac_key_len > 0) {
OPENSSL_free(key);
goto err;
}
key->key_len = mac_key_len;
if(!EVP_PKEY_assign(ret, EVP_PKEY_HMAC, key)) {
OPENSSL_free(key);
goto err;
}
return ret;
err:
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
EVP_PKEY_free(ret);
return NULL;
}
int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) {
SET_DIT_AUTO_RESET;
if (EVP_PKEY_assign_RSA(pkey, key)) {
RSA_up_ref(key);
return 1;
}
return 0;
}
int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) {
SET_DIT_AUTO_RESET;
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_RSA);
assert(meth != NULL);
evp_pkey_set_method(pkey, meth);
pkey->pkey.ptr = key;
return key != NULL;
}
RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_RSA_PSS) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY);
return NULL;
}
return pkey->pkey.rsa;
}
RSA *EVP_PKEY_get1_RSA(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
RSA *rsa = EVP_PKEY_get0_RSA(pkey);
if (rsa != NULL) {
RSA_up_ref(rsa);
}
return rsa;
}
int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) {
SET_DIT_AUTO_RESET;
if (EVP_PKEY_assign_DSA(pkey, key)) {
DSA_up_ref(key);
return 1;
}
return 0;
}
int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) {
SET_DIT_AUTO_RESET;
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_DSA);
assert(meth != NULL);
evp_pkey_set_method(pkey, meth);
pkey->pkey.ptr = key;
return key != NULL;
}
DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->type != EVP_PKEY_DSA) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY);
return NULL;
}
return pkey->pkey.dsa;
}
DSA *EVP_PKEY_get1_DSA(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
DSA *dsa = EVP_PKEY_get0_DSA(pkey);
if (dsa != NULL) {
DSA_up_ref(dsa);
}
return dsa;
}
int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
SET_DIT_AUTO_RESET;
if (EVP_PKEY_assign_EC_KEY(pkey, key)) {
EC_KEY_up_ref(key);
return 1;
}
return 0;
}
int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
SET_DIT_AUTO_RESET;
const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(EVP_PKEY_EC);
assert(meth != NULL);
evp_pkey_set_method(pkey, meth);
pkey->pkey.ptr = key;
return key != NULL;
}
EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
if (pkey->type != EVP_PKEY_EC) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_EC_KEY_KEY);
return NULL;
}
return pkey->pkey.ec;
}
EC_KEY *EVP_PKEY_get1_EC_KEY(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
if (ec_key != NULL) {
EC_KEY_up_ref(ec_key);
}
return ec_key;
}
int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) {
// This function can only be used to assign RSA, DSA, EC, and DH keys. Other
// key types have internal representations which are not exposed through the
// public API.
SET_DIT_AUTO_RESET;
switch (type) {
case EVP_PKEY_RSA:
return EVP_PKEY_assign_RSA(pkey, key);
case EVP_PKEY_DSA:
return EVP_PKEY_assign_DSA(pkey, key);
case EVP_PKEY_EC:
return EVP_PKEY_assign_EC_KEY(pkey, key);
case EVP_PKEY_DH:
return EVP_PKEY_assign_DH(pkey, key);
default:
if (!EVP_PKEY_set_type(pkey, type)) {
return 0;
}
pkey->pkey.ptr = key;
return key != NULL;
}
}
int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
SET_DIT_AUTO_RESET;
return pkey_set_type(pkey, type, NULL, -1);
}
int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len) {
SET_DIT_AUTO_RESET;
return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
}
EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *unused,
const uint8_t *in, size_t len) {
SET_DIT_AUTO_RESET;
// To avoid pulling in all key types, look for specifically the key types that
// support |set_priv_raw|.
const EVP_PKEY_ASN1_METHOD *method;
switch (type) {
case EVP_PKEY_X25519:
method = &x25519_asn1_meth;
break;
case EVP_PKEY_ED25519:
method = &ed25519_asn1_meth;
break;
case EVP_PKEY_ED25519PH:
method = &ed25519ph_asn1_meth;
break;
case EVP_PKEY_HMAC:
method = &hmac_asn1_meth;
break;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
goto err;
}
evp_pkey_set_method(ret, method);
if (!ret->ameth->set_priv_raw(ret, in, len, NULL, 0)) {
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *unused,
const uint8_t *in, size_t len) {
// To avoid pulling in all key types, look for specifically the key types that
// support |set_pub_raw|.
const EVP_PKEY_ASN1_METHOD *method;
switch (type) {
case EVP_PKEY_X25519:
method = &x25519_asn1_meth;
break;
case EVP_PKEY_ED25519:
method = &ed25519_asn1_meth;
break;
case EVP_PKEY_ED25519PH:
method = &ed25519ph_asn1_meth;
break;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
goto err;
}
evp_pkey_set_method(ret, method);
if (!ret->ameth->set_pub_raw(ret, in, len)) {
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
SET_DIT_AUTO_RESET;
if (pkey == NULL ||
pkey->ameth == NULL ||
pkey->ameth->get_priv_raw == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return pkey->ameth->get_priv_raw(pkey, out, out_len);
}
int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
SET_DIT_AUTO_RESET;
if (pkey == NULL ||
pkey->ameth == NULL ||
pkey->ameth->get_pub_raw == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return pkey->ameth->get_pub_raw(pkey, out, out_len);
}
int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
SET_DIT_AUTO_RESET;
if (a->type != b->type) {
return -1;
}
if (a->ameth && a->ameth->param_cmp) {
return a->ameth->param_cmp(a, b);
}
// TODO(https://crbug.com/boringssl/536): If the algorithm doesn't use
// parameters, they should compare as vacuously equal.
return -2;
}
int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
SET_DIT_AUTO_RESET;
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0,
(void *)md);
}
int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
SET_DIT_AUTO_RESET;
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_MD,
0, (void *)out_md);
}
int EVP_PKEY_CTX_set_signature_context(EVP_PKEY_CTX *ctx,
const uint8_t *context,
size_t context_len) {
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {context, context_len};
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,
EVP_PKEY_CTRL_SIGNING_CONTEXT, 0, &params);
}
int EVP_PKEY_CTX_get0_signature_context(EVP_PKEY_CTX *ctx,
const uint8_t **context,
size_t *context_len) {
GUARD_PTR(context);
GUARD_PTR(context_len);
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {NULL, 0};
if (!EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG,
EVP_PKEY_CTRL_GET_SIGNING_CONTEXT, 0, &params)) {
return 0;
}
*context = params.context;
*context_len = params.context_len;
return 1;
}
void *EVP_PKEY_get0(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
GUARD_PTR(pkey);
switch (pkey->type) {
case EVP_PKEY_RSA:
case EVP_PKEY_RSA_PSS:
case EVP_PKEY_DSA:
case EVP_PKEY_EC:
case EVP_PKEY_DH:
return pkey->pkey.ptr;
default:
return NULL;
}
}
void OpenSSL_add_all_algorithms(void) {}
void OPENSSL_add_all_algorithms_conf(void) {}
void OpenSSL_add_all_ciphers(void) {}
void OpenSSL_add_all_digests(void) {}
void EVP_cleanup(void) {}
int EVP_PKEY_base_id(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET;
// OpenSSL has two notions of key type because it supports multiple OIDs for
// the same algorithm: NID_rsa vs NID_rsaEncryption and five distinct spelling
// of DSA. We do not support these, so the base ID is simply the ID.
return EVP_PKEY_id(pkey);
}
static int evp_pkey_tls_encodedpoint_ec_curve_supported(const EC_KEY *ec_key) {
int ret = 0;
int curve_nid = 0;
const EC_GROUP *ec_key_group = NULL;
if (NULL == ec_key) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
ec_key_group = EC_KEY_get0_group(ec_key);
if (NULL == ec_key_group) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
goto err;
}
curve_nid = EC_GROUP_get_curve_name(ec_key_group);
if ((NID_secp224r1 != curve_nid) &&
(NID_X9_62_prime256v1 != curve_nid) &&
(NID_secp384r1 != curve_nid) &&
(NID_secp521r1 != curve_nid)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
ret = 1;
err:
return ret;
}
static int evp_pkey_set1_tls_encodedpoint_ec_key(EVP_PKEY *pkey,
const uint8_t *in,
size_t len) {
int ret = 0;
EC_KEY *ec_key = NULL;
const EC_GROUP *ec_key_group = NULL;
EC_POINT *ec_point = NULL;
if ((NULL == pkey) || (NULL == in)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
if (1 > len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
goto err;
}
if (EVP_PKEY_EC != pkey->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
// This function is TLS-specific. Only support TLS EC point representation,
// which must be uncompressed
// (https://tools.ietf.org/html/rfc8422#section-5.4.1)
// TLS wire-encoding format for supported NIST curves are:
// compression || x-coordinate || y-coordinate
// where:
// compression = 0x04 if uncompressed
// compression = 0x02/0x03 if compressed (depending on y-coordinate parity)
if (POINT_CONVERSION_UNCOMPRESSED != in[0]) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
ec_key = EVP_PKEY_get0_EC_KEY(pkey);
if (NULL == ec_key) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
goto err;
}
if (0 == evp_pkey_tls_encodedpoint_ec_curve_supported(ec_key)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
ec_key_group = EC_KEY_get0_group(ec_key);
if (NULL == ec_key_group) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
goto err;
}
ec_point = EC_POINT_new(ec_key_group);
if (NULL == ec_point) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
if (0 == EC_POINT_oct2point(ec_key_group, ec_point, in, len, NULL)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
if (0 == EC_KEY_set_public_key(ec_key, (const EC_POINT *) ec_point)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
ret = 1;
err:
EC_POINT_free(ec_point);
return ret;
}
static int evp_pkey_set1_tls_encodedpoint_x25519(EVP_PKEY *pkey,
const uint8_t *in,
size_t len) {
int ret = 0;
if ((NULL == pkey) || (NULL == in)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
if (EVP_PKEY_X25519 != pkey->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
if (1 > len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
goto err;
}
if ((NULL == pkey->ameth) || (NULL == pkey->ameth->set_pub_raw)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto err;
}
if (0 == pkey->ameth->set_pub_raw(pkey, in, len)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
ret = 1;
err:
return ret;
}
int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
size_t len) {
SET_DIT_AUTO_RESET;
if (NULL == pkey) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
switch (pkey->type) {
case EVP_PKEY_X25519:
return evp_pkey_set1_tls_encodedpoint_x25519(pkey, in, len);
case EVP_PKEY_EC:
return evp_pkey_set1_tls_encodedpoint_ec_key(pkey, in, len);
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
err:
return 0;
}
static size_t evp_pkey_get1_tls_encodedpoint_ec_key(const EVP_PKEY *pkey,
uint8_t **out_ptr) {
size_t ret = 0;
const EC_KEY *ec_key = NULL;
if ((NULL == pkey) || (NULL == out_ptr)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
if (EVP_PKEY_EC != pkey->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
ec_key = EVP_PKEY_get0_EC_KEY(pkey);
if (NULL == ec_key) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
goto err;
}
if (0 == evp_pkey_tls_encodedpoint_ec_curve_supported(ec_key)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
// This function is TLS-specific. Only support TLS EC point representation,
// which must be uncompressed
// (https://tools.ietf.org/html/rfc8422#section-5.4.1)
if (POINT_CONVERSION_UNCOMPRESSED != EC_KEY_get_conv_form(ec_key)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
// Returns the length of |*out_ptr|
ret = EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED, out_ptr, NULL);
if (0 == ret) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
err:
return ret;
}
static size_t evp_pkey_get1_tls_encodedpoint_x25519(const EVP_PKEY *pkey,
uint8_t **out_ptr) {
size_t ret = 0;
size_t out_len = 0;
if ((NULL == pkey) || (NULL == out_ptr)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (EVP_PKEY_X25519 != pkey->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
return 0;
}
if ((NULL == pkey->ameth) || (NULL == pkey->ameth->get_pub_raw)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
out_len = X25519_SHARED_KEY_LEN;
*out_ptr = OPENSSL_malloc(X25519_SHARED_KEY_LEN);
if (NULL == *out_ptr) {
return 0;
}
if (0 == pkey->ameth->get_pub_raw(pkey, *out_ptr, &out_len)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
if (X25519_SHARED_KEY_LEN != out_len) {
OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
goto err;
}
ret = X25519_SHARED_KEY_LEN;
err:
if (0 == ret) {
OPENSSL_free(*out_ptr);
*out_ptr = NULL;
}
return ret;
}
size_t EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY *pkey, uint8_t **out_ptr) {
SET_DIT_AUTO_RESET;
if (NULL == pkey) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
goto err;
}
switch (pkey->type) {
case EVP_PKEY_X25519:
return evp_pkey_get1_tls_encodedpoint_x25519(pkey, out_ptr);
case EVP_PKEY_EC:
return evp_pkey_get1_tls_encodedpoint_ec_key(pkey, out_ptr);
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
err:
return 0;
}

View File

@@ -0,0 +1,676 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/experimental/kem_deterministic_api.h>
#include <string.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../../internal.h"
#include "internal.h"
#include "../../evp_extra/internal.h"
DEFINE_LOCAL_DATA(struct fips_evp_pkey_methods, AWSLC_fips_evp_pkey_methods) {
out->methods[0] = EVP_PKEY_rsa_pkey_meth();
out->methods[1] = EVP_PKEY_rsa_pss_pkey_meth();
out->methods[2] = EVP_PKEY_ec_pkey_meth();
out->methods[3] = EVP_PKEY_hkdf_pkey_meth();
out->methods[4] = EVP_PKEY_hmac_pkey_meth();
out->methods[5] = EVP_PKEY_ed25519_pkey_meth();
out->methods[6] = EVP_PKEY_kem_pkey_meth();
out->methods[7] = EVP_PKEY_pqdsa_pkey_meth();
out->methods[8] = EVP_PKEY_ed25519ph_pkey_meth();
}
static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) {
// First we search through the FIPS public key methods. We assume these are
// the most popular.
const struct fips_evp_pkey_methods *const fips_methods = AWSLC_fips_evp_pkey_methods();
for (size_t i = 0; i < FIPS_EVP_PKEY_METHODS; i++) {
if (fips_methods->methods[i]->pkey_id == type) {
return fips_methods->methods[i];
}
}
// Can still seek non-fips validated algorithms in fips mode.
const EVP_PKEY_METHOD *const *non_fips_methods = AWSLC_non_fips_pkey_evp_methods();
for (size_t i = 0; i < NON_FIPS_EVP_PKEY_METHODS; i++) {
if (non_fips_methods[i]->pkey_id == type) {
return non_fips_methods[i];
}
}
return NULL;
}
static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) {
EVP_PKEY_CTX *ret;
const EVP_PKEY_METHOD *pmeth;
if (id == -1) {
if (!pkey || !pkey->ameth) {
return NULL;
}
id = pkey->ameth->pkey_id;
}
pmeth = evp_pkey_meth_find(id);
if (pmeth == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
ERR_add_error_dataf("algorithm %d", id);
return NULL;
}
ret = OPENSSL_zalloc(sizeof(EVP_PKEY_CTX));
if (!ret) {
return NULL;
}
ret->engine = e;
ret->pmeth = pmeth;
ret->operation = EVP_PKEY_OP_UNDEFINED;
if (pkey) {
EVP_PKEY_up_ref(pkey);
ret->pkey = pkey;
}
if (pmeth->init) {
if (pmeth->init(ret) <= 0) {
EVP_PKEY_free(ret->pkey);
OPENSSL_free(ret);
return NULL;
}
}
return ret;
}
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) {
SET_DIT_AUTO_RESET;
return evp_pkey_ctx_new(pkey, e, -1);
}
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) {
return evp_pkey_ctx_new(NULL, e, id);
}
void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (ctx == NULL) {
return;
}
if (ctx->pmeth && ctx->pmeth->cleanup) {
ctx->pmeth->cleanup(ctx);
}
EVP_PKEY_free(ctx->pkey);
EVP_PKEY_free(ctx->peerkey);
OPENSSL_free(ctx);
}
EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx->pmeth || !ctx->pmeth->copy) {
return NULL;
}
EVP_PKEY_CTX *ret = OPENSSL_zalloc(sizeof(EVP_PKEY_CTX));
if (!ret) {
return NULL;
}
ret->pmeth = ctx->pmeth;
ret->engine = ctx->engine;
ret->operation = ctx->operation;
if (ctx->pkey != NULL) {
EVP_PKEY_up_ref(ctx->pkey);
ret->pkey = ctx->pkey;
}
if (ctx->peerkey != NULL) {
EVP_PKEY_up_ref(ctx->peerkey);
ret->peerkey = ctx->peerkey;
}
if (ctx->pmeth->copy(ret, ctx) <= 0) {
ret->pmeth = NULL;
EVP_PKEY_CTX_free(ret);
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
return NULL;
}
return ret;
}
EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
return ctx->pkey;
}
int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
int p1, void *p2) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
if (keytype != -1 && ctx->pmeth->pkey_id != keytype) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET);
return 0;
}
if (optype != -1 && !(ctx->operation & optype)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return ctx->pmeth->ctrl(ctx, cmd, p1, p2);
}
int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (ctx == NULL || ctx->pmeth == NULL ||
(ctx->pmeth->sign == NULL && ctx->pmeth->sign_message == NULL)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_SIGN;
if ((ctx->pmeth->sign_init == NULL) || (ctx->pmeth->sign_init(ctx))) {
return 1;
}
ctx->operation = EVP_PKEY_OP_UNDEFINED;
return 0;
}
int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
const uint8_t *digest, size_t digest_len) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_SIGN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->sign(ctx, sig, sig_len, digest, digest_len);
}
int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (ctx == NULL || ctx->pmeth == NULL ||
(ctx->pmeth->verify == NULL && ctx->pmeth->verify_message == NULL)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_VERIFY;
if ((ctx->pmeth->verify_init == NULL) || (ctx->pmeth->verify_init(ctx))) {
return 1;
}
ctx->operation = EVP_PKEY_OP_UNDEFINED;
return 0;
}
int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len,
const uint8_t *digest, size_t digest_len) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_VERIFY) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->verify(ctx, sig, sig_len, digest, digest_len);
}
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) {
if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_ENCRYPT;
return 1;
}
int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
}
int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_DECRYPT;
return 1;
}
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
}
int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_VERIFYRECOVER;
return 1;
}
int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
const uint8_t *sig, size_t sig_len) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->verify_recover(ctx, out, out_len, sig, sig_len);
}
int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_DERIVE;
return 1;
}
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) {
SET_DIT_AUTO_RESET;
int ret;
if (!ctx || !ctx->pmeth ||
!(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) ||
!ctx->pmeth->ctrl) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_DERIVE &&
ctx->operation != EVP_PKEY_OP_ENCRYPT &&
ctx->operation != EVP_PKEY_OP_DECRYPT) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
if (ret <= 0) {
return 0;
}
if (ret == 2) {
return 1;
}
if (!ctx->pkey) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
if (ctx->pkey->type != peer->type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
return 0;
}
// ran@cryptocom.ru: For clarity. The error is if parameters in peer are
// present (!missing) but don't match. EVP_PKEY_cmp_parameters 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_cmp_parameters(ctx->pkey, peer)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS);
return 0;
}
EVP_PKEY_free(ctx->peerkey);
ctx->peerkey = peer;
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
if (ret <= 0) {
ctx->peerkey = NULL;
return 0;
}
EVP_PKEY_up_ref(peer);
return 1;
}
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_DERIVE) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
return ctx->pmeth->derive(ctx, key, out_key_len);
}
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_KEYGEN;
return 1;
}
int EVP_PKEY_keygen_deterministic(EVP_PKEY_CTX *ctx,
EVP_PKEY **out_pkey,
const uint8_t *seed,
size_t *seed_len) {
int ret = 0;
if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen_deterministic) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
goto end;
}
if ((out_pkey == NULL) != (seed == NULL)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
goto end;
}
// Caller is performing a size check.
if (out_pkey == NULL && seed == NULL) {
if (!ctx->pmeth->keygen_deterministic(ctx, NULL, NULL, seed_len)) {
goto end;
}
ret = 1;
goto end;
}
if (!*out_pkey) {
*out_pkey = EVP_PKEY_new();
if (!*out_pkey) {
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
goto end;
}
}
if (!ctx->pmeth->keygen_deterministic(ctx, *out_pkey, seed, seed_len)) {
EVP_PKEY_free(*out_pkey);
*out_pkey = NULL;
goto end;
}
ret = 1;
end:
return ret;
}
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) {
// We have to avoid potential underlying services updating the indicator state,
// so we lock the state here.
FIPS_service_indicator_lock_state();
SET_DIT_AUTO_RESET;
int ret = 0;
if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
goto end;
}
if (!out_pkey) {
goto end;
}
if (!*out_pkey) {
*out_pkey = EVP_PKEY_new();
if (!*out_pkey) {
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
goto end;
}
}
if (!ctx->pmeth->keygen(ctx, *out_pkey)) {
EVP_PKEY_free(*out_pkey);
*out_pkey = NULL;
goto end;
}
ret = 1;
end:
FIPS_service_indicator_unlock_state();
if(ret) {
EVP_PKEY_keygen_verify_service_indicator(*out_pkey);
}
return ret;
}
int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
ctx->operation = EVP_PKEY_OP_PARAMGEN;
return 1;
}
int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) {
SET_DIT_AUTO_RESET;
if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
if (!out_pkey) {
return 0;
}
if (!*out_pkey) {
*out_pkey = EVP_PKEY_new();
if (!*out_pkey) {
OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
return 0;
}
}
if (!ctx->pmeth->paramgen(ctx, *out_pkey)) {
EVP_PKEY_free(*out_pkey);
*out_pkey = NULL;
return 0;
}
return 1;
}
int EVP_PKEY_encapsulate_deterministic(EVP_PKEY_CTX *ctx,
uint8_t *ciphertext,
size_t *ciphertext_len,
uint8_t *shared_secret,
size_t *shared_secret_len,
const uint8_t *seed,
size_t *seed_len) {
if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->encapsulate_deterministic == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return ctx->pmeth->encapsulate_deterministic(ctx, ciphertext, ciphertext_len,
shared_secret, shared_secret_len,
seed, seed_len);
}
int EVP_PKEY_encapsulate(EVP_PKEY_CTX *ctx, uint8_t *ciphertext,
size_t *ciphertext_len, uint8_t *shared_secret,
size_t *shared_secret_len) {
SET_DIT_AUTO_RESET;
// We have to avoid potential underlying services updating the indicator
// state, so we lock the state here.
FIPS_service_indicator_lock_state();
int ret = 0;
if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->encapsulate == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
if (!ctx->pmeth->encapsulate(ctx, ciphertext, ciphertext_len, shared_secret,
shared_secret_len)) {
goto end;
}
ret = 1;
end:
FIPS_service_indicator_unlock_state();
if (ret && ciphertext != NULL && shared_secret != NULL) {
EVP_PKEY_encapsulate_verify_service_indicator(ctx);
}
return ret;
}
int EVP_PKEY_decapsulate(EVP_PKEY_CTX *ctx, uint8_t *shared_secret,
size_t *shared_secret_len, const uint8_t *ciphertext,
size_t ciphertext_len) {
SET_DIT_AUTO_RESET;
// We have to avoid potential underlying services updating the indicator
// state, so we lock the state here.
FIPS_service_indicator_lock_state();
int ret = 0;
if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->decapsulate == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
goto end;
}
if (!ctx->pmeth->decapsulate(ctx, shared_secret, shared_secret_len,
ciphertext, ciphertext_len)) {
goto end;
}
ret = 1;
end:
FIPS_service_indicator_unlock_state();
if (ret && shared_secret != NULL) {
EVP_PKEY_decapsulate_verify_service_indicator(ctx);
}
return ret;
}
int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md) {
const EVP_MD *m;
if (md == NULL || (m = EVP_get_digestbyname(md)) == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
return 0;
}
return EVP_PKEY_CTX_ctrl(ctx, -1, optype, cmd, 0, (void *)m);
}
int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *name,
const char *value) {
if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return -2;
}
if (strcmp(name, "digest") == 0) {
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, value);
OPENSSL_END_ALLOW_DEPRECATED
}
return ctx->pmeth->ctrl_str(ctx, name, value);
}
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);
}
void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb) {
if (ctx == NULL) {
return;
}
ctx->pkey_gencb = cb;
}
void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data) {
if (ctx == NULL) {
return;
}
ctx->app_data = data;
}
void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx) {
if (ctx == NULL) {
return NULL;
}
return ctx->app_data;
}
int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx) {
GUARD_PTR(ctx);
if (idx == -1) {
return EVP_PKEY_CTX_KEYGEN_INFO_COUNT;
}
if (idx < 0 || idx >= EVP_PKEY_CTX_KEYGEN_INFO_COUNT ||
(ctx->operation != EVP_PKEY_OP_KEYGEN &&
ctx->operation != EVP_PKEY_OP_PARAMGEN)) {
return 0;
}
return ctx->keygen_info[idx];
}

View File

@@ -0,0 +1,560 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include "internal.h"
#include <gtest/gtest.h>
#include <openssl/dh.h>
#include <openssl/dsa.h>
#include <openssl/ec_key.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/rsa.h>
#include "../../internal.h"
#include "../../test/test_util.h"
#include "internal.h"
class EvpPkeyCtxCtrlStrTest : public ::testing::Test {
protected:
void SetUp() override {}
void TearDown() override {}
};
class EvpPkeyCtxCtrlStrParamTest : public testing::TestWithParam<const char *> {
protected:
void SetUp() override {}
void TearDown() override {}
};
static bssl::UniquePtr<EVP_PKEY_CTX> gen_RSA() {
EVP_PKEY *raw = nullptr;
bssl::UniquePtr<EVP_PKEY_CTX> keygen_ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
if (!EVP_PKEY_keygen_init(keygen_ctx.get()) ||
!EVP_PKEY_CTX_set_rsa_keygen_bits(keygen_ctx.get(), 2048) ||
!EVP_PKEY_keygen(keygen_ctx.get(), &raw)) {
return nullptr;
}
bssl::UniquePtr<EVP_PKEY> pkey(raw);
return bssl::UniquePtr<EVP_PKEY_CTX>(EVP_PKEY_CTX_new(pkey.get(), nullptr));
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaMissingValue) {
// Create a EVP_PKEY_CTX with a newly generated RSA key
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
EXPECT_FALSE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", nullptr));
unsigned long err = ERR_get_error();
EXPECT_EQ(ERR_GET_LIB(err), ERR_LIB_EVP);
EXPECT_EQ(ERR_GET_REASON(err), RSA_R_VALUE_MISSING);
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaPaddingModeValid) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
int padding = 0;
// Padding for sign
ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
EXPECT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pkcs1"));
EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding));
EXPECT_EQ(padding, RSA_PKCS1_PADDING);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "none"), 1);
EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding));
EXPECT_EQ(padding, RSA_NO_PADDING);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pss"), 1);
EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding));
EXPECT_EQ(padding, RSA_PKCS1_PSS_PADDING);
// Padding for encrypt
ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get()));
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "oaep"), 1);
EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding));
EXPECT_EQ(padding, RSA_PKCS1_OAEP_PADDING);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "oeap"), 1);
EXPECT_TRUE(EVP_PKEY_CTX_get_rsa_padding(ctx.get(), &padding));
EXPECT_EQ(padding, RSA_PKCS1_OAEP_PADDING);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "nonsense"),
-2);
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaPssSaltlen) {
// Create a EVP_PKEY_CTX with a newly generated RSA key
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_padding_mode", "pss"), 1);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "128"), 1);
int saltlen = 0;
EXPECT_EQ(EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx.get(), &saltlen), 1);
EXPECT_EQ(saltlen, 128);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "digest"), 1);
EXPECT_EQ(EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx.get(), &saltlen), 1);
EXPECT_EQ(saltlen, -1);
EXPECT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pss_saltlen", "-3"), -2);
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaKeygenBits) {
// Create a EVP_PKEY_CTX with a newly generated RSA key
EVP_PKEY *raw = nullptr;
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_bits", "2048"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_bits", "-3"), -2);
ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
bssl::UniquePtr<EVP_PKEY> pkey(raw);
ASSERT_TRUE(pkey);
ASSERT_EQ(EVP_PKEY_bits(pkey.get()), 2048);
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaKeygenPubexp) {
// Create a EVP_PKEY_CTX with a newly generated RSA key
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
#if defined(BORINGSSL_FIPS)
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "65537"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "729"), 0);
#else
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "729"), 1);
#endif
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_keygen_pubexp", "gg"), -2);
EVP_PKEY *raw = nullptr;
ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
bssl::UniquePtr<EVP_PKEY> pkey(raw);
ASSERT_TRUE(pkey);
bssl::UniquePtr<RSA> rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
ASSERT_TRUE(rsa_key);
const BIGNUM *const_pe_bn = RSA_get0_e(rsa_key.get());
ASSERT_TRUE(const_pe_bn != nullptr);
#if defined(BORINGSSL_FIPS)
const uint64_t expected_pe = 65537;
#else
const uint64_t expected_pe = 729;
#endif
uint64_t pe_u64;
ASSERT_TRUE(BN_get_u64(const_pe_bn, &pe_u64));
EXPECT_EQ(pe_u64, expected_pe);
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaMgf1Md) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_sign_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PSS_PADDING));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_mgf1_md", "sha256"), 1);
const EVP_MD *out_md;
ASSERT_TRUE(EVP_PKEY_CTX_get_rsa_mgf1_md(ctx.get(), &out_md));
ASSERT_STREQ(EVP_MD_name(out_md), "SHA256");
}
// rsa_oaep_md
TEST_F(EvpPkeyCtxCtrlStrTest, RsaOaepMd) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_md", "sha256"), 1);
const EVP_MD *out_md;
ASSERT_TRUE(EVP_PKEY_CTX_get_rsa_oaep_md(ctx.get(), &out_md));
ASSERT_STREQ(EVP_MD_name(out_md), "SHA256");
}
TEST_F(EvpPkeyCtxCtrlStrTest, RsaOaepLabel) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx = gen_RSA();
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_encrypt_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), EVP_sha256()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_label", "aabb11"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_oaep_label", "gg"), 0);
const char expected_label[4] = "\xaa\xbb\x11";
const uint8_t *actual_label;
ASSERT_TRUE(EVP_PKEY_CTX_get0_rsa_oaep_label(ctx.get(), &actual_label));
ASSERT_TRUE(OPENSSL_memcmp(actual_label, expected_label, 3) == 0);
}
TEST_P(EvpPkeyCtxCtrlStrParamTest, EcParamgenCurve) {
const char* name = GetParam();
// Create a EVP_PKEY_CTX with a newly generated EC key
EVP_PKEY *raw = nullptr;
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "ec_paramgen_curve", name), 1);
ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &raw));
bssl::UniquePtr<EVP_PKEY> pkey(raw);
ASSERT_TRUE(pkey);
const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
ASSERT_TRUE(ec_key != nullptr);
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
ASSERT_TRUE(ec_group != nullptr);
ASSERT_EQ(NID_X9_62_prime256v1, EC_GROUP_get_curve_name(ec_group));
}
INSTANTIATE_TEST_SUITE_P(EcParamgenCurve,
EvpPkeyCtxCtrlStrParamTest,
testing::Values("P-256", "prime256v1"));
TEST_F(EvpPkeyCtxCtrlStrTest, EcParamEnc) {
// Create a EVP_PKEY_CTX with a newly generated EC key
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "ec_param_enc", "named_curve"), 1);
// The `EVP_PKEY_CTX_set_ec_param_enc` function that is called does not
// alter any state, so there's nothing to verify afterward.
}
TEST_F(EvpPkeyCtxCtrlStrTest, DhPad) {
// Create a EVP_PKEY_CTX with a newly generated DH
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_pad", "17"), 1);
// There is no function to retrieve the DH pad value.
}
TEST_F(EvpPkeyCtxCtrlStrTest, DhParamGen) {
// Create a EVP_PKEY_CTX with a newly generated DH
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "256"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "gg"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "255"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_generator", "5"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "gg"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dh_paramgen_prime_len", "1"), 1);
EVP_PKEY* raw = nullptr;
ASSERT_EQ(EVP_PKEY_paramgen(ctx.get(), &raw), 1);
// Only parameters have been generated, but no key has actually been set.
EXPECT_FALSE(EVP_PKEY_param_check(ctx.get()));
bssl::UniquePtr<EVP_PKEY> pkey(raw);
ASSERT_TRUE(raw);
const DH* dh = EVP_PKEY_get0_DH(pkey.get());
ASSERT_TRUE(dh);
const BIGNUM* p = DH_get0_p(dh);
ASSERT_TRUE(p);
unsigned p_size = BN_num_bits(p);
ASSERT_EQ(p_size, 256u);
}
static const char *hkdf_hexsalt = "000102030405060708090a0b0c";
static const char *hkdf_hexinfo = "f0f1f2f3f4f5f6f7f8f9";
static const char *hkdf_hexkey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
static const char *hkdf_hex_expected_okm =
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5"
"b887185865";
static const char *hkdf_hex_expected_prk =
"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5";
TEST_F(EvpPkeyCtxCtrlStrTest, HkdfHex) {
// Test Cases from RFC 5869.
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_AND_EXPAND"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", hkdf_hexsalt), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexinfo", hkdf_hexinfo), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexkey", hkdf_hexkey), 1);
size_t okm_len;
bssl::UniquePtr<uint8_t> expected_okm(
OPENSSL_hexstr2buf(hkdf_hex_expected_okm, &okm_len));
ASSERT_TRUE(expected_okm);
bssl::UniquePtr<uint8_t> actual_okm(
static_cast<uint8_t *>(OPENSSL_zalloc(okm_len)));
ASSERT_TRUE(actual_okm);
ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_okm.get(), &okm_len));
ASSERT_EQ(OPENSSL_memcmp(actual_okm.get(), expected_okm.get(), okm_len), 0);
}
TEST_F(EvpPkeyCtxCtrlStrTest, HkdfRaw) {
// Test Cases from RFC 5869.
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_AND_EXPAND"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);
// The salt in the KAT contains a 0-byte so "salt" cannot be used.
ASSERT_EQ(
EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", "000102030405060708090a0b0c"),
1);
size_t len;
bssl::UniquePtr<uint8_t> info_parsed(OPENSSL_hexstr2buf(hkdf_hexinfo, &len));
bssl::UniquePtr<uint8_t> info((uint8_t*)OPENSSL_zalloc(len+1));
OPENSSL_memcpy(info.get(), info_parsed.get(), len);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "info",
reinterpret_cast<const char *>(info.get())),
1);
bssl::UniquePtr<uint8_t> key_parsed(OPENSSL_hexstr2buf(hkdf_hexkey, &len));
bssl::UniquePtr<uint8_t> key((uint8_t*)OPENSSL_zalloc(len+1));
OPENSSL_memcpy(key.get(), key_parsed.get(), len);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "key",
reinterpret_cast<const char *>(key.get())),
1);
size_t okm_len;
bssl::UniquePtr<uint8_t> expected_okm(
OPENSSL_hexstr2buf(hkdf_hex_expected_okm, &okm_len));
ASSERT_TRUE(expected_okm);
bssl::UniquePtr<uint8_t> actual_okm(
static_cast<uint8_t *>(OPENSSL_zalloc(okm_len)));
ASSERT_TRUE(actual_okm);
ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_okm.get(), &okm_len));
ASSERT_EQ(OPENSSL_memcmp(actual_okm.get(), expected_okm.get(), okm_len), 0);
}
TEST_F(EvpPkeyCtxCtrlStrTest, HkdfExtract) {
// Test Cases from RFC 5869.
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_derive_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "mode", "EXTRACT_ONLY"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "md", "SHA256"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexsalt", hkdf_hexsalt), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexinfo", hkdf_hexinfo), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexkey", hkdf_hexkey), 1);
size_t prk_len;
bssl::UniquePtr<uint8_t> expected_prk(
OPENSSL_hexstr2buf(hkdf_hex_expected_prk, &prk_len));
ASSERT_TRUE(expected_prk);
bssl::UniquePtr<uint8_t> actual_prk(
static_cast<uint8_t *>(OPENSSL_zalloc(prk_len)));
ASSERT_TRUE(actual_prk);
ASSERT_TRUE(EVP_PKEY_derive(ctx.get(), actual_prk.get(), &prk_len));
ASSERT_EQ(OPENSSL_memcmp(actual_prk.get(), expected_prk.get(), prk_len), 0);
}
static const char *hmac_hexkey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
TEST_F(EvpPkeyCtxCtrlStrTest, HMACKey) {
bssl::UniquePtr<EVP_PKEY> pkey_hex;
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx_hex(EVP_PKEY_CTX_new_id(EVP_PKEY_HMAC, NULL));
ASSERT_TRUE(ctx_hex);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx_hex.get()));
ASSERT_NE(1, EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "hexkey", "nonsense"));
ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "hexkey", hmac_hexkey));
EVP_PKEY* my_pkey = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx_hex.get(), &my_pkey));
pkey_hex.reset(my_pkey);
ASSERT_TRUE(pkey_hex);
}
bssl::UniquePtr<EVP_PKEY> pkey_raw;
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx_hex(EVP_PKEY_CTX_new_id(EVP_PKEY_HMAC, NULL));
ASSERT_TRUE(ctx_hex);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx_hex.get()));
std::vector<uint8_t> raw_key;
DecodeHex(&raw_key, hmac_hexkey);
raw_key.push_back(0);
ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx_hex.get(), "key", (char*)raw_key.data()));
EVP_PKEY* my_pkey = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx_hex.get(), &my_pkey));
pkey_raw.reset(my_pkey);
ASSERT_TRUE(pkey_raw);
}
ASSERT_TRUE(EVP_PKEY_cmp(pkey_hex.get(), pkey_raw.get()));
}
TEST_F(EvpPkeyCtxCtrlStrTest, HMACKeyCtxDup) {
// Test that EVP_PKEY_CTX_dup works correctly with HMAC keys.
// This tests the hmac_copy function to ensure it copies the key correctly.
// Generate from duplicate FIRST, then from original, to detect if copy
// corrupts the source context.
// Get the expected key bytes
std::vector<uint8_t> expected_key;
DecodeHex(&expected_key, hmac_hexkey);
ASSERT_GT(expected_key.size(), 0u);
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_HMAC, NULL));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
ASSERT_TRUE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "hexkey", hmac_hexkey));
// Duplicate the context
bssl::UniquePtr<EVP_PKEY_CTX> ctx_dup(EVP_PKEY_CTX_dup(ctx.get()));
ASSERT_TRUE(ctx_dup);
// Generate from DUPLICATE first - this verifies the key was copied
EVP_PKEY* pkey_dup_raw = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx_dup.get(), &pkey_dup_raw));
bssl::UniquePtr<EVP_PKEY> pkey_dup(pkey_dup_raw);
ASSERT_TRUE(pkey_dup);
// Generate from ORIGINAL - verifies copy didn't corrupt source
EVP_PKEY* pkey_orig_raw = NULL;
ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &pkey_orig_raw));
bssl::UniquePtr<EVP_PKEY> pkey_orig(pkey_orig_raw);
ASSERT_TRUE(pkey_orig);
// Verify both keys have the correct length and content using raw key access
// EVP_PKEY_cmp returns -2 for HMAC (no pub_cmp method), so we must compare
// the raw key bytes directly.
size_t dup_key_len = 0;
ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey_dup.get(), NULL, &dup_key_len));
ASSERT_EQ(dup_key_len, expected_key.size());
size_t orig_key_len = 0;
ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey_orig.get(), NULL, &orig_key_len));
ASSERT_EQ(orig_key_len, expected_key.size());
std::vector<uint8_t> dup_key(dup_key_len);
ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey_dup.get(), dup_key.data(), &dup_key_len));
std::vector<uint8_t> orig_key(orig_key_len);
ASSERT_TRUE(EVP_PKEY_get_raw_private_key(pkey_orig.get(), orig_key.data(), &orig_key_len));
// Both keys should match each other and the expected key
ASSERT_EQ(orig_key, expected_key);
ASSERT_EQ(dup_key, expected_key);
}
static void verify_DSA(const DSA* dsa, unsigned psize, unsigned qsize) {
const BIGNUM* p = DSA_get0_p(dsa);
EXPECT_TRUE(p != NULL);
if (p == NULL) {
return;
}
EXPECT_EQ(BN_num_bytes(p), psize);
const BIGNUM* q = DSA_get0_q(dsa);
EXPECT_TRUE(q != NULL);
if (q == NULL) {
return;
}
EXPECT_EQ(BN_num_bytes(q), qsize);
}
TEST_F(EvpPkeyCtxCtrlStrTest, DSAParamGen) {
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_bits", "512"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_bits", "256"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_bits", "a125"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_md", "SHA1"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_md", "sha123"), 1);
EVP_PKEY *pkey_raw = NULL;
EVP_PKEY_paramgen(ctx.get(), &pkey_raw);
bssl::UniquePtr<EVP_PKEY> pkey(pkey_raw);
ASSERT_TRUE(pkey);
DSA *dsa_raw = EVP_PKEY_get0_DSA(pkey_raw);
ASSERT_TRUE(dsa_raw != NULL);
verify_DSA(dsa_raw, 512 / 8, 160 / 8);
}
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_bits", "768"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_q_bits", "224"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_q_bits", "128"), 1);
ASSERT_NE(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_q_bits", "aghj"), 1);
EVP_PKEY *pkey_raw = NULL;
EVP_PKEY_paramgen(ctx.get(), &pkey_raw);
bssl::UniquePtr<EVP_PKEY> pkey(pkey_raw);
ASSERT_TRUE(pkey);
DSA *dsa_raw = EVP_PKEY_get0_DSA(pkey_raw);
ASSERT_TRUE(dsa_raw != NULL);
verify_DSA(dsa_raw, 768 / 8, 224 / 8);
}
{
bssl::UniquePtr<EVP_PKEY_CTX> ctx(
EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
ASSERT_TRUE(ctx);
ASSERT_TRUE(EVP_PKEY_paramgen_init(ctx.get()));
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_bits", "512"), 1);
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_q_bits", "160"), 1);
// MD takes precedence over qbits
ASSERT_EQ(EVP_PKEY_CTX_ctrl_str(ctx.get(), "dsa_paramgen_md", "SHA256"), 1);
EVP_PKEY *pkey_raw = NULL;
EVP_PKEY_paramgen(ctx.get(), &pkey_raw);
bssl::UniquePtr<EVP_PKEY> pkey(pkey_raw);
ASSERT_TRUE(pkey);
DSA *dsa_raw = EVP_PKEY_get0_DSA(pkey_raw);
ASSERT_TRUE(dsa_raw != NULL);
verify_DSA(dsa_raw, 512 / 8, 256 / 8);
}
}

View File

@@ -0,0 +1,360 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENSSL_HEADER_EVP_INTERNAL_H
#define OPENSSL_HEADER_EVP_INTERNAL_H
#include <openssl/base.h>
#include <openssl/rsa.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#if defined(__cplusplus)
extern "C" {
#endif
// EVP_MD_CTX_FLAG_KEEP_PKEY_CTX ensures |md_ctx->pctx| is not freed up in
// |EVP_MD_CTX_cleanup|. Only intended for internal use when |*pctx| was set
// externally with |EVP_MD_CTX_set_pkey_ctx|.
#define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX 0x0400
// EVP_MD_CTX_HMAC causes the |EVP_MD|'s |init| function not to
// be called, the |update| member not to be copied from the |EVP_MD| in
// |EVP_DigestInit_ex| and for |md_data| not to be initialised.
// This is an implementation detail of |EVP_PKEY_HMAC|.
#define EVP_MD_CTX_HMAC 0x0800
typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
struct evp_pkey_asn1_method_st {
int pkey_id;
uint8_t oid[11];
uint8_t oid_len;
const char *pem_str;
const char *info;
// pub_decode decodes |params| and |key| as a SubjectPublicKeyInfo
// and writes the result into |out|. It returns one on success and zero on
// error. |params| is the AlgorithmIdentifier after the OBJECT IDENTIFIER
// type field, and |key| is the contents of the subjectPublicKey with the
// leading padding byte checked and removed. Although X.509 uses BIT STRINGs
// to represent SubjectPublicKeyInfo, every key type defined encodes the key
// as a byte string with the same conversion to BIT STRING.
int (*pub_decode)(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key);
// pub_encode encodes |key| as a SubjectPublicKeyInfo and appends the result
// to |out|. It returns one on success and zero on error.
int (*pub_encode)(CBB *out, const EVP_PKEY *key);
int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
// priv_decode decodes |params| and |key| as a PrivateKeyInfo and writes the
// result into |out|. It returns one on success and zero on error. |params| is
// the AlgorithmIdentifier after the OBJECT IDENTIFIER type field, and |key|
// is the contents of the OCTET STRING privateKey field.
int (*priv_decode)(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey);
// priv_encode encodes |key| as a PrivateKeyInfo and appends the result to
// |out|. It returns one on success and zero on error.
int (*priv_encode)(CBB *out, const EVP_PKEY *key);
// priv_encode_v2 encodes |key| as a OneAsymmetricKey (RFC 5958) and appends
// the result to |out|. It returns one on success and zero on error.
int (*priv_encode_v2)(CBB *out, const EVP_PKEY *key);
int (*set_priv_raw)(EVP_PKEY *pkey, const uint8_t *privkey, size_t privkey_len, const uint8_t *pubkey, size_t pubkey_len);
int (*set_pub_raw)(EVP_PKEY *pkey, const uint8_t *in, size_t len);
int (*get_priv_raw)(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len);
int (*get_pub_raw)(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len);
// pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by
// custom implementations which do not expose key material and parameters.
int (*pkey_opaque)(const EVP_PKEY *pk);
int (*pkey_size)(const EVP_PKEY *pk);
int (*pkey_bits)(const EVP_PKEY *pk);
int (*param_missing)(const EVP_PKEY *pk);
int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from);
int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
void (*pkey_free)(EVP_PKEY *pkey);
}; // EVP_PKEY_ASN1_METHOD
struct evp_pkey_st {
CRYPTO_refcount_t references;
// type contains one of the EVP_PKEY_* values or NID_undef and determines
// which element (if any) of the |pkey| union is valid.
int type;
union {
void *ptr;
RSA *rsa;
DSA *dsa;
DH *dh;
EC_KEY *ec;
KEM_KEY *kem_key;
PQDSA_KEY *pqdsa_key;
} pkey;
// ameth contains a pointer to a method table that contains many ASN.1
// methods for the key type.
const EVP_PKEY_ASN1_METHOD *ameth;
} /* EVP_PKEY */;
#define EVP_PKEY_OP_UNDEFINED 0
#define EVP_PKEY_OP_KEYGEN (1 << 2)
#define EVP_PKEY_OP_SIGN (1 << 3)
#define EVP_PKEY_OP_VERIFY (1 << 4)
#define EVP_PKEY_OP_VERIFYRECOVER (1 << 5)
#define EVP_PKEY_OP_ENCRYPT (1 << 6)
#define EVP_PKEY_OP_DECRYPT (1 << 7)
#define EVP_PKEY_OP_DERIVE (1 << 8)
#define EVP_PKEY_OP_PARAMGEN (1 << 9)
#define EVP_PKEY_OP_TYPE_SIG \
(EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER)
#define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT)
#define EVP_PKEY_OP_TYPE_NOGEN \
(EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE)
#define EVP_PKEY_OP_TYPE_GEN (EVP_PKEY_OP_KEYGEN | EVP_PKEY_OP_PARAMGEN)
// EVP_PKEY_CTX_ctrl performs |cmd| on |ctx|. The |keytype| and |optype|
// arguments can be -1 to specify that any type and operation are acceptable,
// otherwise |keytype| must match the type of |ctx| and the bits of |optype|
// must intersect the operation flags set on |ctx|.
//
// The |p1| and |p2| arguments depend on the value of |cmd|.
//
// It returns one on success and zero on error.
OPENSSL_EXPORT int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
int cmd, int p1, void *p2);
// EVP_PKEY_CTX_md sets the message digest type for a specific operation.
// This function is deprecated and should not be used in new code.
//
// |ctx| is the context to operate on.
// |optype| is the operation type (e.g., EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_OP_KEYGEN).
// |cmd| is the specific command (e.g., EVP_PKEY_CTRL_MD).
// |md| is the name of the message digest algorithm to use.
//
// It returns 1 for success and 0 or a negative value for failure.
OPENSSL_EXPORT int EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md);
// EVP_RSA_PKEY_CTX_ctrl is a wrapper of |EVP_PKEY_CTX_ctrl|.
// Before calling |EVP_PKEY_CTX_ctrl|, a check is added to make sure
// the |ctx->pmeth->pkey_id| is either |EVP_PKEY_RSA| or |EVP_PKEY_RSA_PSS|.
int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2);
#define EVP_PKEY_CTRL_MD 1
#define EVP_PKEY_CTRL_GET_MD 2
#define EVP_PKEY_CTRL_SIGNING_CONTEXT 3
#define EVP_PKEY_CTRL_GET_SIGNING_CONTEXT 4
// EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|:
// 0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key.
// If the return value is <= 0, the key is rejected.
// 1: Is called at the end of |EVP_PKEY_derive_set_peer| and |p2| contains a
// peer key. If the return value is <= 0, the key is rejected.
// 2: Is called with |p2| == NULL to test whether the peer's key was used.
// (EC)DH always return one in this case.
// 3: Is called with |p2| == NULL to set whether the peer's key was used.
// (EC)DH always return one in this case. This was only used for GOST.
#define EVP_PKEY_CTRL_PEER_KEY 3
// EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl
// commands are numbered.
#define EVP_PKEY_ALG_CTRL 0x1000
#define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1)
#define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 2)
#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 3)
#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 4)
#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 5)
#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 6)
#define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 7)
#define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 8)
#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 9)
#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 10)
#define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 11)
#define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12)
#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 13)
#define EVP_PKEY_CTRL_HKDF_MODE (EVP_PKEY_ALG_CTRL + 14)
#define EVP_PKEY_CTRL_HKDF_MD (EVP_PKEY_ALG_CTRL + 15)
#define EVP_PKEY_CTRL_HKDF_KEY (EVP_PKEY_ALG_CTRL + 16)
#define EVP_PKEY_CTRL_HKDF_SALT (EVP_PKEY_ALG_CTRL + 17)
#define EVP_PKEY_CTRL_HKDF_INFO (EVP_PKEY_ALG_CTRL + 18)
#define EVP_PKEY_CTRL_DH_PAD (EVP_PKEY_ALG_CTRL + 19)
#define EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN (EVP_PKEY_ALG_CTRL + 20)
#define EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR (EVP_PKEY_ALG_CTRL + 21)
#define EVP_PKEY_CTRL_SET_MAC_KEY (EVP_PKEY_ALG_CTRL + 22)
#define EVP_PKEY_CTRL_DSA_PARAMGEN_BITS (EVP_PKEY_ALG_CTRL + 23)
#define EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS (EVP_PKEY_ALG_CTRL + 24)
#define EVP_PKEY_CTRL_DSA_PARAMGEN_MD (EVP_PKEY_ALG_CTRL + 25)
// EVP_PKEY_CTX_KEYGEN_INFO_COUNT is the maximum array length for
// |EVP_PKEY_CTX->keygen_info|. The array length corresponds to the number of
// arguments |BN_GENCB|'s callback function handles.
//
// |ctx->keygen_info| map to the following values in |BN_GENCB|:
// 1. |ctx->keygen_info[0]| -> |event|
// 2. |ctx->keygen_info[1]| -> |n|
#define EVP_PKEY_CTX_KEYGEN_INFO_COUNT 2
struct evp_pkey_ctx_st {
// Method associated with this operation
const EVP_PKEY_METHOD *pmeth;
// Engine that implements this method or NULL if builtin
ENGINE *engine;
// Key: may be NULL
EVP_PKEY *pkey;
// Peer key for key agreement, may be NULL
EVP_PKEY *peerkey;
// operation contains one of the |EVP_PKEY_OP_*| values.
int operation;
// Algorithm specific data
void *data;
// Application specific data used by the callback.
void *app_data;
// Callback and specific keygen data that is mapped to |BN_GENCB| for relevant
// implementations. This is only used for DSA, DH, and RSA in OpenSSL. AWS-LC
// only supports RSA as of now.
// See |EVP_PKEY_CTX_get_keygen_info| for more details.
EVP_PKEY_gen_cb *pkey_gencb;
int keygen_info[EVP_PKEY_CTX_KEYGEN_INFO_COUNT];
}; // EVP_PKEY_CTX
struct evp_pkey_method_st {
int pkey_id;
int (*init)(EVP_PKEY_CTX *ctx);
int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);
void (*cleanup)(EVP_PKEY_CTX *ctx);
int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
int (*sign_init)(EVP_PKEY_CTX *ctx);
int (*sign)(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
const uint8_t *tbs, size_t tbslen);
int (*sign_message)(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
const uint8_t *tbs, size_t tbslen);
int (*verify_init)(EVP_PKEY_CTX *ctx);
int (*verify)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
const uint8_t *tbs, size_t tbslen);
int (*verify_message)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
const uint8_t *tbs, size_t tbslen);
int (*verify_recover)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
const uint8_t *sig, size_t sig_len);
int (*encrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen);
int (*decrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen);
int (*derive)(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *keylen);
int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
int (*ctrl_str) (EVP_PKEY_CTX *ctx, const char *type, const char *value);
// Encapsulate, encapsulate_deterministic, keygen_deterministic, and
// decapsulate are operations defined for a Key Encapsulation Mechanism (KEM).
int (*keygen_deterministic)(EVP_PKEY_CTX *ctx,
EVP_PKEY *pkey,
const uint8_t *seed,
size_t *seed_len);
int (*encapsulate_deterministic)(EVP_PKEY_CTX *ctx,
uint8_t *ciphertext,
size_t *ciphertext_len,
uint8_t *shared_secret,
size_t *shared_secret_len,
const uint8_t *seed,
size_t *seed_len);
int (*encapsulate)(EVP_PKEY_CTX *ctx,
uint8_t *ciphertext, size_t *ciphertext_len,
uint8_t *shared_secret, size_t *shared_secret_len);
int (*decapsulate)(EVP_PKEY_CTX *ctx,
uint8_t *shared_secret, size_t *shared_secret_len,
const uint8_t *ciphertext, size_t ciphertext_len);
}; // EVP_PKEY_METHOD
// used_for_hmac indicates if |ctx| is used specifically for the |EVP_PKEY_HMAC|
// operation.
int used_for_hmac(EVP_MD_CTX *ctx);
typedef struct {
uint8_t *key;
size_t key_len;
} HMAC_KEY;
typedef struct {
const EVP_MD *md; // MD for HMAC use.
HMAC_CTX ctx;
HMAC_KEY ktmp;
} HMAC_PKEY_CTX;
// HMAC_KEY_set copies provided key into hmac_key. It frees any existing key
// on hmac_key. It returns 1 on success, and 0 otherwise.
int HMAC_KEY_set(HMAC_KEY* hmac_key, const uint8_t* key, const size_t key_len);
// HMAC_KEY_copy allocates and a new |HMAC_KEY| with identical contents (internal use).
int HMAC_KEY_copy(HMAC_KEY* dest, HMAC_KEY* src);
// HMAC_KEY_new allocates and zeroizes a |HMAC_KEY| for internal use.
HMAC_KEY *HMAC_KEY_new(void);
typedef struct {
// key is the concatenation of the private seed and public key. It is stored
// as a single 64-bit array to allow passing to |ED25519_sign|. If
// |has_private| is false, the first 32 bytes are uninitialized and the public
// key is in the last 32 bytes.
uint8_t key[64];
char has_private;
} ED25519_KEY;
// evp_pkey_set_cb_translate translates |ctx|'s |pkey_gencb| and sets it as the
// callback function for |cb|.
void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
#define ED25519_PUBLIC_KEY_OFFSET 32
#define FIPS_EVP_PKEY_METHODS 9
#define NON_FIPS_EVP_PKEY_METHODS 3
#define ASN1_EVP_PKEY_METHODS 11
struct fips_evp_pkey_methods {
const EVP_PKEY_METHOD * methods[FIPS_EVP_PKEY_METHODS];
};
const EVP_PKEY_METHOD *EVP_PKEY_rsa_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_rsa_pss_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_ec_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_hkdf_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_hmac_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_ed25519_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_kem_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_pqdsa_pkey_meth(void);
const EVP_PKEY_METHOD *EVP_PKEY_ed25519ph_pkey_meth(void);
struct evp_pkey_ctx_signature_context_params_st {
const uint8_t *context;
size_t context_len;
}; // EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS
#if defined(__cplusplus)
} // extern C
#endif
#endif // OPENSSL_HEADER_EVP_INTERNAL_H

View File

@@ -0,0 +1,288 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <string.h>
#include <openssl/bn.h>
#include <openssl/digest.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
#include "internal.h"
#include "../ec/internal.h"
#include "../../internal.h"
typedef struct {
// message digest
const EVP_MD *md;
const EC_GROUP *gen_group;
} EC_PKEY_CTX;
static int pkey_ec_init(EVP_PKEY_CTX *ctx) {
EC_PKEY_CTX *dctx;
dctx = OPENSSL_zalloc(sizeof(EC_PKEY_CTX));
if (!dctx) {
return 0;
}
ctx->data = dctx;
return 1;
}
static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
if (!pkey_ec_init(dst)) {
return 0;
}
const EC_PKEY_CTX *sctx = src->data;
EC_PKEY_CTX *dctx = dst->data;
dctx->md = sctx->md;
dctx->gen_group = sctx->gen_group;
return 1;
}
static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) {
EC_PKEY_CTX *dctx = ctx->data;
if (!dctx) {
return;
}
OPENSSL_free(dctx);
}
static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
const uint8_t *tbs, size_t tbslen) {
unsigned int sltmp;
EC_KEY *ec = ctx->pkey->pkey.ec;
if (!sig) {
*siglen = ECDSA_size(ec);
return 1;
} else if (*siglen < (size_t)ECDSA_size(ec)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (!ECDSA_sign(0, tbs, tbslen, sig, &sltmp, ec)) {
return 0;
}
*siglen = (size_t)sltmp;
return 1;
}
static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
const uint8_t *tbs, size_t tbslen) {
return ECDSA_verify(0, tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
}
static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
size_t *keylen) {
const EC_POINT *pubkey = NULL;
EC_KEY *eckey;
uint8_t buf[EC_MAX_BYTES];
size_t buflen = sizeof(buf);
if (!ctx->pkey || !ctx->peerkey) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
eckey = ctx->pkey->pkey.ec;
if (!key) {
// This only outputs the expected |keylen| and does no actual crypto.
const EC_GROUP *group;
group = EC_KEY_get0_group(eckey);
*keylen = (EC_GROUP_get_degree(group) + 7) / 8;
return 1;
}
pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
// NB: unlike PKCS#3 DH, if the returned buflen is less than
// the requested size in *keylen, this is not an error;
// the result is truncated.
// Note: This is an internal function which will not update
// the service indicator.
if (!ECDH_compute_shared_secret(buf, &buflen, pubkey, eckey)) {
return 0;
}
if (buflen < *keylen) {
*keylen = buflen;
}
OPENSSL_memcpy(key, buf, *keylen);
// Insert service indicator check here because the pointer address cannot be
// referenced from the higher level function |EVP_PKEY_derive|. |EC_KEY| is
// is the only possible key that can do derivations.
ECDH_verify_service_indicator(eckey);
return 1;
}
static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
EC_PKEY_CTX *dctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_MD: {
const EVP_MD *md = p2;
int md_type = EVP_MD_type(md);
if (md_type != NID_sha1 && md_type != NID_sha224 &&
md_type != NID_sha256 && md_type != NID_sha384 &&
md_type != NID_sha512 && md_type != NID_sha512_224 &&
md_type != NID_sha512_256 && md_type != NID_sha3_224 &&
md_type != NID_sha3_256 && md_type != NID_sha3_384 &&
md_type != NID_sha3_512
) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
return 0;
}
dctx->md = md;
return 1;
}
case EVP_PKEY_CTRL_GET_MD:
*(const EVP_MD **)p2 = dctx->md;
return 1;
case EVP_PKEY_CTRL_PEER_KEY:
// Default behaviour is OK
return 1;
case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: {
const EC_GROUP *group = EC_GROUP_new_by_curve_name(p1);
if (group == NULL) {
return 0;
}
dctx->gen_group = group;
return 1;
}
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
static int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (strcmp(type, "ec_paramgen_curve") == 0) {
int nid;
nid = EC_curve_nist2nid(value);
if (nid == NID_undef) {
nid = OBJ_sn2nid(value);
}
if (nid == NID_undef) {
nid = OBJ_ln2nid(value);
}
if (nid == NID_undef) {
OPENSSL_PUT_ERROR(EVP, EC_R_INVALID_ENCODING);
return 0;
}
return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
}
if (strcmp(type, "ec_param_enc") == 0) {
int param_enc;
// We don't support "explicit"
if (strcmp(value, "named_curve") == 0) {
param_enc = OPENSSL_EC_NAMED_CURVE;
} else {
return -2;
}
return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc);
}
// We don't support "ecdh_kdf_md" nor "ecdh_cofactor_mode"
return -2;
}
static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
int ret = 0;
EC_PKEY_CTX *dctx = ctx->data;
const EC_GROUP *group = dctx->gen_group;
if (group == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
group = EC_KEY_get0_group(ctx->pkey->pkey.ec);
}
EC_KEY *ec = EC_KEY_new();
// In FIPS build, |EC_KEY_generate_key_fips| updates the service indicator so lock it here
FIPS_service_indicator_lock_state();
if (ec == NULL ||
!EC_KEY_set_group(ec, group) ||
(!is_fips_build() && !EC_KEY_generate_key(ec)) ||
( is_fips_build() && !EC_KEY_generate_key_fips(ec))) {
EC_KEY_free(ec);
goto end;
}
EVP_PKEY_assign_EC_KEY(pkey, ec);
ret = 1;
end:
FIPS_service_indicator_unlock_state();
return ret;
}
static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
EC_PKEY_CTX *dctx = ctx->data;
if (dctx->gen_group == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
EC_KEY *ec = EC_KEY_new();
if (ec == NULL ||
!EC_KEY_set_group(ec, dctx->gen_group)) {
EC_KEY_free(ec);
return 0;
}
EVP_PKEY_assign_EC_KEY(pkey, ec);
return 1;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ec_pkey_meth) {
out->pkey_id = EVP_PKEY_EC;
out->init = pkey_ec_init;
out->copy = pkey_ec_copy;
out->cleanup = pkey_ec_cleanup;
out->keygen = pkey_ec_keygen;
out->sign_init = NULL; /* sign_init */
out->sign = pkey_ec_sign;
out->sign_message = NULL; /* sign_message */
out->verify_init = NULL; /* verify_init */
out->verify = pkey_ec_verify;
out->verify_message = NULL; /* verify_message */
out->verify_recover = NULL; /* verify_recover */
out->encrypt = NULL; /* encrypt */
out->decrypt = NULL; /* decrypt */
out->derive = pkey_ec_derive;
out->paramgen = pkey_ec_paramgen;
out->ctrl = pkey_ec_ctrl;
out->ctrl_str = pkey_ec_ctrl_str;
}
int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_TYPE_GEN,
EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, NULL);
}
int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int encoding) {
// BoringSSL only supports named curve syntax.
if (encoding != OPENSSL_EC_NAMED_CURVE) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
return 1;
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2017, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
#include "../curve25519/internal.h"
// Ed25519 has no parameters to copy.
static int pkey_ed25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; }
static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY));
if (key == NULL) {
return 0;
}
evp_pkey_set_method(pkey, &ed25519_asn1_meth);
uint8_t pubkey_unused[32];
int result = ED25519_keypair_internal(pubkey_unused, key->key);
if (result) {
key->has_private = 1;
OPENSSL_free(pkey->pkey.ptr);
pkey->pkey.ptr = key;
}
return result;
}
static int pkey_ed25519_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig,
size_t *siglen, const uint8_t *tbs,
size_t tbslen) {
ED25519_KEY *key = ctx->pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (sig == NULL) {
*siglen = 64;
return 1;
}
if (*siglen < 64) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (!ED25519_sign(sig, tbs, tbslen, key->key)) {
return 0;
}
*siglen = 64;
return 1;
}
static int pkey_ed25519_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t siglen, const uint8_t *tbs,
size_t tbslen) {
ED25519_KEY *key = ctx->pkey->pkey.ptr;
if (siglen != 64 ||
!ED25519_verify(tbs, tbslen, sig, key->key + ED25519_PUBLIC_KEY_OFFSET)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
return 0;
}
return 1;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519_pkey_meth) {
out->pkey_id = EVP_PKEY_ED25519;
out->init = NULL;
out->copy = pkey_ed25519_copy;
out->cleanup = NULL;
out->keygen = pkey_ed25519_keygen;
out->sign_init = NULL;
out->sign = NULL;
out->sign_message = pkey_ed25519_sign_message;
out->verify_init = NULL;
out->verify = NULL;
out->verify_message = pkey_ed25519_verify_message;
out->verify_recover = NULL;
out->encrypt = NULL;
out->decrypt = NULL;
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = NULL;
out->ctrl_str = NULL;
out->keygen_deterministic = NULL;
out->encapsulate_deterministic = NULL;
out->encapsulate = NULL;
out->decapsulate = NULL;
}

View File

@@ -0,0 +1,170 @@
// Copyright (c) 2017, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../../internal.h"
#include "internal.h"
typedef struct {
uint8_t context[255];
size_t context_len;
} ED25519PH_PKEY_CTX;
static int pkey_ed25519ph_init(EVP_PKEY_CTX *ctx) {
ED25519PH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(ED25519PH_PKEY_CTX));
if (dctx == NULL) {
return 0;
}
ctx->data = dctx;
return 1;
}
static void pkey_ed25519ph_cleanup(EVP_PKEY_CTX *ctx) {
ED25519PH_PKEY_CTX *dctx = ctx->data;
if (!dctx) {
return;
}
OPENSSL_free(dctx);
}
static int pkey_ed25519ph_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
if (!pkey_ed25519ph_init(dst)) {
return 0;
}
ED25519PH_PKEY_CTX *dctx = dst->data;
ED25519PH_PKEY_CTX *sctx = src->data;
GUARD_PTR(dctx);
GUARD_PTR(sctx);
OPENSSL_memcpy(dctx->context, sctx->context, sizeof(sctx->context));
dctx->context_len = sctx->context_len;
return 1;
}
static int pkey_ed25519ph_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
const uint8_t *tbs, size_t tbslen) {
ED25519_KEY *key = ctx->pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (sig == NULL) {
*siglen = ED25519_SIGNATURE_LEN;
return 1;
}
if (*siglen < ED25519_SIGNATURE_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (tbslen < SHA512_DIGEST_LENGTH) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
ED25519PH_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
if (!ED25519ph_sign_digest(sig, tbs, key->key, dctx->context,
dctx->context_len)) {
return 0;
}
*siglen = ED25519_SIGNATURE_LEN;
return 1;
}
static int pkey_ed25519ph_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t siglen, const uint8_t *tbs,
size_t tbslen) {
ED25519_KEY *key = ctx->pkey->pkey.ptr;
ED25519PH_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
if (siglen != ED25519_SIGNATURE_LEN || tbslen < SHA512_DIGEST_LENGTH ||
!ED25519ph_verify_digest(tbs, sig, key->key + ED25519_PUBLIC_KEY_OFFSET,
dctx->context, dctx->context_len)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
return 0;
}
return 1;
}
static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
GUARD_PTR(ctx);
ED25519PH_PKEY_CTX *dctx = (ED25519PH_PKEY_CTX *)ctx->data;
switch (type) {
case EVP_PKEY_CTRL_MD: {
const EVP_MD *md = p2;
int md_type = EVP_MD_type(md);
// MUST be SHA-512
if (md_type != NID_sha512) {
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
break;
}
case EVP_PKEY_CTRL_SIGNING_CONTEXT: {
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2;
if (!params || !dctx || params->context_len > sizeof(dctx->context)) {
return 0;
}
OPENSSL_memcpy(dctx->context, params->context, params->context_len);
dctx->context_len = params->context_len;
break;
}
case EVP_PKEY_CTRL_GET_SIGNING_CONTEXT: {
EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2;
if (!params || !dctx) {
return 0;
}
if (dctx->context_len == 0) {
params->context = NULL;
params->context_len = 0;
} else {
params->context = dctx->context;
params->context_len = dctx->context_len;
}
return 1;
}
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
return 1;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519ph_pkey_meth) {
out->pkey_id = EVP_PKEY_ED25519PH;
out->init = pkey_ed25519ph_init;
out->copy = pkey_ed25519ph_copy;
out->cleanup = pkey_ed25519ph_cleanup;
out->keygen = NULL;
out->sign_init = NULL;
out->sign = pkey_ed25519ph_sign;
out->verify_init = NULL;
out->verify = pkey_ed25519ph_verify;
out->verify_message = NULL;
out->verify_recover = NULL;
out->encrypt = NULL;
out->decrypt = NULL;
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = pkey_ed25519ph_ctrl;
out->ctrl_str = NULL;
out->keygen_deterministic = NULL;
out->encapsulate_deterministic = NULL;
out->encapsulate = NULL;
out->decapsulate = NULL;
}

View File

@@ -0,0 +1,316 @@
// Copyright (c) 2022, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/hkdf.h>
#include <openssl/kdf.h>
#include <openssl/mem.h>
#include "../../internal.h"
#include "internal.h"
typedef struct {
int mode;
const EVP_MD *md;
uint8_t *key;
size_t key_len;
uint8_t *salt;
size_t salt_len;
CBB info;
} HKDF_PKEY_CTX;
static int pkey_hkdf_init(EVP_PKEY_CTX *ctx) {
HKDF_PKEY_CTX *hctx = OPENSSL_zalloc(sizeof(HKDF_PKEY_CTX));
if (hctx == NULL) {
return 0;
}
if (!CBB_init(&hctx->info, 0)) {
OPENSSL_free(hctx);
return 0;
}
ctx->data = hctx;
return 1;
}
static int pkey_hkdf_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
if (!pkey_hkdf_init(dst)) {
return 0;
}
HKDF_PKEY_CTX *hctx_dst = dst->data;
const HKDF_PKEY_CTX *hctx_src = src->data;
hctx_dst->mode = hctx_src->mode;
hctx_dst->md = hctx_src->md;
if (hctx_src->key_len != 0) {
hctx_dst->key = OPENSSL_memdup(hctx_src->key, hctx_src->key_len);
if (hctx_dst->key == NULL) {
return 0;
}
hctx_dst->key_len = hctx_src->key_len;
}
if (hctx_src->salt_len != 0) {
hctx_dst->salt = OPENSSL_memdup(hctx_src->salt, hctx_src->salt_len);
if (hctx_dst->salt == NULL) {
return 0;
}
hctx_dst->salt_len = hctx_src->salt_len;
}
if (!CBB_add_bytes(&hctx_dst->info, CBB_data(&hctx_src->info),
CBB_len(&hctx_src->info))) {
return 0;
}
return 1;
}
static void pkey_hkdf_cleanup(EVP_PKEY_CTX *ctx) {
HKDF_PKEY_CTX *hctx = ctx->data;
if (hctx != NULL) {
OPENSSL_free(hctx->key);
OPENSSL_free(hctx->salt);
CBB_cleanup(&hctx->info);
OPENSSL_free(hctx);
ctx->data = NULL;
}
}
static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len) {
HKDF_PKEY_CTX *hctx = ctx->data;
if (hctx->md == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
if (EVP_MD_size(hctx->md) <= 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
if (hctx->key_len == 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
if (out == NULL) {
if (hctx->mode == EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) {
*out_len = EVP_MD_size(hctx->md);
}
// HKDF-Expand is variable-length and returns |*out_len| bytes. "Output" the
// input length by leaving it alone.
return 1;
}
switch (hctx->mode) {
case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
return HKDF(out, *out_len, hctx->md, hctx->key, hctx->key_len, hctx->salt,
hctx->salt_len, CBB_data(&hctx->info), CBB_len(&hctx->info));
case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
if (*out_len < EVP_MD_size(hctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
return HKDF_extract(out, out_len, hctx->md, hctx->key, hctx->key_len,
hctx->salt, hctx->salt_len);
case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
return HKDF_expand(out, *out_len, hctx->md, hctx->key, hctx->key_len,
CBB_data(&hctx->info), CBB_len(&hctx->info));
}
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
HKDF_PKEY_CTX *hctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_HKDF_MODE:
if (p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND &&
p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY &&
p1 != EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
hctx->mode = p1;
return 1;
case EVP_PKEY_CTRL_HKDF_MD:
if (p2 == NULL || EVP_MD_size((const EVP_MD *)p2) <= 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
if (EVP_MD_flags((const EVP_MD *)p2) & EVP_MD_FLAG_XOF) {
OPENSSL_PUT_ERROR(EVP, HKDF_R_UNSUPPORTED_DIGEST);
return 0;
}
hctx->md = (const EVP_MD *)p2;
return 1;
case EVP_PKEY_CTRL_HKDF_KEY: {
const CBS *key = p2;
if (!CBS_stow(key, &hctx->key, &hctx->key_len)) {
return 0;
}
return 1;
}
case EVP_PKEY_CTRL_HKDF_SALT: {
const CBS *salt = p2;
if (!CBS_stow(salt, &hctx->salt, &hctx->salt_len)) {
return 0;
}
return 1;
}
case EVP_PKEY_CTRL_HKDF_INFO: {
const CBS *info = p2;
// |EVP_PKEY_CTX_add1_hkdf_info| appends to the info string, rather than
// replacing it.
if (!CBB_add_bytes(&hctx->info, CBS_data(info), CBS_len(info))) {
return 0;
}
return 1;
}
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (strcmp(type, "mode") == 0) {
int mode;
if (strcmp(value, "EXTRACT_AND_EXPAND") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND;
} else if (strcmp(value, "EXTRACT_ONLY") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
} else if (strcmp(value, "EXPAND_ONLY") == 0) {
mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
} else {
return 0;
}
return EVP_PKEY_CTX_hkdf_mode(ctx, mode);
}
if (strcmp(type, "md") == 0) {
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_DERIVE, EVP_PKEY_CTRL_HKDF_MD,
value);
OPENSSL_END_ALLOW_DEPRECATED
}
if (strcmp(type, "salt") == 0) {
// What if the salt contains a 0-byte?
const size_t saltlen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_set1_hkdf_salt(ctx, (const uint8_t *)value, saltlen);
}
if (strcmp(type, "hexsalt") == 0) {
size_t hex_saltlen = 0;
uint8_t *salt = OPENSSL_hexstr2buf(value, &hex_saltlen);
if (salt == NULL) {
return 0;
}
int result = EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, hex_saltlen);
OPENSSL_free(salt);
return result;
}
if (strcmp(type, "key") == 0) {
// What if the key contains a 0-byte?
const size_t keylen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_set1_hkdf_key(ctx, (const uint8_t *)value, keylen);
}
if (strcmp(type, "hexkey") == 0) {
size_t hex_keylen = 0;
uint8_t *key = OPENSSL_hexstr2buf(value, &hex_keylen);
if (key == NULL) {
return 0;
}
int result = EVP_PKEY_CTX_set1_hkdf_key(ctx, key, hex_keylen);
OPENSSL_free(key);
return result;
}
if (strcmp(type, "info") == 0) {
// What if info contains a 0-byte?
const size_t infolen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_add1_hkdf_info(ctx, (const uint8_t *)value, infolen);
}
if (strcmp(type, "hexinfo") == 0) {
size_t hex_infolen = 0;
uint8_t *info = OPENSSL_hexstr2buf(value, &hex_infolen);
if (info == NULL) {
return 0;
}
int result = EVP_PKEY_CTX_add1_hkdf_info(ctx, info, hex_infolen);
OPENSSL_free(info);
return result;
}
return -2;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hkdf_pkey_meth) {
out->pkey_id = EVP_PKEY_HKDF;
out->init = pkey_hkdf_init;
out->copy = pkey_hkdf_copy;
out->cleanup = pkey_hkdf_cleanup;
out->keygen = NULL; /* keygen */
out->sign_init = NULL; /* sign_init */
out->sign = NULL; /* sign */
out->sign_message = NULL; /* sign_message */
out->verify_init = NULL; /* verify_init */
out->verify = NULL; /* verify */
out->verify_message = NULL; /* verify_message */
out->verify_recover = NULL; /* verify_recover */
out->encrypt = NULL; /* encrypt */
out->decrypt = NULL; /* decrypt */
out->derive = pkey_hkdf_derive;
out->paramgen = NULL; /* paramgen */
out->ctrl = pkey_hkdf_ctrl;
out->ctrl_str = pkey_hkdf_ctrl_str;
}
int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_HKDF_MODE, mode, NULL);
}
int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_HKDF_MD, 0, (void *)md);
}
int EVP_PKEY_CTX_set1_hkdf_key(EVP_PKEY_CTX *ctx, const uint8_t *key,
size_t key_len) {
SET_DIT_AUTO_RESET;
CBS cbs;
CBS_init(&cbs, key, key_len);
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_HKDF_KEY, 0, &cbs);
}
int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *ctx, const uint8_t *salt,
size_t salt_len) {
CBS cbs;
CBS_init(&cbs, salt, salt_len);
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_HKDF_SALT, 0, &cbs);
}
int EVP_PKEY_CTX_add1_hkdf_info(EVP_PKEY_CTX *ctx, const uint8_t *info,
size_t info_len) {
CBS cbs;
CBS_init(&cbs, info, info_len);
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_HKDF_INFO, 0, &cbs);
}

View File

@@ -0,0 +1,182 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2007.
// Copyright (c) 2007 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include "../../evp_extra/internal.h"
#include "internal.h"
static int hmac_init(EVP_PKEY_CTX *ctx) {
HMAC_PKEY_CTX *hctx;
hctx = OPENSSL_zalloc(sizeof(HMAC_PKEY_CTX));
if (hctx == NULL) {
return 0;
}
HMAC_CTX_init(&hctx->ctx);
ctx->data = hctx;
return 1;
}
static int hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
HMAC_PKEY_CTX *sctx, *dctx;
if (!hmac_init(dst)) {
return 0;
}
sctx = src->data;
dctx = dst->data;
dctx->md = sctx->md;
if(sctx->ktmp.key != NULL && !HMAC_KEY_copy(&dctx->ktmp, &sctx->ktmp)) {
HMAC_CTX_cleanup(&dctx->ctx);
OPENSSL_free(dctx);
dst->data = NULL;
return 0;
}
if (!HMAC_CTX_copy_ex(&dctx->ctx, &sctx->ctx)) {
HMAC_CTX_cleanup(&dctx->ctx);
OPENSSL_free(dctx->ktmp.key);
OPENSSL_free(dctx);
dst->data = NULL;
return 0;
}
return 1;
}
static void hmac_cleanup(EVP_PKEY_CTX *ctx) {
HMAC_PKEY_CTX *hctx = ctx->data;
if (hctx == NULL) {
return;
}
HMAC_CTX_cleanup(&hctx->ctx);
OPENSSL_free(hctx->ktmp.key);
OPENSSL_free(hctx);
ctx->data = NULL;
}
static int hmac_ctrl(EVP_PKEY_CTX *ctx, int cmd, int p1, void *p2) {
int result = -2;
HMAC_PKEY_CTX *hctx = ctx->data;
switch (cmd) {
case EVP_PKEY_CTRL_SET_MAC_KEY:
if (p1 >= 0 && p1 <= INT16_MAX) {
// p1 is the key length
// p2 is the key
if (HMAC_KEY_set(&hctx->ktmp, p2, p1)) {
result = 1;
} else {
result = 0;
}
}
break;
case EVP_PKEY_CTRL_MD:
hctx->md = p2;
result = 1;
break;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
}
return result;
}
static int hmac_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (!value) {
return 0;
}
if (strcmp(type, "key") == 0) {
// What if the key contains a 0-byte?
const size_t keylen = OPENSSL_strnlen(value, INT16_MAX);
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HMAC, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_SET_MAC_KEY, keylen, (void*)value);
}
if (strcmp(type, "hexkey") == 0) {
size_t hex_keylen = 0;
uint8_t *key = OPENSSL_hexstr2buf(value, &hex_keylen);
if (key == NULL) {
return 0;
}
int result =
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HMAC, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_SET_MAC_KEY, hex_keylen, key);
OPENSSL_free(key);
return result;
}
return -2;
}
static int hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
GUARD_PTR(pkey);
HMAC_KEY *hmac = NULL;
HMAC_PKEY_CTX *hctx = ctx->data;
if(hctx == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
if (!(hmac = HMAC_KEY_new())) {
return 0;
}
if (!HMAC_KEY_copy(hmac, &hctx->ktmp) ||
!EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hmac)) {
OPENSSL_free(hmac->key);
OPENSSL_free(hmac);
return 0;
}
return 1;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_hmac_pkey_meth) {
out->pkey_id = EVP_PKEY_HMAC;
out->init = hmac_init;
out->copy = hmac_copy;
out->cleanup = hmac_cleanup;
out->keygen = hmac_keygen;
out->ctrl = hmac_ctrl;
out->ctrl_str = hmac_ctrl_str;
}
int used_for_hmac(EVP_MD_CTX *ctx) {
return ctx->flags == EVP_MD_CTX_HMAC && ctx->pctx != NULL;
}
HMAC_KEY *HMAC_KEY_new(void) {
HMAC_KEY *key = OPENSSL_zalloc(sizeof(HMAC_KEY));
if (key == NULL) {
return NULL;
}
return key;
}
int HMAC_KEY_set(HMAC_KEY* hmac_key, const uint8_t* key, const size_t key_len) {
if(hmac_key == NULL ) {
return 0;
}
if (key == NULL || key_len == 0) {
hmac_key->key = NULL;
hmac_key->key_len = 0;
return 1;
}
uint8_t* new_key = OPENSSL_memdup(key, key_len);
if(new_key == NULL) {
return 0;
}
OPENSSL_free(hmac_key->key);
hmac_key->key = new_key;
hmac_key->key_len = key_len;
return 1;
}
int HMAC_KEY_copy(HMAC_KEY* dest, HMAC_KEY* src) {
GUARD_PTR(dest);
GUARD_PTR(src);
return HMAC_KEY_set(dest, src->key, src->key_len);
}

View File

@@ -0,0 +1,547 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../crypto/evp_extra/internal.h"
#include "internal.h"
#include "../delocate.h"
#include "../kem/internal.h"
#include "../../internal.h"
#include "internal.h"
typedef struct {
const KEM *kem;
} KEM_PKEY_CTX;
static int pkey_kem_init(EVP_PKEY_CTX *ctx) {
KEM_PKEY_CTX *dctx;
dctx = OPENSSL_zalloc(sizeof(KEM_PKEY_CTX));
if (dctx == NULL) {
return 0;
}
ctx->data = dctx;
return 1;
}
static void pkey_kem_cleanup(EVP_PKEY_CTX *ctx) {
OPENSSL_free(ctx->data);
}
static int pkey_kem_keygen_deterministic(EVP_PKEY_CTX *ctx,
EVP_PKEY *pkey,
const uint8_t *seed,
size_t *seed_len) {
GUARD_PTR(ctx);
KEM_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
const KEM *kem = dctx->kem;
if (kem == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key);
}
// Check that size buffers can be written to.
if (seed_len == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// Caller is getting parameter values.
if (seed == NULL) {
*seed_len = kem->keygen_seed_len;
return 1;
}
// The seed should be of the correct length.
if (*seed_len != kem->keygen_seed_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
KEM_KEY *key = KEM_KEY_new();
size_t pubkey_len = kem->public_key_len;
size_t secret_len = kem->secret_key_len;
if (key == NULL ||
!KEM_KEY_init(key, kem) ||
!kem->method->keygen_deterministic(key->public_key, &pubkey_len, key->secret_key, &secret_len, seed) ||
!EVP_PKEY_assign(pkey, EVP_PKEY_KEM, key)) {
KEM_KEY_free(key);
return 0;
}
return 1;
}
static int pkey_kem_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
GUARD_PTR(ctx);
KEM_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
const KEM *kem = dctx->kem;
if (kem == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key);
}
KEM_KEY *key = KEM_KEY_new();
size_t pubkey_len = kem->public_key_len;
size_t secret_len = kem->secret_key_len;
if (key == NULL ||
!KEM_KEY_init(key, kem) ||
!kem->method->keygen(key->public_key, &pubkey_len, key->secret_key, &secret_len) ||
!EVP_PKEY_set_type(pkey, EVP_PKEY_KEM)) {
KEM_KEY_free(key);
return 0;
}
pkey->pkey.kem_key = key;
return 1;
}
static int pkey_kem_encapsulate_deterministic(EVP_PKEY_CTX *ctx,
uint8_t *ciphertext,
size_t *ciphertext_len,
uint8_t *shared_secret,
size_t *shared_secret_len,
const uint8_t *seed,
size_t *seed_len) {
GUARD_PTR(ctx);
KEM_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
const KEM *kem = dctx->kem;
if (kem == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key);
}
// Check that size buffers can be written to.
if (ciphertext_len == NULL || shared_secret_len == NULL || seed_len == NULL ) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// Caller is getting parameter values.
if (ciphertext == NULL && shared_secret == NULL && seed == NULL) {
*ciphertext_len = kem->ciphertext_len;
*shared_secret_len = kem->shared_secret_len;
*seed_len = kem->encaps_seed_len;
return 1;
}
// If not getting parameter values, then all three
// output buffers need to be valid (non-NULL)
if (ciphertext == NULL || shared_secret == NULL || seed == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
// The output buffers need to be large enough.
if (*ciphertext_len < kem->ciphertext_len ||
*shared_secret_len < kem->shared_secret_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
// The seed should be of the correct length.
if (*seed_len != kem->encaps_seed_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
// Check that the context is properly configured.
if (ctx->pkey == NULL ||
ctx->pkey->pkey.kem_key == NULL ||
ctx->pkey->type != EVP_PKEY_KEM) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
// Check that the key has a public key set.
KEM_KEY *key = ctx->pkey->pkey.kem_key;
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
if (!kem->method->encaps_deterministic(ciphertext, ciphertext_len, shared_secret, shared_secret_len, key->public_key, seed)) {
return 0;
}
// The size of the ciphertext and the shared secret
// that has been writen to the output buffers.
*ciphertext_len = kem->ciphertext_len;
*shared_secret_len = kem->shared_secret_len;
return 1;
}
static int pkey_kem_encapsulate(EVP_PKEY_CTX *ctx,
uint8_t *ciphertext,
size_t *ciphertext_len,
uint8_t *shared_secret,
size_t *shared_secret_len) {
KEM_PKEY_CTX *dctx = ctx->data;
const KEM *kem = dctx->kem;
if (kem == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key);
}
// Caller is getting parameter values.
if (ciphertext == NULL && shared_secret == NULL) {
*ciphertext_len = kem->ciphertext_len;
*shared_secret_len = kem->shared_secret_len;
return 1;
}
// If not getting parameter values, then both
// output buffers need to be valid (non-NULL)
if (ciphertext == NULL || shared_secret == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
// The output buffers need to be large enough.
if (*ciphertext_len < kem->ciphertext_len ||
*shared_secret_len < kem->shared_secret_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
// Check that the context is properly configured.
if (ctx->pkey == NULL ||
ctx->pkey->pkey.kem_key == NULL ||
ctx->pkey->type != EVP_PKEY_KEM) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
// Check that the key has a public key set.
KEM_KEY *key = ctx->pkey->pkey.kem_key;
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
if (!kem->method->encaps(ciphertext, ciphertext_len, shared_secret, shared_secret_len, key->public_key)) {
return 0;
}
// The size of the ciphertext and the shared secret
// that has been writen to the output buffers.
*ciphertext_len = kem->ciphertext_len;
*shared_secret_len = kem->shared_secret_len;
return 1;
}
static int pkey_kem_decapsulate(EVP_PKEY_CTX *ctx,
uint8_t *shared_secret,
size_t *shared_secret_len,
const uint8_t *ciphertext,
size_t ciphertext_len) {
KEM_PKEY_CTX *dctx = ctx->data;
const KEM *kem = dctx->kem;
if (kem == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
kem = KEM_KEY_get0_kem(ctx->pkey->pkey.kem_key);
}
// Caller is getting parameter values.
if (shared_secret == NULL) {
*shared_secret_len = kem->shared_secret_len;
return 1;
}
// The input and output buffers need to be large enough.
if (ciphertext_len != kem->ciphertext_len ||
*shared_secret_len < kem->shared_secret_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
// Check that the context is properly configured.
if (ctx->pkey == NULL ||
ctx->pkey->pkey.kem_key == NULL ||
ctx->pkey->type != EVP_PKEY_KEM) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
// Check that the key has a secret key set.
KEM_KEY *key = ctx->pkey->pkey.kem_key;
if (key->secret_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
if (!kem->method->decaps(shared_secret, shared_secret_len, ciphertext, key->secret_key)) {
return 0;
}
// The size of the shared secret that has been written to the output buffer.
*shared_secret_len = kem->shared_secret_len;
return 1;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_kem_pkey_meth) {
out->pkey_id = EVP_PKEY_KEM;
out->init = pkey_kem_init;
out->copy = NULL;
out->cleanup = pkey_kem_cleanup;
out->keygen = pkey_kem_keygen;
out->sign_init = NULL;
out->sign = NULL;
out->sign_message = NULL;
out->verify_init = NULL;
out->verify = NULL;
out->verify_message = NULL;
out->verify_recover = NULL;
out->encrypt = NULL;
out->decrypt = NULL;
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = NULL;
out->ctrl_str = NULL;
out->keygen_deterministic = pkey_kem_keygen_deterministic;
out->encapsulate_deterministic = pkey_kem_encapsulate_deterministic;
out->encapsulate = pkey_kem_encapsulate;
out->decapsulate = pkey_kem_decapsulate;
}
// Additional KEM specific EVP functions.
int EVP_PKEY_CTX_kem_set_params(EVP_PKEY_CTX *ctx, int nid) {
if (ctx == NULL || ctx->data == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// It's not allowed to change context parameters if
// a PKEY is already associated with the context.
if (ctx->pkey != NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
const KEM *kem = KEM_find_kem_by_nid(nid);
if (kem == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
KEM_PKEY_CTX *dctx = ctx->data;
dctx->kem = kem;
return 1;
}
// This function sets KEM parameters defined by |nid| in |pkey|.
int EVP_PKEY_kem_set_params(EVP_PKEY *pkey, int nid) {
const KEM *kem = KEM_find_kem_by_nid(nid);
if (kem == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
evp_pkey_set_method(pkey, &kem_asn1_meth);
KEM_KEY *key = KEM_KEY_new();
if (key == NULL) {
// KEM_KEY_new sets the appropriate error.
return 0;
}
key->kem = kem;
pkey->pkey.kem_key = key;
return 1;
}
// Returns a fresh EVP_PKEY object of type EVP_PKEY_KEM,
// and sets KEM parameters defined by |nid|.
static EVP_PKEY *EVP_PKEY_kem_new(int nid) {
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL || !EVP_PKEY_kem_set_params(ret, nid)) {
EVP_PKEY_free(ret);
return NULL;
}
return ret;
}
EVP_PKEY *EVP_PKEY_kem_new_raw_public_key(int nid, const uint8_t *in, size_t len) {
if (in == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_kem_new(nid);
if (ret == NULL || ret->pkey.kem_key == NULL) {
// EVP_PKEY_kem_new sets the appropriate error.
goto err;
}
const KEM *kem = KEM_KEY_get0_kem(ret->pkey.kem_key);
if (kem->public_key_len != len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
goto err;
}
if (!KEM_KEY_set_raw_public_key(ret->pkey.kem_key, in)) {
// KEM_KEY_set_raw_public_key sets the appropriate error.
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
EVP_PKEY *EVP_PKEY_kem_new_raw_secret_key(int nid, const uint8_t *in, size_t len) {
if (in == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_kem_new(nid);
if (ret == NULL || ret->pkey.kem_key == NULL) {
// EVP_PKEY_kem_new sets the appropriate error.
goto err;
}
const KEM *kem = KEM_KEY_get0_kem(ret->pkey.kem_key);
if (kem->secret_key_len != len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
goto err;
}
if (!KEM_KEY_set_raw_secret_key(ret->pkey.kem_key, in)) {
// KEM_KEY_set_raw_secret_key sets the appropriate error.
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
EVP_PKEY *EVP_PKEY_kem_new_raw_key(int nid,
const uint8_t *in_public, size_t len_public,
const uint8_t *in_secret, size_t len_secret) {
if (in_public == NULL || in_secret == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_kem_new(nid);
if (ret == NULL || ret->pkey.kem_key == NULL) {
// EVP_PKEY_kem_new sets the appropriate error.
goto err;
}
const KEM *kem = KEM_KEY_get0_kem(ret->pkey.kem_key);
if (kem->public_key_len != len_public || kem->secret_key_len != len_secret) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
goto err;
}
if (!KEM_KEY_set_raw_key(ret->pkey.kem_key, in_public, in_secret)) {
// KEM_KEY_set_raw_key sets the appropriate error.
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
// EVP_PKEY_kem_check_key validates that the public key in |key| corresponds
// to the secret key in |key| by performing encapsulation and decapsulation
// and checking that the generated shared secrets are equal.
int EVP_PKEY_kem_check_key(EVP_PKEY *key) {
if (key == NULL || key->pkey.kem_key == NULL ||
key->pkey.kem_key->public_key == NULL ||
key->pkey.kem_key->secret_key == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
if (ctx == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
int ret = 0;
// Get the required buffer lengths and allocate the buffers.
size_t ct_len, ss_len;
uint8_t *ct = NULL, *ss_a = NULL, *ss_b = NULL;
if (!EVP_PKEY_encapsulate(ctx, NULL, &ct_len, NULL, &ss_len)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
goto end;
}
ct = OPENSSL_malloc(ct_len);
ss_a = OPENSSL_malloc(ss_len);
ss_b = OPENSSL_malloc(ss_len);
if (ct == NULL || ss_a == NULL || ss_b == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
goto end;
}
// Encapsulate and decapsulate.
if (!EVP_PKEY_encapsulate(ctx, ct, &ct_len, ss_b, &ss_len) ||
!EVP_PKEY_decapsulate(ctx, ss_a, &ss_len, ct, ct_len)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
goto end;
}
// Compare the shared secrets.
uint8_t res = 0;
for (size_t i = 0; i < ss_len; i++) {
res |= ss_a[i] ^ ss_b[i];
}
// If the shared secrets |ss_a| and |ss_b| are the same then |res| is equal
// to zero, otherwise it's not. |constant_time_is_zero_8| returns 0xff when
// |res| is equal to zero, and returns 0 otherwise. To be consistent with the
// rest of the library, we extract only the first bit so that |ret| is either
// 0 or 1.
ret = constant_time_is_zero_8(res) & 1;
end:
OPENSSL_free(ct);
OPENSSL_free(ss_a);
OPENSSL_free(ss_b);
EVP_PKEY_CTX_free(ctx);
return ret;
}

View File

@@ -0,0 +1,372 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../crypto/evp_extra/internal.h"
#include "../delocate.h"
#include "../ml_dsa/ml_dsa.h"
#include "../crypto/internal.h"
#include "../pqdsa/internal.h"
// PQDSA PKEY functions
typedef struct {
const PQDSA *pqdsa;
} PQDSA_PKEY_CTX;
static int pkey_pqdsa_init(EVP_PKEY_CTX *ctx) {
PQDSA_PKEY_CTX *dctx;
dctx = OPENSSL_zalloc(sizeof(PQDSA_PKEY_CTX));
if (dctx == NULL) {
return 0;
}
ctx->data = dctx;
return 1;
}
static void pkey_pqdsa_cleanup(EVP_PKEY_CTX *ctx) {
OPENSSL_free(ctx->data);
}
static int pkey_pqdsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
GUARD_PTR(ctx);
PQDSA_PKEY_CTX *dctx = ctx->data;
GUARD_PTR(dctx);
const PQDSA *pqdsa = dctx->pqdsa;
if (pqdsa == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key);
}
PQDSA_KEY *key = PQDSA_KEY_new();
if (key == NULL ||
!PQDSA_KEY_init(key, pqdsa) ||
!pqdsa->method->pqdsa_keygen(key->public_key, key->private_key, key->seed) ||
!EVP_PKEY_assign(pkey, EVP_PKEY_PQDSA, key)) {
PQDSA_KEY_free(key);
return 0;
}
return 1;
}
static int pkey_pqdsa_sign_generic(EVP_PKEY_CTX *ctx, uint8_t *sig,
size_t *sig_len, const uint8_t *message,
size_t message_len, int sign_digest) {
GUARD_PTR(sig_len);
PQDSA_PKEY_CTX *dctx = ctx->data;
const PQDSA *pqdsa = dctx->pqdsa;
if (pqdsa == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key);
}
// Caller is getting parameter values.
if (sig == NULL) {
*sig_len = pqdsa->signature_len;
return 1;
}
if (*sig_len != pqdsa->signature_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
// Check that the context is properly configured.
if (ctx->pkey == NULL ||
ctx->pkey->pkey.pqdsa_key == NULL ||
ctx->pkey->type != EVP_PKEY_PQDSA) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key;
if (!key || !key->private_key) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
// |sign_digest| is a flag we use to indicate that the message to be signed has
// already been pre-processed and hashed into a message digest.
// When the PQDSA algorithm is selected as ML-DSA (i.e., NID_MLDSA{44/65/87}),
// |sign_digest| indicates that the input is |mu| which is the result of a SHAKE256
// hash of the associated public key concatenated with a zero byte to indicate
// pure-mode, the context string length, the contents of the context string,
// and the input message in this order e.g.
// mu = SHAKE256(SHAKE256(pk) || 0 || |ctx| || ctx || M).
// RAW sign mode
if (!sign_digest) {
if (!pqdsa->method->pqdsa_sign_message(key->private_key, sig, sig_len, message, message_len, NULL, 0)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
}
// DIGEST sign mode
else {
if (!pqdsa->method->pqdsa_sign(key->private_key, sig, sig_len, message, message_len)) {
OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
}
return 1;
}
// DIGEST signing
static int pkey_pqdsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig,
size_t *sig_len, const uint8_t *digest,
size_t digest_len) {
return pkey_pqdsa_sign_generic(ctx, sig, sig_len, digest, digest_len, 1);
}
// RAW message signing
static int pkey_pqdsa_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig,
size_t *sig_len, const uint8_t *message,
size_t message_len) {
return pkey_pqdsa_sign_generic(ctx, sig, sig_len, message, message_len, 0);
}
static int pkey_pqdsa_verify_generic(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t sig_len, const uint8_t *message,
size_t message_len, int verify_digest) {
PQDSA_PKEY_CTX *dctx = ctx->data;
const PQDSA *pqdsa = dctx->pqdsa;
if (sig == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
if (pqdsa == NULL) {
if (ctx->pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
pqdsa = PQDSA_KEY_get0_dsa(ctx->pkey->pkey.pqdsa_key);
}
// Check that the context is properly configured.
if (ctx->pkey == NULL ||
ctx->pkey->pkey.pqdsa_key == NULL ||
ctx->pkey->type != EVP_PKEY_PQDSA) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
return 0;
}
PQDSA_KEY *key = ctx->pkey->pkey.pqdsa_key;
if (!key || !key->public_key) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
// |verify_digest| is a flag we use to indicate that the message to be verified has
// already been pre-processed and hashed into a message digest.
// When the PQDSA algorithm is selected as ML-DSA (i.e., NID_MLDSA{44/65/87}),
// |verify_digest| indicates that the input is |mu| which is the result of a SHAKE256
// hash of the associated public key concatenated with a zero byte to indicate
// pure-mode, the context string length, the contents of the context string,
// and the input message in this order e.g.
// mu = SHAKE256(SHAKE256(pk) || 0 || |ctx| || ctx || M).
// RAW verify mode
if(!verify_digest) {
if (sig_len != pqdsa->signature_len ||
!pqdsa->method->pqdsa_verify_message(key->public_key, sig, sig_len, message, message_len, NULL, 0)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
return 0;
}
}
// DIGEST verify mode
else {
if (sig_len != pqdsa->signature_len ||
!pqdsa->method->pqdsa_verify(key->public_key, sig, sig_len, message, message_len)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
return 0;
}
}
return 1;
}
// DIGEST verification
static int pkey_pqdsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t sig_len, const uint8_t *message,
size_t message_len) {
return pkey_pqdsa_verify_generic(ctx, sig, sig_len, message, message_len, 1);
}
// RAW message verification
static int pkey_pqdsa_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t sig_len, const uint8_t *message,
size_t message_len) {
return pkey_pqdsa_verify_generic(ctx, sig, sig_len, message, message_len, 0);
}
// Additional PQDSA specific EVP functions.
// This function sets pqdsa parameters defined by |nid| in |pkey|.
int EVP_PKEY_pqdsa_set_params(EVP_PKEY *pkey, int nid) {
const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid);
if (pqdsa == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
evp_pkey_set_method(pkey, &pqdsa_asn1_meth);
PQDSA_KEY *key = PQDSA_KEY_new();
if (key == NULL) {
// PQDSA_KEY_new sets the appropriate error.
return 0;
}
key->pqdsa = pqdsa;
pkey->pkey.pqdsa_key = key;
return 1;
}
// Takes an EVP_PKEY_CTX object |ctx| and sets pqdsa parameters defined
// by |nid|
int EVP_PKEY_CTX_pqdsa_set_params(EVP_PKEY_CTX *ctx, int nid) {
if (ctx == NULL || ctx->data == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// It's not allowed to change context parameters if
// a PKEY is already associated with the context.
if (ctx->pkey != NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
const PQDSA *pqdsa = PQDSA_find_dsa_by_nid(nid);
if (pqdsa == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
PQDSA_PKEY_CTX *dctx = ctx->data;
dctx->pqdsa = pqdsa;
return 1;
}
// Returns a fresh EVP_PKEY object of type EVP_PKEY_PQDSA,
// and sets PQDSA parameters defined by |nid|.
static EVP_PKEY *EVP_PKEY_pqdsa_new(int nid) {
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL || !EVP_PKEY_pqdsa_set_params(ret, nid)) {
EVP_PKEY_free(ret);
return NULL;
}
return ret;
}
EVP_PKEY *EVP_PKEY_pqdsa_new_raw_public_key(int nid, const uint8_t *in, size_t len) {
if (in == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_pqdsa_new(nid);
if (ret == NULL || ret->pkey.pqdsa_key == NULL) {
// EVP_PKEY_pqdsa_new sets the appropriate error.
goto err;
}
CBS cbs;
CBS_init(&cbs, in, len);
if (!PQDSA_KEY_set_raw_public_key(ret->pkey.pqdsa_key, &cbs)) {
// PQDSA_KEY_set_raw_public_key sets the appropriate error.
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
EVP_PKEY *EVP_PKEY_pqdsa_new_raw_private_key(int nid, const uint8_t *in, size_t len) {
if (in == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
EVP_PKEY *ret = EVP_PKEY_pqdsa_new(nid);
if (ret == NULL || ret->pkey.pqdsa_key == NULL) {
// EVP_PKEY_pqdsa_new sets the appropriate error.
goto err;
}
// Get PQDSA instance and validate lengths
const PQDSA *pqdsa = PQDSA_KEY_get0_dsa(ret->pkey.pqdsa_key);
if (len != pqdsa->private_key_len && len != pqdsa->keygen_seed_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
goto err;
}
CBS cbs;
CBS_init(&cbs, in, len);
// Set key based on input length
if (len == pqdsa->private_key_len) {
if (!PQDSA_KEY_set_raw_private_key(ret->pkey.pqdsa_key, &cbs)) {
// PQDSA_KEY_set_raw_private_key sets the appropriate error.
goto err;
}
} else if (len == pqdsa->keygen_seed_len) {
if (!PQDSA_KEY_set_raw_keypair_from_seed(ret->pkey.pqdsa_key, &cbs)) {
// PQDSA_KEY_set_raw_keypair_from_seed sets the appropriate error.
goto err;
}
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_pqdsa_pkey_meth) {
out->pkey_id = EVP_PKEY_PQDSA;
out->init = pkey_pqdsa_init;
out->copy = NULL;
out->cleanup = pkey_pqdsa_cleanup;
out->keygen = pkey_pqdsa_keygen;
out->sign_init = NULL;
out->sign = pkey_pqdsa_sign;
out->sign_message = pkey_pqdsa_sign_message;
out->verify_init = NULL;
out->verify = pkey_pqdsa_verify;
out->verify_message = pkey_pqdsa_verify_message;
out->verify_recover = NULL;
out->encrypt = NULL;
out->decrypt = NULL;
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = NULL;
out->ctrl_str = NULL;
out->keygen_deterministic = NULL;
out->encapsulate_deterministic = NULL;
out->encapsulate = NULL;
out->decapsulate = NULL;
}

View File

@@ -0,0 +1,896 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <limits.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rsa.h>
#include "internal.h"
#include "../rsa/internal.h"
#include "../../rsa_extra/internal.h"
#define NO_PSS_SALT_LEN_RESTRICTION -1
typedef struct {
// Key gen parameters
int nbits;
BIGNUM *pub_exp;
// RSA padding mode
int pad_mode;
// message digest
const EVP_MD *md;
// message digest for MGF1
const EVP_MD *mgf1md;
// PSS salt length
int saltlen;
// Minimum salt length or NO_PSS_SALT_LEN_RESTRICTION.
int min_saltlen;
// tbuf is a buffer which is either NULL, or is the size of the RSA modulus.
// It's used to store the output of RSA operations.
uint8_t *tbuf;
// OAEP label
uint8_t *oaep_label;
size_t oaep_labellen;
} RSA_PKEY_CTX;
typedef struct {
uint8_t *data;
size_t len;
} RSA_OAEP_LABEL_PARAMS;
static int pkey_ctx_is_pss(EVP_PKEY_CTX *ctx) {
return ctx->pmeth->pkey_id == EVP_PKEY_RSA_PSS;
}
// This method checks if the NID of |s_md| is the same as the NID of |k_md| when
// |pkey_ctx_is_pss(ctx)| is true and there is PSS restriction, which means
// |min_saltlen| != |NO_PSS_SALT_LEN_RESTRICTION|.
static int pss_hash_algorithm_match(EVP_PKEY_CTX *ctx, int min_saltlen,
const EVP_MD *k_md, const EVP_MD *s_md) {
if (pkey_ctx_is_pss(ctx) && min_saltlen != NO_PSS_SALT_LEN_RESTRICTION) {
if (k_md != NULL && s_md != NULL) {
return EVP_MD_type(k_md) == EVP_MD_type(s_md);
} else {
return 0;
}
}
return 1;
}
// Set PSS parameters when generating a key, if necessary.
static int rsa_set_pss_param(RSA *rsa, EVP_PKEY_CTX *ctx) {
if (!pkey_ctx_is_pss(ctx)) {
return 1;
}
RSA_PKEY_CTX *rctx = ctx->data;
return RSASSA_PSS_PARAMS_create(rctx->md, rctx->mgf1md, rctx->saltlen, &(rsa->pss));
}
// Called for PSS sign or verify initialisation: checks PSS parameter
// sanity and sets any restrictions on key usage.
static int pkey_pss_init(EVP_PKEY_CTX *ctx) {
RSA *rsa;
RSA_PKEY_CTX *rctx = ctx->data;
const EVP_MD *md = NULL;
const EVP_MD *mgf1md = NULL;
int min_saltlen, max_saltlen;
// Should never happen.
if (!pkey_ctx_is_pss(ctx)) {
return 0;
}
if (ctx->pkey == NULL) {
return 0;
}
rsa = ctx->pkey->pkey.rsa;
// If no restrictions just return.
if (rsa->pss == NULL) {
return 1;
}
// Get and check parameters.
if (!RSASSA_PSS_PARAMS_get(rsa->pss, &md, &mgf1md, &min_saltlen)) {
return 0;
}
// See if minimum salt length exceeds maximum possible.
// 8.1.1. Step1 https://tools.ietf.org/html/rfc8017#section-8.1.1
// 9.1.1. Step3 https://tools.ietf.org/html/rfc8017#section-9.1.1
max_saltlen = RSA_size(rsa) - EVP_MD_size(md) - 2;
if ((RSA_bits(rsa) & 0x7) == 1) {
max_saltlen--;
}
if (min_saltlen > max_saltlen) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALT_LEN);
return 0;
}
// Set PSS restrictions as defaults: we can then block any attempt to
// use invalid values in pkey_rsa_ctrl
rctx->md = md;
rctx->mgf1md = mgf1md;
rctx->saltlen = min_saltlen;
rctx->min_saltlen = min_saltlen;
return 1;
}
// |pkey_pss_init| was assigned to both the sign and verify operations
// of the |EVP_PKEY_RSA_PSS| methods. This created an unwanted assembler
// optimization for the gcc-8 FIPS static release build on Ubuntu x86_64.
// The gcc-8 assembler will attempt to optimize function pointers used in
// multiple places under a ".data.rel.ro.local" section, but "delocate.go"
// does not have the ability to handle ".data" sections. Splitting
// |pkey_pss_init| into two functions: |pkey_pss_init_sign| and
// |pkey_pss_init_verify|, gets around this undesired behaviour.
static int pkey_pss_init_sign(EVP_PKEY_CTX *ctx) {
return pkey_pss_init(ctx);
}
static int pkey_pss_init_verify(EVP_PKEY_CTX *ctx) {
return pkey_pss_init(ctx);
}
static int pkey_rsa_init(EVP_PKEY_CTX *ctx) {
RSA_PKEY_CTX *rctx;
rctx = OPENSSL_zalloc(sizeof(RSA_PKEY_CTX));
if (!rctx) {
return 0;
}
rctx->nbits = 2048;
if (pkey_ctx_is_pss(ctx)) {
rctx->pad_mode = RSA_PKCS1_PSS_PADDING;
} else {
rctx->pad_mode = RSA_PKCS1_PADDING;
}
rctx->saltlen = -2;
rctx->min_saltlen = NO_PSS_SALT_LEN_RESTRICTION;
ctx->data = rctx;
return 1;
}
static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
RSA_PKEY_CTX *dctx, *sctx;
if (!pkey_rsa_init(dst)) {
return 0;
}
sctx = src->data;
dctx = dst->data;
dctx->nbits = sctx->nbits;
if (sctx->pub_exp) {
dctx->pub_exp = BN_dup(sctx->pub_exp);
if (!dctx->pub_exp) {
return 0;
}
}
dctx->pad_mode = sctx->pad_mode;
dctx->md = sctx->md;
dctx->mgf1md = sctx->mgf1md;
dctx->saltlen = sctx->saltlen;
if (sctx->oaep_label) {
OPENSSL_free(dctx->oaep_label);
dctx->oaep_label = OPENSSL_memdup(sctx->oaep_label, sctx->oaep_labellen);
if (!dctx->oaep_label) {
return 0;
}
dctx->oaep_labellen = sctx->oaep_labellen;
}
return 1;
}
static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) {
RSA_PKEY_CTX *rctx = ctx->data;
if (rctx == NULL) {
return;
}
BN_free(rctx->pub_exp);
OPENSSL_free(rctx->tbuf);
OPENSSL_free(rctx->oaep_label);
OPENSSL_free(rctx);
}
static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) {
if (ctx->tbuf) {
return 1;
}
ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey));
if (!ctx->tbuf) {
return 0;
}
return 1;
}
static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
const uint8_t *tbs, size_t tbslen) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (!sig) {
*siglen = key_len;
return 1;
}
if (*siglen < key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (rctx->md) {
unsigned out_len;
switch (rctx->pad_mode) {
case RSA_PKCS1_PADDING:
if (!RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &out_len, rsa)) {
return 0;
}
*siglen = out_len;
return 1;
case RSA_PKCS1_PSS_PADDING:
return RSA_sign_pss_mgf1(rsa, siglen, sig, *siglen, tbs, tbslen,
rctx->md, rctx->mgf1md, rctx->saltlen);
default:
return 0;
}
}
return RSA_sign_raw(rsa, siglen, sig, *siglen, tbs, tbslen, rctx->pad_mode);
}
static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t siglen, const uint8_t *tbs,
size_t tbslen) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
if (rctx->md) {
switch (rctx->pad_mode) {
case RSA_PKCS1_PADDING:
return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa);
case RSA_PKCS1_PSS_PADDING:
return RSA_verify_pss_mgf1(rsa, tbs, tbslen, rctx->md, rctx->mgf1md,
rctx->saltlen, sig, siglen);
default:
return 0;
}
}
size_t rslen;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (!setup_tbuf(rctx, ctx) ||
!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen,
rctx->pad_mode) ||
rslen != tbslen ||
CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) {
return 0;
}
return 1;
}
static int pkey_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out,
size_t *out_len, const uint8_t *sig,
size_t sig_len) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (out == NULL) {
*out_len = key_len;
return 1;
}
if (*out_len < key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (rctx->md == NULL) {
return RSA_verify_raw(rsa, out_len, out, *out_len, sig, sig_len,
rctx->pad_mode);
}
if (rctx->pad_mode != RSA_PKCS1_PADDING) {
return 0;
}
// Assemble the encoded hash, using a placeholder hash value.
static const uint8_t kDummyHash[EVP_MAX_MD_SIZE] = {0};
const size_t hash_len = EVP_MD_size(rctx->md);
uint8_t *asn1_prefix;
size_t asn1_prefix_len;
int asn1_prefix_allocated;
if (!setup_tbuf(rctx, ctx) ||
!RSA_add_pkcs1_prefix(&asn1_prefix, &asn1_prefix_len,
&asn1_prefix_allocated, EVP_MD_type(rctx->md),
kDummyHash, hash_len)) {
return 0;
}
size_t rslen;
int ok = 1;
if (!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, sig_len,
RSA_PKCS1_PADDING) ||
rslen != asn1_prefix_len ||
// Compare all but the hash suffix.
CRYPTO_memcmp(rctx->tbuf, asn1_prefix, asn1_prefix_len - hash_len) != 0) {
ok = 0;
}
if (asn1_prefix_allocated) {
OPENSSL_free(asn1_prefix);
}
if (!ok) {
return 0;
}
if (out != NULL) {
OPENSSL_memcpy(out, rctx->tbuf + rslen - hash_len, hash_len);
}
*out_len = hash_len;
return 1;
}
static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (!out) {
*outlen = key_len;
return 1;
}
if (*outlen < key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
if (!setup_tbuf(rctx, ctx) ||
!RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, key_len, in, inlen,
rctx->oaep_label, rctx->oaep_labellen,
rctx->md, rctx->mgf1md) ||
!RSA_encrypt(rsa, outlen, out, *outlen, rctx->tbuf, key_len,
RSA_NO_PADDING)) {
return 0;
}
return 1;
}
return RSA_encrypt(rsa, outlen, out, *outlen, in, inlen, rctx->pad_mode);
}
static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out,
size_t *outlen, const uint8_t *in,
size_t inlen) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (!out) {
*outlen = key_len;
return 1;
}
if (*outlen < key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
size_t padded_len;
if (!setup_tbuf(rctx, ctx) ||
!RSA_decrypt(rsa, &padded_len, rctx->tbuf, key_len, in, inlen,
RSA_NO_PADDING) ||
!RSA_padding_check_PKCS1_OAEP_mgf1(
out, outlen, key_len, rctx->tbuf, padded_len, rctx->oaep_label,
rctx->oaep_labellen, rctx->md, rctx->mgf1md)) {
return 0;
}
return 1;
}
return RSA_decrypt(rsa, outlen, out, key_len, in, inlen, rctx->pad_mode);
}
static int check_padding_md(const EVP_MD *md, int padding) {
if (!md) {
return 1;
}
if (padding == RSA_NO_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
return 0;
}
return 1;
}
static int is_known_padding(int padding_mode) {
switch (padding_mode) {
case RSA_PKCS1_PADDING:
case RSA_NO_PADDING:
case RSA_PKCS1_OAEP_PADDING:
case RSA_PKCS1_PSS_PADDING:
return 1;
default:
return 0;
}
}
static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
RSA_PKEY_CTX *rctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_RSA_PADDING:
if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) ||
(p1 == RSA_PKCS1_PSS_PADDING &&
0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) ||
(p1 == RSA_PKCS1_OAEP_PADDING &&
0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
return 0;
}
if (p1 != RSA_PKCS1_PSS_PADDING && pkey_ctx_is_pss(ctx)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
return 0;
}
if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) &&
rctx->md == NULL) {
rctx->md = EVP_sha1();
}
rctx->pad_mode = p1;
return 1;
case EVP_PKEY_CTRL_GET_RSA_PADDING:
*(int *)p2 = rctx->pad_mode;
return 1;
case EVP_PKEY_CTRL_RSA_PSS_SALTLEN:
case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN:
if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN);
return 0;
}
if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) {
*(int *)p2 = rctx->saltlen;
} else {
// |p1| can be |-2|, |-1| and non-negative.
// The functions of these values are mentioned in the API doc of
// |EVP_PKEY_CTX_set_rsa_pss_saltlen| in |evp.h|.
// Accordingly, |-2| is the smallest value that |p1| can be.
if (p1 < -2) {
return 0;
}
int min_saltlen = rctx->min_saltlen;
if (min_saltlen != NO_PSS_SALT_LEN_RESTRICTION) {
// Check |min_saltlen| when |p1| is -1.
if ((p1 == RSA_PSS_SALTLEN_DIGEST &&
(size_t)min_saltlen > EVP_MD_size(rctx->md)) ||
// Check |min_saltlen| when |p1| is the value gives the size of
// the salt in bytes.
(p1 >= 0 && p1 < min_saltlen)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN);
return 0;
}
}
rctx->saltlen = p1;
}
return 1;
case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
if (p1 < 256) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS);
return 0;
}
rctx->nbits = p1;
return 1;
case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
if (!p2) {
return 0;
}
#if defined(AWSLC_FIPS)
if (BN_get_word(p2) != RSA_F4) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
#endif
BN_free(rctx->pub_exp);
rctx->pub_exp = p2;
return 1;
case EVP_PKEY_CTRL_RSA_OAEP_MD:
case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
return 0;
}
if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) {
*(const EVP_MD **)p2 = rctx->md;
} else {
rctx->md = p2;
}
return 1;
case EVP_PKEY_CTRL_MD:
if (!check_padding_md(p2, rctx->pad_mode)) {
return 0;
}
// Check if the hashAlgorithm is matched.
// Sec 3.3 https://tools.ietf.org/html/rfc4055#section-3.3
if (!pss_hash_algorithm_match(ctx, rctx->min_saltlen, rctx->md, p2)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_MD);
return 0;
}
rctx->md = p2;
return 1;
case EVP_PKEY_CTRL_GET_MD:
*(const EVP_MD **)p2 = rctx->md;
return 1;
case EVP_PKEY_CTRL_RSA_MGF1_MD:
case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING &&
rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD);
return 0;
}
if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
if (rctx->mgf1md) {
*(const EVP_MD **)p2 = rctx->mgf1md;
} else {
*(const EVP_MD **)p2 = rctx->md;
}
} else {
// Check if the hashAlgorithm is matched.
// Sec 3.3 https://tools.ietf.org/html/rfc4055#section-3.3
if (!pss_hash_algorithm_match(ctx, rctx->min_saltlen, rctx->mgf1md, p2)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD);
return 0;
}
rctx->mgf1md = p2;
}
return 1;
case EVP_PKEY_CTRL_RSA_OAEP_LABEL: {
if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
return 0;
}
OPENSSL_free(rctx->oaep_label);
RSA_OAEP_LABEL_PARAMS *params = p2;
rctx->oaep_label = params->data;
rctx->oaep_labellen = params->len;
return 1;
}
case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
return 0;
}
CBS_init((CBS *)p2, rctx->oaep_label, rctx->oaep_labellen);
return 1;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
int ret = 0;
RSA *rsa = NULL;
RSA_PKEY_CTX *rctx = ctx->data;
BN_GENCB *pkey_ctx_cb = NULL;
// In FIPS mode, the public exponent is set within |RSA_generate_key_fips|
if (!is_fips_build() && !rctx->pub_exp) {
rctx->pub_exp = BN_new();
if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4)) {
goto end;
}
}
rsa = RSA_new();
if (!rsa) {
goto end;
}
if (ctx->pkey_gencb) {
pkey_ctx_cb = BN_GENCB_new();
if (pkey_ctx_cb == NULL) {
goto end;
}
evp_pkey_set_cb_translate(pkey_ctx_cb, ctx);
}
// In FIPS build, |RSA_generate_key_fips| updates the service indicator so lock it here
FIPS_service_indicator_lock_state();
if ((!is_fips_build() &&
!RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, pkey_ctx_cb)) ||
(is_fips_build() &&
!RSA_generate_key_fips(rsa, rctx->nbits, pkey_ctx_cb)) ||
!rsa_set_pss_param(rsa, ctx)) {
FIPS_service_indicator_unlock_state();
goto end;
}
FIPS_service_indicator_unlock_state();
if (pkey_ctx_is_pss(ctx)) {
ret = EVP_PKEY_assign(pkey, EVP_PKEY_RSA_PSS, rsa);
} else {
ret = EVP_PKEY_assign_RSA(pkey, rsa);
}
end:
BN_GENCB_free(pkey_ctx_cb);
if (!ret && rsa) {
RSA_free(rsa);
}
return ret;
}
static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (value == NULL) {
OPENSSL_PUT_ERROR(EVP, RSA_R_VALUE_MISSING);
return 0;
}
if (strcmp(type, "rsa_padding_mode") == 0) {
// "sslv23" and "x931" are not supported
int pm;
if (strcmp(value, "pkcs1") == 0) {
pm = RSA_PKCS1_PADDING;
} else if (strcmp(value, "none") == 0) {
pm = RSA_NO_PADDING;
// OpenSSL also supports the typo.
} else if (strcmp(value, "oeap") == 0) {
pm = RSA_PKCS1_OAEP_PADDING;
} else if (strcmp(value, "oaep") == 0) {
pm = RSA_PKCS1_OAEP_PADDING;
} else if (strcmp(value, "pss") == 0) {
pm = RSA_PKCS1_PSS_PADDING;
} else {
OPENSSL_PUT_ERROR(EVP, RSA_R_UNKNOWN_PADDING_TYPE);
return -2;
}
return EVP_PKEY_CTX_set_rsa_padding(ctx, pm);
}
if (strcmp(type, "rsa_pss_saltlen") == 0) {
// "max" and "auto" are not supported
long saltlen;
// A value of "digest" or "-1" causes the salt to be the same length as the
// digest in the signature
if (!strcmp(value, "digest") || !strcmp(value, "-1")) {
saltlen = RSA_PSS_SALTLEN_DIGEST;
} else {
char* str_end;
saltlen = strtol(value, &str_end, 10);
if(str_end == value || saltlen < 0 || saltlen > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, RSA_R_INTERNAL_ERROR);
return -2;
}
}
return EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, (int)saltlen);
}
if (strcmp(type, "rsa_keygen_bits") == 0) {
char* str_end;
long nbits = strtol(value, &str_end, 10);
if (str_end == value || nbits <= 0 || nbits > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, RSA_R_INTERNAL_ERROR);
return -2;
}
return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)nbits);
}
if (strcmp(type, "rsa_keygen_pubexp") == 0) {
int ret;
BIGNUM *pubexp = NULL;
if (!BN_asc2bn(&pubexp, value)) {
return -2;
}
ret = EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp);
if (ret <= 0) {
BN_free(pubexp);
}
return ret;
}
if (strcmp(type, "rsa_mgf1_md") == 0) {
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_RSA_MGF1_MD, value);
OPENSSL_END_ALLOW_DEPRECATED
}
// rsa_pss_keygen_XXX options are not supported
if (strcmp(type, "rsa_oaep_md") == 0) {
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_RSA_OAEP_MD, value);
OPENSSL_END_ALLOW_DEPRECATED
}
if (strcmp(type, "rsa_oaep_label") == 0) {
size_t lablen = 0;
uint8_t *lab = OPENSSL_hexstr2buf(value, &lablen);
if (lab == NULL) {
return 0;
}
int ret = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, lab, lablen);
if (ret <= 0) {
OPENSSL_free(lab);
}
return ret;
}
return -2;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pkey_meth) {
out->pkey_id = EVP_PKEY_RSA;
out->init = pkey_rsa_init;
out->copy = pkey_rsa_copy;
out->cleanup = pkey_rsa_cleanup;
out->keygen = pkey_rsa_keygen;
out->sign_init = NULL; /* sign_init */
out->sign = pkey_rsa_sign;
out->sign_message = NULL; /* sign_message */
out->verify_init = NULL; /* verify_init */
out->verify = pkey_rsa_verify;
out->verify_message = NULL; /* verify_message */
out->verify_recover = pkey_rsa_verify_recover; /* verify_recover */
out->encrypt = pkey_rsa_encrypt; /* encrypt */
out->decrypt = pkey_rsa_decrypt; /* decrypt */
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = pkey_rsa_ctrl;
out->ctrl_str = pkey_rsa_ctrl_str;
}
DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_rsa_pss_pkey_meth) {
out->pkey_id = EVP_PKEY_RSA_PSS;
out->init = pkey_rsa_init;
out->copy = pkey_rsa_copy;
out->cleanup = pkey_rsa_cleanup;
out->keygen = pkey_rsa_keygen;
out->sign_init = pkey_pss_init_sign; /* sign_init */
out->sign = pkey_rsa_sign;
out->sign_message = NULL; /* sign_message */
out->verify_init = pkey_pss_init_verify; /* verify_init */
out->verify = pkey_rsa_verify;
out->verify_message = NULL; /* verify_message */
out->verify_recover = NULL; /* verify_recover */
out->encrypt = NULL; /* encrypt */
out->decrypt = NULL; /* decrypt */
out->derive = NULL;
out->paramgen = NULL;
out->ctrl = pkey_rsa_ctrl;
out->ctrl_str = pkey_rsa_ctrl_str;
}
int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2) {
/* If key type is not RSA or RSA-PSS return error */
if ((ctx != NULL) && (ctx->pmeth != NULL)
&& (ctx->pmeth->pkey_id != EVP_PKEY_RSA)
&& (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
return EVP_PKEY_CTX_ctrl(ctx, -1, optype, cmd, p1, p2);
}
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) {
return EVP_RSA_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, padding, NULL);
}
int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) {
return EVP_RSA_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, out_padding);
}
int EVP_PKEY_CTX_set_rsa_pss_keygen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
return 0;
}
int EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(EVP_PKEY_CTX *ctx, int salt_len) {
return 0;
}
int EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(EVP_PKEY_CTX *ctx,
const EVP_MD *md) {
return 0;
}
int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) {
return EVP_RSA_PKEY_CTX_ctrl(ctx,
(EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL);
}
int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) {
return EVP_RSA_PKEY_CTX_ctrl(ctx,
(EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len);
}
int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) {
return EVP_RSA_PKEY_CTX_ctrl(ctx, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL);
}
int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) {
return EVP_RSA_PKEY_CTX_ctrl(ctx, EVP_PKEY_OP_KEYGEN,
EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e);
}
int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md);
}
int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md);
}
int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
return EVP_RSA_PKEY_CTX_ctrl(ctx,
EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md);
}
int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
return EVP_RSA_PKEY_CTX_ctrl(ctx,
EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md);
}
int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, uint8_t *label,
size_t label_len) {
RSA_OAEP_LABEL_PARAMS params = {label, label_len};
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_RSA_OAEP_LABEL, 0, &params);
}
int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
const uint8_t **out_label) {
CBS label;
if (!EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, &label)) {
return -1;
}
if (CBS_len(&label) > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
return -1;
}
*out_label = CBS_data(&label);
return (int)CBS_len(&label);
}