diff options
Diffstat (limited to 'lib/handshake-checks.c')
-rw-r--r-- | lib/handshake-checks.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/lib/handshake-checks.c b/lib/handshake-checks.c new file mode 100644 index 0000000..f5a3a4d --- /dev/null +++ b/lib/handshake-checks.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015-2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +/* Functions that relate to the TLS handshake procedure. + */ + +#include "gnutls_int.h" +#include "errors.h" +#include "debug.h" +#include "handshake.h" +#include <auth/cert.h> +#include "constate.h" +#include <record.h> +#include <state.h> +#include <ext/safe_renegotiation.h> +#include <auth/anon.h> /* for gnutls_anon_server_credentials_t */ +#include <auth/psk.h> /* for gnutls_psk_server_credentials_t */ +#ifdef ENABLE_SRP +# include <auth/srp_kx.h> +#endif + +int _gnutls_check_id_for_change(gnutls_session_t session) +{ + int cred_type; + + /* This checks in PSK and SRP ciphersuites that the username remained the + * same on a rehandshake. */ + if (session->internals.flags & GNUTLS_ALLOW_ID_CHANGE) + return 0; + + cred_type = gnutls_auth_get_type(session); + if (cred_type == GNUTLS_CRD_PSK || cred_type == GNUTLS_CRD_SRP) { + const char *username = NULL; + int username_length; + + if (cred_type == GNUTLS_CRD_PSK) { + psk_auth_info_t ai; + + ai = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); + if (ai == NULL) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + username = ai->username; + username_length = ai->username_len; +#ifdef ENABLE_SRP + } else { + srp_server_auth_info_t ai = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP); + if (ai == NULL) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + username = ai->username; + username_length = strlen(ai->username); +#endif + } + + if (username == NULL) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + if (session->internals.saved_username && + session->internals.saved_username_size != -1) { + if (session->internals.saved_username_size == username_length && + strncmp(session->internals.saved_username, username, username_length)) { + _gnutls_debug_log("Session's PSK username changed during rehandshake; aborting!\n"); + return gnutls_assert_val(GNUTLS_E_SESSION_USER_ID_CHANGED); + } + } else if (session->internals.saved_username == NULL && + session->internals.saved_username_size == -1) { + if (username_length > MAX_USERNAME_SIZE) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + char *tmp = gnutls_malloc(username_length + 1); + if (tmp == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + memcpy(tmp, username, username_length); + tmp[username_length] = '\0'; + session->internals.saved_username = tmp; + session->internals.saved_username_size = username_length; + } else + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + } + + return 0; +} + +int _gnutls_check_if_cert_hash_is_same(gnutls_session_t session, gnutls_certificate_credentials_t cred) +{ + cert_auth_info_t ai; + char tmp[32]; + int ret; + + if (session->internals.flags & GNUTLS_ALLOW_ID_CHANGE) + return 0; + + ai = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE); + if (ai == NULL || ai->ncerts == 0) + return 0; + + ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, + ai->raw_certificate_list[0].data, + ai->raw_certificate_list[0].size, + tmp); + if (ret < 0) + return gnutls_assert_val(ret); + + if (session->internals.cert_hash_set) { + if (memcmp(tmp, session->internals.cert_hash, 32) != 0) { + _gnutls_debug_log("Session certificate changed during rehandshake; aborting!\n"); + return gnutls_assert_val(GNUTLS_E_SESSION_USER_ID_CHANGED); + } + } else { + memcpy(session->internals.cert_hash, tmp, 32); + session->internals.cert_hash_set = 1; + } + + return 0; +} |