Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/ext/status_request.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2012-2017 Free Software Foundation, Inc.
3
 * Copyright (C) 2017 Red Hat, Inc.
4
 *
5
 * Author: Simon Josefsson, Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/*
25
  Status Request (OCSP) TLS extension.  See RFC 6066 section 8:
26
  https://tools.ietf.org/html/rfc6066#section-8
27
*/
28
29
#include "gnutls_int.h"
30
#include "errors.h"
31
#include "hello_ext.h"
32
#include "ext/status_request.h"
33
#include "mbuffers.h"
34
#include "auth.h"
35
#include "auth/cert.h"
36
#include "handshake.h"
37
38
#ifdef ENABLE_OCSP
39
40
typedef struct {
41
  /* server response */
42
  gnutls_datum_t sresp;
43
44
  unsigned int expect_cstatus;
45
} status_request_ext_st;
46
47
/*
48
  From RFC 6066.  Client sends:
49
50
      struct {
51
    CertificateStatusType status_type;
52
    select (status_type) {
53
        case ocsp: OCSPStatusRequest;
54
    } request;
55
      } CertificateStatusRequest;
56
57
      enum { ocsp(1), (255) } CertificateStatusType;
58
59
      struct {
60
    ResponderID responder_id_list<0..2^16-1>;
61
    Extensions  request_extensions;
62
      } OCSPStatusRequest;
63
64
      opaque ResponderID<1..2^16-1>;
65
      opaque Extensions<0..2^16-1>;
66
*/
67
68
static int client_send(gnutls_session_t session, gnutls_buffer_st *extdata,
69
           status_request_ext_st *priv)
70
0
{
71
0
  const uint8_t data[5] = "\x01\x00\x00\x00\x00";
72
0
  const int len = 5;
73
0
  int ret;
74
75
  /* We do not support setting either ResponderID or Extensions */
76
77
0
  ret = _gnutls_buffer_append_data(extdata, data, len);
78
0
  if (ret < 0)
79
0
    return gnutls_assert_val(ret);
80
81
0
  session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
82
83
0
  return len;
84
0
}
85
86
static int server_recv(gnutls_session_t session, const uint8_t *data,
87
           size_t data_size)
88
0
{
89
0
  unsigned rid_bytes = 0;
90
91
  /* minimum message is type (1) + responder_id_list (2) +
92
     request_extension (2) = 5 */
93
0
  if (data_size < 5)
94
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
95
96
  /* We ignore non-ocsp CertificateStatusType.  The spec is unclear
97
     what should be done. */
98
0
  if (data[0] != 0x01) {
99
0
    gnutls_assert();
100
0
    _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
101
0
              session, data[0]);
102
0
    return 0;
103
0
  }
104
0
  DECR_LEN(data_size, 1);
105
0
  data++;
106
107
0
  rid_bytes = _gnutls_read_uint16(data);
108
109
0
  DECR_LEN(data_size, 2);
110
  /*data += 2; */
111
112
  /* sanity check only, we don't use any of the data below */
113
114
0
  if (data_size < rid_bytes)
115
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
116
117
0
  _gnutls_handshake_log("EXT[%p]: OCSP status was requested\n", session);
118
0
  session->internals.hsk_flags |= HSK_OCSP_REQUESTED;
119
120
0
  return 0;
121
0
}
122
123
static int client_recv(gnutls_session_t session, status_request_ext_st *priv,
124
           const uint8_t *data, size_t size)
125
0
{
126
0
  if (size != 0)
127
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
128
0
  else {
129
0
    priv->expect_cstatus = 1;
130
0
    return 0;
131
0
  }
132
0
}
133
134
/*
135
 * Servers return a certificate response along with their certificate
136
 * by sending a "CertificateStatus" message immediately after the
137
 * "Certificate" message (and before any "ServerKeyExchange" or
138
 * "CertificateRequest" messages).  If a server returns a
139
 * "CertificateStatus" message, then the server MUST have included an
140
 * extension of type "status_request" with empty "extension_data" in
141
 * the extended server hello.
142
 *
143
 * According to the description above, as a server we could simply 
144
 * return GNUTLS_E_INT_RET_0 on this function. In that case we would
145
 * only need to use the callbacks at the time we need to send the data,
146
 * and skip the status response packet if no such data are there.
147
 * However, that behavior would break gnutls 3.3.x which expects the status 
148
 * response to be always send if the extension is present.
149
 *
150
 * Instead we ensure that this extension is parsed after the CS/certificate
151
 * are selected (with the _GNUTLS_EXT_TLS_POST_CS type), and we discover
152
 * (or not) the response to send early.
153
 */
154
static int server_send(gnutls_session_t session, gnutls_buffer_st *extdata,
155
           status_request_ext_st *priv)
156
0
{
157
0
  int ret;
158
0
  gnutls_certificate_credentials_t cred;
159
0
  gnutls_status_request_ocsp_func func;
160
0
  void *func_ptr;
161
0
  const version_entry_st *ver = get_version(session);
162
163
0
  cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(
164
0
    session, GNUTLS_CRD_CERTIFICATE);
165
0
  if (cred == NULL) /* no certificate authentication */
166
0
    return 0;
167
168
  /* no need to set sresp; responses are send during certificate sending and
169
   * no response is required from server side. */
170
0
  if (ver && ver->multi_ocsp)
171
0
    return 0;
172
173
  /* Under TLS1.2 we obtain the response at this point in order to respond
174
   * appropriately (empty extension vs no response) */
175
0
  if (session->internals.selected_ocsp_length > 0) {
176
0
    if (session->internals.selected_ocsp[0].response.data) {
177
0
      if (session->internals.selected_ocsp[0].exptime != 0 &&
178
0
          (gnutls_time(0) >=
179
0
           session->internals.selected_ocsp[0].exptime)) {
180
0
        gnutls_assert();
181
0
        return 0;
182
0
      }
183
184
0
      ret = _gnutls_set_datum(
185
0
        &priv->sresp,
186
0
        session->internals.selected_ocsp[0]
187
0
          .response.data,
188
0
        session->internals.selected_ocsp[0]
189
0
          .response.size);
190
0
      if (ret < 0)
191
0
        return gnutls_assert_val(ret);
192
0
      return GNUTLS_E_INT_RET_0;
193
0
    } else {
194
0
      return 0;
195
0
    }
196
0
  } else if (session->internals.selected_ocsp_func) {
197
0
    func = session->internals.selected_ocsp_func;
198
0
    func_ptr = session->internals.selected_ocsp_func_ptr;
199
200
0
    if (func == NULL)
201
0
      return 0;
202
203
0
    ret = func(session, func_ptr, &priv->sresp);
204
0
    if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS)
205
0
      return 0;
206
0
    else if (ret < 0)
207
0
      return gnutls_assert_val(ret);
208
0
  } else {
209
0
    return 0;
210
0
  }
211
212
0
  return GNUTLS_E_INT_RET_0;
213
0
}
214
215
static int _gnutls_status_request_send_params(gnutls_session_t session,
216
                gnutls_buffer_st *extdata)
217
0
{
218
0
  gnutls_ext_priv_data_t epriv;
219
0
  status_request_ext_st *priv;
220
0
  int ret;
221
222
  /* Do not bother sending the OCSP status request extension
223
   * if we are not using certificate authentication */
224
0
  if (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL)
225
0
    return 0;
226
227
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
228
0
    if (session->internals.flags & GNUTLS_NO_STATUS_REQUEST)
229
0
      return 0;
230
231
0
    ret = _gnutls_hello_ext_get_priv(
232
0
      session, GNUTLS_EXTENSION_STATUS_REQUEST, &epriv);
233
0
    if (ret < 0 || epriv == NULL) /* it is ok not to have it */
234
0
      return 0;
235
0
    priv = epriv;
236
237
0
    return client_send(session, extdata, priv);
238
0
  } else {
239
0
    epriv = priv = gnutls_calloc(1, sizeof(*priv));
240
0
    if (priv == NULL)
241
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
242
243
0
    _gnutls_hello_ext_set_priv(
244
0
      session, GNUTLS_EXTENSION_STATUS_REQUEST, epriv);
245
246
0
    return server_send(session, extdata, priv);
247
0
  }
248
0
}
249
250
static int _gnutls_status_request_recv_params(gnutls_session_t session,
251
                const uint8_t *data, size_t size)
252
0
{
253
0
  gnutls_ext_priv_data_t epriv;
254
0
  status_request_ext_st *priv;
255
0
  int ret;
256
257
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
258
0
    ret = _gnutls_hello_ext_get_priv(
259
0
      session, GNUTLS_EXTENSION_STATUS_REQUEST, &epriv);
260
0
    if (ret < 0 || epriv == NULL) /* it is ok not to have it */
261
0
      return 0;
262
0
    priv = epriv;
263
264
0
    return client_recv(session, priv, data, size);
265
0
  } else {
266
0
    return server_recv(session, data, size);
267
0
  }
268
0
}
269
270
/**
271
 * gnutls_ocsp_status_request_enable_client:
272
 * @session: is a #gnutls_session_t type.
273
 * @responder_id: ignored, must be %NULL
274
 * @responder_id_size: ignored, must be zero
275
 * @extensions: ignored, must be %NULL
276
 *
277
 * This function is to be used by clients to request OCSP response
278
 * from the server, using the "status_request" TLS extension.  Only
279
 * OCSP status type is supported.
280
 *
281
 * Previous versions of GnuTLS supported setting @responder_id and
282
 * @extensions fields, but due to the difficult semantics of the
283
 * parameter usage, and other issues, this support was removed
284
 * since 3.6.0 and these parameters must be set to %NULL.
285
 *
286
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
287
 *   otherwise a negative error code is returned.
288
 *
289
 * Since: 3.1.3
290
 **/
291
int gnutls_ocsp_status_request_enable_client(gnutls_session_t session,
292
               gnutls_datum_t *responder_id,
293
               size_t responder_id_size,
294
               gnutls_datum_t *extensions)
295
0
{
296
0
  status_request_ext_st *priv;
297
0
  gnutls_ext_priv_data_t epriv;
298
299
0
  if (session->security_parameters.entity == GNUTLS_SERVER)
300
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
301
302
0
  epriv = priv = gnutls_calloc(1, sizeof(*priv));
303
0
  if (priv == NULL)
304
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
305
306
0
  _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_STATUS_REQUEST,
307
0
           epriv);
308
309
0
  session->internals.flags &= ~GNUTLS_NO_STATUS_REQUEST;
310
0
  if (session->internals.priorities)
311
0
    session->internals.priorities->no_status_request = 0;
312
313
0
  return 0;
314
0
}
315
316
static void _gnutls_status_request_deinit_data(gnutls_ext_priv_data_t epriv)
317
0
{
318
0
  status_request_ext_st *priv = epriv;
319
320
0
  if (priv == NULL)
321
0
    return;
322
323
0
  gnutls_free(priv->sresp.data);
324
0
  gnutls_free(priv);
325
0
}
326
327
const hello_ext_entry_st ext_mod_status_request = {
328
  .name = "OCSP Status Request",
329
  .tls_id = STATUS_REQUEST_TLS_ID,
330
  .gid = GNUTLS_EXTENSION_STATUS_REQUEST,
331
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
332
        GNUTLS_EXT_FLAG_CLIENT_HELLO |
333
        GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
334
  .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
335
  .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
336
  .recv_func = _gnutls_status_request_recv_params,
337
  .send_func = _gnutls_status_request_send_params,
338
  .deinit_func = _gnutls_status_request_deinit_data,
339
  .cannot_be_overriden = 1
340
};
341
342
/* Functions to be called from handshake */
343
344
int _gnutls_send_server_certificate_status(gnutls_session_t session, int again)
345
0
{
346
0
  mbuffer_st *bufel = NULL;
347
0
  uint8_t *data;
348
0
  int data_size = 0;
349
0
  int ret;
350
0
  gnutls_ext_priv_data_t epriv;
351
0
  status_request_ext_st *priv;
352
353
0
  if (!(session->internals.hsk_flags & HSK_OCSP_REQUESTED))
354
0
    return 0;
355
356
0
  if (again == 0) {
357
0
    ret = _gnutls_hello_ext_get_priv(
358
0
      session, GNUTLS_EXTENSION_STATUS_REQUEST, &epriv);
359
0
    if (ret < 0)
360
0
      return 0;
361
362
0
    priv = epriv;
363
364
0
    if (!priv->sresp.size)
365
0
      return 0;
366
367
0
    data_size = priv->sresp.size + 4;
368
0
    bufel = _gnutls_handshake_alloc(session, data_size);
369
0
    if (!bufel) {
370
0
      _gnutls_free_datum(&priv->sresp);
371
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
372
0
    }
373
374
0
    data = _mbuffer_get_udata_ptr(bufel);
375
376
0
    data[0] = 0x01;
377
0
    _gnutls_write_uint24(priv->sresp.size, &data[1]);
378
0
    memcpy(&data[4], priv->sresp.data, priv->sresp.size);
379
380
0
    _gnutls_free_datum(&priv->sresp);
381
0
  }
382
0
  return _gnutls_send_handshake(session, data_size ? bufel : NULL,
383
0
              GNUTLS_HANDSHAKE_CERTIFICATE_STATUS);
384
0
}
385
386
int _gnutls_parse_ocsp_response(gnutls_session_t session, const uint8_t *data,
387
        ssize_t data_size, gnutls_datum_t *resp)
388
0
{
389
0
  int ret;
390
0
  ssize_t r_size;
391
392
0
  resp->data = 0;
393
0
  resp->size = 0;
394
395
  /* minimum message is type (1) + response (3) + data */
396
0
  if (data_size < 4)
397
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
398
399
0
  if (data[0] != 0x01) {
400
0
    gnutls_assert();
401
0
    _gnutls_handshake_log("EXT[%p]: unknown status_type %d\n",
402
0
              session, data[0]);
403
0
    return 0;
404
0
  }
405
406
0
  DECR_LENGTH_RET(data_size, 1, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
407
0
  data++;
408
409
0
  DECR_LENGTH_RET(data_size, 3, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
410
411
0
  r_size = _gnutls_read_uint24(data);
412
0
  data += 3;
413
414
0
  DECR_LENGTH_RET(data_size, r_size, GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
415
416
0
  if (r_size < 1)
417
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
418
419
0
  ret = _gnutls_set_datum(resp, data, r_size);
420
0
  if (ret < 0)
421
0
    return gnutls_assert_val(ret);
422
423
0
  return 0;
424
0
}
425
426
int _gnutls_recv_server_certificate_status(gnutls_session_t session)
427
0
{
428
0
  uint8_t *data;
429
0
  ssize_t data_size;
430
0
  gnutls_buffer_st buf;
431
0
  int ret;
432
0
  gnutls_datum_t resp;
433
0
  status_request_ext_st *priv = NULL;
434
0
  gnutls_ext_priv_data_t epriv;
435
0
  cert_auth_info_t info =
436
0
    _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
437
438
0
  if (info == NULL)
439
0
    return 0;
440
441
0
  ret = _gnutls_hello_ext_get_priv(
442
0
    session, GNUTLS_EXTENSION_STATUS_REQUEST, &epriv);
443
0
  if (ret < 0)
444
0
    return 0;
445
446
0
  priv = epriv;
447
448
0
  if (!priv->expect_cstatus)
449
0
    return 0;
450
451
0
  ret = _gnutls_recv_handshake(
452
0
    session, GNUTLS_HANDSHAKE_CERTIFICATE_STATUS, 1, &buf);
453
0
  if (ret < 0)
454
0
    return gnutls_assert_val_fatal(ret);
455
456
0
  priv->expect_cstatus = 0;
457
458
0
  data = buf.data;
459
0
  data_size = buf.length;
460
461
0
  if (data_size == 0) {
462
0
    ret = 0;
463
0
    goto error;
464
0
  }
465
466
0
  ret = _gnutls_parse_ocsp_response(session, data, data_size, &resp);
467
0
  if (ret < 0) {
468
0
    gnutls_assert();
469
0
    goto error;
470
0
  }
471
472
0
  if (resp.data && resp.size > 0) {
473
0
    for (unsigned int i = 0; i < info->nocsp; i++)
474
0
      gnutls_free(info->raw_ocsp_list[i].data);
475
0
    gnutls_free(info->raw_ocsp_list);
476
477
0
    info->raw_ocsp_list = gnutls_malloc(sizeof(gnutls_datum_t));
478
0
    if (info->raw_ocsp_list == NULL) {
479
0
      ret = GNUTLS_E_MEMORY_ERROR;
480
0
      goto error;
481
0
    }
482
0
    info->raw_ocsp_list[0].data = resp.data;
483
0
    info->raw_ocsp_list[0].size = resp.size;
484
0
    info->nocsp = 1;
485
0
  }
486
487
0
  ret = 0;
488
489
0
error:
490
0
  _gnutls_buffer_clear(&buf);
491
492
0
  return ret;
493
0
}
494
495
#endif