aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.c2
-rw-r--r--src/dh.c26
-rw-r--r--src/ecdh_crypto.c33
-rw-r--r--src/ecdh_gcrypt.c59
-rw-r--r--src/kex.c6
-rw-r--r--src/packet_cb.c2
-rw-r--r--src/server.c2
-rw-r--r--src/session.c4
8 files changed, 124 insertions, 10 deletions
diff --git a/src/client.c b/src/client.c
index 3b120bbc..11a00229 100644
--- a/src/client.c
+++ b/src/client.c
@@ -260,6 +260,8 @@ static int dh_handshake(ssh_session session) {
break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ case SSH_KEX_ECDH_SHA2_NISTP521:
rc = ssh_client_ecdh_init(session);
break;
#endif
diff --git a/src/dh.c b/src/dh.c
index c54bb9f1..0339be02 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -608,7 +608,9 @@ int ssh_make_sessionid(ssh_session session) {
}
#ifdef HAVE_ECDH
- } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ } else if ((session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) ||
+ (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP384) ||
+ (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP521)) {
if (session->next_crypto->ecdh_client_pubkey == NULL ||
session->next_crypto->ecdh_server_pubkey == NULL) {
SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
@@ -670,6 +672,28 @@ int ssh_make_sessionid(ssh_session session) {
sha256(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
session->next_crypto->secret_hash);
break;
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
+ session->next_crypto->mac_type = SSH_MAC_SHA384;
+ session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
+ if (session->next_crypto->secret_hash == NULL) {
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ sha384(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
+ session->next_crypto->secret_hash);
+ break;
+ case SSH_KEX_ECDH_SHA2_NISTP521:
+ session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
+ session->next_crypto->mac_type = SSH_MAC_SHA512;
+ session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
+ if (session->next_crypto->secret_hash == NULL) {
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ sha512(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
+ session->next_crypto->secret_hash);
+ break;
}
/* During the first kex, secret hash and session ID are equal. However, after
* a key re-exchange, a new secret hash is calculated. This hash will not replace
diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c
index e774e560..041e6c0e 100644
--- a/src/ecdh_crypto.c
+++ b/src/ecdh_crypto.c
@@ -36,6 +36,20 @@
#define NISTP521 NID_secp521r1
/** @internal
+ * @brief Map the given key exchange enum value to its curve name.
+ */
+static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
+ if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ return NISTP256;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
+ return NISTP384;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
+ return NISTP521;
+ }
+ return SSH_ERROR;
+}
+
+/** @internal
* @brief Starts ecdh-sha2-nistp256 key exchange
*/
int ssh_client_ecdh_init(ssh_session session){
@@ -43,6 +57,7 @@ int ssh_client_ecdh_init(ssh_session session){
const EC_GROUP *group;
const EC_POINT *pubkey;
ssh_string client_pubkey;
+ int curve;
int len;
int rc;
bignum_CTX ctx = BN_CTX_new();
@@ -53,7 +68,13 @@ int ssh_client_ecdh_init(ssh_session session){
return SSH_ERROR;
}
- key = EC_KEY_new_by_curve_name(NISTP256);
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == SSH_ERROR) {
+ BN_CTX_free(ctx);
+ return SSH_ERROR;
+ }
+
+ key = EC_KEY_new_by_curve_name(curve);
if (key == NULL) {
BN_CTX_free(ctx);
return SSH_ERROR;
@@ -185,6 +206,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
+ int curve;
int len;
int rc;
@@ -199,7 +221,14 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
/* Build server's keypair */
ctx = BN_CTX_new();
- ecdh_key = EC_KEY_new_by_curve_name(NISTP256);
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == SSH_ERROR) {
+ BN_CTX_free(ctx);
+ return SSH_ERROR;
+ }
+
+ ecdh_key = EC_KEY_new_by_curve_name(curve);
if (ecdh_key == NULL) {
ssh_set_error_oom(session);
BN_CTX_free(ctx);
diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c
index 08d45c9a..f7430800 100644
--- a/src/ecdh_gcrypt.c
+++ b/src/ecdh_gcrypt.c
@@ -34,7 +34,21 @@
#include <gcrypt.h>
/** @internal
- * @brief Starts ecdh-sha2-nistp256 key exchange
+ * @brief Map the given key exchange enum value to its curve name.
+ */
+static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
+ if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ return "NIST P-256";
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
+ return "NIST P-384";
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
+ return "NIST P-521";
+ }
+ return NULL;
+}
+
+/** @internal
+ * @brief Starts ecdh-sha2-nistp{256,384,521} key exchange.
*/
int ssh_client_ecdh_init(ssh_session session)
{
@@ -43,6 +57,13 @@ int ssh_client_ecdh_init(ssh_session session)
ssh_string client_pubkey = NULL;
gcry_sexp_t param = NULL;
gcry_sexp_t key = NULL;
+ const char *curve = NULL;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
@@ -53,7 +74,7 @@ int ssh_client_ecdh_init(ssh_session session)
err = gcry_sexp_build(&param,
NULL,
"(genkey(ecdh(curve %s)))",
- "NIST P-256");
+ curve);
if (err) {
rc = SSH_ERROR;
goto out;
@@ -105,12 +126,20 @@ int ecdh_build_k(ssh_session session)
gcry_mpi_t s = NULL;
gcry_mpi_point_t point;
#else
+ size_t k_len = 0;
+ enum ssh_key_exchange_e kex_type = session->next_crypto->kex_type;
ssh_string s;
#endif
ssh_string pubkey_raw;
gcry_sexp_t pubkey = NULL;
ssh_string privkey = NULL;
int rc = SSH_ERROR;
+ const char *curve = NULL;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == NULL) {
+ goto out;
+ }
pubkey_raw = session->server
? session->next_crypto->ecdh_client_pubkey
@@ -119,7 +148,7 @@ int ecdh_build_k(ssh_session session)
err = gcry_sexp_build(&pubkey,
NULL,
"(key-data(public-key(ecdh(curve %s)(q %b))))",
- "NIST P-256",
+ curve,
ssh_string_len(pubkey_raw),
ssh_string_data(pubkey_raw));
if (err) {
@@ -173,7 +202,19 @@ int ecdh_build_k(ssh_session session)
goto out;
}
- if (ssh_string_len(s) != 65) {
+ if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ k_len = 65;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
+ k_len = 97;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
+ k_len = 133;
+ } else {
+ ssh_string_burn(s);
+ ssh_string_free(s);
+ goto out;
+ }
+
+ if (ssh_string_len(s) != k_length) {
ssh_string_burn(s);
ssh_string_free(s);
goto out;
@@ -182,7 +223,7 @@ int ecdh_build_k(ssh_session session)
err = gcry_mpi_scan(&session->next_crypto->k,
GCRYMPI_FMT_USG,
(const char *)ssh_string_data(s) + 1,
- 32,
+ k_length / 2,
NULL);
ssh_string_burn(s);
ssh_string_free(s);
@@ -228,6 +269,12 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
ssh_key privkey;
ssh_string sig_blob = NULL;
int rc = SSH_ERROR;
+ const char *curve = NULL;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == NULL) {
+ goto out;
+ }
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
@@ -239,7 +286,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
/* Build server's keypair */
err = gcry_sexp_build(&param, NULL, "(genkey(ecdh(curve %s)))",
- "NIST P-256");
+ curve);
if (err) {
goto out;
}
diff --git a/src/kex.c b/src/kex.c
index f34728c7..2e7702b8 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -78,7 +78,7 @@
#endif
#ifdef HAVE_ECDH
-#define ECDH "ecdh-sha2-nistp256,"
+#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
#define HOSTKEYS "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"
#else
#define HOSTKEYS "ssh-ed25519,ssh-rsa,ssh-dss"
@@ -589,6 +589,10 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
+ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp384") == 0){
+ session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP384;
+ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
+ session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
}
diff --git a/src/packet_cb.c b/src/packet_cb.c
index 472e8a73..106c5d9b 100644
--- a/src/packet_cb.c
+++ b/src/packet_cb.c
@@ -110,6 +110,8 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ case SSH_KEX_ECDH_SHA2_NISTP521:
rc = ssh_client_ecdh_reply(session, packet);
break;
#endif
diff --git a/src/server.c b/src/server.c
index 3c1ee74c..25fdd0c5 100644
--- a/src/server.c
+++ b/src/server.c
@@ -198,6 +198,8 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ case SSH_KEX_ECDH_SHA2_NISTP521:
rc = ssh_server_ecdh_init(session, packet);
break;
#endif
diff --git a/src/session.c b/src/session.c
index 01773c52..60c72b92 100644
--- a/src/session.c
+++ b/src/session.c
@@ -357,6 +357,10 @@ const char* ssh_get_kex_algo(ssh_session session) {
return "diffie-hellman-group14-sha1";
case SSH_KEX_ECDH_SHA2_NISTP256:
return "ecdh-sha2-nistp256";
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ return "ecdh-sha2-nistp384";
+ case SSH_KEX_ECDH_SHA2_NISTP521:
+ return "ecdh-sha2-nistp521";
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
return "curve25519-sha256@libssh.org";
default: