From: Shane Lontis Date: Mon, 27 May 2019 11:52:37 +0000 (+1000) Subject: Add d2i_KeyParams/i2d_KeyParams API's. X-Git-Tag: openssl-3.0.0-alpha1~2029 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=6aa2e59e1c52761cc5ad60170106118d7c1aa090;p=oweals%2Fopenssl.git Add d2i_KeyParams/i2d_KeyParams API's. Convert EVP_PKEY Parameters to/from binary. This wraps the low level i2d/d2i calls for DH,DSA and EC key parameters in a similar way to Public and Private Keys. The API's can be used by applications (including openssl apps) that only want to use EVP_PKEY without needing to access low level key API's. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/8903) --- diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 7fe46edfd0..0e1edc773a 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 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 @@ -107,6 +107,7 @@ static const ERR_STRING_DATA ASN1_str_functs[] = { {ERR_PACK(ERR_LIB_ASN1, ASN1_F_D2I_ASN1_UINTEGER, 0), "d2i_ASN1_UINTEGER"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_D2I_AUTOPRIVATEKEY, 0), "d2i_AutoPrivateKey"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_D2I_KEYPARAMS, 0), "d2i_KeyParams"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_D2I_PRIVATEKEY, 0), "d2i_PrivateKey"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_D2I_PUBLICKEY, 0), "d2i_PublicKey"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_DO_BUF, 0), "do_buf"}, @@ -119,6 +120,7 @@ static const ERR_STRING_DATA ASN1_str_functs[] = { {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_ASN1_OBJECT, 0), "i2d_ASN1_OBJECT"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_DSA_PUBKEY, 0), "i2d_DSA_PUBKEY"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_EC_PUBKEY, 0), "i2d_EC_PUBKEY"}, + {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_KEYPARAMS, 0), "i2d_KeyParams"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_PRIVATEKEY, 0), "i2d_PrivateKey"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_PUBLICKEY, 0), "i2d_PublicKey"}, {ERR_PACK(ERR_LIB_ASN1, ASN1_F_I2D_RSA_PUBKEY, 0), "i2d_RSA_PUBKEY"}, diff --git a/crypto/asn1/build.info b/crypto/asn1/build.info index d3e92c81ac..32fdaaa1a9 100644 --- a/crypto/asn1/build.info +++ b/crypto/asn1/build.info @@ -13,4 +13,5 @@ SOURCE[../../libcrypto]=\ x_pkey.c bio_asn1.c bio_ndef.c asn_mime.c \ asn1_gen.c asn1_par.c asn1_lib.c asn1_err.c a_strnid.c \ evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p5_scrypt.c p8_pkey.c \ - asn_moid.c asn_mstbl.c asn1_item_list.c + asn_moid.c asn_mstbl.c asn1_item_list.c \ + d2i_param.c i2d_param.c diff --git a/crypto/asn1/d2i_param.c b/crypto/asn1/d2i_param.c new file mode 100644 index 0000000000..e852470a66 --- /dev/null +++ b/crypto/asn1/d2i_param.c @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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 +#include "internal/cryptlib.h" +#include +#include +#include "internal/evp_int.h" +#include "internal/asn1_int.h" + +EVP_PKEY *d2i_KeyParams(int type, EVP_PKEY **a, const unsigned char **pp, + long length) +{ + EVP_PKEY *ret = NULL; + const unsigned char *p = *pp; + + if ((a == NULL) || (*a == NULL)) { + if ((ret = EVP_PKEY_new()) == NULL) + return NULL; + } else + ret = *a; + + if (type != EVP_PKEY_id(ret) && !EVP_PKEY_set_type(ret, type)) + goto err; + + if (ret->ameth == NULL || ret->ameth->param_decode == NULL) { + ASN1err(ASN1_F_D2I_KEYPARAMS, ASN1_R_UNSUPPORTED_TYPE); + goto err; + } + + if (!ret->ameth->param_decode(ret, &p, length)) + goto err; + + if (a != NULL) + (*a) = ret; + return ret; +err: + if (a == NULL || *a != ret) + EVP_PKEY_free(ret); + return NULL; +} + +EVP_PKEY *d2i_KeyParams_bio(int type, EVP_PKEY **a, BIO *in) +{ + BUF_MEM *b = NULL; + const unsigned char *p; + void *ret = NULL; + int len; + + len = asn1_d2i_read_bio(in, &b); + if (len < 0) + goto err; + + p = (unsigned char *)b->data; + ret = d2i_KeyParams(type, a, &p, len); +err: + BUF_MEM_free(b); + return ret; +} diff --git a/crypto/asn1/i2d_param.c b/crypto/asn1/i2d_param.c new file mode 100644 index 0000000000..2e9000891a --- /dev/null +++ b/crypto/asn1/i2d_param.c @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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 +#include "internal/cryptlib.h" +#include +#include +#include +#include "internal/asn1_int.h" +#include "internal/evp_int.h" + +int i2d_KeyParams(const EVP_PKEY *a, unsigned char **pp) +{ + if (a->ameth != NULL && a->ameth->param_encode != NULL) + return a->ameth->param_encode(a, pp); + ASN1err(ASN1_F_I2D_KEYPARAMS, ASN1_R_UNSUPPORTED_TYPE); + return -1; +} + +int i2d_KeyParams_bio(BIO *bp, const EVP_PKEY *pkey) +{ + return ASN1_i2d_bio_of(EVP_PKEY, i2d_KeyParams, bp, pkey); +} + diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index eee3092385..46a1f88ddc 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -80,6 +80,7 @@ ASN1_F_COLLECT_DATA:140:collect_data ASN1_F_D2I_ASN1_OBJECT:147:d2i_ASN1_OBJECT ASN1_F_D2I_ASN1_UINTEGER:150:d2i_ASN1_UINTEGER ASN1_F_D2I_AUTOPRIVATEKEY:207:d2i_AutoPrivateKey +ASN1_F_D2I_KEYPARAMS:144:d2i_KeyParams ASN1_F_D2I_PRIVATEKEY:154:d2i_PrivateKey ASN1_F_D2I_PUBLICKEY:155:d2i_PublicKey ASN1_F_DO_BUF:142:do_buf @@ -91,6 +92,7 @@ ASN1_F_I2D_ASN1_BIO_STREAM:211:i2d_ASN1_bio_stream ASN1_F_I2D_ASN1_OBJECT:143:i2d_ASN1_OBJECT ASN1_F_I2D_DSA_PUBKEY:161:i2d_DSA_PUBKEY ASN1_F_I2D_EC_PUBKEY:181:i2d_EC_PUBKEY +ASN1_F_I2D_KEYPARAMS:145:i2d_KeyParams ASN1_F_I2D_PRIVATEKEY:163:i2d_PrivateKey ASN1_F_I2D_PUBLICKEY:164:i2d_PublicKey ASN1_F_I2D_RSA_PUBKEY:165:i2d_RSA_PUBKEY diff --git a/doc/man3/d2i_PrivateKey.pod b/doc/man3/d2i_PrivateKey.pod index 0bce594d37..dc3618eb53 100644 --- a/doc/man3/d2i_PrivateKey.pod +++ b/doc/man3/d2i_PrivateKey.pod @@ -2,9 +2,9 @@ =head1 NAME -d2i_PrivateKey, d2i_PublicKey, d2i_AutoPrivateKey, -i2d_PrivateKey, i2d_PublicKey, -d2i_PrivateKey_bio, d2i_PrivateKey_fp +d2i_PrivateKey, d2i_PublicKey, d2i_KeyParams, d2i_AutoPrivateKey, +i2d_PrivateKey, i2d_PublicKey, i2d_KeyParams, i2d_KeyParams_bio, +d2i_PrivateKey_bio, d2i_PrivateKey_fp, d2i_KeyParams_bio - decode and encode functions for reading and saving EVP_PKEY structures =head1 SYNOPSIS @@ -15,13 +15,19 @@ d2i_PrivateKey_bio, d2i_PrivateKey_fp long length); EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, long length); + EVP_PKEY *d2i_KeyParams(int type, EVP_PKEY **a, const unsigned char **pp, + long length); EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, long length); + int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp); int i2d_PublicKey(const EVP_PKEY *a, unsigned char **pp); + int i2d_KeyParams(const EVP_PKEY *a, unsigned char **pp); + int i2d_KeyParams_bio(BIO *bp, const EVP_PKEY *pkey); EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) + EVP_PKEY *d2i_KeyParams_bio(int type, EVP_PKEY **a, BIO *in); =head1 DESCRIPTION @@ -30,6 +36,7 @@ use any key specific format or PKCS#8 unencrypted PrivateKeyInfo format. The B parameter should be a public key algorithm constant such as B. An error occurs if the decoded key does not match B. d2i_PublicKey() does the same for public keys. +d2i_KeyParams() does the same for domain parameter keys. d2i_AutoPrivateKey() is similar to d2i_PrivateKey() except it attempts to automatically detect the private key format. @@ -37,7 +44,7 @@ automatically detect the private key format. i2d_PrivateKey() encodes B. It uses a key specific format or, if none is defined for that key type, PKCS#8 unencrypted PrivateKeyInfo format. i2d_PublicKey() does the same for public keys. - +i2d_KeyParams() does the same for domain parameter keys. These functions are similar to the d2i_X509() functions; see L. =head1 NOTES @@ -57,12 +64,13 @@ EC_GROUP. =head1 RETURN VALUES The d2i_PrivateKey(), d2i_AutoPrivateKey(), d2i_PrivateKey_bio(), d2i_PrivateKey_fp(), -and d2i_PublicKey() functions return a valid B structure or B if an -error occurs. The error code can be obtained by calling L. +d2i_PublicKey(), d2i_KeyParams() and d2i_KeyParams_bio() functions return a valid +B structure or B if an error occurs. The error code can be +obtained by calling L. -i2d_PrivateKey() and i2d_PublicKey() return the number of bytes successfully -encoded or a negative value if an error occurs. The error code can be obtained -by calling L. +i2d_PrivateKey(), i2d_PublicKey(), i2d_KeyParams() i2d_KeyParams_bio() return +the number of bytes successfully encoded or a negative value if an error occurs. +The error code can be obtained by calling L. =head1 SEE ALSO diff --git a/include/openssl/asn1err.h b/include/openssl/asn1err.h index 97e9d0518b..2ae486f1f3 100644 --- a/include/openssl/asn1err.h +++ b/include/openssl/asn1err.h @@ -97,6 +97,7 @@ int ERR_load_ASN1_strings(void); # define ASN1_F_D2I_ASN1_OBJECT 147 # define ASN1_F_D2I_ASN1_UINTEGER 150 # define ASN1_F_D2I_AUTOPRIVATEKEY 207 +# define ASN1_F_D2I_KEYPARAMS 144 # define ASN1_F_D2I_PRIVATEKEY 154 # define ASN1_F_D2I_PUBLICKEY 155 # define ASN1_F_DO_BUF 142 @@ -108,6 +109,7 @@ int ERR_load_ASN1_strings(void); # define ASN1_F_I2D_ASN1_OBJECT 143 # define ASN1_F_I2D_DSA_PUBKEY 161 # define ASN1_F_I2D_EC_PUBKEY 181 +# define ASN1_F_I2D_KEYPARAMS 145 # define ASN1_F_I2D_PRIVATEKEY 163 # define ASN1_F_I2D_PUBLICKEY 164 # define ASN1_F_I2D_RSA_PUBKEY 165 diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 6fc0f35114..593753cb27 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1115,6 +1115,12 @@ EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, long length); int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp); +int i2d_KeyParams(const EVP_PKEY *a, unsigned char **pp); +EVP_PKEY *d2i_KeyParams(int type, EVP_PKEY **a, const unsigned char **pp, + long length); +int i2d_KeyParams_bio(BIO *bp, const EVP_PKEY *pkey); +EVP_PKEY *d2i_KeyParams_bio(int type, EVP_PKEY **a, BIO *in); + int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode); diff --git a/test/build.info b/test/build.info index 5d8448ff87..fa3c1f1ea6 100644 --- a/test/build.info +++ b/test/build.info @@ -50,7 +50,7 @@ IF[{- !$disabled{tests} -}] time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \ sysdefaulttest errtest gosttest \ - context_internal_test aesgcmtest params_test + context_internal_test aesgcmtest params_test evp_pkey_dparams_test SOURCE[versions]=versions.c INCLUDE[versions]=../include ../apps/include @@ -350,6 +350,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[evp_kdf_test]=../include ../apps/include DEPEND[evp_kdf_test]=../libcrypto libtestutil.a + SOURCE[evp_pkey_dparams_test]=evp_pkey_dparams_test.c + INCLUDE[evp_pkey_dparams_test]=../include ../apps/include + DEPEND[evp_pkey_dparams_test]=../libcrypto libtestutil.a + SOURCE[x509_time_test]=x509_time_test.c INCLUDE[x509_time_test]=../include ../apps/include DEPEND[x509_time_test]=../libcrypto libtestutil.a diff --git a/test/evp_pkey_dparams_test.c b/test/evp_pkey_dparams_test.c new file mode 100644 index 0000000000..30da6ed8b1 --- /dev/null +++ b/test/evp_pkey_dparams_test.c @@ -0,0 +1,73 @@ +/* + * Copyright 2019 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 +#include +#include + +#include "internal/nelem.h" +#include +#include +#include +#include +#include +#include +#include +#include "testutil.h" + +static int pkey_param_types[] = { +#ifndef OPENSSL_NO_DH + EVP_PKEY_DH, +#endif +#ifndef OPENSSL_NO_DSA + EVP_PKEY_DSA, +#endif +#ifndef OPENSSL_NO_EC + EVP_PKEY_EC +#endif +}; + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC) + +static int params_bio_test(int id) +{ + int ret; + BIO *mem_bio = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *params_key = NULL, *out_key = NULL; + int type = pkey_param_types[id]; + + ret = + TEST_ptr(mem_bio = BIO_new(BIO_s_mem())) + && TEST_ptr(ctx = EVP_PKEY_CTX_new_id(type, NULL)) + && TEST_int_gt(EVP_PKEY_paramgen_init(ctx), 0) + && (type != EVP_PKEY_EC + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_secp256k1) > 0) + && TEST_int_gt(EVP_PKEY_paramgen(ctx, ¶ms_key), 0) + && TEST_int_gt(i2d_KeyParams_bio(mem_bio, params_key), 0) + && TEST_ptr(d2i_KeyParams_bio(type, &out_key, mem_bio)) + && TEST_int_gt(EVP_PKEY_cmp_parameters(out_key, params_key), 0); + + BIO_free(mem_bio); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(params_key); + EVP_PKEY_free(out_key); + return ret; +} +#endif + +int setup_tests(void) +{ +#if defined(OPENSSL_NO_DH) && defined(OPENSSL_NO_DSA) && defined(OPENSSL_NO_EC) + TEST_note("No DH/DSA/EC support"); +#else + ADD_ALL_TESTS(params_bio_test, OSSL_NELEM(pkey_param_types)); +#endif + return 1; +} diff --git a/test/recipes/30-test_evp_pkey_dparam.t b/test/recipes/30-test_evp_pkey_dparam.t new file mode 100644 index 0000000000..647413ecdf --- /dev/null +++ b/test/recipes/30-test_evp_pkey_dparam.t @@ -0,0 +1,11 @@ +#! /usr/bin/env perl +# Copyright 2019 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 + +use OpenSSL::Test::Simple; + +simple_test("test_evp_pkey_dparam", "evp_pkey_dparams_test"); diff --git a/util/libcrypto.num b/util/libcrypto.num index 34d4d846a7..8af98dff3c 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4804,3 +4804,7 @@ EVP_KDF_CTX_new 4751 3_0_0 EXIST::FUNCTION: EVP_KDF_CTX_kdf 4752 3_0_0 EXIST::FUNCTION: EVP_KDF_nid 4753 3_0_0 EXIST::FUNCTION: EVP_get_kdfbyname 4754 3_0_0 EXIST::FUNCTION: +i2d_KeyParams 4755 3_0_0 EXIST::FUNCTION: +d2i_KeyParams 4756 3_0_0 EXIST::FUNCTION: +i2d_KeyParams_bio 4757 3_0_0 EXIST::FUNCTION: +d2i_KeyParams_bio 4758 3_0_0 EXIST::FUNCTION: