mirror of
https://github.com/QuasarApp/openssl.git
synced 2025-05-21 13:59:40 +00:00
For FIPS validation purposes - Automated Cryptographic Validation Protocol (ACVP) tests need to be performed. (See https://github.com/usnistgov/ACVP). These tests are very similiar to the old CAVS tests. This PR uses a hardwired subset of these test vectors to perform similiar operations, to show the usage and prove that the API's are able to perform the required operations. It may also help with communication with the lab (i.e- The lab could add a test here to show a unworking use case - which we can then address). The EVP layer performs these tests instead of calling lower level API's as was done in the old FOM. Some of these tests require access to internals that are not normally allowed/required. The config option 'acvp_tests' (enabled by default) has been added so that this access may be removed. The mechanism has been implemented as additional OSSL_PARAM values that can be set and get. A callback mechanism did not seem to add any additional benefit. These params will not be added to the gettables lists. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/11572)
333 lines
9.1 KiB
C
333 lines
9.1 KiB
C
/*
|
|
* Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <string.h> /* memset */
|
|
#include <openssl/core_names.h>
|
|
#include "internal/ffc.h"
|
|
#include "internal/param_build_set.h"
|
|
#include "internal/nelem.h"
|
|
#include "e_os.h" /* strcasecmp */
|
|
|
|
#ifndef FIPS_MODULE
|
|
# include <openssl/asn1.h> /* ffc_params_print */
|
|
#endif
|
|
|
|
void ffc_params_init(FFC_PARAMS *params)
|
|
{
|
|
memset(params, 0, sizeof(*params));
|
|
params->pcounter = -1;
|
|
params->gindex = FFC_UNVERIFIABLE_GINDEX;
|
|
params->flags = FFC_PARAM_FLAG_VALIDATE_ALL;
|
|
}
|
|
|
|
void ffc_params_cleanup(FFC_PARAMS *params)
|
|
{
|
|
BN_free(params->p);
|
|
BN_free(params->q);
|
|
BN_free(params->g);
|
|
BN_free(params->j);
|
|
OPENSSL_free(params->seed);
|
|
ffc_params_init(params);
|
|
}
|
|
|
|
void ffc_params_set0_pqg(FFC_PARAMS *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
{
|
|
if (p != NULL && p != d->p) {
|
|
BN_free(d->p);
|
|
d->p = p;
|
|
}
|
|
if (q != NULL && q != d->q) {
|
|
BN_free(d->q);
|
|
d->q = q;
|
|
}
|
|
if (g != NULL && g != d->g) {
|
|
BN_free(d->g);
|
|
d->g = g;
|
|
}
|
|
}
|
|
|
|
void ffc_params_get0_pqg(const FFC_PARAMS *d, const BIGNUM **p,
|
|
const BIGNUM **q, const BIGNUM **g)
|
|
{
|
|
if (p != NULL)
|
|
*p = d->p;
|
|
if (q != NULL)
|
|
*q = d->q;
|
|
if (g != NULL)
|
|
*g = d->g;
|
|
}
|
|
|
|
|
|
/* j is the 'cofactor' that is optionally output for ASN1. */
|
|
void ffc_params_set0_j(FFC_PARAMS *d, BIGNUM *j)
|
|
{
|
|
BN_free(d->j);
|
|
d->j = NULL;
|
|
if (j != NULL)
|
|
d->j = j;
|
|
}
|
|
|
|
int ffc_params_set_seed(FFC_PARAMS *params,
|
|
const unsigned char *seed, size_t seedlen)
|
|
{
|
|
if (params == NULL)
|
|
return 0;
|
|
|
|
if (params->seed != NULL) {
|
|
if (params->seed == seed)
|
|
return 1;
|
|
OPENSSL_free(params->seed);
|
|
}
|
|
|
|
if (seed != NULL && seedlen > 0) {
|
|
params->seed = OPENSSL_memdup(seed, seedlen);
|
|
if (params->seed == NULL)
|
|
return 0;
|
|
params->seedlen = seedlen;
|
|
} else {
|
|
params->seed = NULL;
|
|
params->seedlen = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void ffc_params_set_gindex(FFC_PARAMS *params, int index)
|
|
{
|
|
params->gindex = index;
|
|
}
|
|
|
|
void ffc_params_set_pcounter(FFC_PARAMS *params, int index)
|
|
{
|
|
params->pcounter = index;
|
|
}
|
|
|
|
void ffc_params_set_h(FFC_PARAMS *params, int index)
|
|
{
|
|
params->h = index;
|
|
}
|
|
|
|
void ffc_params_set_flags(FFC_PARAMS *params, unsigned int flags)
|
|
{
|
|
params->flags = flags;
|
|
}
|
|
|
|
int ffc_set_digest(FFC_PARAMS *params, const char *alg, const char *props)
|
|
{
|
|
params->mdname = alg;
|
|
params->mdprops = props;
|
|
return 1;
|
|
}
|
|
|
|
int ffc_params_set_validate_params(FFC_PARAMS *params,
|
|
const unsigned char *seed, size_t seedlen,
|
|
int counter)
|
|
{
|
|
if (!ffc_params_set_seed(params, seed, seedlen))
|
|
return 0;
|
|
params->pcounter = counter;
|
|
return 1;
|
|
}
|
|
|
|
void ffc_params_get_validate_params(const FFC_PARAMS *params,
|
|
unsigned char **seed, size_t *seedlen,
|
|
int *pcounter)
|
|
{
|
|
if (seed != NULL)
|
|
*seed = params->seed;
|
|
if (seedlen != NULL)
|
|
*seedlen = params->seedlen;
|
|
if (pcounter != NULL)
|
|
*pcounter = params->pcounter;
|
|
}
|
|
|
|
static int ffc_bn_cpy(BIGNUM **dst, const BIGNUM *src)
|
|
{
|
|
BIGNUM *a;
|
|
|
|
/*
|
|
* If source is read only just copy the pointer, so
|
|
* we don't have to reallocate it.
|
|
*/
|
|
if (src == NULL)
|
|
a = NULL;
|
|
else if (BN_get_flags(src, BN_FLG_STATIC_DATA)
|
|
&& !BN_get_flags(src, BN_FLG_MALLOCED))
|
|
a = (BIGNUM *)src;
|
|
else if ((a = BN_dup(src)) == NULL)
|
|
return 0;
|
|
BN_clear_free(*dst);
|
|
*dst = a;
|
|
return 1;
|
|
}
|
|
|
|
int ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src)
|
|
{
|
|
if (!ffc_bn_cpy(&dst->p, src->p)
|
|
|| !ffc_bn_cpy(&dst->g, src->g)
|
|
|| !ffc_bn_cpy(&dst->q, src->q)
|
|
|| !ffc_bn_cpy(&dst->j, src->j))
|
|
return 0;
|
|
|
|
OPENSSL_free(dst->seed);
|
|
dst->seedlen = src->seedlen;
|
|
if (src->seed != NULL) {
|
|
dst->seed = OPENSSL_memdup(src->seed, src->seedlen);
|
|
if (dst->seed == NULL)
|
|
return 0;
|
|
} else {
|
|
dst->seed = NULL;
|
|
}
|
|
dst->nid = src->nid;
|
|
dst->pcounter = src->pcounter;
|
|
dst->h = src->h;
|
|
dst->gindex = src->gindex;
|
|
return 1;
|
|
}
|
|
|
|
int ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q)
|
|
{
|
|
return BN_cmp(a->p, b->p) == 0
|
|
&& BN_cmp(a->g, b->g) == 0
|
|
&& (ignore_q || BN_cmp(a->q, b->q) == 0); /* Note: q may be NULL */
|
|
}
|
|
|
|
static const OSSL_ITEM flag_map[] = {
|
|
{ FFC_PARAM_FLAG_VALIDATE_PQ, OSSL_FFC_PARAM_VALIDATE_PQ },
|
|
{ FFC_PARAM_FLAG_VALIDATE_G, OSSL_FFC_PARAM_VALIDATE_G },
|
|
{ FFC_PARAM_FLAG_VALIDATE_ALL, OSSL_FFC_PARAM_VALIDATE_PQG },
|
|
{ 0, "" }
|
|
};
|
|
|
|
int ffc_params_flags_from_name(const char *name)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < OSSL_NELEM(flag_map); ++i) {
|
|
if (strcasecmp(flag_map[i].ptr, name) == 0)
|
|
return flag_map[i].id;
|
|
}
|
|
return NID_undef;
|
|
}
|
|
|
|
const char *ffc_params_flags_to_name(int flags)
|
|
{
|
|
size_t i;
|
|
|
|
flags &= FFC_PARAM_FLAG_VALIDATE_ALL;
|
|
for (i = 0; i < OSSL_NELEM(flag_map); ++i) {
|
|
if ((int)flag_map[i].id == flags)
|
|
return flag_map[i].ptr;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
int ffc_params_todata(const FFC_PARAMS *ffc, OSSL_PARAM_BLD *bld,
|
|
OSSL_PARAM params[])
|
|
{
|
|
if (ffc == NULL)
|
|
return 0;
|
|
|
|
if (ffc->p != NULL
|
|
&& !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_P, ffc->p))
|
|
return 0;
|
|
if (ffc->q != NULL
|
|
&& !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_Q, ffc->q))
|
|
return 0;
|
|
if (ffc->g != NULL
|
|
&& !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_G, ffc->g))
|
|
return 0;
|
|
if (ffc->j != NULL
|
|
&& !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_FFC_COFACTOR,
|
|
ffc->j))
|
|
return 0;
|
|
if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_GINDEX,
|
|
ffc->gindex))
|
|
return 0;
|
|
if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_PCOUNTER,
|
|
ffc->pcounter))
|
|
return 0;
|
|
if (!ossl_param_build_set_int(bld, params, OSSL_PKEY_PARAM_FFC_H, ffc->h))
|
|
return 0;
|
|
if (ffc->seed != NULL
|
|
&& !ossl_param_build_set_octet_string(bld, params,
|
|
OSSL_PKEY_PARAM_FFC_SEED,
|
|
ffc->seed, ffc->seedlen))
|
|
return 0;
|
|
if (ffc->nid != NID_undef) {
|
|
#ifndef OPENSSL_NO_DH
|
|
const char *name = ffc_named_group_from_uid(ffc->nid);
|
|
|
|
if (name == NULL
|
|
|| !ossl_param_build_set_utf8_string(bld, params,
|
|
OSSL_PKEY_PARAM_DH_GROUP,
|
|
name))
|
|
return 0;
|
|
#else
|
|
/* How could this be? We should not have a nid in a no-dh build. */
|
|
return 0;
|
|
#endif
|
|
}
|
|
if (!ossl_param_build_set_utf8_string(bld, params,
|
|
OSSL_PKEY_PARAM_FFC_VALIDATE_TYPE,
|
|
ffc_params_flags_to_name(ffc->flags)))
|
|
return 0;
|
|
if (ffc->mdname != NULL
|
|
&& !ossl_param_build_set_utf8_string(bld, params,
|
|
OSSL_PKEY_PARAM_FFC_DIGEST,
|
|
ffc->mdname))
|
|
return 0;
|
|
if (ffc->mdprops != NULL
|
|
&& !ossl_param_build_set_utf8_string(bld, params,
|
|
OSSL_PKEY_PARAM_FFC_DIGEST_PROPS,
|
|
ffc->mdprops))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
#ifndef FIPS_MODULE
|
|
int ffc_params_print(BIO *bp, const FFC_PARAMS *ffc, int indent)
|
|
{
|
|
if (!ASN1_bn_print(bp, "prime P:", ffc->p, NULL, indent))
|
|
goto err;
|
|
if (!ASN1_bn_print(bp, "generator G:", ffc->g, NULL, indent))
|
|
goto err;
|
|
if (ffc->q != NULL
|
|
&& !ASN1_bn_print(bp, "subgroup order Q:", ffc->q, NULL, indent))
|
|
goto err;
|
|
if (ffc->j != NULL
|
|
&& !ASN1_bn_print(bp, "subgroup factor:", ffc->j, NULL, indent))
|
|
goto err;
|
|
if (ffc->seed != NULL) {
|
|
size_t i;
|
|
BIO_indent(bp, indent, 128);
|
|
BIO_puts(bp, "seed:");
|
|
for (i = 0; i < ffc->seedlen; i++) {
|
|
if ((i % 15) == 0) {
|
|
if (BIO_puts(bp, "\n") <= 0
|
|
|| !BIO_indent(bp, indent + 4, 128))
|
|
goto err;
|
|
}
|
|
if (BIO_printf(bp, "%02x%s", ffc->seed[i],
|
|
((i + 1) == ffc->seedlen) ? "" : ":") <= 0)
|
|
goto err;
|
|
}
|
|
if (BIO_write(bp, "\n", 1) <= 0)
|
|
return 0;
|
|
}
|
|
if (ffc->pcounter != -1) {
|
|
BIO_indent(bp, indent, 128);
|
|
if (BIO_printf(bp, "counter: %d\n", ffc->pcounter) <= 0)
|
|
goto err;
|
|
}
|
|
return 1;
|
|
err:
|
|
return 0;
|
|
}
|
|
#endif /* FIPS_MODULE */
|