feat: add gssapi key exchange

feat: add generic functions for importing name and initializing ctx

feat: add suffix to gsskex algs dynamically

feat: move gssapi key exchange to another file

feat: add gssapi key exchange for server

refactor: remove unnecessary fields in gssapi struct

refactor: add some documentation and improve logging

fix: remove gss_dh callbacks

feat: add a check to see if GSSAPI is configured correctly

fix: memory leaks

feat: add client side "gssapi-keyex" auth

feat: add gssapi_key_exchange_algs for server

fix: some memory issues

feat: add gssapi kex options to config

feat: add check to see if GSSAPI key exchange was performed

feat: add more tests for gssapi key exchange

fix: add valgrind supp

Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Gauravsingh Sisodia
2024-07-17 05:49:24 +00:00
committed by Jakub Jelen
parent 701a2155a7
commit bc5211d055
39 changed files with 2100 additions and 154 deletions

View File

@@ -27,6 +27,10 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef WITH_GSSAPI
#include <gssapi/gssapi.h>
#include "libssh/gssapi.h"
#endif
#include "libssh/priv.h"
#include "libssh/buffer.h"
@@ -173,53 +177,79 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys)
/* server things are done in server.c */
session->dh_handshake_state=DH_STATE_FINISHED;
} else {
ssh_key server_key = NULL;
if (session->opts.gssapi_key_exchange) {
#ifdef WITH_GSSAPI
OM_uint32 maj_stat, min_stat;
gss_buffer_desc mic = GSS_C_EMPTY_BUFFER, msg = GSS_C_EMPTY_BUFFER;
/* client */
mic.length = ssh_string_len(session->gssapi_key_exchange_mic);
mic.value = ssh_string_data(session->gssapi_key_exchange_mic);
/* Verify the host's signature. FIXME do it sooner */
sig_blob = session->next_crypto->dh_server_signature;
session->next_crypto->dh_server_signature = NULL;
msg.length = session->next_crypto->digest_len;
msg.value = session->next_crypto->secret_hash;
/* get the server public key */
server_key = ssh_dh_get_next_server_publickey(session);
if (server_key == NULL) {
goto error;
}
rc = ssh_pki_import_signature_blob(sig_blob, server_key, &sig);
ssh_string_burn(sig_blob);
SSH_STRING_FREE(sig_blob);
if (rc != SSH_OK) {
goto error;
}
/* Check if signature from server matches user preferences */
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
rc = match_group(session->opts.wanted_methods[SSH_HOSTKEYS],
sig->type_c);
if (rc == 0) {
maj_stat = gss_verify_mic(&min_stat,
session->gssapi->ctx,
&msg,
&mic,
NULL);
if (maj_stat != GSS_S_COMPLETE) {
ssh_set_error(session,
SSH_FATAL,
"Public key from server (%s) doesn't match user "
"preference (%s)",
sig->type_c,
session->opts.wanted_methods[SSH_HOSTKEYS]);
"Failed to verify mic after GSSAPI Key Exchange");
goto error;
}
}
SSH_STRING_FREE(session->gssapi_key_exchange_mic);
#endif
} else {
ssh_key server_key = NULL;
rc = ssh_pki_signature_verify(session,
sig,
server_key,
session->next_crypto->secret_hash,
session->next_crypto->digest_len);
SSH_SIGNATURE_FREE(sig);
if (rc == SSH_ERROR) {
ssh_set_error(session,
SSH_FATAL,
"Failed to verify server hostkey signature");
goto error;
/* client */
/* Verify the host's signature. FIXME do it sooner */
sig_blob = session->next_crypto->dh_server_signature;
session->next_crypto->dh_server_signature = NULL;
/* get the server public key */
server_key = ssh_dh_get_next_server_publickey(session);
if (server_key == NULL) {
goto error;
}
rc = ssh_pki_import_signature_blob(sig_blob, server_key, &sig);
ssh_string_burn(sig_blob);
SSH_STRING_FREE(sig_blob);
if (rc != SSH_OK) {
goto error;
}
/* Check if signature from server matches user preferences */
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
rc = match_group(session->opts.wanted_methods[SSH_HOSTKEYS],
sig->type_c);
if (rc == 0) {
ssh_set_error(session,
SSH_FATAL,
"Public key from server (%s) doesn't match user "
"preference (%s)",
sig->type_c,
session->opts.wanted_methods[SSH_HOSTKEYS]);
goto error;
}
}
rc = ssh_pki_signature_verify(session,
sig,
server_key,
session->next_crypto->secret_hash,
session->next_crypto->digest_len);
SSH_SIGNATURE_FREE(sig);
if (rc == SSH_ERROR) {
ssh_set_error(session,
SSH_FATAL,
"Failed to verify server hostkey signature");
goto error;
}
}
SSH_LOG(SSH_LOG_DEBUG, "Signature verified and valid");