Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/tls13/certificate.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
#include "gnutls_int.h"
24
#include "compress.h"
25
#include "errors.h"
26
#include "extv.h"
27
#include "handshake.h"
28
#include "tls13/certificate.h"
29
#include "auth/cert.h"
30
#include "mbuffers.h"
31
#include "ext/compress_certificate.h"
32
#include "ext/status_request.h"
33
34
static int parse_cert_extension(void *ctx, unsigned tls_id, const uint8_t *data,
35
        unsigned data_size);
36
static int parse_cert_list(gnutls_session_t session, uint8_t *data,
37
         size_t data_size);
38
static int compress_certificate(gnutls_buffer_st *buf, unsigned cert_pos_mark,
39
        gnutls_compression_method_t comp_method);
40
static int decompress_certificate(gnutls_session_t session,
41
          gnutls_buffer_st *buf);
42
43
int _gnutls13_recv_certificate(gnutls_session_t session)
44
0
{
45
0
  int ret, err, decompress_cert = 0;
46
0
  gnutls_buffer_st buf;
47
0
  unsigned optional = 0;
48
49
0
  if (!session->internals.initial_negotiation_completed &&
50
0
      session->internals.hsk_flags & HSK_PSK_SELECTED)
51
0
    return 0;
52
53
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
54
    /* if we didn't request a certificate, there will not be any */
55
0
    if (session->internals.send_cert_req == 0)
56
0
      return 0;
57
58
0
    if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
59
0
      optional = 1;
60
0
  }
61
62
0
  ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
63
0
             0, &buf);
64
0
  if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) {
65
    /* check if we received compressed certificate */
66
0
    err = _gnutls_recv_handshake(
67
0
      session, GNUTLS_HANDSHAKE_COMPRESSED_CERTIFICATE_PKT, 0,
68
0
      &buf);
69
0
    if (err >= 0) {
70
      /* fail if we receive unsolicited compressed certificate */
71
0
      if (!(session->internals.hsk_flags &
72
0
            HSK_COMP_CRT_REQ_SENT))
73
0
        return gnutls_assert_val(
74
0
          GNUTLS_E_UNEXPECTED_PACKET);
75
76
0
      decompress_cert = 1;
77
0
      ret = err;
78
0
    }
79
0
  }
80
0
  if (ret < 0) {
81
0
    if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET &&
82
0
        session->internals.send_cert_req)
83
0
      return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
84
85
0
    return gnutls_assert_val(ret);
86
0
  }
87
88
0
  if (buf.length == 0) {
89
0
    gnutls_assert();
90
0
    ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
91
0
    goto cleanup;
92
0
  }
93
94
0
  if (decompress_cert) {
95
0
    ret = decompress_certificate(session, &buf);
96
0
    if (ret < 0) {
97
0
      gnutls_assert();
98
0
      gnutls_alert_send(session, GNUTLS_AL_FATAL,
99
0
            GNUTLS_A_BAD_CERTIFICATE);
100
0
      goto cleanup;
101
0
    }
102
0
  }
103
104
0
  if (session->internals.initial_negotiation_completed &&
105
0
      session->internals.post_handshake_cr_context.size > 0) {
106
0
    gnutls_datum_t context;
107
108
    /* verify whether the context matches */
109
0
    ret = _gnutls_buffer_pop_datum_prefix8(&buf, &context);
110
0
    if (ret < 0) {
111
0
      gnutls_assert();
112
0
      goto cleanup;
113
0
    }
114
115
0
    if (context.size !=
116
0
          session->internals.post_handshake_cr_context.size ||
117
0
        memcmp(context.data,
118
0
         session->internals.post_handshake_cr_context.data,
119
0
         context.size) != 0) {
120
0
      ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
121
0
      gnutls_assert();
122
0
      goto cleanup;
123
0
    }
124
0
  } else {
125
0
    if (buf.data[0] != 0) {
126
      /* The context field must be empty during handshake */
127
0
      gnutls_assert();
128
0
      ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
129
0
      goto cleanup;
130
0
    }
131
132
    /* buf.length is positive */
133
0
    buf.data++;
134
0
    buf.length--;
135
0
  }
136
137
0
  _gnutls_handshake_log("HSK[%p]: parsing certificate message\n",
138
0
            session);
139
140
0
  ret = parse_cert_list(session, buf.data, buf.length);
141
0
  if (ret < 0) {
142
0
    if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
143
0
      if (optional)
144
0
        ret = 0;
145
0
      else if (session->security_parameters.entity ==
146
0
         GNUTLS_SERVER)
147
0
        ret = GNUTLS_E_CERTIFICATE_REQUIRED;
148
0
    }
149
0
    gnutls_assert();
150
0
    goto cleanup;
151
0
  }
152
153
0
  session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;
154
155
0
  ret = 0;
156
0
cleanup:
157
158
0
  _gnutls_buffer_clear(&buf);
159
0
  return ret;
160
0
}
161
162
struct ocsp_req_ctx_st {
163
  gnutls_pcert_st *pcert;
164
  unsigned cert_index;
165
  gnutls_session_t session;
166
  gnutls_certificate_credentials_t cred;
167
};
168
169
static int append_status_request(void *_ctx, gnutls_buffer_st *buf)
170
0
{
171
0
  struct ocsp_req_ctx_st *ctx = _ctx;
172
0
  gnutls_session_t session = ctx->session;
173
0
  int ret;
174
0
  gnutls_datum_t resp;
175
0
  unsigned free_resp = 0;
176
177
0
  assert(session->internals.selected_ocsp_func != NULL ||
178
0
         session->internals.selected_ocsp_length != 0);
179
180
  /* The global ocsp callback function can only be used to return
181
   * a single certificate request */
182
0
  if (session->internals.selected_ocsp_length == 1 &&
183
0
      ctx->cert_index != 0)
184
0
    return 0;
185
186
0
  if (session->internals.selected_ocsp_length > 0) {
187
0
    if (ctx->cert_index < session->internals.selected_ocsp_length) {
188
0
      if ((session->internals.selected_ocsp[ctx->cert_index]
189
0
               .exptime != 0 &&
190
0
           gnutls_time(0) >=
191
0
             session->internals
192
0
               .selected_ocsp[ctx->cert_index]
193
0
               .exptime) ||
194
0
          session->internals.selected_ocsp[ctx->cert_index]
195
0
              .response.data == NULL) {
196
0
        return 0;
197
0
      }
198
199
0
      resp.data = session->internals
200
0
              .selected_ocsp[ctx->cert_index]
201
0
              .response.data;
202
0
      resp.size = session->internals
203
0
              .selected_ocsp[ctx->cert_index]
204
0
              .response.size;
205
0
      ret = 0;
206
0
    } else {
207
0
      return 0;
208
0
    }
209
0
  } else if (session->internals.selected_ocsp_func) {
210
0
    if (ctx->cert_index == 0) {
211
0
      ret = session->internals.selected_ocsp_func(
212
0
        session,
213
0
        session->internals.selected_ocsp_func_ptr,
214
0
        &resp);
215
0
      free_resp = 1;
216
0
    } else {
217
0
      return 0;
218
0
    }
219
0
  } else
220
0
    return 0;
221
222
0
  if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
223
0
    return 0;
224
0
  } else if (ret < 0) {
225
0
    return gnutls_assert_val(ret);
226
0
  }
227
228
0
  ret = _gnutls_buffer_append_data(buf, "\x01", 1);
229
0
  if (ret < 0) {
230
0
    gnutls_assert();
231
0
    goto cleanup;
232
0
  }
233
234
0
  ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
235
0
  if (ret < 0) {
236
0
    gnutls_assert();
237
0
    goto cleanup;
238
0
  }
239
240
0
  ret = 0;
241
0
cleanup:
242
0
  if (free_resp)
243
0
    gnutls_free(resp.data);
244
0
  return ret;
245
0
}
246
247
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
248
0
{
249
0
  int ret, compress_cert;
250
0
  gnutls_pcert_st *apr_cert_list = NULL;
251
0
  gnutls_privkey_t apr_pkey = NULL;
252
0
  int apr_cert_list_length = 0;
253
0
  mbuffer_st *bufel = NULL;
254
0
  gnutls_buffer_st buf;
255
0
  unsigned pos_mark, ext_pos_mark, cert_pos_mark;
256
0
  unsigned i;
257
0
  struct ocsp_req_ctx_st ctx;
258
0
  gnutls_certificate_credentials_t cred;
259
0
  gnutls_compression_method_t comp_method;
260
0
  gnutls_handshake_description_t h_type;
261
262
0
  comp_method = gnutls_compress_certificate_get_selected_method(session);
263
0
  compress_cert = comp_method != GNUTLS_COMP_UNKNOWN;
264
0
  h_type = compress_cert ? GNUTLS_HANDSHAKE_COMPRESSED_CERTIFICATE_PKT :
265
0
         GNUTLS_HANDSHAKE_CERTIFICATE_PKT;
266
267
0
  if (again == 0) {
268
0
    if (!session->internals.initial_negotiation_completed &&
269
0
        session->internals.hsk_flags & HSK_PSK_SELECTED)
270
0
      return 0;
271
272
0
    if (session->security_parameters.entity == GNUTLS_SERVER &&
273
0
        session->internals.resumed)
274
0
      return 0;
275
276
0
    cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(
277
0
      session, GNUTLS_CRD_CERTIFICATE);
278
0
    if (cred == NULL) {
279
0
      gnutls_assert();
280
0
      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
281
0
    }
282
283
0
    if (session->security_parameters.entity == GNUTLS_CLIENT &&
284
0
        !(session->internals.hsk_flags & HSK_CRT_ASKED)) {
285
0
      return 0;
286
0
    }
287
288
0
    ret = _gnutls_get_selected_cert(session, &apr_cert_list,
289
0
            &apr_cert_list_length,
290
0
            &apr_pkey);
291
0
    if (ret < 0)
292
0
      return gnutls_assert_val(ret);
293
294
0
    ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
295
0
    if (ret < 0)
296
0
      return gnutls_assert_val(ret);
297
298
0
    cert_pos_mark = buf.length;
299
300
0
    if (session->security_parameters.entity == GNUTLS_CLIENT) {
301
0
      ret = _gnutls_buffer_append_data_prefix(
302
0
        &buf, 8,
303
0
        session->internals.post_handshake_cr_context
304
0
          .data,
305
0
        session->internals.post_handshake_cr_context
306
0
          .size);
307
0
      if (ret < 0) {
308
0
        gnutls_assert();
309
0
        goto cleanup;
310
0
      }
311
312
0
    } else {
313
0
      ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
314
0
      if (ret < 0) {
315
0
        gnutls_assert();
316
0
        goto cleanup;
317
0
      }
318
0
    }
319
320
    /* mark total size */
321
0
    pos_mark = buf.length;
322
0
    ret = _gnutls_buffer_append_prefix(&buf, 24, 0);
323
0
    if (ret < 0) {
324
0
      gnutls_assert();
325
0
      goto cleanup;
326
0
    }
327
328
0
    for (i = 0; i < (unsigned)apr_cert_list_length; i++) {
329
0
      ret = _gnutls_buffer_append_data_prefix(
330
0
        &buf, 24, apr_cert_list[i].cert.data,
331
0
        apr_cert_list[i].cert.size);
332
0
      if (ret < 0) {
333
0
        gnutls_assert();
334
0
        goto cleanup;
335
0
      }
336
0
#ifdef ENABLE_OCSP
337
0
      if ((session->internals.selected_ocsp_length > 0 ||
338
0
           session->internals.selected_ocsp_func) &&
339
0
          (((session->internals.hsk_flags &
340
0
             HSK_OCSP_REQUESTED) &&
341
0
            IS_SERVER(session)) ||
342
0
           ((session->internals.hsk_flags &
343
0
             HSK_CLIENT_OCSP_REQUESTED) &&
344
0
            !IS_SERVER(session)))) {
345
        /* append status response if available */
346
0
        ret = _gnutls_extv_append_init(&buf);
347
0
        if (ret < 0) {
348
0
          gnutls_assert();
349
0
          goto cleanup;
350
0
        }
351
0
        ext_pos_mark = ret;
352
353
0
        ctx.pcert = &apr_cert_list[i];
354
0
        ctx.cert_index = i;
355
0
        ctx.session = session;
356
0
        ctx.cred = cred;
357
0
        ret = _gnutls_extv_append(
358
0
          &buf, STATUS_REQUEST_TLS_ID, &ctx,
359
0
          append_status_request);
360
0
        if (ret < 0) {
361
0
          gnutls_assert();
362
0
          goto cleanup;
363
0
        }
364
365
0
        ret = _gnutls_extv_append_final(
366
0
          &buf, ext_pos_mark, 0);
367
0
        if (ret < 0) {
368
0
          gnutls_assert();
369
0
          goto cleanup;
370
0
        }
371
0
      } else
372
0
#endif
373
0
      {
374
0
        ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
375
0
        if (ret < 0) {
376
0
          gnutls_assert();
377
0
          goto cleanup;
378
0
        }
379
0
      }
380
0
    }
381
382
0
    _gnutls_write_uint24(buf.length - pos_mark - 3,
383
0
             &buf.data[pos_mark]);
384
385
0
    if (compress_cert) {
386
0
      ret = compress_certificate(&buf, cert_pos_mark,
387
0
               comp_method);
388
0
      if (ret < 0) {
389
0
        gnutls_assert();
390
0
        goto cleanup;
391
0
      }
392
0
    }
393
394
0
    bufel = _gnutls_buffer_to_mbuffer(&buf);
395
0
  }
396
397
0
  return _gnutls_send_handshake(session, bufel, h_type);
398
399
0
cleanup:
400
0
  _gnutls_buffer_clear(&buf);
401
0
  return ret;
402
0
}
403
404
typedef struct crt_cert_ctx_st {
405
  gnutls_session_t session;
406
  gnutls_datum_t *ocsp;
407
  unsigned idx;
408
} crt_cert_ctx_st;
409
410
static int parse_cert_extension(void *_ctx, unsigned tls_id,
411
        const uint8_t *data, unsigned data_size)
412
0
{
413
0
  crt_cert_ctx_st *ctx = _ctx;
414
0
  gnutls_session_t session = ctx->session;
415
0
  int ret;
416
417
0
  if (tls_id == STATUS_REQUEST_TLS_ID) {
418
0
#ifdef ENABLE_OCSP
419
0
    if (!_gnutls_hello_ext_is_present(session,
420
0
              ext_mod_status_request.gid)) {
421
0
      gnutls_assert();
422
0
      goto unexpected;
423
0
    }
424
425
0
    _gnutls_handshake_log("Found OCSP response on cert %d\n",
426
0
              ctx->idx);
427
428
0
    ret = _gnutls_parse_ocsp_response(session, data, data_size,
429
0
              ctx->ocsp);
430
0
    if (ret < 0)
431
0
      return gnutls_assert_val(ret);
432
0
#endif
433
0
  } else {
434
0
    goto unexpected;
435
0
  }
436
437
0
  return 0;
438
439
0
unexpected:
440
0
  _gnutls_debug_log("received unexpected certificate extension (%d)\n",
441
0
        (int)tls_id);
442
0
  return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
443
0
}
444
445
static int parse_cert_list(gnutls_session_t session, uint8_t *data,
446
         size_t data_size)
447
0
{
448
0
  int ret;
449
0
  size_t len;
450
0
  uint8_t *p = data;
451
0
  cert_auth_info_t info;
452
0
  gnutls_certificate_credentials_t cred;
453
0
  size_t size;
454
0
  int i;
455
0
  unsigned npeer_certs, npeer_ocsp, j;
456
0
  crt_cert_ctx_st ctx;
457
0
  gnutls_datum_t *peer_certs = NULL;
458
0
  gnutls_datum_t *peer_ocsp = NULL;
459
0
  unsigned nentries = 0;
460
461
0
  cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(
462
0
    session, GNUTLS_CRD_CERTIFICATE);
463
0
  if (cred == NULL) {
464
0
    gnutls_assert();
465
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
466
0
  }
467
468
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
469
0
            sizeof(cert_auth_info_st), 1)) < 0) {
470
0
    gnutls_assert();
471
0
    return ret;
472
0
  }
473
474
0
  if (data == NULL || data_size == 0) {
475
    /* no certificate was sent */
476
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
477
0
  }
478
479
0
  info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
480
0
  if (info == NULL)
481
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
482
483
0
  DECR_LEN(data_size, 3);
484
0
  size = _gnutls_read_uint24(p);
485
0
  p += 3;
486
487
0
  if (size != data_size)
488
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
489
490
0
  if (size == 0)
491
0
    return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
492
493
0
  i = data_size;
494
495
0
  while (i > 0) {
496
0
    DECR_LEN(data_size, 3);
497
0
    len = _gnutls_read_uint24(p);
498
0
    if (len == 0)
499
0
      return gnutls_assert_val(
500
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
501
502
0
    DECR_LEN(data_size, len);
503
0
    p += len + 3;
504
0
    i -= len + 3;
505
506
0
    DECR_LEN(data_size, 2);
507
0
    len = _gnutls_read_uint16(p);
508
0
    DECR_LEN(data_size, len);
509
510
0
    i -= len + 2;
511
0
    p += len + 2;
512
513
0
    nentries++;
514
0
  }
515
516
0
  if (data_size != 0)
517
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
518
519
  /* this is unnecessary - keeping to avoid a regression due to a re-org
520
   * of the loop above */
521
0
  if (nentries == 0)
522
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
523
524
0
  npeer_ocsp = 0;
525
0
  npeer_certs = 0;
526
527
  /* Ok we now allocate the memory to hold the
528
   * certificate list
529
   */
530
0
  peer_certs = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
531
0
  if (peer_certs == NULL)
532
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
533
534
0
  peer_ocsp = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
535
0
  if (peer_ocsp == NULL) {
536
0
    ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
537
0
    goto cleanup;
538
0
  }
539
540
0
  p = data + 3;
541
542
  /* Now we start parsing the list (again).
543
   * We don't use DECR_LEN since the list has
544
   * been parsed before.
545
   */
546
547
0
  ctx.session = session;
548
549
0
  for (j = 0; j < nentries; j++) {
550
0
    len = _gnutls_read_uint24(p);
551
0
    p += 3;
552
553
0
    ret = _gnutls_set_datum(&peer_certs[j], p, len);
554
0
    if (ret < 0) {
555
0
      gnutls_assert();
556
0
      ret = GNUTLS_E_CERTIFICATE_ERROR;
557
0
      goto cleanup;
558
0
    }
559
0
    npeer_certs++;
560
561
0
    p += len;
562
563
0
    len = _gnutls_read_uint16(p);
564
565
0
    ctx.ocsp = &peer_ocsp[j];
566
0
    ctx.idx = j;
567
568
0
    ret = _gnutls_extv_parse(&ctx, parse_cert_extension, p,
569
0
           len + 2);
570
0
    if (ret < 0) {
571
0
      gnutls_assert();
572
0
      goto cleanup;
573
0
    }
574
575
0
    p += len + 2;
576
0
    npeer_ocsp++;
577
0
  }
578
579
  /* The OCSP entries match the certificate entries, although
580
   * the contents of each OCSP entry may be NULL.
581
   */
582
0
  for (j = 0; j < info->ncerts; j++)
583
0
    gnutls_free(info->raw_certificate_list[j].data);
584
0
  gnutls_free(info->raw_certificate_list);
585
586
0
  for (j = 0; j < info->nocsp; j++)
587
0
    gnutls_free(info->raw_ocsp_list[j].data);
588
0
  gnutls_free(info->raw_ocsp_list);
589
590
0
  info->raw_certificate_list = peer_certs;
591
0
  info->ncerts = npeer_certs;
592
593
0
  info->raw_ocsp_list = peer_ocsp;
594
0
  info->nocsp = npeer_ocsp;
595
596
0
  return 0;
597
598
0
cleanup:
599
0
  for (j = 0; j < npeer_certs; j++)
600
0
    gnutls_free(peer_certs[j].data);
601
602
0
  for (j = 0; j < npeer_ocsp; j++)
603
0
    gnutls_free(peer_ocsp[j].data);
604
0
  gnutls_free(peer_certs);
605
0
  gnutls_free(peer_ocsp);
606
0
  return ret;
607
0
}
608
609
static int compress_certificate(gnutls_buffer_st *buf, unsigned cert_pos_mark,
610
        gnutls_compression_method_t comp_method)
611
0
{
612
0
  int ret, method_num;
613
0
  size_t comp_bound;
614
0
  gnutls_datum_t plain, comp = { NULL, 0 };
615
616
0
  method_num = _gnutls_compress_certificate_method2num(comp_method);
617
0
  if (method_num == GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER)
618
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
619
620
0
  plain.data = buf->data + cert_pos_mark;
621
0
  plain.size = buf->length - cert_pos_mark;
622
623
0
  comp_bound = _gnutls_compress_bound(comp_method, plain.size);
624
0
  if (comp_bound == 0)
625
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
626
0
  comp.data = gnutls_malloc(comp_bound);
627
0
  if (comp.data == NULL)
628
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
629
0
  ret = _gnutls_compress(comp_method, comp.data, comp_bound, plain.data,
630
0
             plain.size);
631
0
  if (ret < 0) {
632
0
    gnutls_assert();
633
0
    goto cleanup;
634
0
  }
635
0
  comp.size = ret;
636
637
0
  buf->length = cert_pos_mark;
638
0
  ret = _gnutls_buffer_append_prefix(buf, 16, method_num);
639
0
  if (ret < 0) {
640
0
    gnutls_assert();
641
0
    goto cleanup;
642
0
  }
643
0
  ret = _gnutls_buffer_append_prefix(buf, 24, plain.size);
644
0
  if (ret < 0) {
645
0
    gnutls_assert();
646
0
    goto cleanup;
647
0
  }
648
0
  ret = _gnutls_buffer_append_data_prefix(buf, 24, comp.data, comp.size);
649
0
  if (ret < 0) {
650
0
    gnutls_assert();
651
0
    goto cleanup;
652
0
  }
653
654
0
cleanup:
655
0
  gnutls_free(comp.data);
656
0
  return ret;
657
0
}
658
659
static int decompress_certificate(gnutls_session_t session,
660
          gnutls_buffer_st *buf)
661
0
{
662
0
  int ret;
663
0
  size_t method_num, plain_exp_len;
664
0
  gnutls_datum_t comp, plain = { NULL, 0 };
665
0
  gnutls_compression_method_t comp_method;
666
667
0
  ret = _gnutls_buffer_pop_prefix16(buf, &method_num, 0);
668
0
  if (ret < 0)
669
0
    return gnutls_assert_val(ret);
670
0
  comp_method = _gnutls_compress_certificate_num2method(method_num);
671
672
0
  if (!_gnutls_compress_certificate_is_method_enabled(session,
673
0
                  comp_method))
674
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
675
676
0
  ret = _gnutls_buffer_pop_prefix24(buf, &plain_exp_len, 0);
677
0
  if (ret < 0)
678
0
    return gnutls_assert_val(ret);
679
680
0
  ret = _gnutls_buffer_pop_datum_prefix24(buf, &comp);
681
0
  if (ret < 0)
682
0
    return gnutls_assert_val(ret);
683
684
0
  plain.data = gnutls_malloc(plain_exp_len);
685
0
  if (plain.data == NULL)
686
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
687
0
  ret = _gnutls_decompress(comp_method, plain.data, plain_exp_len,
688
0
         comp.data, comp.size);
689
0
  if (ret < 0) {
690
0
    gnutls_assert();
691
0
    goto cleanup;
692
0
  }
693
0
  plain.size = ret;
694
695
0
  if (plain.size != plain_exp_len) {
696
0
    gnutls_assert();
697
0
    ret = GNUTLS_E_DECOMPRESSION_FAILED;
698
0
    goto cleanup;
699
0
  }
700
701
0
  _gnutls_buffer_clear(buf);
702
0
  ret = _gnutls_buffer_append_data(buf, plain.data, plain.size);
703
0
  if (ret < 0) {
704
0
    gnutls_assert();
705
0
    goto cleanup;
706
0
  }
707
708
0
cleanup:
709
0
  gnutls_free(plain.data);
710
0
  return ret;
711
0
}