From b0004708730f300a2e5c6a11c887caab50b6c42a Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Wed, 1 Nov 2017 00:45:24 +0800 Subject: [PATCH] Support public key and param check in EVP interface EVP_PKEY_public_check() and EVP_PKEY_param_check() Doc and test cases are added Reviewed-by: Tim Hudson Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/4647) --- apps/pkey.c | 15 +++-- apps/pkeyparam.c | 41 ++++++++++++- crypto/asn1/ameth_lib.c | 12 ++++ crypto/dh/dh_ameth.c | 35 ++++++++++- crypto/dh/dh_check.c | 52 +++++++++++++++++ crypto/dh/dh_err.c | 24 ++++++++ crypto/ec/ec_ameth.c | 33 ++++++++++- crypto/ec/ec_err.c | 1 + crypto/err/openssl.txt | 18 ++++++ crypto/evp/evp_err.c | 4 ++ crypto/evp/pmeth_gn.c | 46 +++++++++++++++ crypto/evp/pmeth_lib.c | 26 +++++++++ crypto/include/internal/asn1_int.h | 2 + crypto/include/internal/evp_int.h | 2 + doc/man1/pkey.pod | 6 ++ doc/man1/pkeyparam.pod | 5 ++ doc/man3/DH_generate_parameters.pod | 18 +++++- doc/man3/EVP_PKEY_ASN1_METHOD.pod | 22 +++++-- doc/man3/EVP_PKEY_keygen.pod | 21 ++++++- doc/man3/EVP_PKEY_meth_new.pod | 18 +++++- include/openssl/dh.h | 3 + include/openssl/dherr.h | 15 +++++ include/openssl/ecerr.h | 1 + include/openssl/evp.h | 20 +++++++ include/openssl/evperr.h | 2 + test/evp_extra_test.c | 90 ++++++++++++++++++++++++----- util/libcrypto.num | 11 ++++ 27 files changed, 510 insertions(+), 33 deletions(-) diff --git a/apps/pkey.c b/apps/pkey.c index 0a3a36a716..6160e5a381 100644 --- a/apps/pkey.c +++ b/apps/pkey.c @@ -18,7 +18,7 @@ typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_INFORM, OPT_OUTFORM, OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_IN, OPT_OUT, OPT_PUBIN, OPT_PUBOUT, OPT_TEXT_PUB, - OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL, OPT_CHECK + OPT_TEXT, OPT_NOOUT, OPT_MD, OPT_TRADITIONAL, OPT_CHECK, OPT_PUB_CHECK } OPTION_CHOICE; const OPTIONS pkey_options[] = { @@ -42,6 +42,7 @@ const OPTIONS pkey_options[] = { {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif {"check", OPT_CHECK, '-', "Check key consistency"}, + {"pubcheck", OPT_PUB_CHECK, '-', "Check public key consistency"}, {NULL} }; @@ -56,7 +57,7 @@ int pkey_main(int argc, char **argv) OPTION_CHOICE o; int informat = FORMAT_PEM, outformat = FORMAT_PEM; int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0, ret = 1; - int private = 0, traditional = 0, check = 0; + int private = 0, traditional = 0, check = 0, pub_check = 0; prog = opt_init(argc, argv, pkey_options); while ((o = opt_next()) != OPT_EOF) { @@ -114,6 +115,9 @@ int pkey_main(int argc, char **argv) case OPT_CHECK: check = 1; break; + case OPT_PUB_CHECK: + pub_check = 1; + break; case OPT_MD: if (!opt_cipher(opt_unknown(), &cipher)) goto opthelp; @@ -143,7 +147,7 @@ int pkey_main(int argc, char **argv) if (pkey == NULL) goto end; - if (check) { + if (check || pub_check) { int r; EVP_PKEY_CTX *ctx; @@ -153,7 +157,10 @@ int pkey_main(int argc, char **argv) goto end; } - r = EVP_PKEY_check(ctx); + if (check) + r = EVP_PKEY_check(ctx); + else + r = EVP_PKEY_public_check(ctx); if (r == 1) { BIO_printf(out, "Key is valid\n"); diff --git a/apps/pkeyparam.c b/apps/pkeyparam.c index 9ac247509a..35cdd8dc92 100644 --- a/apps/pkeyparam.c +++ b/apps/pkeyparam.c @@ -16,7 +16,8 @@ typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_IN, OPT_OUT, OPT_TEXT, OPT_NOOUT, OPT_ENGINE + OPT_IN, OPT_OUT, OPT_TEXT, OPT_NOOUT, + OPT_ENGINE, OPT_CHECK } OPTION_CHOICE; const OPTIONS pkeyparam_options[] = { @@ -28,6 +29,7 @@ const OPTIONS pkeyparam_options[] = { #ifndef OPENSSL_NO_ENGINE {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif + {"check", OPT_CHECK, '-', "Check key param consistency"}, {NULL} }; @@ -36,7 +38,7 @@ int pkeyparam_main(int argc, char **argv) ENGINE *e = NULL; BIO *in = NULL, *out = NULL; EVP_PKEY *pkey = NULL; - int text = 0, noout = 0, ret = 1; + int text = 0, noout = 0, ret = 1, check = 0; OPTION_CHOICE o; char *infile = NULL, *outfile = NULL, *prog; @@ -67,6 +69,9 @@ int pkeyparam_main(int argc, char **argv) case OPT_NOOUT: noout = 1; break; + case OPT_CHECK: + check = 1; + break; } } argc = opt_num_rest(); @@ -86,6 +91,38 @@ int pkeyparam_main(int argc, char **argv) goto end; } + if (check) { + int r; + EVP_PKEY_CTX *ctx; + + ctx = EVP_PKEY_CTX_new(pkey, e); + if (ctx == NULL) { + ERR_print_errors(bio_err); + goto end; + } + + r = EVP_PKEY_param_check(ctx); + + if (r == 1) { + BIO_printf(out, "Parameters are valid\n"); + } else { + /* + * Note: at least for RSA keys if this function returns + * -1, there will be no error reasons. + */ + unsigned long err; + + BIO_printf(out, "Parameters are invalid\n"); + + while ((err = ERR_peek_error()) != 0) { + BIO_printf(out, "Detailed error: %s\n", + ERR_reason_error_string(err)); + ERR_get_error(); /* remove err from error stack */ + } + } + EVP_PKEY_CTX_free(ctx); + } + if (!noout) PEM_write_bio_Parameters(out, pkey); diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c index 87a3eba14a..5662e17688 100644 --- a/crypto/asn1/ameth_lib.c +++ b/crypto/asn1/ameth_lib.c @@ -382,3 +382,15 @@ void EVP_PKEY_asn1_set_check(EVP_PKEY_ASN1_METHOD *ameth, { ameth->pkey_check = pkey_check; } + +void EVP_PKEY_asn1_set_public_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_pub_check) (const EVP_PKEY *pk)) +{ + ameth->pkey_public_check = pkey_pub_check; +} + +void EVP_PKEY_asn1_set_param_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_param_check) (const EVP_PKEY *pk)) +{ + ameth->pkey_param_check = pkey_param_check; +} diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c index e504690fa3..05a1d4227e 100644 --- a/crypto/dh/dh_ameth.c +++ b/crypto/dh/dh_ameth.c @@ -509,6 +509,25 @@ static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) } +static int dh_pkey_public_check(const EVP_PKEY *pkey) +{ + DH *dh = pkey->pkey.dh; + + if (dh->pub_key == NULL) { + DHerr(DH_F_DH_PKEY_PUBLIC_CHECK, DH_R_MISSING_PUBKEY); + return 0; + } + + return DH_check_pub_key_ex(dh, dh->pub_key); +} + +static int dh_pkey_param_check(const EVP_PKEY *pkey) +{ + DH *dh = pkey->pkey.dh; + + return DH_check_ex(dh); +} + const EVP_PKEY_ASN1_METHOD dh_asn1_meth = { EVP_PKEY_DH, EVP_PKEY_DH, @@ -539,7 +558,13 @@ const EVP_PKEY_ASN1_METHOD dh_asn1_meth = { 0, int_dh_free, - 0 + 0, + + 0, 0, 0, 0, 0, + + 0, + dh_pkey_public_check, + dh_pkey_param_check }; const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = { @@ -572,7 +597,13 @@ const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = { 0, int_dh_free, - dh_pkey_ctrl + dh_pkey_ctrl, + + 0, 0, 0, 0, 0, + + 0, + dh_pkey_public_check, + dh_pkey_param_check }; #ifndef OPENSSL_NO_CMS diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c index 066bf83336..fc45577101 100644 --- a/crypto/dh/dh_check.c +++ b/crypto/dh/dh_check.c @@ -18,6 +18,19 @@ * p is odd * 1 < g < p - 1 */ +int DH_check_params_ex(const DH *dh) +{ + int errflags = 0; + + (void)DH_check_params(dh, &errflags); + + if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) + DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_CHECK_P_NOT_PRIME); + if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) + DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_NOT_SUITABLE_GENERATOR); + + return errflags == 0; +} int DH_check_params(const DH *dh, int *ret) { @@ -61,6 +74,29 @@ int DH_check_params(const DH *dh, int *ret) * for 5, p mod 10 == 3 or 7 * should hold. */ +int DH_check_ex(const DH *dh) +{ + int errflags = 0; + + (void)DH_check(dh, &errflags); + + if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_NOT_SUITABLE_GENERATOR); + if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_Q_NOT_PRIME); + if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_Q_VALUE); + if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_J_VALUE); + if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_UNABLE_TO_CHECK_GENERATOR); + if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_PRIME); + if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_SAFE_PRIME); + + return errflags == 0; +} int DH_check(const DH *dh, int *ret) { @@ -142,6 +178,22 @@ int DH_check(const DH *dh, int *ret) return ok; } +int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) +{ + int errflags = 0; + + (void)DH_check(dh, &errflags); + + if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0) + DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_SMALL); + if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0) + DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_LARGE); + if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0) + DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_INVALID); + + return errflags == 0; +} + int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { int ok = 0; diff --git a/crypto/dh/dh_err.c b/crypto/dh/dh_err.c index aae66fa0b9..bbedab593e 100644 --- a/crypto/dh/dh_err.c +++ b/crypto/dh/dh_err.c @@ -18,6 +18,9 @@ static const ERR_STRING_DATA DH_str_functs[] = { {ERR_PACK(ERR_LIB_DH, DH_F_DHPARAMS_PRINT_FP, 0), "DHparams_print_fp"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS, 0), "dh_builtin_genparams"}, + {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_EX, 0), "DH_check_ex"}, + {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_PARAMS_EX, 0), "DH_check_params_ex"}, + {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_PUB_KEY_EX, 0), "DH_check_pub_key_ex"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_DECRYPT, 0), "dh_cms_decrypt"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_SET_PEERKEY, 0), "dh_cms_set_peerkey"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_SET_SHARED_INFO, 0), @@ -28,6 +31,8 @@ static const ERR_STRING_DATA DH_str_functs[] = { {ERR_PACK(ERR_LIB_DH, DH_F_DH_NEW_BY_NID, 0), "DH_new_by_nid"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_NEW_METHOD, 0), "DH_new_method"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_PARAM_DECODE, 0), "dh_param_decode"}, + {ERR_PACK(ERR_LIB_DH, DH_F_DH_PKEY_PUBLIC_CHECK, 0), + "dh_pkey_public_check"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_PRIV_DECODE, 0), "dh_priv_decode"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_PRIV_ENCODE, 0), "dh_priv_encode"}, {ERR_PACK(ERR_LIB_DH, DH_F_DH_PUB_DECODE, 0), "dh_pub_decode"}, @@ -44,6 +49,20 @@ static const ERR_STRING_DATA DH_str_reasons[] = { {ERR_PACK(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR), "bad generator"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_BN_DECODE_ERROR), "bn decode error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_BN_ERROR), "bn error"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_INVALID_J_VALUE), + "check invalid j value"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_INVALID_Q_VALUE), + "check invalid q value"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_PUBKEY_INVALID), + "check pubkey invalid"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_PUBKEY_TOO_LARGE), + "check pubkey too large"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_PUBKEY_TOO_SMALL), + "check pubkey too small"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_P_NOT_PRIME), "check p not prime"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_P_NOT_SAFE_PRIME), + "check p not safe prime"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_CHECK_Q_NOT_PRIME), "check q not prime"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_DECODE_ERROR), "decode error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_PARAMETER_NAME), "invalid parameter name"}, @@ -52,13 +71,18 @@ static const ERR_STRING_DATA DH_str_reasons[] = { {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_PUBKEY), "invalid public key"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_KDF_PARAMETER_ERROR), "kdf parameter error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_KEYS_NOT_SET), "keys not set"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_MISSING_PUBKEY), "missing pubkey"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_LARGE), "modulus too large"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_NOT_SUITABLE_GENERATOR), + "not suitable generator"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PARAMETERS_SET), "no parameters set"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PRIVATE_VALUE), "no private value"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_PARAMETER_ENCODING_ERROR), "parameter encoding error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_PEER_KEY_ERROR), "peer key error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_SHARED_INFO_ERROR), "shared info error"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_UNABLE_TO_CHECK_GENERATOR), + "unable to check generator"}, {0, NULL} }; diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c index 22ad6b0f2d..0682bc3d1d 100644 --- a/crypto/ec/ec_ameth.c +++ b/crypto/ec/ec_ameth.c @@ -533,6 +533,35 @@ static int ec_pkey_check(const EVP_PKEY *pkey) return EC_KEY_check_key(eckey); } +static int ec_pkey_public_check(const EVP_PKEY *pkey) +{ + EC_KEY *eckey = pkey->pkey.ec; + + /* + * Note: it unnecessary to check eckey->pub_key here since + * it will be checked in EC_KEY_check_key(). In fact, the + * EC_KEY_check_key() mainly checks the public key, and checks + * the private key optionally (only if there is one). So if + * someone passes a whole EC key (public + private), this + * will also work... + */ + + return EC_KEY_check_key(eckey); +} + +static int ec_pkey_param_check(const EVP_PKEY *pkey) +{ + EC_KEY *eckey = pkey->pkey.ec; + + /* stay consistent to what EVP_PKEY_check demands */ + if (eckey->group == NULL) { + ECerr(EC_F_EC_PKEY_PARAM_CHECK, EC_R_MISSING_PARAMETERS); + return 0; + } + + return EC_GROUP_check(eckey->group, NULL); +} + const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = { EVP_PKEY_EC, EVP_PKEY_EC, @@ -568,7 +597,9 @@ const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = { 0, 0, 0, - ec_pkey_check + ec_pkey_check, + ec_pkey_public_check, + ec_pkey_param_check }; int EC_KEY_print(BIO *bp, const EC_KEY *x, int off) diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c index 19a7a9d7bd..9f82b4ef7e 100644 --- a/crypto/ec/ec_err.c +++ b/crypto/ec/ec_err.c @@ -182,6 +182,7 @@ static const ERR_STRING_DATA EC_str_functs[] = { {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_SIMPLE_PRIV2OCT, 0), "ec_key_simple_priv2oct"}, {ERR_PACK(ERR_LIB_EC, EC_F_EC_PKEY_CHECK, 0), "ec_pkey_check"}, + {ERR_PACK(ERR_LIB_EC, EC_F_EC_PKEY_PARAM_CHECK, 0), "ec_pkey_param_check"}, {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINTS_MAKE_AFFINE, 0), "EC_POINTs_make_affine"}, {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_ADD, 0), "EC_POINT_add"}, diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index d3e4a62e71..8547d07882 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -351,6 +351,9 @@ CT_F_SCT_SET_VERSION:104:SCT_set_version DH_F_COMPUTE_KEY:102:compute_key DH_F_DHPARAMS_PRINT_FP:101:DHparams_print_fp DH_F_DH_BUILTIN_GENPARAMS:106:dh_builtin_genparams +DH_F_DH_CHECK_EX:121:DH_check_ex +DH_F_DH_CHECK_PARAMS_EX:122:DH_check_params_ex +DH_F_DH_CHECK_PUB_KEY_EX:123:DH_check_pub_key_ex DH_F_DH_CMS_DECRYPT:114:dh_cms_decrypt DH_F_DH_CMS_SET_PEERKEY:115:dh_cms_set_peerkey DH_F_DH_CMS_SET_SHARED_INFO:116:dh_cms_set_shared_info @@ -360,6 +363,7 @@ DH_F_DH_METH_SET1_NAME:119:DH_meth_set1_name DH_F_DH_NEW_BY_NID:104:DH_new_by_nid DH_F_DH_NEW_METHOD:105:DH_new_method DH_F_DH_PARAM_DECODE:107:dh_param_decode +DH_F_DH_PKEY_PUBLIC_CHECK:124:dh_pkey_public_check DH_F_DH_PRIV_DECODE:110:dh_priv_decode DH_F_DH_PRIV_ENCODE:111:dh_priv_encode DH_F_DH_PUB_DECODE:108:dh_pub_decode @@ -542,6 +546,7 @@ EC_F_EC_KEY_SIMPLE_CHECK_KEY:258:ec_key_simple_check_key EC_F_EC_KEY_SIMPLE_OCT2PRIV:259:ec_key_simple_oct2priv EC_F_EC_KEY_SIMPLE_PRIV2OCT:260:ec_key_simple_priv2oct EC_F_EC_PKEY_CHECK:273:ec_pkey_check +EC_F_EC_PKEY_PARAM_CHECK:274:ec_pkey_param_check EC_F_EC_POINTS_MAKE_AFFINE:136:EC_POINTs_make_affine EC_F_EC_POINT_ADD:112:EC_POINT_add EC_F_EC_POINT_CMP:113:EC_POINT_cmp @@ -692,6 +697,8 @@ EVP_F_EVP_PKEY_KEYGEN_INIT:147:EVP_PKEY_keygen_init EVP_F_EVP_PKEY_NEW:106:EVP_PKEY_new EVP_F_EVP_PKEY_PARAMGEN:148:EVP_PKEY_paramgen EVP_F_EVP_PKEY_PARAMGEN_INIT:149:EVP_PKEY_paramgen_init +EVP_F_EVP_PKEY_PARAM_CHECK:189:EVP_PKEY_param_check +EVP_F_EVP_PKEY_PUBLIC_CHECK:190:EVP_PKEY_public_check EVP_F_EVP_PKEY_SET1_ENGINE:187:EVP_PKEY_set1_engine EVP_F_EVP_PKEY_SIGN:140:EVP_PKEY_sign EVP_F_EVP_PKEY_SIGN_INIT:141:EVP_PKEY_sign_init @@ -1794,18 +1801,29 @@ CT_R_UNSUPPORTED_VERSION:103:unsupported version DH_R_BAD_GENERATOR:101:bad generator DH_R_BN_DECODE_ERROR:109:bn decode error DH_R_BN_ERROR:106:bn error +DH_R_CHECK_INVALID_J_VALUE:115:check invalid j value +DH_R_CHECK_INVALID_Q_VALUE:116:check invalid q value +DH_R_CHECK_PUBKEY_INVALID:122:check pubkey invalid +DH_R_CHECK_PUBKEY_TOO_LARGE:123:check pubkey too large +DH_R_CHECK_PUBKEY_TOO_SMALL:124:check pubkey too small +DH_R_CHECK_P_NOT_PRIME:117:check p not prime +DH_R_CHECK_P_NOT_SAFE_PRIME:118:check p not safe prime +DH_R_CHECK_Q_NOT_PRIME:119:check q not prime DH_R_DECODE_ERROR:104:decode error DH_R_INVALID_PARAMETER_NAME:110:invalid parameter name DH_R_INVALID_PARAMETER_NID:114:invalid parameter nid DH_R_INVALID_PUBKEY:102:invalid public key DH_R_KDF_PARAMETER_ERROR:112:kdf parameter error DH_R_KEYS_NOT_SET:108:keys not set +DH_R_MISSING_PUBKEY:125:missing pubkey DH_R_MODULUS_TOO_LARGE:103:modulus too large +DH_R_NOT_SUITABLE_GENERATOR:120:not suitable generator DH_R_NO_PARAMETERS_SET:107:no parameters set DH_R_NO_PRIVATE_VALUE:100:no private value DH_R_PARAMETER_ENCODING_ERROR:105:parameter encoding error DH_R_PEER_KEY_ERROR:111:peer key error DH_R_SHARED_INFO_ERROR:113:shared info error +DH_R_UNABLE_TO_CHECK_GENERATOR:121:unable to check generator DSA_R_BAD_Q_VALUE:102:bad q value DSA_R_BN_DECODE_ERROR:108:bn decode error DSA_R_BN_ERROR:109:bn error diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 9bb37e0db8..6c1dc83c19 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -96,6 +96,10 @@ static const ERR_STRING_DATA EVP_str_functs[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN, 0), "EVP_PKEY_paramgen"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN_INIT, 0), "EVP_PKEY_paramgen_init"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAM_CHECK, 0), + "EVP_PKEY_param_check"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PUBLIC_CHECK, 0), + "EVP_PKEY_public_check"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_SET1_ENGINE, 0), "EVP_PKEY_set1_engine"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_SIGN, 0), "EVP_PKEY_sign"}, diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c index 1a927a8320..e14965f333 100644 --- a/crypto/evp/pmeth_gn.c +++ b/crypto/evp/pmeth_gn.c @@ -191,3 +191,49 @@ int EVP_PKEY_check(EVP_PKEY_CTX *ctx) return pkey->ameth->pkey_check(pkey); } + +int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx) +{ + EVP_PKEY *pkey = ctx->pkey; + + if (pkey == NULL) { + EVPerr(EVP_F_EVP_PKEY_PUBLIC_CHECK, EVP_R_NO_KEY_SET); + return 0; + } + + /* call customized public key check function first */ + if (ctx->pmeth->public_check != NULL) + return ctx->pmeth->public_check(pkey); + + /* use default public key check function in ameth */ + if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL) { + EVPerr(EVP_F_EVP_PKEY_PUBLIC_CHECK, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } + + return pkey->ameth->pkey_public_check(pkey); +} + +int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx) +{ + EVP_PKEY *pkey = ctx->pkey; + + if (pkey == NULL) { + EVPerr(EVP_F_EVP_PKEY_PARAM_CHECK, EVP_R_NO_KEY_SET); + return 0; + } + + /* call customized param check function first */ + if (ctx->pmeth->param_check != NULL) + return ctx->pmeth->param_check(pkey); + + /* use default param check function in ameth */ + if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL) { + EVPerr(EVP_F_EVP_PKEY_PARAM_CHECK, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } + + return pkey->ameth->pkey_param_check(pkey); +} diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 37c5e85257..2d9f4fc6dc 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -630,6 +630,18 @@ void EVP_PKEY_meth_set_check(EVP_PKEY_METHOD *pmeth, pmeth->check = check; } +void EVP_PKEY_meth_set_public_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)) +{ + pmeth->public_check = check; +} + +void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)) +{ + pmeth->param_check = check; +} + void EVP_PKEY_meth_get_init(EVP_PKEY_METHOD *pmeth, int (**pinit) (EVP_PKEY_CTX *ctx)) { @@ -803,3 +815,17 @@ void EVP_PKEY_meth_get_check(EVP_PKEY_METHOD *pmeth, if (*pcheck) *pcheck = pmeth->check; } + +void EVP_PKEY_meth_get_public_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)) +{ + if (*pcheck) + *pcheck = pmeth->public_check; +} + +void EVP_PKEY_meth_get_param_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)) +{ + if (*pcheck) + *pcheck = pmeth->param_check; +} diff --git a/crypto/include/internal/asn1_int.h b/crypto/include/internal/asn1_int.h index d8b6f45bd8..90d525aa8d 100644 --- a/crypto/include/internal/asn1_int.h +++ b/crypto/include/internal/asn1_int.h @@ -56,6 +56,8 @@ struct evp_pkey_asn1_method_st { const ASN1_STRING *sig); /* Check */ int (*pkey_check) (const EVP_PKEY *pk); + int (*pkey_public_check) (const EVP_PKEY *pk); + int (*pkey_param_check) (const EVP_PKEY *pk); } /* EVP_PKEY_ASN1_METHOD */ ; DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD) diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index 562ac42ab5..917245c7d4 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -76,6 +76,8 @@ struct evp_pkey_method_st { size_t siglen, const unsigned char *tbs, size_t tbslen); int (*check) (EVP_PKEY *pkey); + int (*public_check) (EVP_PKEY *pkey); + int (*param_check) (EVP_PKEY *pkey); } /* EVP_PKEY_METHOD */ ; DEFINE_STACK_OF_CONST(EVP_PKEY_METHOD) diff --git a/doc/man1/pkey.pod b/doc/man1/pkey.pod index 47ffb6649f..9569fe0e41 100644 --- a/doc/man1/pkey.pod +++ b/doc/man1/pkey.pod @@ -24,6 +24,7 @@ B B [B<-pubout>] [B<-engine id>] [B<-check>] +[B<-pubcheck>] =head1 DESCRIPTION @@ -117,6 +118,11 @@ for all available algorithms. This option checks the consistency of a key pair for both public and private components. +=item B<-pubcheck> + +This option checks the correctness of either a public key or the public component +of a key pair. + =back =head1 EXAMPLES diff --git a/doc/man1/pkeyparam.pod b/doc/man1/pkeyparam.pod index 45c053cf43..117970582d 100644 --- a/doc/man1/pkeyparam.pod +++ b/doc/man1/pkeyparam.pod @@ -14,6 +14,7 @@ B B [B<-text>] [B<-noout>] [B<-engine id>] +[B<-check>] =head1 DESCRIPTION @@ -53,6 +54,10 @@ to attempt to obtain a functional reference to the specified engine, thus initialising it if needed. The engine will then be set as the default for all available algorithms. +=item B<-check> + +This option checks the correctness of parameters. + =back =head1 EXAMPLE diff --git a/doc/man3/DH_generate_parameters.pod b/doc/man3/DH_generate_parameters.pod index 2e8c3b7172..56ad4b12fe 100644 --- a/doc/man3/DH_generate_parameters.pod +++ b/doc/man3/DH_generate_parameters.pod @@ -3,7 +3,9 @@ =head1 NAME DH_generate_parameters_ex, DH_generate_parameters, -DH_check, DH_check_params - generate and check Diffie-Hellman +DH_check, DH_check_params, +DH_check_ex, DH_check_params_ex, DH_check_pub_key_ex +- generate and check Diffie-Hellman parameters =head1 SYNOPSIS @@ -15,6 +17,10 @@ parameters int DH_check(DH *dh, int *codes); int DH_check_params(DH *dh, int *codes); + int DH_check_ex(const DH *dh); + int DH_check_params_ex(const DH *dh); + int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key); + Deprecated: #if OPENSSL_API_COMPAT < 0x00908000L @@ -105,6 +111,11 @@ The parameter B is invalid. =back +DH_check_ex(), DH_check_params() and DH_check_pub_key_ex() are similiar with +DH_check() and DH_check_params() respectively, but the error reasons are set +to the OpenSSL error handling framework instead of returning by the function +parameters. + =head1 RETURN VALUES DH_generate_parameters_ex(), DH_check() and DH_check_params() return 1 @@ -113,6 +124,9 @@ if the check could be performed, 0 otherwise. DH_generate_parameters() returns a pointer to the DH structure or NULL if the parameter generation fails. +DH_check_ex(), DH_check_params() and DH_check_pub_key_ex() return 1 if the +check is successful, 0 for failed. + The error codes can be obtained by L. =head1 SEE ALSO @@ -127,7 +141,7 @@ DH_generate_parameters_ex() instead. =head1 COPYRIGHT -Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved. Licensed under the OpenSSL license (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/EVP_PKEY_ASN1_METHOD.pod b/doc/man3/EVP_PKEY_ASN1_METHOD.pod index 2ebabd10af..cb03b473aa 100644 --- a/doc/man3/EVP_PKEY_ASN1_METHOD.pod +++ b/doc/man3/EVP_PKEY_ASN1_METHOD.pod @@ -16,6 +16,8 @@ EVP_PKEY_asn1_set_ctrl, EVP_PKEY_asn1_set_item, EVP_PKEY_asn1_set_siginf, EVP_PKEY_asn1_set_check, +EVP_PKEY_asn1_set_public_check, +EVP_PKEY_asn1_set_param_check, EVP_PKEY_asn1_set_security_bits, EVP_PKEY_get0_asn1 - manipulating and registering EVP_PKEY_ASN1_METHOD structure @@ -100,6 +102,12 @@ EVP_PKEY_get0_asn1 void EVP_PKEY_asn1_set_check(EVP_PKEY_ASN1_METHOD *ameth, int (*pkey_check) (const EVP_PKEY *pk)); + void EVP_PKEY_asn1_set_public_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_pub_check) (const EVP_PKEY *pk)); + + void EVP_PKEY_asn1_set_param_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_param_check) (const EVP_PKEY *pk)); + void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth, int (*pkey_security_bits) (const EVP_PKEY *pk)); @@ -309,10 +317,15 @@ It's called as part of L, L and L. int (*pkey_check) (const EVP_PKEY *pk); + int (*pkey_public_check) (const EVP_PKEY *pk); + int (*pkey_param_check) (const EVP_PKEY *pk); -The pkey_check() method is used to check the validity of B. -It MUST return 0 for an invalid key, or 1 for a valid key. -It's called by L. +The pkey_check(), pkey_public_check() and pkey_param_check() methods are used +to check the validity of B for key-pair, public component and parameters, +respectively. +They MUST return 0 for an invalid key, or 1 for a valid key. +They are called by L, L and +L respectively. =head2 Functions @@ -354,7 +367,8 @@ when initializing the application. EVP_PKEY_asn1_set_public(), EVP_PKEY_asn1_set_private(), EVP_PKEY_asn1_set_param(), EVP_PKEY_asn1_set_free(), EVP_PKEY_asn1_set_ctrl(), EVP_PKEY_asn1_set_item(), -EVP_PKEY_asn1_set_siginf(), EVP_PKEY_asn1_set_check(), and +EVP_PKEY_asn1_set_siginf(), EVP_PKEY_asn1_set_check(), +EVP_PKEY_asn1_set_public_check(), EVP_PKEY_asn1_set_param_check() and EVP_PKEY_asn1_set_security_bits() set the diverse methods of the given B object. diff --git a/doc/man3/EVP_PKEY_keygen.pod b/doc/man3/EVP_PKEY_keygen.pod index 099cd0cf8f..a18579c09a 100644 --- a/doc/man3/EVP_PKEY_keygen.pod +++ b/doc/man3/EVP_PKEY_keygen.pod @@ -6,7 +6,8 @@ EVP_PKEY_keygen_init, EVP_PKEY_keygen, EVP_PKEY_paramgen_init, EVP_PKEY_paramgen, EVP_PKEY_CTX_set_cb, EVP_PKEY_CTX_get_cb, EVP_PKEY_CTX_get_keygen_info, EVP_PKEY_CTX_set_app_data, EVP_PKEY_CTX_get_app_data, -EVP_PKEY_gen_cb, EVP_PKEY_check +EVP_PKEY_gen_cb, EVP_PKEY_check, EVP_PKEY_public_check, +EVP_PKEY_param_check - key and parameter generation and check functions =head1 SYNOPSIS @@ -29,6 +30,8 @@ EVP_PKEY_gen_cb, EVP_PKEY_check void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx); int EVP_PKEY_check(EVP_PKEY_CTX *ctx); + int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx); + int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx); =head1 DESCRIPTION @@ -64,6 +67,14 @@ EVP_PKEY_check() validates the key-pair given by B. This function first tri to use customized key check method in B if it's present; otherwise it calls a default one defined in B. +EVP_PKEY_public_check() validates the public component of the key-pair given by B. +This function first tries to use customized key check method in B +if it's present; otherwise it calls a default one defined in B. + +EVP_PKEY_param_check() validates the algorithm parameters of the key-pair given by B. +This function first tries to use customized key check method in B +if it's present; otherwise it calls a default one defined in B. + =head1 NOTES After the call to EVP_PKEY_keygen_init() or EVP_PKEY_paramgen_init() algorithm @@ -95,8 +106,9 @@ EVP_PKEY_paramgen() return 1 for success and 0 or a negative value for failure. In particular a return value of -2 indicates the operation is not supported by the public key algorithm. -EVP_PKEY_check() returns 1 for success or others for failure. It -returns -2 if the operation is not supported for the specific algorithm. +EVP_PKEY_check(), EVP_PKEY_public_check() and EVP_PKEY_param_check() return 1 +for success or others for failure. They return -2 if the operation is not supported +for the specific algorithm. =head1 EXAMPLES @@ -178,6 +190,9 @@ L These functions were first added to OpenSSL 1.0.0. +EVP_PKEY_check(), EVP_PKEY_public_check() and EVP_PKEY_param_check() were added +in OpenSSL 1.1.1. + =head1 COPYRIGHT Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/EVP_PKEY_meth_new.pod b/doc/man3/EVP_PKEY_meth_new.pod index 672ac29cb3..918e4fa141 100644 --- a/doc/man3/EVP_PKEY_meth_new.pod +++ b/doc/man3/EVP_PKEY_meth_new.pod @@ -9,11 +9,13 @@ EVP_PKEY_meth_set_paramgen, EVP_PKEY_meth_set_keygen, EVP_PKEY_meth_set_sign, EVP_PKEY_meth_set_verify, EVP_PKEY_meth_set_verify_recover, EVP_PKEY_meth_set_signctx, EVP_PKEY_meth_set_verifyctx, EVP_PKEY_meth_set_encrypt, EVP_PKEY_meth_set_decrypt, EVP_PKEY_meth_set_derive, EVP_PKEY_meth_set_ctrl, EVP_PKEY_meth_set_check, +EVP_PKEY_meth_set_public_check, EVP_PKEY_meth_set_param_check, EVP_PKEY_meth_get_init, EVP_PKEY_meth_get_copy, EVP_PKEY_meth_get_cleanup, EVP_PKEY_meth_get_paramgen, EVP_PKEY_meth_get_keygen, EVP_PKEY_meth_get_sign, EVP_PKEY_meth_get_verify, EVP_PKEY_meth_get_verify_recover, EVP_PKEY_meth_get_signctx, EVP_PKEY_meth_get_verifyctx, EVP_PKEY_meth_get_encrypt, EVP_PKEY_meth_get_decrypt, EVP_PKEY_meth_get_derive, EVP_PKEY_meth_get_ctrl, EVP_PKEY_meth_get_check, +EVP_PKEY_meth_get_public_check, EVP_PKEY_meth_get_param_check, EVP_PKEY_meth_remove - manipulating EVP_PKEY_METHOD structure @@ -110,6 +112,10 @@ EVP_PKEY_meth_remove const char *value)); void EVP_PKEY_meth_set_check(EVP_PKEY_METHOD *pmeth, int (*check) (EVP_PKEY *pkey)); + void EVP_PKEY_meth_set_public_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)); + void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)); void EVP_PKEY_meth_get_init(EVP_PKEY_METHOD *pmeth, int (**pinit) (EVP_PKEY_CTX *ctx)); @@ -191,6 +197,10 @@ EVP_PKEY_meth_remove const char *value)); void EVP_PKEY_meth_get_check(EVP_PKEY_METHOD *pmeth, int (**pcheck) (EVP_PKEY *pkey)); + void EVP_PKEY_meth_get_public_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)); + void EVP_PKEY_meth_get_param_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)); =head1 DESCRIPTION @@ -316,9 +326,13 @@ a signature in a one-shot mode. They could be called by L and L. int (*check) (EVP_PKEY *pkey); + int (*public_check) (EVP_PKEY *pkey); + int (*param_check) (EVP_PKEY *pkey); -The check() method is used to validate a key-pair for a given B. It -could be called by L. +The check(), public_check() and param_check() methods are used to validate a +key-pair, the public component and parameters respectively for a given B. +They could be called by L, L and +L respectively. =head2 Functions diff --git a/include/openssl/dh.h b/include/openssl/dh.h index 753df4e7ae..00858244b8 100644 --- a/include/openssl/dh.h +++ b/include/openssl/dh.h @@ -142,6 +142,9 @@ DEPRECATEDIN_0_9_8(DH *DH_generate_parameters(int prime_len, int generator, int DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb); +int DH_check_params_ex(const DH *dh); +int DH_check_ex(const DH *dh); +int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key); int DH_check_params(const DH *dh, int *ret); int DH_check(const DH *dh, int *codes); int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *codes); diff --git a/include/openssl/dherr.h b/include/openssl/dherr.h index 02039071e8..ddec341d12 100644 --- a/include/openssl/dherr.h +++ b/include/openssl/dherr.h @@ -25,6 +25,9 @@ int ERR_load_DH_strings(void); # define DH_F_COMPUTE_KEY 102 # define DH_F_DHPARAMS_PRINT_FP 101 # define DH_F_DH_BUILTIN_GENPARAMS 106 +# define DH_F_DH_CHECK_EX 121 +# define DH_F_DH_CHECK_PARAMS_EX 122 +# define DH_F_DH_CHECK_PUB_KEY_EX 123 # define DH_F_DH_CMS_DECRYPT 114 # define DH_F_DH_CMS_SET_PEERKEY 115 # define DH_F_DH_CMS_SET_SHARED_INFO 116 @@ -34,6 +37,7 @@ int ERR_load_DH_strings(void); # define DH_F_DH_NEW_BY_NID 104 # define DH_F_DH_NEW_METHOD 105 # define DH_F_DH_PARAM_DECODE 107 +# define DH_F_DH_PKEY_PUBLIC_CHECK 124 # define DH_F_DH_PRIV_DECODE 110 # define DH_F_DH_PRIV_ENCODE 111 # define DH_F_DH_PUB_DECODE 108 @@ -50,17 +54,28 @@ int ERR_load_DH_strings(void); # define DH_R_BAD_GENERATOR 101 # define DH_R_BN_DECODE_ERROR 109 # define DH_R_BN_ERROR 106 +# define DH_R_CHECK_INVALID_J_VALUE 115 +# define DH_R_CHECK_INVALID_Q_VALUE 116 +# define DH_R_CHECK_PUBKEY_INVALID 122 +# define DH_R_CHECK_PUBKEY_TOO_LARGE 123 +# define DH_R_CHECK_PUBKEY_TOO_SMALL 124 +# define DH_R_CHECK_P_NOT_PRIME 117 +# define DH_R_CHECK_P_NOT_SAFE_PRIME 118 +# define DH_R_CHECK_Q_NOT_PRIME 119 # define DH_R_DECODE_ERROR 104 # define DH_R_INVALID_PARAMETER_NAME 110 # define DH_R_INVALID_PARAMETER_NID 114 # define DH_R_INVALID_PUBKEY 102 # define DH_R_KDF_PARAMETER_ERROR 112 # define DH_R_KEYS_NOT_SET 108 +# define DH_R_MISSING_PUBKEY 125 # define DH_R_MODULUS_TOO_LARGE 103 +# define DH_R_NOT_SUITABLE_GENERATOR 120 # define DH_R_NO_PARAMETERS_SET 107 # define DH_R_NO_PRIVATE_VALUE 100 # define DH_R_PARAMETER_ENCODING_ERROR 105 # define DH_R_PEER_KEY_ERROR 111 # define DH_R_SHARED_INFO_ERROR 113 +# define DH_R_UNABLE_TO_CHECK_GENERATOR 121 #endif diff --git a/include/openssl/ecerr.h b/include/openssl/ecerr.h index b04599a8b3..bd09cb7f1b 100644 --- a/include/openssl/ecerr.h +++ b/include/openssl/ecerr.h @@ -126,6 +126,7 @@ int ERR_load_EC_strings(void); # define EC_F_EC_KEY_SIMPLE_OCT2PRIV 259 # define EC_F_EC_KEY_SIMPLE_PRIV2OCT 260 # define EC_F_EC_PKEY_CHECK 273 +# define EC_F_EC_PKEY_PARAM_CHECK 274 # define EC_F_EC_POINTS_MAKE_AFFINE 136 # define EC_F_EC_POINT_ADD 112 # define EC_F_EC_POINT_CMP 113 diff --git a/include/openssl/evp.h b/include/openssl/evp.h index e002d63d24..aaecc1b80a 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1218,6 +1218,12 @@ void EVP_PKEY_asn1_set_siginf(EVP_PKEY_ASN1_METHOD *ameth, void EVP_PKEY_asn1_set_check(EVP_PKEY_ASN1_METHOD *ameth, int (*pkey_check) (const EVP_PKEY *pk)); +void EVP_PKEY_asn1_set_public_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_pub_check) (const EVP_PKEY *pk)); + +void EVP_PKEY_asn1_set_param_check(EVP_PKEY_ASN1_METHOD *ameth, + int (*pkey_param_check) (const EVP_PKEY *pk)); + void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth, int (*pkey_security_bits) (const EVP_PKEY *pk)); @@ -1367,6 +1373,8 @@ int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); int EVP_PKEY_check(EVP_PKEY_CTX *ctx); +int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx); +int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx); void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb); EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx); @@ -1468,6 +1476,12 @@ void EVP_PKEY_meth_set_ctrl(EVP_PKEY_METHOD *pmeth, void EVP_PKEY_meth_set_check(EVP_PKEY_METHOD *pmeth, int (*check) (EVP_PKEY *pkey)); +void EVP_PKEY_meth_set_public_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)); + +void EVP_PKEY_meth_set_param_check(EVP_PKEY_METHOD *pmeth, + int (*check) (EVP_PKEY *pkey)); + void EVP_PKEY_meth_get_init(EVP_PKEY_METHOD *pmeth, int (**pinit) (EVP_PKEY_CTX *ctx)); @@ -1563,6 +1577,12 @@ void EVP_PKEY_meth_get_ctrl(EVP_PKEY_METHOD *pmeth, void EVP_PKEY_meth_get_check(EVP_PKEY_METHOD *pmeth, int (**pcheck) (EVP_PKEY *pkey)); +void EVP_PKEY_meth_get_public_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)); + +void EVP_PKEY_meth_get_param_check(EVP_PKEY_METHOD *pmeth, + int (**pcheck) (EVP_PKEY *pkey)); + void EVP_add_alg_module(void); int ERR_load_EVP_strings(void); diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index a7a46ae9d9..a870e438dd 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -83,6 +83,8 @@ int ERR_load_EVP_strings(void); # define EVP_F_EVP_PKEY_NEW 106 # define EVP_F_EVP_PKEY_PARAMGEN 148 # define EVP_F_EVP_PKEY_PARAMGEN_INIT 149 +# define EVP_F_EVP_PKEY_PARAM_CHECK 189 +# define EVP_F_EVP_PKEY_PUBLIC_CHECK 190 # define EVP_F_EVP_PKEY_SET1_ENGINE 187 # define EVP_F_EVP_PKEY_SIGN 140 # define EVP_F_EVP_PKEY_SIGN_INIT 141 diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index f49ca80bf7..1e1fa171d3 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -283,6 +283,22 @@ static const unsigned char kExampleBadECKeyDER[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 }; + +/* prime256v1 */ +static const unsigned char kExampleECPubKeyDER[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xba, 0xeb, 0x83, 0xfb, 0x3b, 0xb2, 0xff, 0x30, 0x53, + 0xdb, 0xce, 0x32, 0xf2, 0xac, 0xae, 0x44, 0x0d, 0x3d, 0x13, 0x53, 0xb8, + 0xd1, 0x68, 0x55, 0xde, 0x44, 0x46, 0x05, 0xa6, 0xc9, 0xd2, 0x04, 0xb7, + 0xe3, 0xa2, 0x96, 0xc8, 0xb2, 0x5e, 0x22, 0x03, 0xd7, 0x03, 0x7a, 0x8b, + 0x13, 0x5c, 0x42, 0x49, 0xc2, 0xab, 0x86, 0xd6, 0xac, 0x6b, 0x93, 0x20, + 0x56, 0x6a, 0xc6, 0xc8, 0xa5, 0x0b, 0xe5 +}; + +static const unsigned char pExampleECParamDER[] = { + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 +}; #endif typedef struct APK_DATA_st { @@ -290,6 +306,9 @@ typedef struct APK_DATA_st { size_t size; int evptype; int check; + int pub_check; + int param_check; + int type; /* 0 for private, 1 for public, 2 for params */ } APK_DATA; static APK_DATA keydata[] = { @@ -301,10 +320,14 @@ static APK_DATA keydata[] = { }; static APK_DATA keycheckdata[] = { - {kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER), EVP_PKEY_RSA, 1}, - {kExampleBadRSAKeyDER, sizeof(kExampleBadRSAKeyDER), EVP_PKEY_RSA, 0}, + {kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER), EVP_PKEY_RSA, 1, -2, -2, 0}, + {kExampleBadRSAKeyDER, sizeof(kExampleBadRSAKeyDER), EVP_PKEY_RSA, + 0, -2, -2, 0}, #ifndef OPENSSL_NO_EC - {kExampleECKeyDER, sizeof(kExampleECKeyDER), EVP_PKEY_EC, 1} + {kExampleECKeyDER, sizeof(kExampleECKeyDER), EVP_PKEY_EC, 1, 1, 1, 0}, + /* group is also associated in our pub key */ + {kExampleECPubKeyDER, sizeof(kExampleECPubKeyDER), EVP_PKEY_EC, 0, 1, 1, 1}, + {pExampleECParamDER, sizeof(pExampleECParamDER), EVP_PKEY_EC, 0, 0, 1, 2} #endif }; @@ -458,6 +481,16 @@ static int pkey_custom_check(EVP_PKEY *pkey) return 0xbeef; } +static int pkey_custom_pub_check(EVP_PKEY *pkey) +{ + return 0xbeef; +} + +static int pkey_custom_param_check(EVP_PKEY *pkey) +{ + return 0xbeef; +} + static EVP_PKEY_METHOD *custom_pmeth; static int test_EVP_PKEY_check(int i) @@ -465,6 +498,7 @@ static int test_EVP_PKEY_check(int i) int ret = 0; const unsigned char *p; EVP_PKEY *pkey = NULL; + EC_KEY *eckey = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY_CTX *ctx2 = NULL; const APK_DATA *ak = &keycheckdata[i]; @@ -472,23 +506,44 @@ static int test_EVP_PKEY_check(int i) size_t input_len = ak->size; int expected_id = ak->evptype; int expected_check = ak->check; + int expected_pub_check = ak->pub_check; + int expected_param_check = ak->param_check; + int type = ak->type; + BIO *pubkey = NULL; p = input; - if (!TEST_ptr(pkey = d2i_AutoPrivateKey(NULL, &p, input_len)) - || !TEST_ptr_eq(p, input + input_len) - || !TEST_int_eq(EVP_PKEY_id(pkey), expected_id)) + + if (type == 0 && + (!TEST_ptr(pkey = d2i_AutoPrivateKey(NULL, &p, input_len)) + || !TEST_ptr_eq(p, input + input_len) + || !TEST_int_eq(EVP_PKEY_id(pkey), expected_id))) + goto done; + + if (type == 1 && + (!TEST_ptr(pubkey = BIO_new_mem_buf(input, input_len)) + || !TEST_ptr(eckey = d2i_EC_PUBKEY_bio(pubkey, NULL)) + || !TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_true(EVP_PKEY_assign_EC_KEY(pkey, eckey)))) + goto done; + + if (type == 2 && + (!TEST_ptr(eckey = d2i_ECParameters(NULL, &p, input_len)) + || !TEST_ptr_eq(p, input + input_len) + || !TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_true(EVP_PKEY_assign_EC_KEY(pkey, eckey)))) goto done; if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, NULL))) goto done; - if (expected_check == 1) { - if (!TEST_int_eq(EVP_PKEY_check(ctx), 1)) - goto done; - } else { - if (!TEST_int_ne(EVP_PKEY_check(ctx), 1)) - goto done; - } + if (!TEST_int_eq(EVP_PKEY_check(ctx), expected_check)) + goto done; + + if (!TEST_int_eq(EVP_PKEY_public_check(ctx), expected_pub_check)) + goto done; + + if (!TEST_int_eq(EVP_PKEY_param_check(ctx), expected_param_check)) + goto done; ctx2 = EVP_PKEY_CTX_new_id(0xdefaced, NULL); /* assign the pkey directly, as an internal test */ @@ -498,12 +553,19 @@ static int test_EVP_PKEY_check(int i) if (!TEST_int_eq(EVP_PKEY_check(ctx2), 0xbeef)) goto done; + if (!TEST_int_eq(EVP_PKEY_public_check(ctx2), 0xbeef)) + goto done; + + if (!TEST_int_eq(EVP_PKEY_param_check(ctx2), 0xbeef)) + goto done; + ret = 1; done: EVP_PKEY_CTX_free(ctx); EVP_PKEY_CTX_free(ctx2); EVP_PKEY_free(pkey); + BIO_free(pubkey); return ret; } @@ -519,6 +581,8 @@ int setup_tests(void) if (!TEST_ptr(custom_pmeth)) return 0; EVP_PKEY_meth_set_check(custom_pmeth, pkey_custom_check); + EVP_PKEY_meth_set_public_check(custom_pmeth, pkey_custom_pub_check); + EVP_PKEY_meth_set_param_check(custom_pmeth, pkey_custom_param_check); if (!TEST_int_eq(EVP_PKEY_meth_add0(custom_pmeth), 1)) return 0; ADD_ALL_TESTS(test_EVP_PKEY_check, OSSL_NELEM(keycheckdata)); diff --git a/util/libcrypto.num b/util/libcrypto.num index 100e71f965..8d9db312a6 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4427,3 +4427,14 @@ EVP_sm4_ecb 4371 1_1_1 EXIST::FUNCTION:SM4 EVP_sm4_cfb128 4372 1_1_1 EXIST::FUNCTION:SM4 EVP_sm3 4373 1_1_1 EXIST::FUNCTION:SM3 OCSP_resp_get0_signer 4374 1_1_0h EXIST::FUNCTION:OCSP +EVP_PKEY_public_check 4375 1_1_1 EXIST::FUNCTION: +EVP_PKEY_param_check 4376 1_1_1 EXIST::FUNCTION: +EVP_PKEY_meth_set_public_check 4377 1_1_1 EXIST::FUNCTION: +EVP_PKEY_meth_set_param_check 4378 1_1_1 EXIST::FUNCTION: +EVP_PKEY_meth_get_public_check 4379 1_1_1 EXIST::FUNCTION: +EVP_PKEY_meth_get_param_check 4380 1_1_1 EXIST::FUNCTION: +EVP_PKEY_asn1_set_public_check 4381 1_1_1 EXIST::FUNCTION: +EVP_PKEY_asn1_set_param_check 4382 1_1_1 EXIST::FUNCTION: +DH_check_ex 4383 1_1_1 EXIST::FUNCTION:DH +DH_check_pub_key_ex 4384 1_1_1 EXIST::FUNCTION:DH +DH_check_params_ex 4385 1_1_1 EXIST::FUNCTION:DH -- 2.39.5