commit 2c3ef499bfffce3cfd315edeebf202850ba4e00a Author: Jakub Jelen Date: Tue Apr 16 15:35:18 2019 +0200 Use the new OpenSSL KDF diff --git a/configure.ac b/configure.ac index 2a455e4e..e01c3d43 100644 --- a/configure.ac +++ b/configure.ac @@ -2712,6 +2712,7 @@ if test "x$openssl" = "xyes" ; then HMAC_CTX_init \ RSA_generate_key_ex \ RSA_get_default_method \ + EVP_KDF_CTX_new \ ]) # OpenSSL_add_all_algorithms may be a macro. diff --git a/kex.c b/kex.c index b6f041f4..1fbce2bb 100644 --- a/kex.c +++ b/kex.c @@ -38,6 +38,11 @@ #ifdef WITH_OPENSSL #include #include +# ifdef HAVE_EVP_KDF_CTX_NEW +# include +# include +# include +# endif #endif #include "ssh.h" @@ -942,6 +945,112 @@ kex_choose_conf(struct ssh *ssh) return r; } +#ifdef HAVE_EVP_KDF_CTX_NEW +static const char * +digest_to_md(int digest_type) +{ + switch (digest_type) { + case SSH_DIGEST_SHA1: + return SN_sha1; + case SSH_DIGEST_SHA256: + return SN_sha256; + case SSH_DIGEST_SHA384: + return SN_sha384; + case SSH_DIGEST_SHA512: + return SN_sha512; + } + return NULL; +} + +static int +derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + const struct sshbuf *shared_secret, u_char **keyp) +{ + struct kex *kex = ssh->kex; + u_char *key = NULL; + int r, key_len; + + EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL); + EVP_KDF_CTX *ctx = NULL; + OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new(); + OSSL_PARAM *params = NULL; + const char *md = digest_to_md(kex->hash_alg); + char keytype = (char)id; + + if (!kdf) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + ctx = EVP_KDF_CTX_new(kdf); + EVP_KDF_free(kdf); + if (!ctx) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (md == NULL) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + + if (param_bld == NULL) { + EVP_KDF_CTX_free(ctx); + return -1; + } + if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + + key_len = ROUNDUP(need, key_len); + if ((key = calloc(1, key_len)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + r = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST, + md, strlen(md)) && /* SN */ + OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY, + sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)) && + OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_XCGHASH, + hash, hashlen) && + OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_SESSION_ID, + sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)) && + OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE, + &keytype, 1); + if (r != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (params == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + r = EVP_KDF_derive(ctx, key, key_len, params); + if (r != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +#ifdef DEBUG_KEX + fprintf(stderr, "key '%c'== ", id); + dump_digest("key", key, key_len); +#endif + *keyp = key; + key = NULL; + r = 0; + +out: + OSSL_PARAM_BLD_free(param_bld); + OSSL_PARAM_free(params); + free (key); + EVP_KDF_CTX_free(ctx); + if (r < 0) { + return r; + } + return 0; +} +#else static int derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, const struct sshbuf *shared_secret, u_char **keyp) @@ -1004,6 +1096,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, ssh_digest_free(hashctx); return r; } +#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW */ #define NKEYS 6 int