Coverage Report

Created: 2023-03-26 07:33

/src/gnutls/lib/ext/srtp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2012 Free Software Foundation
3
 * 
4
 * Author: Martin Storsjo
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 "auth.h"
25
#include "errors.h"
26
#include "num.h"
27
#include <ext/srtp.h>
28
29
static int _gnutls_srtp_recv_params(gnutls_session_t session,
30
            const uint8_t * data, size_t data_size);
31
static int _gnutls_srtp_send_params(gnutls_session_t session,
32
            gnutls_buffer_st * extdata);
33
34
static int _gnutls_srtp_unpack(gnutls_buffer_st * ps,
35
             gnutls_ext_priv_data_t * _priv);
36
static int _gnutls_srtp_pack(gnutls_ext_priv_data_t _priv,
37
           gnutls_buffer_st * ps);
38
static void _gnutls_srtp_deinit_data(gnutls_ext_priv_data_t priv);
39
40
const hello_ext_entry_st ext_mod_srtp = {
41
  .name = "SRTP",
42
  .tls_id = 14,
43
  .gid = GNUTLS_EXTENSION_SRTP,
44
  .validity =
45
      GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
46
      GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE |
47
      GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
48
  .client_parse_point = GNUTLS_EXT_APPLICATION,
49
  .server_parse_point = GNUTLS_EXT_APPLICATION,
50
  .recv_func = _gnutls_srtp_recv_params,
51
  .send_func = _gnutls_srtp_send_params,
52
  .pack_func = _gnutls_srtp_pack,
53
  .unpack_func = _gnutls_srtp_unpack,
54
  .deinit_func = _gnutls_srtp_deinit_data,
55
  .cannot_be_overriden = 1
56
};
57
58
typedef struct {
59
  const char *name;
60
  gnutls_srtp_profile_t id;
61
  unsigned int key_length;
62
  unsigned int salt_length;
63
} srtp_profile_st;
64
65
static const srtp_profile_st profile_names[] = {
66
  {
67
   "SRTP_AES128_CM_HMAC_SHA1_80",
68
   GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80,
69
   16, 14},
70
  {
71
   "SRTP_AES128_CM_HMAC_SHA1_32",
72
   GNUTLS_SRTP_AES128_CM_HMAC_SHA1_32,
73
   16, 14},
74
  {
75
   "SRTP_NULL_HMAC_SHA1_80",
76
   GNUTLS_SRTP_NULL_HMAC_SHA1_80,
77
   16, 14},
78
  {
79
   "SRTP_NULL_SHA1_32",
80
   GNUTLS_SRTP_NULL_HMAC_SHA1_32,
81
   16, 14},
82
  {
83
   "SRTP_AEAD_AES_128_GCM",
84
   GNUTLS_SRTP_AEAD_AES_128_GCM,
85
   16, 12},
86
  {
87
   "SRTP_AEAD_AES_256_GCM",
88
   GNUTLS_SRTP_AEAD_AES_256_GCM,
89
   32, 12},
90
  {
91
   NULL,
92
   0, 0, 0}
93
};
94
95
static const srtp_profile_st *get_profile(gnutls_srtp_profile_t profile)
96
0
{
97
0
  const srtp_profile_st *p = profile_names;
98
0
  while (p->name != NULL) {
99
0
    if (p->id == profile)
100
0
      return p;
101
0
    p++;
102
0
  }
103
0
  return NULL;
104
0
}
105
106
static gnutls_srtp_profile_t find_profile(const char *str, const char *end)
107
0
{
108
0
  const srtp_profile_st *prof = profile_names;
109
0
  unsigned int len;
110
0
  if (end != NULL) {
111
0
    len = end - str;
112
0
  } else {
113
0
    len = strlen(str);
114
0
  }
115
116
0
  while (prof->name != NULL) {
117
0
    if (strlen(prof->name) == len && !strncmp(str, prof->name, len)) {
118
0
      return prof->id;
119
0
    }
120
0
    prof++;
121
0
  }
122
0
  return 0;
123
0
}
124
125
/**
126
 * gnutls_srtp_get_profile_id
127
 * @name: The name of the profile to look up
128
 * @profile: Will hold the profile id
129
 *
130
 * This function allows you to look up a profile based on a string.
131
 *
132
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
133
 *   otherwise a negative error code is returned.
134
 *
135
 * Since 3.1.4
136
 **/
137
int gnutls_srtp_get_profile_id(const char *name,
138
             gnutls_srtp_profile_t * profile)
139
0
{
140
0
  *profile = find_profile(name, NULL);
141
0
  if (*profile == 0) {
142
0
    return GNUTLS_E_ILLEGAL_PARAMETER;
143
0
  }
144
0
  return 0;
145
0
}
146
147
0
#define MAX_PROFILES_IN_SRTP_EXTENSION 256
148
149
/**
150
 * gnutls_srtp_get_profile_name
151
 * @profile: The profile to look up a string for
152
 *
153
 * This function allows you to get the corresponding name for a
154
 * SRTP protection profile.
155
 *
156
 * Returns: On success, the name of a SRTP profile as a string,
157
 *   otherwise NULL.
158
 *
159
 * Since 3.1.4
160
 **/
161
const char *gnutls_srtp_get_profile_name(gnutls_srtp_profile_t profile)
162
0
{
163
0
  const srtp_profile_st *p = get_profile(profile);
164
165
0
  if (p != NULL)
166
0
    return p->name;
167
168
0
  return NULL;
169
0
}
170
171
static int
172
_gnutls_srtp_recv_params(gnutls_session_t session,
173
       const uint8_t * data, size_t data_size)
174
0
{
175
0
  unsigned int i;
176
0
  int ret;
177
0
  const uint8_t *p = data;
178
0
  size_t len;
179
0
  srtp_ext_st *priv;
180
0
  gnutls_ext_priv_data_t epriv;
181
0
  uint16_t profile;
182
183
0
  ret =
184
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
185
0
  if (ret < 0)
186
0
    return 0;
187
188
0
  priv = epriv;
189
190
0
  DECR_LENGTH_RET(data_size, 2, 0);
191
0
  len = _gnutls_read_uint16(p);
192
0
  p += 2;
193
194
0
  if (len + 1 > data_size)
195
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
196
197
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
198
0
    if (len > MAX_PROFILES_IN_SRTP_EXTENSION * 2)
199
0
      return 0;
200
0
  } else {
201
0
    if (len != 2)
202
0
      return
203
0
          gnutls_assert_val
204
0
          (GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
205
0
  }
206
207
0
  priv->selected_profile = 0;
208
209
0
  while (len > 0) {
210
0
    DECR_LEN(data_size, 2);
211
0
    profile = _gnutls_read_uint16(p);
212
213
0
    for (i = 0;
214
0
         i < priv->profiles_size
215
0
         && priv->selected_profile == 0; i++) {
216
0
      if (priv->profiles[i] == profile) {
217
0
        priv->selected_profile = profile;
218
0
        break;
219
0
      }
220
0
    }
221
0
    p += 2;
222
0
    len -= 2;
223
0
  }
224
225
0
  DECR_LEN(data_size, 1);
226
0
  priv->mki_size = *p;
227
0
  p++;
228
229
0
  if (priv->mki_size > 0) {
230
0
    DECR_LEN(data_size, priv->mki_size);
231
0
    memcpy(priv->mki, p, priv->mki_size);
232
0
    priv->mki_received = 1;
233
0
  }
234
235
0
  return 0;
236
0
}
237
238
static int
239
_gnutls_srtp_send_params(gnutls_session_t session, gnutls_buffer_st * extdata)
240
0
{
241
0
  unsigned i;
242
0
  int total_size = 0, ret;
243
0
  srtp_ext_st *priv;
244
0
  gnutls_ext_priv_data_t epriv;
245
246
0
  ret =
247
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
248
0
  if (ret < 0)
249
0
    return 0;
250
251
0
  priv = epriv;
252
253
0
  if (priv->profiles_size == 0)
254
0
    return 0;
255
256
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
257
    /* Don't send anything if no matching profile was found */
258
0
    if (priv->selected_profile == 0)
259
0
      return 0;
260
261
0
    ret = _gnutls_buffer_append_prefix(extdata, 16, 2);
262
0
    if (ret < 0)
263
0
      return gnutls_assert_val(ret);
264
0
    ret =
265
0
        _gnutls_buffer_append_prefix(extdata, 16,
266
0
             priv->selected_profile);
267
0
    if (ret < 0)
268
0
      return gnutls_assert_val(ret);
269
0
    total_size = 4;
270
0
  } else {
271
0
    ret =
272
0
        _gnutls_buffer_append_prefix(extdata, 16,
273
0
             2 * priv->profiles_size);
274
0
    if (ret < 0)
275
0
      return gnutls_assert_val(ret);
276
277
0
    for (i = 0; i < priv->profiles_size; i++) {
278
0
      ret =
279
0
          _gnutls_buffer_append_prefix(extdata, 16,
280
0
               priv->profiles[i]);
281
0
      if (ret < 0)
282
0
        return gnutls_assert_val(ret);
283
0
    }
284
0
    total_size = 2 + 2 * priv->profiles_size;
285
0
  }
286
287
  /* use_mki */
288
0
  ret =
289
0
      _gnutls_buffer_append_data_prefix(extdata, 8, priv->mki,
290
0
                priv->mki_size);
291
0
  if (ret < 0)
292
0
    return gnutls_assert_val(ret);
293
0
  total_size += 1 + priv->mki_size;
294
295
0
  return total_size;
296
0
}
297
298
/**
299
 * gnutls_srtp_get_selected_profile:
300
 * @session: is a #gnutls_session_t type.
301
 * @profile: will hold the profile
302
 *
303
 * This function allows you to get the negotiated SRTP profile.
304
 *
305
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
306
 *   otherwise a negative error code is returned.
307
 *
308
 * Since 3.1.4
309
 **/
310
int
311
gnutls_srtp_get_selected_profile(gnutls_session_t session,
312
         gnutls_srtp_profile_t * profile)
313
0
{
314
0
  srtp_ext_st *priv;
315
0
  int ret;
316
0
  gnutls_ext_priv_data_t epriv;
317
318
0
  ret =
319
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
320
0
  if (ret < 0) {
321
0
    gnutls_assert();
322
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
323
0
  }
324
325
0
  priv = epriv;
326
327
0
  if (priv->selected_profile == 0) {
328
0
    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
329
0
  }
330
331
0
  *profile = priv->selected_profile;
332
333
0
  return 0;
334
0
}
335
336
/**
337
 * gnutls_srtp_get_mki:
338
 * @session: is a #gnutls_session_t type.
339
 * @mki: will hold the MKI
340
 *
341
 * This function exports the negotiated Master Key Identifier,
342
 * received by the peer if any. The returned value in @mki should be 
343
 * treated as constant and valid only during the session's lifetime.
344
 *
345
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
346
 *   otherwise a negative error code is returned.
347
 *
348
 * Since 3.1.4
349
 **/
350
int gnutls_srtp_get_mki(gnutls_session_t session, gnutls_datum_t * mki)
351
0
{
352
0
  srtp_ext_st *priv;
353
0
  int ret;
354
0
  gnutls_ext_priv_data_t epriv;
355
356
0
  ret =
357
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
358
0
  if (ret < 0)
359
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
360
361
0
  priv = epriv;
362
363
0
  if (priv->mki_received == 0)
364
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
365
366
0
  mki->data = priv->mki;
367
0
  mki->size = priv->mki_size;
368
369
0
  return 0;
370
0
}
371
372
/**
373
 * gnutls_srtp_set_mki:
374
 * @session: is a #gnutls_session_t type.
375
 * @mki: holds the MKI
376
 *
377
 * This function sets the Master Key Identifier, to be
378
 * used by this session (if any).
379
 *
380
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
381
 *   otherwise a negative error code is returned.
382
 *
383
 * Since 3.1.4
384
 **/
385
int gnutls_srtp_set_mki(gnutls_session_t session, const gnutls_datum_t * mki)
386
0
{
387
0
  int ret;
388
0
  srtp_ext_st *priv;
389
0
  gnutls_ext_priv_data_t epriv;
390
391
0
  ret =
392
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
393
0
  if (ret < 0) {
394
0
    priv = gnutls_calloc(1, sizeof(*priv));
395
0
    if (priv == NULL) {
396
0
      gnutls_assert();
397
0
      return GNUTLS_E_MEMORY_ERROR;
398
0
    }
399
0
    epriv = priv;
400
0
    _gnutls_hello_ext_set_priv(session,
401
0
             GNUTLS_EXTENSION_SRTP, epriv);
402
0
  } else
403
0
    priv = epriv;
404
405
0
  if (mki->size > 0 && mki->size <= sizeof(priv->mki)) {
406
0
    priv->mki_size = mki->size;
407
0
    memcpy(priv->mki, mki->data, mki->size);
408
0
  } else
409
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
410
411
0
  return 0;
412
0
}
413
414
/**
415
 * gnutls_srtp_set_profile:
416
 * @session: is a #gnutls_session_t type.
417
 * @profile: is the profile id to add.
418
 *
419
 * This function is to be used by both clients and servers, to declare
420
 * what SRTP profiles they support, to negotiate with the peer.
421
 *
422
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
423
 *   otherwise a negative error code is returned.
424
 *
425
 * Since 3.1.4
426
 **/
427
int
428
gnutls_srtp_set_profile(gnutls_session_t session, gnutls_srtp_profile_t profile)
429
0
{
430
0
  int ret;
431
0
  srtp_ext_st *priv;
432
0
  gnutls_ext_priv_data_t epriv;
433
434
0
  ret =
435
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
436
0
  if (ret < 0) {
437
0
    priv = gnutls_calloc(1, sizeof(*priv));
438
0
    if (priv == NULL) {
439
0
      gnutls_assert();
440
0
      return GNUTLS_E_MEMORY_ERROR;
441
0
    }
442
0
    epriv = priv;
443
0
    _gnutls_hello_ext_set_priv(session,
444
0
             GNUTLS_EXTENSION_SRTP, epriv);
445
0
  } else
446
0
    priv = epriv;
447
448
0
  if (priv->profiles_size < MAX_SRTP_PROFILES)
449
0
    priv->profiles_size++;
450
0
  priv->profiles[priv->profiles_size - 1] = profile;
451
452
0
  return 0;
453
0
}
454
455
/**
456
 * gnutls_srtp_set_profile_direct:
457
 * @session: is a #gnutls_session_t type.
458
 * @profiles: is a string that contains the supported SRTP profiles,
459
 *   separated by colons.
460
 * @err_pos: In case of an error this will have the position in the string the error occurred, may be NULL.
461
 *
462
 * This function is to be used by both clients and servers, to declare
463
 * what SRTP profiles they support, to negotiate with the peer.
464
 *
465
 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
466
 * %GNUTLS_E_SUCCESS on success, or an error code.
467
 *
468
 * Since 3.1.4
469
 **/
470
int
471
gnutls_srtp_set_profile_direct(gnutls_session_t session,
472
             const char *profiles, const char **err_pos)
473
0
{
474
0
  int ret;
475
0
  srtp_ext_st *priv;
476
0
  gnutls_ext_priv_data_t epriv;
477
0
  int set = 0;
478
0
  const char *col;
479
0
  gnutls_srtp_profile_t id;
480
481
0
  ret =
482
0
      _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SRTP, &epriv);
483
0
  if (ret < 0) {
484
0
    set = 1;
485
0
    priv = gnutls_calloc(1, sizeof(*priv));
486
0
    if (priv == NULL) {
487
0
      if (err_pos != NULL)
488
0
        *err_pos = profiles;
489
0
      gnutls_assert();
490
0
      return GNUTLS_E_MEMORY_ERROR;
491
0
    }
492
0
    epriv = priv;
493
0
  } else
494
0
    priv = epriv;
495
496
0
  do {
497
0
    col = strchr(profiles, ':');
498
0
    id = find_profile(profiles, col);
499
0
    if (id == 0) {
500
0
      if (set != 0)
501
0
        gnutls_free(priv);
502
0
      if (err_pos != NULL)
503
0
        *err_pos = profiles;
504
0
      return GNUTLS_E_INVALID_REQUEST;
505
0
    }
506
507
0
    if (priv->profiles_size < MAX_SRTP_PROFILES) {
508
0
      priv->profiles_size++;
509
0
    }
510
0
    priv->profiles[priv->profiles_size - 1] = id;
511
0
    profiles = col + 1;
512
0
  } while (col != NULL);
513
514
0
  if (set != 0)
515
0
    _gnutls_hello_ext_set_priv(session,
516
0
             GNUTLS_EXTENSION_SRTP, epriv);
517
518
0
  return 0;
519
0
}
520
521
/**
522
 * gnutls_srtp_get_keys:
523
 * @session: is a #gnutls_session_t type.
524
 * @key_material: Space to hold the generated key material
525
 * @key_material_size: The maximum size of the key material
526
 * @client_key: The master client write key, pointing inside the key material
527
 * @server_key: The master server write key, pointing inside the key material
528
 * @client_salt: The master client write salt, pointing inside the key material
529
 * @server_salt: The master server write salt, pointing inside the key material
530
 *
531
 * This is a helper function to generate the keying material for SRTP.
532
 * It requires the space of the key material to be pre-allocated (should be at least
533
 * 2x the maximum key size and salt size). The @client_key, @client_salt, @server_key
534
 * and @server_salt are convenience datums that point inside the key material. They may
535
 * be %NULL.
536
 *
537
 * Returns: On success the size of the key material is returned,
538
 * otherwise, %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not 
539
 * sufficient, or a negative error code.
540
 *
541
 * Since 3.1.4
542
 **/
543
int
544
gnutls_srtp_get_keys(gnutls_session_t session,
545
         void *key_material,
546
         unsigned int key_material_size,
547
         gnutls_datum_t * client_key,
548
         gnutls_datum_t * client_salt,
549
         gnutls_datum_t * server_key, gnutls_datum_t * server_salt)
550
0
{
551
0
  int ret;
552
0
  const srtp_profile_st *p;
553
0
  gnutls_srtp_profile_t profile;
554
0
  unsigned int msize;
555
0
  uint8_t *km = key_material;
556
557
0
  ret = gnutls_srtp_get_selected_profile(session, &profile);
558
0
  if (ret < 0)
559
0
    return gnutls_assert_val(ret);
560
561
0
  p = get_profile(profile);
562
0
  if (p == NULL)
563
0
    return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
564
565
0
  msize = 2 * (p->key_length + p->salt_length);
566
0
  if (msize > key_material_size)
567
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
568
569
0
  if (msize == 0)
570
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
571
572
0
  ret =
573
0
      gnutls_prf(session, sizeof("EXTRACTOR-dtls_srtp") - 1,
574
0
           "EXTRACTOR-dtls_srtp", 0, 0, NULL, msize, key_material);
575
0
  if (ret < 0)
576
0
    return gnutls_assert_val(ret);
577
578
0
  if (client_key) {
579
0
    client_key->data = km;
580
0
    client_key->size = p->key_length;
581
0
  }
582
583
0
  if (server_key) {
584
0
    server_key->data = km + p->key_length;
585
0
    server_key->size = p->key_length;
586
0
  }
587
588
0
  if (client_salt) {
589
0
    client_salt->data = km + 2 * p->key_length;
590
0
    client_salt->size = p->salt_length;
591
0
  }
592
593
0
  if (server_salt) {
594
0
    server_salt->data = km + 2 * p->key_length + p->salt_length;
595
0
    server_salt->size = p->salt_length;
596
0
  }
597
598
0
  return msize;
599
0
}
600
601
static void _gnutls_srtp_deinit_data(gnutls_ext_priv_data_t priv)
602
0
{
603
0
  gnutls_free(priv);
604
0
}
605
606
static int
607
_gnutls_srtp_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
608
0
{
609
0
  srtp_ext_st *priv = epriv;
610
0
  unsigned int i;
611
0
  int ret;
612
613
0
  BUFFER_APPEND_NUM(ps, priv->profiles_size);
614
0
  for (i = 0; i < priv->profiles_size; i++) {
615
0
    BUFFER_APPEND_NUM(ps, priv->profiles[i]);
616
0
  }
617
618
0
  BUFFER_APPEND_NUM(ps, priv->mki_received);
619
0
  if (priv->mki_received) {
620
0
    BUFFER_APPEND_NUM(ps, priv->selected_profile);
621
0
    BUFFER_APPEND_PFX4(ps, priv->mki, priv->mki_size);
622
0
  }
623
0
  return 0;
624
0
}
625
626
static int
627
_gnutls_srtp_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
628
0
{
629
0
  srtp_ext_st *priv;
630
0
  unsigned int i;
631
0
  int ret;
632
0
  gnutls_ext_priv_data_t epriv;
633
634
0
  priv = gnutls_calloc(1, sizeof(*priv));
635
0
  if (priv == NULL) {
636
0
    gnutls_assert();
637
0
    return GNUTLS_E_MEMORY_ERROR;
638
0
  }
639
640
0
  BUFFER_POP_NUM(ps, priv->profiles_size);
641
0
  for (i = 0; i < priv->profiles_size; i++) {
642
0
    BUFFER_POP_NUM(ps, priv->profiles[i]);
643
0
  }
644
0
  BUFFER_POP_NUM(ps, priv->selected_profile);
645
646
0
  BUFFER_POP_NUM(ps, priv->mki_received);
647
0
  if (priv->mki_received) {
648
0
    BUFFER_POP_NUM(ps, priv->mki_size);
649
0
    BUFFER_POP(ps, priv->mki, priv->mki_size);
650
0
  }
651
652
0
  epriv = priv;
653
0
  *_priv = epriv;
654
655
0
  return 0;
656
657
0
 error:
658
0
  gnutls_free(priv);
659
0
  return ret;
660
0
}