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