|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Nikos Mavrogiannopoulos
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Functions that relate to the TLS handshake procedure.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "errors.h"
|
|
Packit Service |
4684c1 |
#include "dh.h"
|
|
Packit Service |
4684c1 |
#include "debug.h"
|
|
Packit Service |
4684c1 |
#include "algorithms.h"
|
|
Packit Service |
4684c1 |
#include "cipher.h"
|
|
Packit Service |
4684c1 |
#include "buffers.h"
|
|
Packit Service |
4684c1 |
#include "mbuffers.h"
|
|
Packit Service |
4684c1 |
#include "kx.h"
|
|
Packit Service |
4684c1 |
#include "handshake.h"
|
|
Packit Service |
4684c1 |
#include "num.h"
|
|
Packit Service |
4684c1 |
#include "hash_int.h"
|
|
Packit Service |
4684c1 |
#include "db.h"
|
|
Packit Service |
4684c1 |
#include "hello_ext.h"
|
|
Packit Service |
4684c1 |
#include "supplemental.h"
|
|
Packit Service |
4684c1 |
#include "auth.h"
|
|
Packit Service |
4684c1 |
#include "sslv2_compat.h"
|
|
Packit Service |
4684c1 |
#include <auth/cert.h>
|
|
Packit Service |
4684c1 |
#include "constate.h"
|
|
Packit Service |
4684c1 |
#include <record.h>
|
|
Packit Service |
4684c1 |
#include <state.h>
|
|
Packit Service |
4684c1 |
#include <random.h>
|
|
Packit Service |
4684c1 |
#include <dtls.h>
|
|
Packit Service |
4684c1 |
#include "tls13/certificate_request.h"
|
|
Packit Service |
4684c1 |
#include "tls13/certificate_verify.h"
|
|
Packit Service |
4684c1 |
#include "tls13/certificate.h"
|
|
Packit Service |
4684c1 |
#include "tls13/finished.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#undef AGAIN
|
|
Packit Service |
4684c1 |
#define AGAIN(x) ((x)==(REAUTH_STATE))
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* _gnutls13_reauth_client
|
|
Packit Service |
4684c1 |
* This function performs the client side of the post-handshake authentication
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
int _gnutls13_reauth_client(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret = 0;
|
|
Packit Service |
4684c1 |
size_t tmp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!session->internals.initial_negotiation_completed)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->internals.reauth_buffer.length == 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
switch (REAUTH_STATE) {
|
|
Packit Service |
4684c1 |
case REAUTH_STATE0:
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* restore handshake transcript */
|
|
Packit Service |
4684c1 |
_gnutls_buffer_reset(&session->internals.handshake_hash_buffer);
|
|
Packit Service |
4684c1 |
ret = gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
session->internals.post_handshake_hash_buffer.data,
|
|
Packit Service |
4684c1 |
session->internals.post_handshake_hash_buffer.length);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* append the previously received certificate request message, to the
|
|
Packit Service |
4684c1 |
* transcript. */
|
|
Packit Service |
4684c1 |
ret = gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
session->internals.reauth_buffer.data,
|
|
Packit Service |
4684c1 |
session->internals.reauth_buffer.length);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.handshake_hash_buffer_prev_len = session->internals.handshake_hash_buffer.length;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* skip the reauth buffer handshake message headers */
|
|
Packit Service |
4684c1 |
ret = _gnutls_buffer_pop_prefix32(&session->internals.reauth_buffer, &tmp, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE1:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_recv_certificate_request_int(session,
|
|
Packit Service |
4684c1 |
&session->internals.reauth_buffer);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE1;
|
|
Packit Service |
4684c1 |
IMED_RET("recv certificate request", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE2:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_send_certificate(session, AGAIN(REAUTH_STATE2));
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE2;
|
|
Packit Service |
4684c1 |
IMED_RET("send certificate", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE3:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_send_certificate_verify(session, AGAIN(REAUTH_STATE3));
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE3;
|
|
Packit Service |
4684c1 |
IMED_RET("send certificate verify", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE4:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_send_finished(session, AGAIN(REAUTH_STATE4));
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE4;
|
|
Packit Service |
4684c1 |
IMED_RET("send finished", ret, 0);
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_hash_buffers_clear(session);
|
|
Packit Service |
4684c1 |
_gnutls_buffer_reset(&session->internals.reauth_buffer);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* _gnutls13_reauth_server
|
|
Packit Service |
4684c1 |
* This function does the server stuff of the post-handshake authentication.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
int _gnutls13_reauth_server(gnutls_session_t session)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->security_parameters.post_handshake_auth == 0 ||
|
|
Packit Service |
4684c1 |
(!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->internals.send_cert_req == 0) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("You need to call gnutls_certificate_server_set_request to enable post handshake auth\n");
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
switch (REAUTH_STATE) {
|
|
Packit Service |
4684c1 |
case REAUTH_STATE0:
|
|
Packit Service |
4684c1 |
/* restore handshake transcript */
|
|
Packit Service |
4684c1 |
_gnutls_buffer_reset(&session->internals.handshake_hash_buffer);
|
|
Packit Service |
4684c1 |
ret = gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
|
|
Packit Service |
4684c1 |
session->internals.post_handshake_hash_buffer.data,
|
|
Packit Service |
4684c1 |
session->internals.post_handshake_hash_buffer.length);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
session->internals.handshake_hash_buffer_prev_len = session->internals.handshake_hash_buffer.length;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE1:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_send_certificate_request(session, AGAIN(REAUTH_STATE1));
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE1;
|
|
Packit Service |
4684c1 |
IMED_RET("send certificate request", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE2:
|
|
Packit Service |
4684c1 |
/* here we should tolerate application data */
|
|
Packit Service |
4684c1 |
ret = _gnutls13_recv_certificate(session);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE2;
|
|
Packit Service |
4684c1 |
IMED_RET("recv certificate", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE3:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_recv_certificate_verify(session);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE3;
|
|
Packit Service |
4684c1 |
IMED_RET("recv certificate verify", ret, 0);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE4:
|
|
Packit Service |
4684c1 |
ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE4;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(ret);
|
|
Packit Service |
4684c1 |
FALLTHROUGH;
|
|
Packit Service |
4684c1 |
case REAUTH_STATE5:
|
|
Packit Service |
4684c1 |
ret = _gnutls13_recv_finished(session);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE5;
|
|
Packit Service |
4684c1 |
IMED_RET("recv finished", ret, 0);
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_gnutls_handshake_hash_buffers_clear(session);
|
|
Packit Service |
4684c1 |
REAUTH_STATE = REAUTH_STATE0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_reauth:
|
|
Packit Service |
4684c1 |
* @session: is a #gnutls_session_t type.
|
|
Packit Service |
4684c1 |
* @flags: must be zero
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function performs the post-handshake authentication
|
|
Packit Service |
4684c1 |
* for TLS 1.3. The post-handshake authentication is initiated by the server
|
|
Packit Service |
4684c1 |
* by calling this function. Clients respond when %GNUTLS_E_REAUTH_REQUEST
|
|
Packit Service |
4684c1 |
* has been seen while receiving data.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The non-fatal errors expected by this function are:
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_INTERRUPTED, %GNUTLS_E_AGAIN, as well as
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_GOT_APPLICATION_DATA when called on server side.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The former two interrupt the authentication procedure due to the transport
|
|
Packit Service |
4684c1 |
* layer being interrupted, and the latter because there were pending data prior
|
|
Packit Service |
4684c1 |
* to peer initiating the re-authentication. The server should read/process that
|
|
Packit Service |
4684c1 |
* data as unauthenticated and retry calling gnutls_reauth().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* When this function is called under TLS1.2 or earlier or the peer didn't
|
|
Packit Service |
4684c1 |
* advertise post-handshake auth, it always fails with
|
|
Packit Service |
4684c1 |
* %GNUTLS_E_INVALID_REQUEST. The verification of the received peers certificate
|
|
Packit Service |
4684c1 |
* is delegated to the session or credentials verification callbacks. A
|
|
Packit Service |
4684c1 |
* server can check whether post handshake authentication is supported
|
|
Packit Service |
4684c1 |
* by the client by checking the session flags with gnutls_session_get_flags().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Prior to calling this function in server side, the function
|
|
Packit Service |
4684c1 |
* gnutls_certificate_server_set_request() must be called setting expectations
|
|
Packit Service |
4684c1 |
* for the received certificate (request or require). If none are set
|
|
Packit Service |
4684c1 |
* this function will return with %GNUTLS_E_INVALID_REQUEST.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Note that post handshake authentication is available irrespective
|
|
Packit Service |
4684c1 |
* of the initial negotiation type (PSK or certificate). In all cases
|
|
Packit Service |
4684c1 |
* however, certificate credentials must be set to the session prior
|
|
Packit Service |
4684c1 |
* to calling this function.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: %GNUTLS_E_SUCCESS on a successful authentication, otherwise a negative error code.
|
|
Packit Service |
4684c1 |
**/
|
|
Packit Service |
4684c1 |
int gnutls_reauth(gnutls_session_t session, unsigned int flags)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const version_entry_st *vers = get_version(session);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (unlikely(!vers->tls13_sem))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (session->security_parameters.entity == GNUTLS_SERVER)
|
|
Packit Service |
4684c1 |
return _gnutls13_reauth_server(session);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return _gnutls13_reauth_client(session);
|
|
Packit Service |
4684c1 |
}
|