Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Using EVP_PKEY in OpenSSH #445

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
AC_INIT([OpenSSH],[Portable],[openssh-unix-dev@mindrot.org])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([ssh.c])

Expand Down
103 changes: 103 additions & 0 deletions dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@

#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
#include <openssl/core_names.h>
#include <openssl/param_build.h>
#endif

#include "dh.h"
#include "pathnames.h"
Expand Down Expand Up @@ -283,6 +288,103 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub)
int
dh_gen_key(DH *dh, int need)
{
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are just going to switch over to EVP_PKEY, this should be possible without wholesale code duplication for OpenSSL 3.0 - The EVP_pkey interface isn't significantly different between 1.1.1 and 3.0.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think as a first step you should separate out all the OpenSSL 3.0 stuff from this, and make a PR that ONLY converts to the EVP_PKEY API with the LibreSSL (1.1.1) api.

const BIGNUM *dh_p, *dh_g;
BIGNUM *pub_key = NULL, *priv_key = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
OSSL_PARAM_BLD *param_bld = NULL;
OSSL_PARAM *params = NULL;
int pbits, r = 0;

DH_get0_pqg(dh, &dh_p, NULL, &dh_g);

if (need < 0 || dh_p == NULL ||
(pbits = BN_num_bits(dh_p)) <= 0 ||
need > INT_MAX / 2 || 2 * need > pbits)
return SSH_ERR_INVALID_ARGUMENT;
if (need < 256)
need = 256;

if ((param_bld = OSSL_PARAM_BLD_new()) == NULL ||
(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) {
OSSL_PARAM_BLD_free(param_bld);
return SSH_ERR_ALLOC_FAIL;
}

if (OSSL_PARAM_BLD_push_BN(param_bld,
OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 ||
OSSL_PARAM_BLD_push_BN(param_bld,
OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) {
error_f("Could not set p,q,g parameters");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
/*
* Pollard Rho, Big step/Little Step attacks are O(sqrt(n)),
* so double requested need here.
*/
if (OSSL_PARAM_BLD_push_int(param_bld,
OSSL_PKEY_PARAM_DH_PRIV_LEN,
MINIMUM(need * 2, pbits - 1)) != 1 ||
(params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (EVP_PKEY_fromdata_init(ctx) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (EVP_PKEY_fromdata(ctx, &pkey,
EVP_PKEY_KEY_PARAMETERS, params) != 1) {
error_f("Failed key generation");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}

/* reuse context for key generation */
EVP_PKEY_CTX_free(ctx);
ctx = NULL;

if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL ||
EVP_PKEY_keygen_init(ctx) != 1) {
error_f("Could not create or init context");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (EVP_PKEY_generate(ctx, &pkey) != 1) {
error_f("Could not generate keys");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if (EVP_PKEY_public_check(ctx) != 1) {
error_f("The public key is incorrect");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}

if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
&pub_key) != 1 ||
EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
&priv_key) != 1 ||
DH_set0_key(dh, pub_key, priv_key) != 1) {
error_f("Could not set pub/priv keys to DH struct");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}

/* transferred */
pub_key = NULL;
priv_key = NULL;
out:
OSSL_PARAM_free(params);
OSSL_PARAM_BLD_free(param_bld);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
BN_clear_free(pub_key);
BN_clear_free(priv_key);
return r;
#else
int pbits;
const BIGNUM *dh_p, *pub_key;

Expand All @@ -307,6 +409,7 @@ dh_gen_key(DH *dh, int need)
if (!dh_pub_is_valid(dh, pub_key))
return SSH_ERR_INVALID_FORMAT;
return 0;
#endif
}

DH *
Expand Down
16 changes: 16 additions & 0 deletions digest-openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ const struct ssh_digest digests[] = {
{ -1, NULL, 0, NULL },
};

const EVP_MD *
ssh_digest_to_md(int digest_type)
{
switch (digest_type) {
case SSH_DIGEST_SHA1:
return EVP_sha1();
case SSH_DIGEST_SHA256:
return EVP_sha256();
case SSH_DIGEST_SHA384:
return EVP_sha384();
case SSH_DIGEST_SHA512:
return EVP_sha512();
}
return NULL;
}

static const struct ssh_digest *
ssh_digest_by_alg(int alg)
{
Expand Down
6 changes: 6 additions & 0 deletions digest.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
struct sshbuf;
struct ssh_digest_ctx;

#ifdef WITH_OPENSSL
#include <openssl/evp.h>
/* Converts internal digest representation to the OpenSSL one */
const EVP_MD *ssh_digest_to_md(int digest_type);
#endif

/* Looks up a digest algorithm by name */
int ssh_digest_alg_by_name(const char *name);

Expand Down
4 changes: 1 addition & 3 deletions kex.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,9 +784,7 @@ kex_free(struct kex *kex)

#ifdef WITH_OPENSSL
DH_free(kex->dh);
#ifdef OPENSSL_HAS_ECC
EC_KEY_free(kex->ec_client_key);
#endif /* OPENSSL_HAS_ECC */
EVP_PKEY_free(kex->pkey);
#endif /* WITH_OPENSSL */
for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(kex->newkeys[mode]);
Expand Down
25 changes: 7 additions & 18 deletions kex.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,15 @@
# include <openssl/bn.h>
# include <openssl/dh.h>
# include <openssl/ecdsa.h>
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# else /* OPENSSL_HAS_ECC */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
# endif /* OPENSSL_HAS_ECC */
# include <openssl/evp.h>
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
# include <openssl/core_names.h>
# include <openssl/param_build.h>
#endif
#else /* WITH_OPENSSL */
# define DH void
# define BIGNUM void
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
# define EVP_PKEY void
#endif /* WITH_OPENSSL */

#define KEX_COOKIE_LEN 16
Expand Down Expand Up @@ -171,8 +167,7 @@ struct kex {
/* kex specific state */
DH *dh; /* DH */
u_int min, max, nbits; /* GEX */
EC_KEY *ec_client_key; /* ECDH */
const EC_GROUP *ec_group; /* ECDH */
EVP_PKEY *pkey; /* ECDH */
u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 + KEM */
u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */
u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */
Expand Down Expand Up @@ -261,10 +256,4 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
void dump_digest(const char *, const u_char *, int);
#endif

#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC)
# undef EC_KEY
# undef EC_GROUP
# undef EC_POINT
#endif

#endif
Loading
Loading