Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/tls13/post_handshake.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
/* Functions that relate to the TLS handshake procedure.
24
 */
25
26
#include "gnutls_int.h"
27
#include "errors.h"
28
#include "dh.h"
29
#include "debug.h"
30
#include "algorithms.h"
31
#include "cipher.h"
32
#include "buffers.h"
33
#include "mbuffers.h"
34
#include "kx.h"
35
#include "handshake.h"
36
#include "num.h"
37
#include "hash_int.h"
38
#include "db.h"
39
#include "hello_ext.h"
40
#include "supplemental.h"
41
#include "auth.h"
42
#include "sslv2_compat.h"
43
#include "auth/cert.h"
44
#include "constate.h"
45
#include "record.h"
46
#include "state.h"
47
#include "random.h"
48
#include "dtls.h"
49
#include "tls13/certificate_request.h"
50
#include "tls13/certificate_verify.h"
51
#include "tls13/certificate.h"
52
#include "tls13/finished.h"
53
54
#undef AGAIN
55
0
#define AGAIN(x) ((x) == (REAUTH_STATE))
56
57
/*
58
 * _gnutls13_reauth_client
59
 * This function performs the client side of the post-handshake authentication
60
 */
61
static int _gnutls13_reauth_client(gnutls_session_t session)
62
0
{
63
0
  int ret = 0;
64
0
  size_t tmp;
65
66
0
  if (!session->internals.initial_negotiation_completed)
67
0
    return gnutls_assert_val(GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE);
68
69
0
  if (!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH))
70
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
71
72
0
  if (session->internals.reauth_buffer.length == 0)
73
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
74
75
0
  switch (REAUTH_STATE) {
76
0
  case REAUTH_STATE0:
77
78
    /* restore handshake transcript */
79
0
    _gnutls_buffer_reset(&session->internals.handshake_hash_buffer);
80
0
    ret = gnutls_buffer_append_data(
81
0
      &session->internals.handshake_hash_buffer,
82
0
      session->internals.post_handshake_hash_buffer.data,
83
0
      session->internals.post_handshake_hash_buffer.length);
84
0
    if (ret < 0)
85
0
      return gnutls_assert_val(ret);
86
87
    /* append the previously received certificate request message, to the
88
     * transcript. */
89
0
    ret = gnutls_buffer_append_data(
90
0
      &session->internals.handshake_hash_buffer,
91
0
      session->internals.reauth_buffer.data,
92
0
      session->internals.reauth_buffer.length);
93
0
    if (ret < 0)
94
0
      return gnutls_assert_val(ret);
95
96
0
    session->internals.handshake_hash_buffer_prev_len =
97
0
      session->internals.handshake_hash_buffer.length;
98
99
    /* skip the reauth buffer handshake message headers */
100
0
    ret = _gnutls_buffer_pop_prefix32(
101
0
      &session->internals.reauth_buffer, &tmp, 0);
102
0
    if (ret < 0)
103
0
      return gnutls_assert_val(ret);
104
105
0
    FALLTHROUGH;
106
0
  case REAUTH_STATE1:
107
0
    ret = _gnutls13_recv_certificate_request_int(
108
0
      session, &session->internals.reauth_buffer);
109
0
    REAUTH_STATE = REAUTH_STATE1;
110
0
    IMED_RET("recv certificate request", ret, 0);
111
0
    FALLTHROUGH;
112
0
  case REAUTH_STATE2:
113
0
    ret = _gnutls13_send_certificate(session, AGAIN(REAUTH_STATE2));
114
0
    REAUTH_STATE = REAUTH_STATE2;
115
0
    IMED_RET("send certificate", ret, 0);
116
0
    FALLTHROUGH;
117
0
  case REAUTH_STATE3:
118
0
    ret = _gnutls13_send_certificate_verify(session,
119
0
              AGAIN(REAUTH_STATE3));
120
0
    REAUTH_STATE = REAUTH_STATE3;
121
0
    IMED_RET("send certificate verify", ret, 0);
122
0
    FALLTHROUGH;
123
0
  case REAUTH_STATE4:
124
0
    ret = _gnutls13_send_finished(session, AGAIN(REAUTH_STATE4));
125
0
    REAUTH_STATE = REAUTH_STATE4;
126
0
    IMED_RET("send finished", ret, 0);
127
0
    break;
128
0
  default:
129
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
130
0
  }
131
132
0
  _gnutls_handshake_hash_buffers_clear(session);
133
0
  _gnutls_buffer_reset(&session->internals.reauth_buffer);
134
0
  REAUTH_STATE = REAUTH_STATE0;
135
136
0
  return 0;
137
0
}
138
139
/*
140
 * _gnutls13_reauth_server
141
 * This function does the server stuff of the post-handshake authentication.
142
 */
143
static int _gnutls13_reauth_server(gnutls_session_t session)
144
0
{
145
0
  int ret = 0;
146
147
0
  if (session->security_parameters.post_handshake_auth == 0 ||
148
0
      (!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)))
149
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
150
151
0
  if (session->internals.send_cert_req == 0) {
152
0
    _gnutls_debug_log(
153
0
      "You need to call gnutls_certificate_server_set_request to enable post handshake auth\n");
154
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
155
0
  }
156
157
0
  switch (REAUTH_STATE) {
158
0
  case REAUTH_STATE0:
159
    /* restore handshake transcript */
160
0
    _gnutls_buffer_reset(&session->internals.handshake_hash_buffer);
161
0
    ret = gnutls_buffer_append_data(
162
0
      &session->internals.handshake_hash_buffer,
163
0
      session->internals.post_handshake_hash_buffer.data,
164
0
      session->internals.post_handshake_hash_buffer.length);
165
0
    if (ret < 0)
166
0
      return gnutls_assert_val(ret);
167
168
0
    session->internals.handshake_hash_buffer_prev_len =
169
0
      session->internals.handshake_hash_buffer.length;
170
171
0
    FALLTHROUGH;
172
0
  case REAUTH_STATE1:
173
0
    ret = _gnutls13_send_certificate_request(session,
174
0
               AGAIN(REAUTH_STATE1));
175
0
    REAUTH_STATE = REAUTH_STATE1;
176
0
    IMED_RET("send certificate request", ret, 0);
177
0
    FALLTHROUGH;
178
0
  case REAUTH_STATE2:
179
    /* here we should tolerate application data */
180
0
    ret = _gnutls13_recv_certificate(session);
181
0
    REAUTH_STATE = REAUTH_STATE2;
182
0
    IMED_RET("recv certificate", ret, 0);
183
0
    FALLTHROUGH;
184
0
  case REAUTH_STATE3:
185
0
    ret = _gnutls13_recv_certificate_verify(session);
186
0
    REAUTH_STATE = REAUTH_STATE3;
187
0
    IMED_RET("recv certificate verify", ret, 0);
188
0
    FALLTHROUGH;
189
0
  case REAUTH_STATE4:
190
0
    ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT);
191
0
    REAUTH_STATE = REAUTH_STATE4;
192
0
    if (ret < 0)
193
0
      return gnutls_assert_val(ret);
194
0
    FALLTHROUGH;
195
0
  case REAUTH_STATE5:
196
0
    ret = _gnutls13_recv_finished(session);
197
0
    REAUTH_STATE = REAUTH_STATE5;
198
0
    IMED_RET("recv finished", ret, 0);
199
0
    break;
200
0
  default:
201
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
202
0
  }
203
204
0
  _gnutls_handshake_hash_buffers_clear(session);
205
0
  REAUTH_STATE = REAUTH_STATE0;
206
207
0
  return 0;
208
0
}
209
210
/**
211
 * gnutls_reauth:
212
 * @session: is a #gnutls_session_t type.
213
 * @flags: must be zero
214
 *
215
 * This function performs the post-handshake authentication
216
 * for TLS 1.3. The post-handshake authentication is initiated by the server
217
 * by calling this function. Clients respond when %GNUTLS_E_REAUTH_REQUEST
218
 * has been seen while receiving data.
219
 *
220
 * The non-fatal errors expected by this function are:
221
 * %GNUTLS_E_INTERRUPTED, %GNUTLS_E_AGAIN, as well as
222
 * %GNUTLS_E_GOT_APPLICATION_DATA when called on server side.
223
 *
224
 * The former two interrupt the authentication procedure due to the transport
225
 * layer being interrupted, and the latter because there were pending data prior
226
 * to peer initiating the re-authentication. The server should read/process that
227
 * data as unauthenticated and retry calling gnutls_reauth().
228
 *
229
 * When this function is called under TLS1.2 or earlier or the peer didn't
230
 * advertise post-handshake auth, it always fails with
231
 * %GNUTLS_E_INVALID_REQUEST. The verification of the received peers certificate
232
 * is delegated to the session or credentials verification callbacks. A
233
 * server can check whether post handshake authentication is supported
234
 * by the client by checking the session flags with gnutls_session_get_flags().
235
 *
236
 * Prior to calling this function in server side, the function
237
 * gnutls_certificate_server_set_request() must be called setting expectations
238
 * for the received certificate (request or require). If none are set
239
 * this function will return with %GNUTLS_E_INVALID_REQUEST.
240
 *
241
 * Note that post handshake authentication is available irrespective
242
 * of the initial negotiation type (PSK or certificate). In all cases
243
 * however, certificate credentials must be set to the session prior
244
 * to calling this function.
245
 *
246
 * Returns: %GNUTLS_E_SUCCESS on a successful authentication, otherwise a negative error code.
247
 **/
248
int gnutls_reauth(gnutls_session_t session, unsigned int flags)
249
0
{
250
0
  const version_entry_st *vers = get_version(session);
251
252
0
  if (unlikely(!vers->tls13_sem))
253
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
254
255
0
  if (session->security_parameters.entity == GNUTLS_SERVER)
256
0
    return _gnutls13_reauth_server(session);
257
0
  else
258
0
    return _gnutls13_reauth_client(session);
259
0
}