Add DHX serialization

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/12575)
This commit is contained in:
Shane Lontis 2020-08-04 11:39:49 +10:00
parent 116d2510f7
commit 31d2daecb3
13 changed files with 135 additions and 71 deletions

View File

@ -35,9 +35,19 @@
static DH *d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp,
long length)
{
if (pkey->ameth == &dhx_asn1_meth)
return d2i_DHxparams(NULL, pp, length);
return d2i_DHparams(NULL, pp, length);
DH *dh = NULL;
int is_dhx = (pkey->ameth == &dhx_asn1_meth);
if (is_dhx)
dh = d2i_DHxparams(NULL, pp, length);
else
dh = d2i_DHparams(NULL, pp, length);
if (dh != NULL) {
DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
DH_set_flags(dh, is_dhx ? DH_FLAG_TYPE_DHX : DH_FLAG_TYPE_DH);
}
return dh;
}
static int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp)
@ -101,7 +111,6 @@ static int dh_pub_decode(EVP_PKEY *pkey, const X509_PUBKEY *pubkey)
ASN1_INTEGER_free(public_key);
DH_free(dh);
return 0;
}
static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
@ -548,12 +557,16 @@ err:
return rv;
}
static int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
static int dh_pkey_import_from_type(const OSSL_PARAM params[], void *vpctx,
int type)
{
EVP_PKEY_CTX *pctx = vpctx;
EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
DH *dh = dh_new_with_libctx(pctx->libctx);
DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
DH_set_flags(dh, type == EVP_PKEY_DH ? DH_FLAG_TYPE_DH : DH_FLAG_TYPE_DHX);
if (dh == NULL) {
ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
return 0;
@ -561,13 +574,23 @@ static int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
if (!dh_ffc_params_fromdata(dh, params)
|| !dh_key_fromdata(dh, params)
|| !EVP_PKEY_assign_DH(pkey, dh)) {
|| !EVP_PKEY_assign(pkey, type, dh)) {
DH_free(dh);
return 0;
}
return 1;
}
static int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
{
return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DH);
}
static int dhx_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
{
return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DHX);
}
const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
EVP_PKEY_DH,
EVP_PKEY_DH,
@ -649,7 +672,11 @@ const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = {
0,
dh_pkey_public_check,
dh_pkey_param_check
dh_pkey_param_check,
0, 0, 0, 0,
dh_pkey_dirty_cnt,
dh_pkey_export_to,
dhx_pkey_import_from,
};
#ifndef OPENSSL_NO_CMS

View File

@ -1001,6 +1001,8 @@ int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name)
#ifndef OPENSSL_NO_DH
else if (strcasecmp(name, "DH") == 0)
type = EVP_PKEY_DH;
else if (strcasecmp(name, "X9.42 DH") == 0)
type = EVP_PKEY_DHX;
#endif
#ifndef OPENSSL_NO_DSA
else if (strcasecmp(name, "DSA") == 0)

View File

@ -369,41 +369,39 @@ negotiated protocol version. Otherwise it should be left unset.
=head2 DSA parameters
The EVP_PKEY_CTX_set_dsa_paramgen_bits() method sets the number of bits used
for DSA parameter generation to I<nbits>. If not specified, 2048 is used.
EVP_PKEY_CTX_set_dsa_paramgen_bits() sets the number of bits used for DSA
parameter generation to B<nbits>. If not specified, 2048 is used.
The EVP_PKEY_CTX_set_dsa_paramgen_q_bits() method sets the number of bits in the
subprime parameter I<q> for DSA parameter generation to I<qbits>. If not
specified, 224 is used. If a digest function is specified below, this parameter
is ignored and instead, the number of bits in I<q> matches the size of the
digest.
EVP_PKEY_CTX_set_dsa_paramgen_q_bits() sets the number of bits in the subprime
parameter I<q> for DSA parameter generation to I<qbits>. If not specified, 224
is used. If a digest function is specified below, this parameter is ignored and
instead, the number of bits in I<q> matches the size of the digest.
The EVP_PKEY_CTX_set_dsa_paramgen_md() method sets the digest function used for
DSA parameter generation to I<md>. If not specified, one of SHA-1, SHA-224, or
EVP_PKEY_CTX_set_dsa_paramgen_md() sets the digest function used for DSA
parameter generation to I<md>. If not specified, one of SHA-1, SHA-224, or
SHA-256 is selected to match the bit length of I<q> above.
The EVP_PKEY_CTX_set_dsa_paramgen_md_props() method sets the digest function
used for DSA parameter generation using I<md_name> and I<md_properties> to
retrieve the digest from a provider.
EVP_PKEY_CTX_set_dsa_paramgen_md_props() sets the digest function used for DSA
parameter generation using I<md_name> and I<md_properties> to retrieve the
digest from a provider.
If not specified, I<md_name> will be set to one of SHA-1, SHA-224, or
SHA-256 depending on the bit length of I<q> above. I<md_properties> is a
property query string that has a default value of '' if not specified.
The EVP_PKEY_CTX_set_dsa_paramgen_gindex() method sets the I<gindex> used by
the generator G. The default value is -1 which uses unverifiable g, otherwise
a positive value uses verifiable g. This value must be saved if key validation
of g is required, since it is not part of a persisted key.
EVP_PKEY_CTX_set_dsa_paramgen_gindex() sets the I<gindex> used by the generator
G. The default value is -1 which uses unverifiable g, otherwise a positive value
uses verifiable g. This value must be saved if key validation of g is required,
since it is not part of a persisted key.
The EVP_PKEY_CTX_set_dsa_paramgen_seed() method sets the I<seed> to use for
generation rather than using a randomly generated value for the seed. This is
useful for testing purposes only and can fail if the seed does not produce
primes for both p & q on its first iteration. This value must be saved if
key validation of p, q, and verifiable g are required, since it is not part of
a persisted key.
EVP_PKEY_CTX_set_dsa_paramgen_seed() sets the I<seed> to use for generation
rather than using a randomly generated value for the seed. This is useful for
testing purposes only and can fail if the seed does not produce primes for both
p & q on its first iteration. This value must be saved if key validation of
p, q, and verifiable g are required, since it is not part of a persisted key.
The EVP_PKEY_CTX_set_dsa_paramgen_type() method sets the generation type to
use FIPS186-4 generation if I<name> is "fips186_4", or FIPS186-2 generation if
I<name> is "fips186_2". The default value is "fips186_4".
EVP_PKEY_CTX_set_dsa_paramgen_type() sets the generation type to use FIPS186-4
generation if I<name> is "fips186_4", or FIPS186-2 generation if I<name> is
"fips186_2". The default value is "fips186_4".
=head2 DH parameters
@ -445,17 +443,16 @@ Uses a safe prime generator g (PKCS#3 format).
The default is B<DH_PARAMGEN_TYPE_GENERATOR>.
The EVP_PKEY_CTX_set_dh_paramgen_gindex() method sets the I<gindex> used by
the generator G. The default value is -1 which uses unverifiable g, otherwise
a positive value uses verifiable g. This value must be saved if key validation
of g is required, since it is not part of a persisted key.
EVP_PKEY_CTX_set_dh_paramgen_gindex() sets the I<gindex> used by the generator G.
The default value is -1 which uses unverifiable g, otherwise a positive value
uses verifiable g. This value must be saved if key validation of g is required,
since it is not part of a persisted key.
The EVP_PKEY_CTX_set_dh_paramgen_seed() method sets the I<seed> to use for
generation rather than using a randomly generated value for the seed. This is
useful for testing purposes only and can fail if the seed does not produce
primes for both p & q on its first iteration. This value must be saved if
key validation of p, q, and verifiable g are required, since it is not part of
a persisted key.
EVP_PKEY_CTX_set_dh_paramgen_seed() sets the I<seed> to use for generation
rather than using a randomly generated value for the seed. This is useful for
testing purposes only and can fail if the seed does not produce primes for both
p & q on its first iteration. This value must be saved if key validation of p, q,
and verifiable g are required, since it is not part of a persisted key.
The EVP_PKEY_CTX_set_dh_pad() function sets the DH padding mode.
If I<pad> is 1 the shared secret is padded with zeros up to the size of the DH
@ -486,47 +483,47 @@ EVP_PKEY_derive() is the output of the KDF instead of the DH shared secret.
The KDF output is typically used as a Key Encryption Key (KEK) that in turn
encrypts a Content Encryption Key (CEK).
The EVP_PKEY_CTX_set_dh_kdf_type() method sets the key derivation function type
to I<kdf> for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE>
and B<EVP_PKEY_DH_KDF_X9_42> which uses the key derivation specified in RFC2631
EVP_PKEY_CTX_set_dh_kdf_type() sets the key derivation function type to I<kdf>
for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE> and
B<EVP_PKEY_DH_KDF_X9_42> which uses the key derivation specified in RFC2631
(based on the keying algorithm described in X9.42). When using key derivation,
the I<kdf_oid>, I<kdf_md> and I<kdf_outlen> parameters must also be specified.
The EVP_PKEY_CTX_get_dh_kdf_type() method gets the key derivation function type
for I<ctx> used for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE>
and B<EVP_PKEY_DH_KDF_X9_42>.
EVP_PKEY_CTX_get_dh_kdf_type() gets the key derivation function type for I<ctx>
used for DH key derivation. Possible values are B<EVP_PKEY_DH_KDF_NONE> and
B<EVP_PKEY_DH_KDF_X9_42>.
The EVP_PKEY_CTX_set0_dh_kdf_oid() method sets the key derivation function
object identifier to I<oid> for DH key derivation. This OID should identify
the algorithm to be used with the Content Encryption Key.
EVP_PKEY_CTX_set0_dh_kdf_oid() sets the key derivation function object
identifier to I<oid> for DH key derivation. This OID should identify the
algorithm to be used with the Content Encryption Key.
The library takes ownership of the object identifier so the caller should not
free the original memory pointed to by I<oid>.
The EVP_PKEY_CTX_get0_dh_kdf_oid() method gets the key derivation function oid
for I<ctx> used for DH key derivation. The resulting pointer is owned by the
library and should not be freed by the caller.
EVP_PKEY_CTX_get0_dh_kdf_oid() gets the key derivation function oid for I<ctx>
used for DH key derivation. The resulting pointer is owned by the library and
should not be freed by the caller.
The EVP_PKEY_CTX_set_dh_kdf_md() method sets the key derivation function
message digest to I<md> for DH key derivation. Note that RFC2631 specifies
that this digest should be SHA1 but OpenSSL tolerates other digests.
EVP_PKEY_CTX_set_dh_kdf_md() sets the key derivation function message digest to
I<md> for DH key derivation. Note that RFC2631 specifies that this digest should
be SHA1 but OpenSSL tolerates other digests.
The EVP_PKEY_CTX_get_dh_kdf_md() method gets the key derivation function
message digest for I<ctx> used for DH key derivation.
EVP_PKEY_CTX_get_dh_kdf_md() gets the key derivation function message digest for
I<ctx> used for DH key derivation.
The EVP_PKEY_CTX_set_dh_kdf_outlen() method sets the key derivation function
output length to I<len> for DH key derivation.
EVP_PKEY_CTX_set_dh_kdf_outlen() sets the key derivation function output length
to I<len> for DH key derivation.
The EVP_PKEY_CTX_get_dh_kdf_outlen() method gets the key derivation function
output length for I<ctx> used for DH key derivation.
EVP_PKEY_CTX_get_dh_kdf_outlen() gets the key derivation function output length
for I<ctx> used for DH key derivation.
The EVP_PKEY_CTX_set0_dh_kdf_ukm() method sets the user key material to
I<ukm> and its length to I<len> for DH key derivation. This parameter is optional
and corresponds to the partyAInfo field in RFC2631 terms. The specification
EVP_PKEY_CTX_set0_dh_kdf_ukm() sets the user key material to I<ukm> and its
length to I<len> for DH key derivation. This parameter is optional and
corresponds to the partyAInfo field in RFC2631 terms. The specification
requires that it is 512 bits long but this is not enforced by OpenSSL.
The library takes ownership of the user key material so the caller should not
free the original memory pointed to by I<ukm>.
The EVP_PKEY_CTX_get0_dh_kdf_ukm() method gets the user key material for I<ctx>.
EVP_PKEY_CTX_get0_dh_kdf_ukm() gets the user key material for I<ctx>.
The return value is the user key material length. The resulting pointer is owned
by the library and should not be freed by the caller.

View File

@ -13,6 +13,7 @@
#ifndef OPENSSL_NO_DH
DESER("DH", "yes", "der", der_to_dh_deserializer_functions),
DESER("DHX", "yes", "der", der_to_dhx_deserializer_functions),
#endif
#ifndef OPENSSL_NO_DSA
DESER("DSA", "yes", "der", der_to_dsa_deserializer_functions),

View File

@ -365,6 +365,7 @@ extern const OSSL_DISPATCH ec_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH ec_param_pem_serializer_functions[];
extern const OSSL_DISPATCH der_to_dh_deserializer_functions[];
extern const OSSL_DISPATCH der_to_dhx_deserializer_functions[];
extern const OSSL_DISPATCH der_to_dsa_deserializer_functions[];
extern const OSSL_DISPATCH msblob_to_dsa_deserializer_functions[];
extern const OSSL_DISPATCH pvk_to_dsa_deserializer_functions[];

View File

@ -221,6 +221,7 @@ static int der2key_export_object(void *vctx,
#ifndef OPENSSL_NO_DH
IMPLEMENT_NEWCTX("DH", DH, dh, EVP_PKEY_get1_DH, DH_free);
IMPLEMENT_NEWCTX("DHX", DHX, dhx, EVP_PKEY_get1_DH, DH_free);
#endif
#ifndef OPENSSL_NO_DSA
IMPLEMENT_NEWCTX("DSA", DSA, dsa, EVP_PKEY_get1_DSA, DSA_free);

View File

@ -149,3 +149,8 @@ int ossl_prov_dh_priv_to_der(const void *dh, unsigned char **pder)
return ret;
}
int ossl_prov_dh_type_to_evp(const DH *dh)
{
return DH_test_flags(dh, DH_FLAG_TYPE_DHX) ? EVP_PKEY_DHX : EVP_PKEY_DH;
}

View File

@ -153,7 +153,8 @@ static int dh_priv_der(void *vctx, void *dh, OSSL_CORE_BIO *cout,
ctx->sc.cb = cb;
ctx->sc.cbarg = cbarg;
ret = ossl_prov_write_priv_der_from_obj(out, dh, EVP_PKEY_DH,
ret = ossl_prov_write_priv_der_from_obj(out, dh,
ossl_prov_dh_type_to_evp(dh),
ossl_prov_prepare_dh_params,
ossl_prov_dh_priv_to_der,
&ctx->sc);
@ -198,7 +199,8 @@ static int dh_pem_priv(void *vctx, void *dh, OSSL_CORE_BIO *cout,
ctx->sc.cb = cb;
ctx->sc.cbarg = cbarg;
ret = ossl_prov_write_priv_pem_from_obj(out, dh, EVP_PKEY_DH,
ret = ossl_prov_write_priv_pem_from_obj(out, dh,
ossl_prov_dh_type_to_evp(dh),
ossl_prov_prepare_dh_params,
ossl_prov_dh_priv_to_der,
&ctx->sc);

View File

@ -80,7 +80,8 @@ static int dh_pub_der(void *ctx, void *dh, OSSL_CORE_BIO *cout,
if (out == NULL)
return 0;
ret = ossl_prov_write_pub_der_from_obj(out, dh, EVP_PKEY_DH,
ret = ossl_prov_write_pub_der_from_obj(out, dh,
ossl_prov_dh_type_to_evp(dh),
ossl_prov_prepare_dh_params,
ossl_prov_dh_pub_to_der);
BIO_free(out);
@ -120,7 +121,8 @@ static int dh_pub_pem(void *ctx, void *dh, OSSL_CORE_BIO *cout,
if (out == NULL)
return 0;
ret = ossl_prov_write_pub_pem_from_obj(out, dh, EVP_PKEY_DH,
ret = ossl_prov_write_pub_pem_from_obj(out, dh,
ossl_prov_dh_type_to_evp(dh),
ossl_prov_prepare_dh_params,
ossl_prov_dh_pub_to_der);
BIO_free(out);

View File

@ -64,6 +64,7 @@ int ossl_prov_prepare_dh_params(const void *dh, int nid,
void **pstr, int *pstrtype);
int ossl_prov_dh_pub_to_der(const void *dh, unsigned char **pder);
int ossl_prov_dh_priv_to_der(const void *dh, unsigned char **pder);
int ossl_prov_dh_type_to_evp(const DH *dh);
#ifndef OPENSSL_NO_EC
void ecx_get_new_free_import(ECX_KEY_TYPE type,

View File

@ -35,6 +35,16 @@
SER("DH", "yes", "pem", "private", dh_priv_pem_serializer_functions),
SER("DH", "yes", "pem", "public", dh_pub_pem_serializer_functions),
SER("DH", "yes", "pem", "parameters", dh_param_pem_serializer_functions),
SER("DHX", "yes", "text", "private", dh_priv_text_serializer_functions),
SER("DHX", "yes", "text", "public", dh_pub_text_serializer_functions),
SER("DHX", "yes", "text", "parameters", dh_param_text_serializer_functions),
SER("DHX", "yes", "der", "private", dh_priv_der_serializer_functions),
SER("DHX", "yes", "der", "public", dh_pub_der_serializer_functions),
SER("DHX", "yes", "der", "parameters", dh_param_der_serializer_functions),
SER("DHX", "yes", "pem", "private", dh_priv_pem_serializer_functions),
SER("DHX", "yes", "pem", "public", dh_pub_pem_serializer_functions),
SER("DHX", "yes", "pem", "parameters", dh_param_pem_serializer_functions),
#endif
#ifndef OPENSSL_NO_DSA

View File

@ -740,6 +740,8 @@ static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key)
#ifndef OPENSSL_NO_DH
DOMAIN_KEYS(DH);
IMPLEMENT_TEST_SUITE(DH, "DH")
DOMAIN_KEYS(DHX);
IMPLEMENT_TEST_SUITE(DHX, "X9.42 DH")
#endif
#ifndef OPENSSL_NO_DSA
DOMAIN_KEYS(DSA);
@ -804,6 +806,7 @@ int setup_tests(void)
TEST_info("Generating keys...");
#ifndef OPENSSL_NO_DH
MAKE_DOMAIN_KEYS(DH, "DH", NULL);
MAKE_DOMAIN_KEYS(DHX, "X9.42 DH", NULL);
#endif
#ifndef OPENSSL_NO_DSA
MAKE_DOMAIN_KEYS(DSA, "DSA", DSA_params);
@ -822,6 +825,7 @@ int setup_tests(void)
if (ok) {
#ifndef OPENSSL_NO_DH
ADD_TEST_SUITE(DH);
ADD_TEST_SUITE(DHX);
#endif
#ifndef OPENSSL_NO_DSA
ADD_TEST_SUITE(DSA);
@ -854,6 +858,7 @@ void cleanup_tests(void)
{
#ifndef OPENSSL_NO_DH
FREE_DOMAIN_KEYS(DH);
FREE_DOMAIN_KEYS(DHX);
#endif
#ifndef OPENSSL_NO_DSA
FREE_DOMAIN_KEYS(DSA);

View File

@ -5240,3 +5240,13 @@ EVP_PKEY_CTX_set_scrypt_N ? 3_0_0 EXIST::FUNCTION:
EVP_PKEY_CTX_set_scrypt_r ? 3_0_0 EXIST::FUNCTION:
EVP_PKEY_CTX_set_scrypt_p ? 3_0_0 EXIST::FUNCTION:
EVP_PKEY_CTX_set_scrypt_maxmem_bytes ? 3_0_0 EXIST::FUNCTION:
EVP_PKEY_CTX_set_dh_kdf_type ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_get_dh_kdf_type ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set0_dh_kdf_oid ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_get0_dh_kdf_oid ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set_dh_kdf_md ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_get_dh_kdf_md ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set_dh_kdf_outlen ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_get_dh_kdf_outlen ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set0_dh_kdf_ukm ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_get0_dh_kdf_ukm ? 3_0_0 EXIST::FUNCTION:DH