singe/thirdparty/openssl/oqs-provider/oqsprov/oqs_sig.c
2023-11-16 22:15:24 -06:00

807 lines
28 KiB
C

// SPDX-License-Identifier: Apache-2.0 AND MIT
/*
* OQS OpenSSL 3 provider
*
* Code strongly inspired by OpenSSL DSA signature provider.
*
*/
#include "oqs/sig.h"
#include <string.h>
#include <openssl/asn1.h>
#include <openssl/crypto.h>
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
#include <openssl/params.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include "oqs_prov.h"
// TBD: Review what we really need/want: For now go with OSSL settings:
#define OSSL_MAX_NAME_SIZE 50
#define OSSL_MAX_PROPQUERY_SIZE 256 /* Property query strings */
#ifdef NDEBUG
#define OQS_SIG_PRINTF(a)
#define OQS_SIG_PRINTF2(a, b)
#define OQS_SIG_PRINTF3(a, b, c)
#else
#define OQS_SIG_PRINTF(a) if (getenv("OQSSIG")) printf(a)
#define OQS_SIG_PRINTF2(a, b) if (getenv("OQSSIG")) printf(a, b)
#define OQS_SIG_PRINTF3(a, b, c) if (getenv("OQSSIG")) printf(a, b, c)
#endif // NDEBUG
static OSSL_FUNC_signature_newctx_fn oqs_sig_newctx;
static OSSL_FUNC_signature_sign_init_fn oqs_sig_sign_init;
static OSSL_FUNC_signature_verify_init_fn oqs_sig_verify_init;
static OSSL_FUNC_signature_sign_fn oqs_sig_sign;
static OSSL_FUNC_signature_verify_fn oqs_sig_verify;
static OSSL_FUNC_signature_digest_sign_init_fn oqs_sig_digest_sign_init;
static OSSL_FUNC_signature_digest_sign_update_fn oqs_sig_digest_signverify_update;
static OSSL_FUNC_signature_digest_sign_final_fn oqs_sig_digest_sign_final;
static OSSL_FUNC_signature_digest_verify_init_fn oqs_sig_digest_verify_init;
static OSSL_FUNC_signature_digest_verify_update_fn oqs_sig_digest_signverify_update;
static OSSL_FUNC_signature_digest_verify_final_fn oqs_sig_digest_verify_final;
static OSSL_FUNC_signature_freectx_fn oqs_sig_freectx;
static OSSL_FUNC_signature_dupctx_fn oqs_sig_dupctx;
static OSSL_FUNC_signature_get_ctx_params_fn oqs_sig_get_ctx_params;
static OSSL_FUNC_signature_gettable_ctx_params_fn oqs_sig_gettable_ctx_params;
static OSSL_FUNC_signature_set_ctx_params_fn oqs_sig_set_ctx_params;
static OSSL_FUNC_signature_settable_ctx_params_fn oqs_sig_settable_ctx_params;
static OSSL_FUNC_signature_get_ctx_md_params_fn oqs_sig_get_ctx_md_params;
static OSSL_FUNC_signature_gettable_ctx_md_params_fn oqs_sig_gettable_ctx_md_params;
static OSSL_FUNC_signature_set_ctx_md_params_fn oqs_sig_set_ctx_md_params;
static OSSL_FUNC_signature_settable_ctx_md_params_fn oqs_sig_settable_ctx_md_params;
// OIDS:
static int get_aid(unsigned char** oidbuf, const char *tls_name) {
X509_ALGOR *algor = X509_ALGOR_new();
int aidlen = 0;
X509_ALGOR_set0(algor, OBJ_txt2obj(tls_name, 0), V_ASN1_UNDEF, NULL);
aidlen = i2d_X509_ALGOR(algor, oidbuf);
X509_ALGOR_free(algor);
return(aidlen);
}
/*
* What's passed as an actual key is defined by the KEYMGMT interface.
*/
typedef struct {
OSSL_LIB_CTX *libctx;
char *propq;
OQSX_KEY *sig;
/*
* Flag to determine if the hash function can be changed (1) or not (0)
* Because it's dangerous to change during a DigestSign or DigestVerify
* operation, this flag is cleared by their Init function, and set again
* by their Final function.
*/
unsigned int flag_allow_md : 1;
char mdname[OSSL_MAX_NAME_SIZE];
/* The Algorithm Identifier of the combined signature algorithm */
unsigned char *aid;
size_t aid_len;
/* main digest */
EVP_MD *md;
EVP_MD_CTX *mdctx;
size_t mdsize;
// for collecting data if no MD is active:
unsigned char* mddata;
int operation;
} PROV_OQSSIG_CTX;
static void *oqs_sig_newctx(void *provctx, const char *propq)
{
PROV_OQSSIG_CTX *poqs_sigctx;
OQS_SIG_PRINTF2("OQS SIG provider: newctx called with propq %s\n", propq);
poqs_sigctx = OPENSSL_zalloc(sizeof(PROV_OQSSIG_CTX));
if (poqs_sigctx == NULL)
return NULL;
poqs_sigctx->libctx = ((PROV_OQS_CTX*)provctx)->libctx;
if (propq != NULL && (poqs_sigctx->propq = OPENSSL_strdup(propq)) == NULL) {
OPENSSL_free(poqs_sigctx);
poqs_sigctx = NULL;
ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE);
}
return poqs_sigctx;
}
static int oqs_sig_setup_md(PROV_OQSSIG_CTX *ctx,
const char *mdname, const char *mdprops)
{
OQS_SIG_PRINTF3("OQS SIG provider: setup_md called for MD %s (alg %s)\n", mdname, ctx->sig->tls_name);
if (mdprops == NULL)
mdprops = ctx->propq;
if (mdname != NULL) {
EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
if ((md == NULL)||(EVP_MD_nid(md)==NID_undef)) {
if (md == NULL)
ERR_raise_data(ERR_LIB_USER, OQSPROV_R_INVALID_DIGEST,
"%s could not be fetched", mdname);
EVP_MD_free(md);
return 0;
}
EVP_MD_CTX_free(ctx->mdctx);
ctx->mdctx = NULL;
EVP_MD_free(ctx->md);
ctx->md = NULL;
if (ctx->aid)
OPENSSL_free(ctx->aid);
ctx->aid = NULL; // ensure next function allocates memory
ctx->aid_len = get_aid(&(ctx->aid), ctx->sig->tls_name);
ctx->md = md;
OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
}
return 1;
}
static int oqs_sig_signverify_init(void *vpoqs_sigctx, void *voqssig, int operation)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: signverify_init called\n");
if ( poqs_sigctx == NULL
|| voqssig == NULL
|| !oqsx_key_up_ref(voqssig))
return 0;
oqsx_key_free(poqs_sigctx->sig);
poqs_sigctx->sig = voqssig;
poqs_sigctx->operation = operation;
poqs_sigctx->flag_allow_md = 1; /* change permitted until first use */
if ( (operation==EVP_PKEY_OP_SIGN && !poqs_sigctx->sig->privkey) ||
(operation==EVP_PKEY_OP_VERIFY && !poqs_sigctx->sig->pubkey)) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_KEY);
return 0;
}
return 1;
}
static int oqs_sig_sign_init(void *vpoqs_sigctx, void *voqssig, const OSSL_PARAM params[])
{
OQS_SIG_PRINTF("OQS SIG provider: sign_init called\n");
return oqs_sig_signverify_init(vpoqs_sigctx, voqssig, EVP_PKEY_OP_SIGN);
}
static int oqs_sig_verify_init(void *vpoqs_sigctx, void *voqssig, const OSSL_PARAM params[])
{
OQS_SIG_PRINTF("OQS SIG provider: verify_init called\n");
return oqs_sig_signverify_init(vpoqs_sigctx, voqssig, EVP_PKEY_OP_VERIFY);
}
/* On entry to this function, data to be signed (tbs) might have been hashed already:
* this would be the case if poqs_sigctx->mdctx != NULL; if that is NULL, we have to hash
* in case of hybrid signatures
*/
static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen,
size_t sigsize, const unsigned char *tbs, size_t tbslen)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQSX_KEY* oqsxkey = poqs_sigctx->sig;
OQS_SIG* oqs_key = poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig;
EVP_PKEY* evpkey = oqsxkey->classical_pkey; // if this value is not NULL, we're running hybrid
EVP_PKEY_CTX *classical_ctx_sign = NULL;
OQS_SIG_PRINTF2("OQS SIG provider: sign called for %ld bytes\n", tbslen);
int is_hybrid = evpkey!=NULL;
size_t max_sig_len = oqs_key->length_signature;
size_t classical_sig_len = 0, oqs_sig_len = 0;
size_t actual_classical_sig_len = 0;
size_t index = 0;
int rv = 0;
if (!oqsxkey || !oqs_key || !oqsxkey->privkey) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_NO_PRIVATE_KEY);
return rv;
}
if (is_hybrid) {
actual_classical_sig_len = oqsxkey->evp_info->length_signature;
max_sig_len += (SIZE_OF_UINT32 + actual_classical_sig_len);
}
if (sig == NULL) {
*siglen = max_sig_len;
OQS_SIG_PRINTF2("OQS SIG provider: sign test returning size %ld\n", *siglen);
return 1;
}
if (*siglen < max_sig_len) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_BUFFER_LENGTH_WRONG);
return rv;
}
if (is_hybrid) {
if ((classical_ctx_sign = EVP_PKEY_CTX_new(evpkey, NULL)) == NULL ||
EVP_PKEY_sign_init(classical_ctx_sign) <= 0) {
ERR_raise(ERR_LIB_USER, ERR_R_FATAL);
goto endsign;
}
if (oqsxkey->evp_info->keytype == EVP_PKEY_RSA) {
if (EVP_PKEY_CTX_set_rsa_padding(classical_ctx_sign, RSA_PKCS1_PADDING) <= 0) {
ERR_raise(ERR_LIB_USER, ERR_R_FATAL);
goto endsign;
}
}
/* unconditionally hash to be in line with oqs-openssl111:
* uncomment the following line if using pre-performed hash:
* if (poqs_sigctx->mdctx == NULL) { // hashing not yet done
*/
const EVP_MD *classical_md;
int digest_len;
unsigned char digest[SHA512_DIGEST_LENGTH]; /* init with max length */
/* classical schemes can't sign arbitrarily large data; we hash it first */
switch (oqs_key->claimed_nist_level) {
case 1:
classical_md = EVP_sha256();
digest_len = SHA256_DIGEST_LENGTH;
SHA256(tbs, tbslen, (unsigned char*) &digest);
break;
case 2:
case 3:
classical_md = EVP_sha384();
digest_len = SHA384_DIGEST_LENGTH;
SHA384(tbs, tbslen, (unsigned char*) &digest);
break;
case 4:
case 5:
default:
classical_md = EVP_sha512();
digest_len = SHA512_DIGEST_LENGTH;
SHA512(tbs, tbslen, (unsigned char*) &digest);
break;
}
if ((EVP_PKEY_CTX_set_signature_md(classical_ctx_sign, classical_md) <= 0) ||
(EVP_PKEY_sign(classical_ctx_sign, sig + SIZE_OF_UINT32, &actual_classical_sig_len, digest, digest_len) <= 0)) {
ERR_raise(ERR_LIB_USER, ERR_R_FATAL);
goto endsign;
}
/* activate in case we want to use pre-performed hashes:
* }
* else { // hashing done before; just sign:
* if (EVP_PKEY_sign(classical_ctx_sign, sig + SIZE_OF_UINT32, &actual_classical_sig_len, tbs, tbslen) <= 0) {
* ERR_raise(ERR_LIB_USER, OQSPROV_R_SIGNING_FAILED);
* goto endsign;
* }
* }
*/
if (actual_classical_sig_len > oqsxkey->evp_info->length_signature) {
/* sig is bigger than expected */
ERR_raise(ERR_LIB_USER, OQSPROV_R_BUFFER_LENGTH_WRONG);
goto endsign;
}
ENCODE_UINT32(sig, actual_classical_sig_len);
classical_sig_len = SIZE_OF_UINT32 + actual_classical_sig_len;
index += classical_sig_len;
}
if (OQS_SIG_sign(oqs_key, sig + index, &oqs_sig_len, tbs, tbslen, oqsxkey->comp_privkey[oqsxkey->numkeys-1]) != OQS_SUCCESS) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_SIGNING_FAILED);
goto endsign;
}
*siglen = classical_sig_len + oqs_sig_len;
OQS_SIG_PRINTF2("OQS SIG provider: signing completes with size %ld\n", *siglen);
rv = 1; /* success */
endsign:
if (classical_ctx_sign) {
EVP_PKEY_CTX_free(classical_ctx_sign);
}
return rv;
}
static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, size_t siglen,
const unsigned char *tbs, size_t tbslen)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQSX_KEY* oqsxkey = poqs_sigctx->sig;
OQS_SIG* oqs_key = poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig;
EVP_PKEY* evpkey = oqsxkey->classical_pkey; // if this value is not NULL, we're running hybrid
EVP_PKEY_CTX *classical_ctx_sign = NULL;
EVP_PKEY_CTX *ctx_verify = NULL;
int is_hybrid = evpkey!=NULL;
size_t classical_sig_len = 0;
size_t index = 0;
int rv = 0;
OQS_SIG_PRINTF3("OQS SIG provider: verify called with siglen %ld bytes and tbslen %ld\n", siglen, tbslen);
if (!oqsxkey || !oqs_key || !oqsxkey->pubkey || sig == NULL || (tbs == NULL && tbslen > 0)) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_WRONG_PARAMETERS);
goto endverify;
}
if (is_hybrid) {
const EVP_MD *classical_md;
size_t actual_classical_sig_len = 0;
int digest_len;
unsigned char digest[SHA512_DIGEST_LENGTH]; /* init with max length */
if ((ctx_verify = EVP_PKEY_CTX_new(oqsxkey->classical_pkey, NULL)) == NULL ||
EVP_PKEY_verify_init(ctx_verify) <= 0) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR);
goto endverify;
}
if (oqsxkey->evp_info->keytype == EVP_PKEY_RSA) {
if (EVP_PKEY_CTX_set_rsa_padding(ctx_verify, RSA_PKCS1_PADDING) <= 0) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_WRONG_PARAMETERS);
goto endverify;
}
}
DECODE_UINT32(actual_classical_sig_len, sig);
/* same as with sign: activate if pre-existing hashing to be used:
* if (poqs_sigctx->mdctx == NULL) { // hashing not yet done
*/
switch (oqs_key->claimed_nist_level) {
case 1:
classical_md = EVP_sha256();
digest_len = SHA256_DIGEST_LENGTH;
SHA256(tbs, tbslen, (unsigned char*) &digest);
break;
case 2:
case 3:
classical_md = EVP_sha384();
digest_len = SHA384_DIGEST_LENGTH;
SHA384(tbs, tbslen, (unsigned char*) &digest);
break;
case 4:
case 5:
default:
classical_md = EVP_sha512();
digest_len = SHA512_DIGEST_LENGTH;
SHA512(tbs, tbslen, (unsigned char*) &digest);
break;
}
if ((EVP_PKEY_CTX_set_signature_md(ctx_verify, classical_md) <= 0) ||
(EVP_PKEY_verify(ctx_verify, sig + SIZE_OF_UINT32, actual_classical_sig_len, digest, digest_len) <= 0)) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR);
goto endverify;
}
else {
OQS_SIG_PRINTF("OQS SIG: classic verification OK\n");
}
/* activate for using pre-existing digest:
* }
* else { // hashing already done:
* if (EVP_PKEY_verify(ctx_verify, sig + SIZE_OF_UINT32, actual_classical_sig_len, tbs, tbslen) <= 0) {
* ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR);
* goto endverify;
* }
* }
*/
classical_sig_len = SIZE_OF_UINT32 + actual_classical_sig_len;
index += classical_sig_len;
}
if (!oqsxkey->comp_pubkey[oqsxkey->numkeys-1]) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_WRONG_PARAMETERS);
goto endverify;
}
if (OQS_SIG_verify(oqs_key, tbs, tbslen, sig + index, siglen - classical_sig_len, oqsxkey->comp_pubkey[oqsxkey->numkeys-1]) != OQS_SUCCESS) {
ERR_raise(ERR_LIB_USER, OQSPROV_R_VERIFY_ERROR);
goto endverify;
}
rv = 1;
endverify:
if (ctx_verify) {
EVP_PKEY_CTX_free(ctx_verify);
}
OQS_SIG_PRINTF2("OQS SIG provider: verify rv = %d\n", rv);
return rv;
}
static int oqs_sig_digest_signverify_init(void *vpoqs_sigctx, const char *mdname,
void *voqssig, int operation)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF2("OQS SIG provider: digest_signverify_init called for mdname %s\n", mdname);
poqs_sigctx->flag_allow_md = 1; /* permitted until first use */
if (!oqs_sig_signverify_init(vpoqs_sigctx, voqssig, operation))
return 0;
if (!oqs_sig_setup_md(poqs_sigctx, mdname, NULL))
return 0;
if (mdname != NULL) {
poqs_sigctx->mdctx = EVP_MD_CTX_new();
if (poqs_sigctx->mdctx == NULL)
goto error;
if (!EVP_DigestInit_ex(poqs_sigctx->mdctx, poqs_sigctx->md, NULL))
goto error;
}
return 1;
error:
EVP_MD_CTX_free(poqs_sigctx->mdctx);
EVP_MD_free(poqs_sigctx->md);
poqs_sigctx->mdctx = NULL;
poqs_sigctx->md = NULL;
OQS_SIG_PRINTF(" OQS SIG provider: digest_signverify FAILED\n");
return 0;
}
static int oqs_sig_digest_sign_init(void *vpoqs_sigctx, const char *mdname,
void *voqssig, const OSSL_PARAM params[])
{
OQS_SIG_PRINTF("OQS SIG provider: digest_sign_init called\n");
return oqs_sig_digest_signverify_init(vpoqs_sigctx, mdname, voqssig, EVP_PKEY_OP_SIGN);
}
static int oqs_sig_digest_verify_init(void *vpoqs_sigctx, const char *mdname, void *voqssig, const OSSL_PARAM params[])
{
OQS_SIG_PRINTF("OQS SIG provider: sig_digest_verify called\n");
return oqs_sig_digest_signverify_init(vpoqs_sigctx, mdname, voqssig, EVP_PKEY_OP_VERIFY);
}
int oqs_sig_digest_signverify_update(void *vpoqs_sigctx, const unsigned char *data,
size_t datalen)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: digest_signverify_update called\n");
if (poqs_sigctx == NULL)
return 0;
// disallow MD changes after update has been called at least once
poqs_sigctx->flag_allow_md = 0;
if (poqs_sigctx->mdctx)
return EVP_DigestUpdate(poqs_sigctx->mdctx, data, datalen);
else {
// unconditionally collect data for passing in full to OQS API
if (poqs_sigctx->mddata) {
unsigned char* newdata = OPENSSL_realloc(poqs_sigctx->mddata, poqs_sigctx->mdsize+datalen);
if (newdata == NULL) return 0;
memcpy(newdata+poqs_sigctx->mdsize, data, datalen);
poqs_sigctx->mddata = newdata;
poqs_sigctx->mdsize += datalen;
}
else { // simple alloc and copy
poqs_sigctx->mddata = OPENSSL_malloc(datalen);
if (poqs_sigctx->mddata == NULL) return 0;
poqs_sigctx->mdsize=datalen;
memcpy(poqs_sigctx->mddata, data, poqs_sigctx->mdsize);
}
OQS_SIG_PRINTF2("OQS SIG provider: digest_signverify_update collected %ld bytes...\n", poqs_sigctx->mdsize);
}
return 1;
}
int oqs_sig_digest_sign_final(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen,
size_t sigsize)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dlen = 0;
OQS_SIG_PRINTF("OQS SIG provider: digest_sign_final called\n");
if (poqs_sigctx == NULL)
return 0;
/*
* If sig is NULL then we're just finding out the sig size. Other fields
* are ignored. Defer to oqs_sig_sign.
*/
if (sig != NULL) {
/*
* TODO(3.0): There is the possibility that some externally provided
* digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
* but that problem is much larger than just here.
*/
if (poqs_sigctx->mdctx != NULL)
if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen))
return 0;
}
poqs_sigctx->flag_allow_md = 1;
if (poqs_sigctx->mdctx != NULL)
return oqs_sig_sign(vpoqs_sigctx, sig, siglen, sigsize, digest, (size_t)dlen);
else
return oqs_sig_sign(vpoqs_sigctx, sig, siglen, sigsize, poqs_sigctx->mddata, poqs_sigctx->mdsize);
}
int oqs_sig_digest_verify_final(void *vpoqs_sigctx, const unsigned char *sig,
size_t siglen)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dlen = 0;
OQS_SIG_PRINTF("OQS SIG provider: digest_verify_final called\n");
if (poqs_sigctx == NULL)
return 0;
// TBC for hybrids:
if (poqs_sigctx->mdctx) {
if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen))
return 0;
poqs_sigctx->flag_allow_md = 1;
return oqs_sig_verify(vpoqs_sigctx, sig, siglen, digest, (size_t)dlen);
}
else
return oqs_sig_verify(vpoqs_sigctx, sig, siglen, poqs_sigctx->mddata, poqs_sigctx->mdsize);
}
static void oqs_sig_freectx(void *vpoqs_sigctx)
{
PROV_OQSSIG_CTX *ctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: freectx called\n");
OPENSSL_free(ctx->propq);
EVP_MD_CTX_free(ctx->mdctx);
EVP_MD_free(ctx->md);
ctx->propq = NULL;
ctx->mdctx = NULL;
ctx->md = NULL;
oqsx_key_free(ctx->sig);
OPENSSL_free(ctx->mddata);
ctx->mddata = NULL;
ctx->mdsize = 0;
OPENSSL_free(ctx->aid);
ctx->aid = NULL;
ctx->aid_len = 0;
OPENSSL_free(ctx);
}
static void *oqs_sig_dupctx(void *vpoqs_sigctx)
{
PROV_OQSSIG_CTX *srcctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
PROV_OQSSIG_CTX *dstctx;
OQS_SIG_PRINTF("OQS SIG provider: dupctx called\n");
dstctx = OPENSSL_zalloc(sizeof(*srcctx));
if (dstctx == NULL)
return NULL;
*dstctx = *srcctx;
dstctx->sig = NULL;
dstctx->md = NULL;
dstctx->mdctx = NULL;
if (srcctx->sig != NULL && !oqsx_key_up_ref(srcctx->sig))
goto err;
dstctx->sig = srcctx->sig;
if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
goto err;
dstctx->md = srcctx->md;
if (srcctx->mdctx != NULL) {
dstctx->mdctx = EVP_MD_CTX_new();
if (dstctx->mdctx == NULL
|| !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
goto err;
}
if (srcctx->mddata) {
dstctx->mddata=OPENSSL_memdup(srcctx->mddata, srcctx->mdsize);
if (dstctx->mddata == NULL)
goto err;
dstctx->mdsize = srcctx->mdsize;
}
if (srcctx->aid) {
dstctx->aid = OPENSSL_memdup(srcctx->aid, srcctx->aid_len);
if (dstctx->aid == NULL)
goto err;
dstctx->aid_len = srcctx->aid_len;
}
if (srcctx->propq) {
dstctx->propq = OPENSSL_strdup(srcctx->propq);
if (dstctx->propq == NULL)
goto err;
}
return dstctx;
err:
oqs_sig_freectx(dstctx);
return NULL;
}
static int oqs_sig_get_ctx_params(void *vpoqs_sigctx, OSSL_PARAM *params)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OSSL_PARAM *p;
OQS_SIG_PRINTF("OQS SIG provider: get_ctx_params called\n");
if (poqs_sigctx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
if (poqs_sigctx->aid == NULL) {
poqs_sigctx->aid_len = get_aid(&(poqs_sigctx->aid), poqs_sigctx->sig->tls_name);
}
if (p != NULL
&& !OSSL_PARAM_set_octet_string(p, poqs_sigctx->aid, poqs_sigctx->aid_len))
return 0;
p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
if (p != NULL && !OSSL_PARAM_set_utf8_string(p, poqs_sigctx->mdname))
return 0;
return 1;
}
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *oqs_sig_gettable_ctx_params(ossl_unused void *vpoqs_sigctx, ossl_unused void *vctx)
{
OQS_SIG_PRINTF("OQS SIG provider: gettable_ctx_params called\n");
return known_gettable_ctx_params;
}
static int oqs_sig_set_ctx_params(void *vpoqs_sigctx, const OSSL_PARAM params[])
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
const OSSL_PARAM *p;
OQS_SIG_PRINTF("OQS SIG provider: set_ctx_params called\n");
if (poqs_sigctx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
/* Not allowed during certain operations */
if (p != NULL && !poqs_sigctx->flag_allow_md)
return 0;
if (p != NULL) {
char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
const OSSL_PARAM *propsp =
OSSL_PARAM_locate_const(params,
OSSL_SIGNATURE_PARAM_PROPERTIES);
if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
return 0;
if (propsp != NULL
&& !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
return 0;
if (!oqs_sig_setup_md(poqs_sigctx, mdname, mdprops))
return 0;
}
return 1;
}
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *oqs_sig_settable_ctx_params(ossl_unused void *vpsm2ctx,
ossl_unused void *provctx)
{
/*
* TODO(3.0): Should this function return a different set of settable ctx
* params if the ctx is being used for a DigestSign/DigestVerify? In that
* case it is not allowed to set the digest size/digest name because the
* digest is explicitly set as part of the init.
* NOTE: Ideally we would check poqs_sigctx->flag_allow_md, but this is
* problematic because there is no nice way of passing the
* PROV_OQSSIG_CTX down to this function...
* Because we have API's that dont know about their parent..
* e.g: EVP_SIGNATURE_gettable_ctx_params(const EVP_SIGNATURE *sig).
* We could pass NULL for that case (but then how useful is the check?).
*/
OQS_SIG_PRINTF("OQS SIG provider: settable_ctx_params called\n");
return known_settable_ctx_params;
}
static int oqs_sig_get_ctx_md_params(void *vpoqs_sigctx, OSSL_PARAM *params)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: get_ctx_md_params called\n");
if (poqs_sigctx->mdctx == NULL)
return 0;
return EVP_MD_CTX_get_params(poqs_sigctx->mdctx, params);
}
static const OSSL_PARAM *oqs_sig_gettable_ctx_md_params(void *vpoqs_sigctx)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: gettable_ctx_md_params called\n");
if (poqs_sigctx->md == NULL)
return 0;
return EVP_MD_gettable_ctx_params(poqs_sigctx->md);
}
static int oqs_sig_set_ctx_md_params(void *vpoqs_sigctx, const OSSL_PARAM params[])
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
OQS_SIG_PRINTF("OQS SIG provider: set_ctx_md_params called\n");
if (poqs_sigctx->mdctx == NULL)
return 0;
return EVP_MD_CTX_set_params(poqs_sigctx->mdctx, params);
}
static const OSSL_PARAM *oqs_sig_settable_ctx_md_params(void *vpoqs_sigctx)
{
PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx;
if (poqs_sigctx->md == NULL)
return 0;
OQS_SIG_PRINTF("OQS SIG provider: settable_ctx_md_params called\n");
return EVP_MD_settable_ctx_params(poqs_sigctx->md);
}
const OSSL_DISPATCH oqs_signature_functions[] = {
{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))oqs_sig_newctx },
{ OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))oqs_sig_sign_init },
{ OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))oqs_sig_sign },
{ OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))oqs_sig_verify_init },
{ OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))oqs_sig_verify },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
(void (*)(void))oqs_sig_digest_sign_init },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
(void (*)(void))oqs_sig_digest_signverify_update },
{ OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
(void (*)(void))oqs_sig_digest_sign_final },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
(void (*)(void))oqs_sig_digest_verify_init },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
(void (*)(void))oqs_sig_digest_signverify_update },
{ OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
(void (*)(void))oqs_sig_digest_verify_final },
{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))oqs_sig_freectx },
{ OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))oqs_sig_dupctx },
{ OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))oqs_sig_get_ctx_params },
{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
(void (*)(void))oqs_sig_gettable_ctx_params },
{ OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))oqs_sig_set_ctx_params },
{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
(void (*)(void))oqs_sig_settable_ctx_params },
{ OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
(void (*)(void))oqs_sig_get_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
(void (*)(void))oqs_sig_gettable_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
(void (*)(void))oqs_sig_set_ctx_md_params },
{ OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
(void (*)(void))oqs_sig_settable_ctx_md_params },
{ 0, NULL }
};