Coverage Report

Created: 2023-03-26 08:33

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