mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
gssapi: Add support for ECDH GSSAPI KEX
In particular, gss-nistp256-sha256-* and gss-curve25519-sha256-*. Signed-off-by: Pavol Žáčik <pzacik@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
@@ -99,6 +99,10 @@ enum ssh_key_exchange_e {
|
||||
SSH_GSS_KEX_DH_GROUP14_SHA256,
|
||||
/* gss-group16-sha512-* */
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512,
|
||||
/* gss-nistp256-sha256-* */
|
||||
SSH_GSS_KEX_ECDH_NISTP256_SHA256,
|
||||
/* gss-curve25519-sha256-* */
|
||||
SSH_GSS_KEX_CURVE25519_SHA256,
|
||||
};
|
||||
|
||||
enum ssh_cipher_e {
|
||||
|
||||
@@ -29,7 +29,10 @@
|
||||
/* all OID begin with the tag identifier + length */
|
||||
#define SSH_OID_TAG 06
|
||||
|
||||
#define GSSAPI_KEY_EXCHANGE_SUPPORTED "gss-group14-sha256-,gss-group16-sha512-,"
|
||||
#define GSSAPI_KEY_EXCHANGE_SUPPORTED "gss-group14-sha256-," \
|
||||
"gss-group16-sha512-," \
|
||||
"gss-nistp256-sha256-," \
|
||||
"gss-curve25519-sha256-"
|
||||
|
||||
typedef struct ssh_gssapi_struct *ssh_gssapi;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* dh-gss.h - diffie-hellman GSSAPI key exchange
|
||||
* kex-gss.h - GSSAPI key exchange
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
@@ -20,17 +20,17 @@
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef DH_GSS_H_
|
||||
#define DH_GSS_H_
|
||||
#ifndef KEX_GSS_H_
|
||||
#define KEX_GSS_H_
|
||||
|
||||
#include "config.h"
|
||||
#ifdef WITH_GSSAPI
|
||||
|
||||
int ssh_client_gss_dh_init(ssh_session session);
|
||||
void ssh_server_gss_dh_init(ssh_session session);
|
||||
int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet);
|
||||
void ssh_client_gss_dh_remove_callbacks(ssh_session session);
|
||||
void ssh_client_gss_dh_remove_callback_hostkey(ssh_session session);
|
||||
int ssh_client_gss_kex_init(ssh_session session);
|
||||
void ssh_server_gss_kex_init(ssh_session session);
|
||||
int ssh_server_gss_kex_process_init(ssh_session session, ssh_buffer packet);
|
||||
void ssh_client_gss_kex_remove_callbacks(ssh_session session);
|
||||
void ssh_client_gss_kex_remove_callback_hostkey(ssh_session session);
|
||||
|
||||
#endif /* WITH_GSSAPI */
|
||||
#endif /* DH_GSS_H_ */
|
||||
#endif /* KEX_GSS_H_ */
|
||||
@@ -286,7 +286,7 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
gssapi.c
|
||||
dh-gss.c
|
||||
kex-gss.c
|
||||
)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/dh-gss.h"
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/options.h"
|
||||
#include "libssh/packet.h"
|
||||
@@ -271,7 +271,9 @@ int dh_handshake(ssh_session session)
|
||||
#ifdef WITH_GSSAPI
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
rc = ssh_client_gss_dh_init(session);
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
rc = ssh_client_gss_kex_init(session);
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
|
||||
@@ -56,6 +56,7 @@ static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#endif
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
return NISTP256;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
#ifdef HAVE_MLKEM
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
* @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) {
|
||||
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256 ||
|
||||
kex_type == SSH_GSS_KEX_ECDH_NISTP256_SHA256) {
|
||||
return "NIST P-256";
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
|
||||
return "NIST P-384";
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
#ifdef HAVE_ECDH
|
||||
|
||||
static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
|
||||
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256 ||
|
||||
kex_type == SSH_GSS_KEX_ECDH_NISTP256_SHA256) {
|
||||
return MBEDTLS_ECP_DP_SECP256R1;
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
|
||||
return MBEDTLS_ECP_DP_SECP384R1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* dh-gss.c - diffie-hellman GSSAPI key exchange
|
||||
* kex-gss.c - GSSAPI key exchange
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
@@ -30,50 +30,112 @@
|
||||
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/dh-gss.h"
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ssh2.h"
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_reply);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_gss_kex_reply);
|
||||
|
||||
static ssh_packet_callback gss_dh_client_callbacks[] = {
|
||||
ssh_packet_client_gss_dh_reply,
|
||||
static ssh_packet_callback gss_kex_client_callbacks[] = {
|
||||
ssh_packet_client_gss_kex_reply,
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_dh_client_callbacks = {
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_kex_client_callbacks = {
|
||||
.start = SSH2_MSG_KEXGSS_COMPLETE,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = gss_dh_client_callbacks,
|
||||
.callbacks = gss_kex_client_callbacks,
|
||||
.user = NULL,
|
||||
};
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_hostkey);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_gss_kex_hostkey);
|
||||
|
||||
static ssh_packet_callback gss_dh_client_callback_hostkey[] = {
|
||||
ssh_packet_client_gss_dh_hostkey,
|
||||
static ssh_packet_callback gss_kex_client_callback_hostkey[] = {
|
||||
ssh_packet_client_gss_kex_hostkey,
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_dh_client_callback_hostkey = {
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_kex_client_callback_hostkey = {
|
||||
.start = SSH2_MSG_KEXGSS_HOSTKEY,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = gss_dh_client_callback_hostkey,
|
||||
.callbacks = gss_kex_client_callback_hostkey,
|
||||
.user = NULL,
|
||||
};
|
||||
|
||||
static ssh_string dh_init(ssh_session session)
|
||||
{
|
||||
int rc, keypair;
|
||||
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
const_bignum const_pubkey;
|
||||
#endif
|
||||
bignum pubkey = NULL;
|
||||
ssh_string pubkey_string = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
|
||||
if (session->server) {
|
||||
keypair = DH_SERVER_KEYPAIR;
|
||||
} else {
|
||||
keypair = DH_CLIENT_KEYPAIR;
|
||||
}
|
||||
|
||||
rc = ssh_dh_init_common(crypto);
|
||||
if (rc != SSH_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_gen_keys(crypto->dh_ctx, keypair);
|
||||
if (rc != SSH_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
rc = ssh_dh_keypair_get_keys(crypto->dh_ctx, keypair, NULL, &const_pubkey);
|
||||
bignum_dup(const_pubkey, &pubkey);
|
||||
#else
|
||||
rc = ssh_dh_keypair_get_keys(crypto->dh_ctx, keypair, NULL, &pubkey);
|
||||
#endif
|
||||
if (rc != SSH_OK) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
pubkey_string = ssh_make_bignum_string(pubkey);
|
||||
|
||||
end:
|
||||
bignum_safe_free(pubkey);
|
||||
return pubkey_string;
|
||||
}
|
||||
|
||||
static int dh_import_peer_key(ssh_session session, ssh_string peer_key)
|
||||
{
|
||||
int rc, keypair;
|
||||
bignum peer_key_bn;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
|
||||
if (session->server) {
|
||||
keypair = DH_CLIENT_KEYPAIR;
|
||||
} else {
|
||||
keypair = DH_SERVER_KEYPAIR;
|
||||
}
|
||||
|
||||
peer_key_bn = ssh_make_string_bn(peer_key);
|
||||
rc = ssh_dh_keypair_set_keys(crypto->dh_ctx, keypair, NULL, peer_key_bn);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(peer_key_bn);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Starts gssapi key exchange
|
||||
*/
|
||||
int ssh_client_gss_dh_init(ssh_session session)
|
||||
int ssh_client_gss_kex_init(ssh_session session)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
const_bignum pubkey;
|
||||
#else
|
||||
bignum pubkey = NULL;
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
int rc;
|
||||
int rc, ret = SSH_ERROR;
|
||||
/* oid selected for authentication */
|
||||
gss_OID_set selected = GSS_C_NO_OID_SET;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
@@ -81,27 +143,52 @@ int ssh_client_gss_dh_init(ssh_session session)
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
OM_uint32 oflags;
|
||||
ssh_string pubkey = NULL;
|
||||
|
||||
rc = ssh_dh_init_common(crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
pubkey = dh_init(session);
|
||||
if (pubkey == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to generate DH keypair");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_gen_keys(crypto->dh_ctx, DH_CLIENT_KEYPAIR);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_keypair_get_keys(crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR,
|
||||
NULL,
|
||||
&pubkey);
|
||||
break;
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
rc = ssh_ecdh_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to generate ECDH keypair");
|
||||
goto out;
|
||||
}
|
||||
pubkey = ssh_string_copy(crypto->ecdh_client_pubkey);
|
||||
break;
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to generate Curve25519 keypair");
|
||||
goto out;
|
||||
}
|
||||
pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
|
||||
if (pubkey == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto out;
|
||||
}
|
||||
rc = ssh_string_fill(pubkey,
|
||||
crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to copy Curve25519 pubkey");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unsupported GSSAPI KEX method");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ssh_gssapi_init(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
if (rc != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (session->opts.gss_server_identity != NULL) {
|
||||
@@ -110,12 +197,12 @@ int ssh_client_gss_dh_init(ssh_session session)
|
||||
|
||||
rc = ssh_gssapi_import_name(session->gssapi, gss_host);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ssh_gssapi_client_identity(session, &selected);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
if (rc != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->gssapi->client.flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
|
||||
@@ -129,61 +216,58 @@ int ssh_client_gss_dh_init(ssh_session session)
|
||||
"Initializing gssapi context",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
if (!(oflags & GSS_C_INTEG_FLAG) || !(oflags & GSS_C_MUTUAL_FLAG)) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"GSSAPI(init) integrity and mutual flags were not set");
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdPB",
|
||||
"bdPS",
|
||||
SSH2_MSG_KEXGSS_INIT,
|
||||
output_token.length,
|
||||
(size_t)output_token.length,
|
||||
output_token.value,
|
||||
pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
bignum_safe_free(pubkey);
|
||||
#endif
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_dh_client_callbacks);
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_dh_client_callback_hostkey);
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_kex_client_callbacks);
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_kex_client_callback_hostkey);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
return rc;
|
||||
error:
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
bignum_safe_free(pubkey);
|
||||
#endif
|
||||
if (rc != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
out:
|
||||
gss_release_buffer(&min_stat, &output_token);
|
||||
ssh_dh_cleanup(crypto);
|
||||
return SSH_ERROR;
|
||||
ssh_string_free(pubkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ssh_client_gss_dh_remove_callbacks(ssh_session session)
|
||||
void ssh_client_gss_kex_remove_callbacks(ssh_session session)
|
||||
{
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_dh_client_callbacks);
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_kex_client_callbacks);
|
||||
}
|
||||
|
||||
void ssh_client_gss_dh_remove_callback_hostkey(ssh_session session)
|
||||
void ssh_client_gss_kex_remove_callback_hostkey(ssh_session session)
|
||||
{
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_dh_client_callback_hostkey);
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_kex_client_callback_hostkey);
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_reply)
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_gss_kex_reply)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
ssh_string pubkey_blob = NULL, mic = NULL, otoken = NULL;
|
||||
ssh_string mic = NULL, otoken = NULL, server_pubkey = NULL;
|
||||
uint8_t b;
|
||||
bignum server_pubkey;
|
||||
int rc;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
@@ -193,12 +277,14 @@ SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_reply)
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_client_gss_dh_remove_callbacks(session);
|
||||
ssh_client_gss_kex_remove_callbacks(session);
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "BSbS", &server_pubkey, &mic, &b, &otoken);
|
||||
if (rc == SSH_ERROR) {
|
||||
rc = ssh_buffer_unpack(packet, "SSbS", &server_pubkey, &mic, &b, &otoken);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "No public key in server reply");
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_STRING_FREE(session->gssapi_key_exchange_mic);
|
||||
session->gssapi_key_exchange_mic = mic;
|
||||
input_token.length = ssh_string_len(otoken);
|
||||
@@ -211,23 +297,37 @@ SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_reply)
|
||||
goto error;
|
||||
}
|
||||
SSH_STRING_FREE(otoken);
|
||||
rc = ssh_dh_keypair_set_keys(crypto->dh_ctx,
|
||||
DH_SERVER_KEYPAIR,
|
||||
NULL,
|
||||
server_pubkey);
|
||||
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
rc = dh_import_peer_key(session, server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
bignum_safe_free(server_pubkey);
|
||||
ssh_set_error(session, SSH_FATAL, "Could not import server pubkey");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
|
||||
rc = ssh_dh_compute_shared_secret(crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR,
|
||||
DH_SERVER_KEYPAIR,
|
||||
&session->next_crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(session->next_crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
&crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(crypto);
|
||||
break;
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
crypto->ecdh_server_pubkey = ssh_string_copy(server_pubkey);
|
||||
rc = ecdh_build_k(session);
|
||||
break;
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
memcpy(crypto->curve25519_server_pubkey,
|
||||
ssh_string_data(server_pubkey),
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
rc = ssh_curve25519_build_k(session);
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unsupported GSSAPI KEX method");
|
||||
goto error;
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not derive shared secret");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -236,15 +336,18 @@ SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_reply)
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(server_pubkey);
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
ssh_string_free(server_pubkey);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_hostkey)
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_gss_kex_hostkey)
|
||||
{
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc;
|
||||
@@ -252,7 +355,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_hostkey)
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_client_gss_dh_remove_callback_hostkey(session);
|
||||
ssh_client_gss_kex_remove_callback_hostkey(session);
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "S", &pubkey_blob);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -270,52 +373,45 @@ SSH_PACKET_CALLBACK(ssh_packet_client_gss_dh_hostkey)
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_gss_dh_init);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_gss_kex_init);
|
||||
|
||||
static ssh_packet_callback gss_dh_server_callbacks[] = {
|
||||
ssh_packet_server_gss_dh_init,
|
||||
static ssh_packet_callback gss_kex_server_callbacks[] = {
|
||||
ssh_packet_server_gss_kex_init,
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_dh_server_callbacks = {
|
||||
static struct ssh_packet_callbacks_struct ssh_gss_kex_server_callbacks = {
|
||||
.start = SSH2_MSG_KEXGSS_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = gss_dh_server_callbacks,
|
||||
.callbacks = gss_kex_server_callbacks,
|
||||
.user = NULL,
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the gssapi kex callbacks
|
||||
*/
|
||||
void ssh_server_gss_dh_init(ssh_session session)
|
||||
void ssh_server_gss_kex_init(ssh_session session)
|
||||
{
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_dh_server_callbacks);
|
||||
|
||||
ssh_dh_init_common(session->next_crypto);
|
||||
ssh_packet_set_callbacks(session, &ssh_gss_kex_server_callbacks);
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief processes a SSH_MSG_KEXGSS_INIT and sends
|
||||
* the appropriate SSH_MSG_KEXGSS_COMPLETE
|
||||
*/
|
||||
int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
int ssh_server_gss_kex_process_init(ssh_session session, ssh_buffer packet)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
ssh_key privkey = NULL;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
bignum client_pubkey;
|
||||
#if !defined(HAVE_LIBCRYPTO) || OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
const_bignum server_pubkey;
|
||||
#else
|
||||
bignum server_pubkey = NULL;
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
ssh_string client_pubkey = NULL;
|
||||
ssh_string server_pubkey = NULL;
|
||||
int rc;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
@@ -336,33 +432,70 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
input_token.length = ssh_string_len(otoken);
|
||||
input_token.value = ssh_string_data(otoken);
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "B", &client_pubkey);
|
||||
rc = ssh_buffer_unpack(packet, "S", &client_pubkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "No e number in client request");
|
||||
ssh_set_error(session, SSH_FATAL, "No public key in client request");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_set_keys(crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR,
|
||||
NULL,
|
||||
client_pubkey);
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
server_pubkey = dh_init(session);
|
||||
if (server_pubkey == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate a DH keypair");
|
||||
goto error;
|
||||
}
|
||||
rc = dh_import_peer_key(session, client_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(client_pubkey);
|
||||
ssh_set_error(session, SSH_FATAL, "Could not import client pubkey");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_gen_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_compute_shared_secret(crypto->dh_ctx,
|
||||
DH_SERVER_KEYPAIR,
|
||||
DH_CLIENT_KEYPAIR,
|
||||
&crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
break;
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
rc = ssh_ecdh_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate an ECDH keypair");
|
||||
goto error;
|
||||
}
|
||||
crypto->ecdh_client_pubkey = ssh_string_copy(client_pubkey);
|
||||
server_pubkey = ssh_string_copy(crypto->ecdh_server_pubkey);
|
||||
rc = ecdh_build_k(session);
|
||||
break;
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate a Curve25519 keypair");
|
||||
goto error;
|
||||
}
|
||||
server_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
|
||||
if (server_pubkey == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_string_fill(server_pubkey,
|
||||
crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to copy Curve25519 pubkey");
|
||||
goto error;
|
||||
}
|
||||
memcpy(crypto->curve25519_client_pubkey,
|
||||
ssh_string_data(client_pubkey),
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
rc = ssh_curve25519_build_k(session);
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unsupported GSSAPI KEX method");
|
||||
goto error;
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not derive shared secret");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -400,14 +533,6 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
SSH_STRING_FREE(server_pubkey_blob);
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(crypto->dh_ctx,
|
||||
DH_SERVER_KEYPAIR,
|
||||
NULL,
|
||||
&server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_gssapi_init(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
@@ -485,7 +610,7 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bBdPbdP",
|
||||
"bSdPbdP",
|
||||
SSH2_MSG_KEXGSS_COMPLETE,
|
||||
server_pubkey,
|
||||
mic.length,
|
||||
@@ -495,9 +620,6 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
output_token.length,
|
||||
(size_t)output_token.length,
|
||||
output_token.value);
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
bignum_safe_free(server_pubkey);
|
||||
#endif
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
@@ -520,15 +642,14 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(server_pubkey);
|
||||
ssh_string_free(client_pubkey);
|
||||
return SSH_OK;
|
||||
error:
|
||||
SSH_STRING_FREE(server_pubkey_blob);
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
bignum_safe_free(server_pubkey);
|
||||
#endif
|
||||
|
||||
ssh_string_free(server_pubkey);
|
||||
ssh_string_free(client_pubkey);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -536,13 +657,13 @@ error:
|
||||
* @brief parse an incoming SSH_MSG_KEXGSS_INIT packet and complete
|
||||
* Diffie-Hellman key exchange
|
||||
**/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_gss_dh_init)
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_gss_kex_init)
|
||||
{
|
||||
(void)type;
|
||||
(void)user;
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_KEXGSS_INIT");
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_dh_server_callbacks);
|
||||
ssh_server_gss_dh_process_init(session, packet);
|
||||
ssh_packet_remove_callbacks(session, &ssh_gss_kex_server_callbacks);
|
||||
ssh_server_gss_kex_process_init(session, packet);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
16
src/kex.c
16
src/kex.c
@@ -44,13 +44,13 @@
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/hybrid_mlkem.h"
|
||||
#endif
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/token.h"
|
||||
#include "libssh/gssapi.h"
|
||||
#include "libssh/dh-gss.h"
|
||||
|
||||
#ifdef HAVE_BLOWFISH
|
||||
# define BLOWFISH ",blowfish-cbc"
|
||||
@@ -958,6 +958,10 @@ kex_select_kex_type(const char *kex)
|
||||
return SSH_GSS_KEX_DH_GROUP14_SHA256;
|
||||
} else if (strncmp(kex, "gss-group16-sha512-", 19) == 0) {
|
||||
return SSH_GSS_KEX_DH_GROUP16_SHA512;
|
||||
} else if (strncmp(kex, "gss-nistp256-sha256-", 20) == 0) {
|
||||
return SSH_GSS_KEX_ECDH_NISTP256_SHA256;
|
||||
} else if (strncmp(kex, "gss-curve25519-sha256-", 22) == 0) {
|
||||
return SSH_GSS_KEX_CURVE25519_SHA256;
|
||||
} else if (strcmp(kex, "diffie-hellman-group14-sha1") == 0) {
|
||||
return SSH_KEX_DH_GROUP14_SHA1;
|
||||
} else if (strcmp(kex, "diffie-hellman-group14-sha256") == 0) {
|
||||
@@ -1017,8 +1021,10 @@ static void revert_kex_callbacks(ssh_session session)
|
||||
break;
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
#ifdef WITH_GSSAPI
|
||||
ssh_client_gss_dh_remove_callbacks(session);
|
||||
ssh_client_gss_kex_remove_callbacks(session);
|
||||
#endif /* WITH_GSSAPI */
|
||||
break;
|
||||
#ifdef WITH_GEX
|
||||
@@ -1591,6 +1597,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
if (session->next_crypto->ecdh_client_pubkey == NULL ||
|
||||
session->next_crypto->ecdh_server_pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "ECDH parameter missing");
|
||||
@@ -1609,6 +1616,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"dPdP",
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
@@ -1727,6 +1735,8 @@ int ssh_make_sessionid(ssh_session session)
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#endif
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
#ifdef WITH_GEX
|
||||
case SSH_KEX_DH_GEX_SHA256:
|
||||
#endif /* WITH_GEX */
|
||||
@@ -2043,6 +2053,8 @@ bool ssh_kex_is_gss(struct ssh_crypto_struct *crypto)
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -434,7 +434,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
|
||||
*
|
||||
* Transitions:
|
||||
* - session->dh_handshake_state = DH_STATE_INIT_SENT
|
||||
* then calls ssh_packet_client_gss_dh_reply which triggers:
|
||||
* then calls ssh_packet_client_gss_kex_reply which triggers:
|
||||
* - session->dh_handshake_state = DH_STATE_NEWKEYS_SENT
|
||||
* */
|
||||
|
||||
|
||||
@@ -489,6 +489,8 @@ const char* ssh_get_kex_algo(ssh_session session) {
|
||||
return "diffie-hellman-group18-sha512";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
return "ecdh-sha2-nistp256";
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
return "gss-nistp256-sha256-";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
return "ecdh-sha2-nistp384";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
@@ -497,6 +499,8 @@ const char* ssh_get_kex_algo(ssh_session session) {
|
||||
return "curve25519-sha256";
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
return "curve25519-sha256@libssh.org";
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
return "gss-curve25519-sha256-";
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
return "sntrup761x25519-sha512@openssh.com";
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512:
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
#include "libssh/dh-gex.h"
|
||||
#endif /* WITH_GEX */
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/hybrid_mlkem.h"
|
||||
#endif
|
||||
#include "libssh/dh-gss.h"
|
||||
|
||||
static struct ssh_hmac_struct ssh_hmac_tab[] = {
|
||||
{ "hmac-sha1", SSH_HMAC_SHA1, false },
|
||||
@@ -591,7 +591,9 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
#ifdef WITH_GSSAPI
|
||||
case SSH_GSS_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_GSS_KEX_DH_GROUP16_SHA512:
|
||||
ssh_server_gss_dh_init(session);
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
ssh_server_gss_kex_init(session);
|
||||
break;
|
||||
#endif /* WITH_GSSAPI */
|
||||
#ifdef WITH_GEX
|
||||
|
||||
@@ -130,90 +130,80 @@ static void torture_gssapi_key_exchange_no_tgt(void **state)
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_not_equal(session->current_crypto->kex_type,
|
||||
SSH_GSS_KEX_DH_GROUP14_SHA256);
|
||||
assert_int_not_equal(session->current_crypto->kex_type,
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
assert_false(ssh_kex_is_gss(session->current_crypto));
|
||||
|
||||
torture_teardown_kdc_server(state);
|
||||
}
|
||||
|
||||
static void torture_gssapi_key_exchange_alg(void **state,
|
||||
const char *kex_string,
|
||||
enum ssh_key_exchange_e kex_type)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
state,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
kex_string);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_equal(session->current_crypto->kex_type, kex_type);
|
||||
|
||||
torture_teardown_kdc_server(state);
|
||||
}
|
||||
|
||||
static void torture_gssapi_key_exchange_gss_group14_sha256(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
state,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
"gss-group14-sha256-");
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_equal(session->current_crypto->kex_type,
|
||||
torture_gssapi_key_exchange_alg(state,
|
||||
"gss-group14-sha256-",
|
||||
SSH_GSS_KEX_DH_GROUP14_SHA256);
|
||||
|
||||
torture_teardown_kdc_server(state);
|
||||
}
|
||||
|
||||
static void torture_gssapi_key_exchange_gss_group16_sha512(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
torture_gssapi_key_exchange_alg(state,
|
||||
"gss-group16-sha512-",
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
}
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
static void torture_gssapi_key_exchange_gss_nistp256_sha256(void **state)
|
||||
{
|
||||
torture_gssapi_key_exchange_alg(state,
|
||||
"gss-nistp256-sha256-",
|
||||
SSH_GSS_KEX_ECDH_NISTP256_SHA256);
|
||||
}
|
||||
|
||||
static void torture_gssapi_key_exchange_gss_curve25519_sha256(void **state)
|
||||
{
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
state,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
"gss-group16-sha512-");
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_true(session->current_crypto->kex_type ==
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
|
||||
torture_teardown_kdc_server(state);
|
||||
torture_gssapi_key_exchange_alg(state,
|
||||
"gss-curve25519-sha256-",
|
||||
SSH_GSS_KEX_CURVE25519_SHA256);
|
||||
}
|
||||
|
||||
static void torture_gssapi_key_exchange_auth(void **state)
|
||||
@@ -304,6 +294,14 @@ int torture_run_tests(void)
|
||||
torture_gssapi_key_exchange_gss_group16_sha512,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_gssapi_key_exchange_gss_nistp256_sha256,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_gssapi_key_exchange_gss_curve25519_sha256,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_gssapi_key_exchange_auth,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
|
||||
@@ -137,7 +137,10 @@ static void setup_config(void **state)
|
||||
|
||||
/* Enable GSSAPI key exchange */
|
||||
ss->gssapi_key_exchange = true;
|
||||
ss->gssapi_key_exchange_algs = "gss-group14-sha256-,gss-group16-sha512-";
|
||||
ss->gssapi_key_exchange_algs = "gss-group14-sha256-,"
|
||||
"gss-group16-sha512-,"
|
||||
"gss-nistp256-sha256-,"
|
||||
"gss-curve25519-sha256-";
|
||||
|
||||
tss->state = s;
|
||||
tss->ss = ss;
|
||||
@@ -348,108 +351,89 @@ static void torture_gssapi_server_key_exchange_no_tgt(void **state)
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_not_equal(session->current_crypto->kex_type,
|
||||
SSH_GSS_KEX_DH_GROUP14_SHA256);
|
||||
assert_int_not_equal(session->current_crypto->kex_type,
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
assert_false(ssh_kex_is_gss(session->current_crypto));
|
||||
|
||||
torture_teardown_kdc_server((void **)&s);
|
||||
}
|
||||
|
||||
static void torture_gssapi_server_key_exchange_alg(void **state,
|
||||
const char *kex_string,
|
||||
enum ssh_key_exchange_e kex_type)
|
||||
{
|
||||
struct test_server_st *tss = *state;
|
||||
struct torture_state *s = NULL;
|
||||
ssh_session session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
assert_non_null(tss);
|
||||
|
||||
s = tss->state;
|
||||
assert_non_null(s);
|
||||
|
||||
session = s->ssh.session;
|
||||
assert_non_null(session);
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
(void **)&s,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
kex_string);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_equal(session->current_crypto->kex_type, kex_type);
|
||||
|
||||
torture_teardown_kdc_server((void **)&s);
|
||||
}
|
||||
|
||||
static void torture_gssapi_server_key_exchange_gss_group14_sha256(void **state)
|
||||
{
|
||||
struct test_server_st *tss = *state;
|
||||
struct torture_state *s = NULL;
|
||||
ssh_session session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
assert_non_null(tss);
|
||||
|
||||
s = tss->state;
|
||||
assert_non_null(s);
|
||||
|
||||
session = s->ssh.session;
|
||||
assert_non_null(session);
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
(void **)&s,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
"gss-group14-sha256-");
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_equal(session->current_crypto->kex_type,
|
||||
torture_gssapi_server_key_exchange_alg(state,
|
||||
"gss-group14-sha256-",
|
||||
SSH_GSS_KEX_DH_GROUP14_SHA256);
|
||||
|
||||
torture_teardown_kdc_server((void **)&s);
|
||||
}
|
||||
|
||||
static void torture_gssapi_server_key_exchange_gss_group16_sha512(void **state)
|
||||
{
|
||||
struct test_server_st *tss = *state;
|
||||
struct torture_state *s = NULL;
|
||||
ssh_session session;
|
||||
int rc;
|
||||
bool t = true;
|
||||
torture_gssapi_server_key_exchange_alg(state,
|
||||
"gss-group16-sha512-",
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
}
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
static void torture_gssapi_server_key_exchange_gss_nistp256_sha256(void **state)
|
||||
{
|
||||
torture_gssapi_server_key_exchange_alg(state,
|
||||
"gss-nistp256-sha256-",
|
||||
SSH_GSS_KEX_ECDH_NISTP256_SHA256);
|
||||
}
|
||||
|
||||
static void torture_gssapi_server_key_exchange_gss_curve25519_sha256(void **state)
|
||||
{
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
assert_non_null(tss);
|
||||
|
||||
s = tss->state;
|
||||
assert_non_null(s);
|
||||
|
||||
session = s->ssh.session;
|
||||
assert_non_null(session);
|
||||
|
||||
/* Valid */
|
||||
torture_setup_kdc_server(
|
||||
(void **)&s,
|
||||
"kadmin.local addprinc -randkey host/server.libssh.site \n"
|
||||
"kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n"
|
||||
"kadmin.local addprinc -pw bar alice \n"
|
||||
"kadmin.local list_principals",
|
||||
|
||||
"echo bar | kinit alice");
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session,
|
||||
SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS,
|
||||
"gss-group16-sha512-");
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
assert_int_equal(session->current_crypto->kex_type,
|
||||
SSH_GSS_KEX_DH_GROUP16_SHA512);
|
||||
|
||||
torture_teardown_kdc_server((void **)&s);
|
||||
torture_gssapi_server_key_exchange_alg(state,
|
||||
"gss-curve25519-sha256-",
|
||||
SSH_GSS_KEX_CURVE25519_SHA256);
|
||||
}
|
||||
|
||||
static void torture_gssapi_server_key_exchange_auth(void **state)
|
||||
@@ -559,6 +543,14 @@ int torture_run_tests(void)
|
||||
torture_gssapi_server_key_exchange_gss_group16_sha512,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_gssapi_server_key_exchange_gss_nistp256_sha256,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_gssapi_server_key_exchange_gss_curve25519_sha256,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_gssapi_server_key_exchange_auth,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
|
||||
@@ -95,7 +95,10 @@ static void setup_config(void **state)
|
||||
|
||||
/* Enable GSSAPI key exchange */
|
||||
ss->gssapi_key_exchange = true;
|
||||
ss->gssapi_key_exchange_algs = "gss-group14-sha256-,gss-group16-sha512-";
|
||||
ss->gssapi_key_exchange_algs = "gss-group14-sha256-,"
|
||||
"gss-group16-sha512-,"
|
||||
"gss-nistp256-sha256-,"
|
||||
"gss-curve25519-sha256-";
|
||||
|
||||
tss->state = s;
|
||||
tss->ss = ss;
|
||||
|
||||
Reference in New Issue
Block a user