Coverage Report

Created: 2026-06-15 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/coturn/src/client/ns_turn_msg.c
Line
Count
Source
1
/*
2
 * SPDX-License-Identifier: BSD-3-Clause
3
 *
4
 * https://opensource.org/license/bsd-3-clause
5
 *
6
 * Copyright (C) 2011, 2012, 2013 Citrix Systems
7
 *
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the project nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 */
34
35
#include "ns_turn_msg.h"
36
#include "ns_turn_msg_addr.h"
37
38
///////////// Security functions implementation from ns_turn_msg.h ///////////
39
40
#include "ns_turn_openssl.h"
41
#include "ns_turn_utils.h"
42
43
///////////
44
45
#include <ctype.h> // for tolower
46
#include <stdbool.h>
47
#include <stdio.h> // for fprintf, printf, stderr, snprintf
48
#include <stdlib.h>
49
#include <string.h> // for memcpy, strlen, memset, strncpy, strcmp
50
51
///////////
52
53
#define FINGERPRINT_XOR 0x5354554e
54
// Longest method string is "CONNECTION_ATTEMPT" (20 chars)
55
0
#define STUN_METHOD_STR_MAX 32
56
///////////
57
58
0
int stun_method_str(uint16_t method, char *smethod) {
59
0
  int ret = 0;
60
61
0
  const char *s = "UNKNOWN";
62
63
0
  switch (method) {
64
0
  case STUN_METHOD_BINDING:
65
0
    s = "BINDING";
66
0
    break;
67
0
  case STUN_METHOD_ALLOCATE:
68
0
    s = "ALLOCATE";
69
0
    break;
70
0
  case STUN_METHOD_REFRESH:
71
0
    s = "REFRESH";
72
0
    break;
73
0
  case STUN_METHOD_SEND:
74
0
    s = "SEND";
75
0
    break;
76
0
  case STUN_METHOD_DATA:
77
0
    s = "DATA";
78
0
    break;
79
0
  case STUN_METHOD_CREATE_PERMISSION:
80
0
    s = "CREATE_PERMISSION";
81
0
    break;
82
0
  case STUN_METHOD_CHANNEL_BIND:
83
0
    s = "CHANNEL_BIND";
84
0
    break;
85
0
  case STUN_METHOD_CONNECT:
86
0
    s = "CONNECT";
87
0
    break;
88
0
  case STUN_METHOD_CONNECTION_BIND:
89
0
    s = "CONNECTION_BIND";
90
0
    break;
91
0
  case STUN_METHOD_CONNECTION_ATTEMPT:
92
0
    s = "CONNECTION_ATTEMPT";
93
0
    break;
94
0
  default:
95
0
    ret = -1;
96
0
  };
97
98
0
  if (smethod) {
99
0
    strncpy(smethod, s, STUN_METHOD_STR_MAX - 1);
100
0
    smethod[STUN_METHOD_STR_MAX - 1] = '\0';
101
0
  }
102
103
0
  return ret;
104
0
}
105
106
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
107
/*
108
 * CIFuzz memory builds use an unsanitized OpenSSL. Hitting RAND_bytes() from
109
 * harness setup produces startup-only MSan reports inside libcrypto that mask
110
 * the message-construction logic we actually want to fuzz.
111
 */
112
40.9k
static uint64_t fuzz_prng_next(void) {
113
40.9k
  static uint64_t state = UINT64_C(0x9e3779b97f4a7c15);
114
115
40.9k
  state += UINT64_C(0x9e3779b97f4a7c15);
116
40.9k
  uint64_t z = state;
117
40.9k
  z = (z ^ (z >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
118
40.9k
  z = (z ^ (z >> 27)) * UINT64_C(0x94d049bb133111eb);
119
40.9k
  return z ^ (z >> 31);
120
40.9k
}
121
#endif
122
123
40.9k
long turn_random_number(void) {
124
40.9k
  long ret = 0;
125
40.9k
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
126
40.9k
  ret = (long)fuzz_prng_next();
127
#else
128
  if (!RAND_bytes((unsigned char *)&ret, sizeof(ret)))
129
#if defined(WINDOWS)
130
    ret = rand();
131
#else
132
    ret = random();
133
#endif
134
#endif
135
40.9k
  return ret;
136
40.9k
}
137
138
0
static void generate_random_nonce(unsigned char *nonce, size_t sz) {
139
0
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
140
0
  if (nonce) {
141
0
    for (size_t i = 0; i < sz; ++i) {
142
0
      nonce[i] = (unsigned char)turn_random_number();
143
0
    }
144
0
  }
145
#else
146
  if (!RAND_bytes(nonce, (int)sz)) {
147
    for (size_t i = 0; i < sz; ++i) {
148
      nonce[i] = (unsigned char)turn_random_number();
149
    }
150
  }
151
#endif
152
0
}
153
154
13.4k
static void turn_random_tid_size(void *id) {
155
13.4k
  uint32_t *ar = (uint32_t *)id;
156
13.4k
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
157
13.4k
  if (ar) {
158
53.9k
    for (size_t i = 0; i < 3; ++i) {
159
40.4k
      ar[i] = (uint32_t)turn_random_number();
160
40.4k
    }
161
13.4k
  }
162
#else
163
  if (!RAND_bytes((unsigned char *)ar, 12)) {
164
    for (size_t i = 0; i < 3; ++i) {
165
      ar[i] = (uint32_t)turn_random_number();
166
    }
167
  }
168
#endif
169
13.4k
}
170
171
bool stun_calculate_hmac(const uint8_t *buf, size_t len, const uint8_t *key, size_t keylen, uint8_t *hmac,
172
0
                         unsigned int *hmac_len, SHATYPE shatype) {
173
0
  ERR_clear_error();
174
0
  UNUSED_ARG(shatype);
175
176
0
  if (shatype == SHATYPE_SHA256) {
177
0
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
178
0
    if (!HMAC(EVP_sha256(), key, (int)keylen, buf, len, hmac, hmac_len)) {
179
0
      return false;
180
0
    }
181
#else
182
    fprintf(stderr, "SHA256 is not supported\n");
183
    return false;
184
#endif
185
0
  } else if (shatype == SHATYPE_SHA384) {
186
0
#if !defined(OPENSSL_NO_SHA384) && defined(SHA384_DIGEST_LENGTH)
187
0
    if (!HMAC(EVP_sha384(), key, (int)keylen, buf, len, hmac, hmac_len)) {
188
0
      return false;
189
0
    }
190
#else
191
    fprintf(stderr, "SHA384 is not supported\n");
192
    return false;
193
#endif
194
0
  } else if (shatype == SHATYPE_SHA512) {
195
0
#if !defined(OPENSSL_NO_SHA512) && defined(SHA512_DIGEST_LENGTH)
196
0
    if (!HMAC(EVP_sha512(), key, (int)keylen, buf, len, hmac, hmac_len)) {
197
0
      return false;
198
0
    }
199
#else
200
    fprintf(stderr, "SHA512 is not supported\n");
201
    return false;
202
#endif
203
0
  } else if (!HMAC(EVP_sha1(), key, (int)keylen, buf, len, hmac, hmac_len)) {
204
0
    return false;
205
0
  }
206
207
0
  return true;
208
0
}
209
210
bool stun_produce_integrity_key_str(const uint8_t *uname, const uint8_t *realm, const uint8_t *upwd, hmackey_t key,
211
0
                                    SHATYPE shatype) {
212
0
  bool ret;
213
214
0
  ERR_clear_error();
215
0
  UNUSED_ARG(shatype);
216
217
0
  const size_t ulen = strlen((const char *)uname);
218
0
  const size_t rlen = strlen((const char *)realm);
219
0
  const size_t plen = strlen((const char *)upwd);
220
0
  const size_t sz = ulen + 1 + rlen + 1 + plen + 1 + 10;
221
0
  const size_t strl = ulen + 1 + rlen + 1 + plen;
222
0
  uint8_t *str = (uint8_t *)malloc(sz + 1);
223
0
  if (str == NULL) {
224
0
    return false;
225
0
  }
226
227
0
  if (!str) {
228
0
    return false;
229
0
  }
230
231
0
  strncpy((char *)str, (const char *)uname, sz);
232
0
  str[ulen] = ':';
233
0
  strncpy((char *)str + ulen + 1, (const char *)realm, sz - ulen - 1);
234
0
  str[ulen + 1 + rlen] = ':';
235
0
  strncpy((char *)str + ulen + 1 + rlen + 1, (const char *)upwd, sz - ulen - 1 - rlen - 1);
236
0
  str[strl] = 0;
237
238
0
  if (shatype == SHATYPE_SHA256) {
239
0
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
240
0
    unsigned int keylen = 0;
241
0
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
242
0
    EVP_DigestInit(ctx, EVP_sha256());
243
0
    EVP_DigestUpdate(ctx, str, strl);
244
0
    EVP_DigestFinal(ctx, key, &keylen);
245
0
    EVP_MD_CTX_free(ctx);
246
0
    ret = true;
247
#else
248
    fprintf(stderr, "SHA256 is not supported\n");
249
    ret = false;
250
#endif
251
0
  } else if (shatype == SHATYPE_SHA384) {
252
0
#if !defined(OPENSSL_NO_SHA384) && defined(SHA384_DIGEST_LENGTH)
253
0
    unsigned int keylen = 0;
254
0
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
255
0
    EVP_DigestInit(ctx, EVP_sha384());
256
0
    EVP_DigestUpdate(ctx, str, strl);
257
0
    EVP_DigestFinal(ctx, key, &keylen);
258
0
    EVP_MD_CTX_free(ctx);
259
0
    ret = true;
260
#else
261
    fprintf(stderr, "SHA384 is not supported\n");
262
    ret = false;
263
#endif
264
0
  } else if (shatype == SHATYPE_SHA512) {
265
0
#if !defined(OPENSSL_NO_SHA512) && defined(SHA512_DIGEST_LENGTH)
266
0
    unsigned int keylen = 0;
267
0
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
268
0
    EVP_DigestInit(ctx, EVP_sha512());
269
0
    EVP_DigestUpdate(ctx, str, strl);
270
0
    EVP_DigestFinal(ctx, key, &keylen);
271
0
    EVP_MD_CTX_free(ctx);
272
0
    ret = true;
273
#else
274
    fprintf(stderr, "SHA512 is not supported\n");
275
    ret = false;
276
#endif
277
0
  } else {
278
0
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
279
0
    unsigned int keylen = 0;
280
0
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
281
0
    if (EVP_default_properties_is_fips_enabled(NULL)) {
282
0
      EVP_default_properties_enable_fips(NULL, 0);
283
0
    }
284
0
    EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
285
0
    EVP_DigestUpdate(ctx, str, strl);
286
0
    EVP_DigestFinal(ctx, key, &keylen);
287
0
    EVP_MD_CTX_free(ctx);
288
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
289
    unsigned int keylen = 0;
290
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
291
#if defined EVP_MD_CTX_FLAG_NON_FIPS_ALLOW && !defined(LIBRESSL_VERSION_NUMBER)
292
    if (FIPS_mode()) {
293
      EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
294
    }
295
#endif
296
    EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
297
    EVP_DigestUpdate(ctx, str, strl);
298
    EVP_DigestFinal(ctx, key, &keylen);
299
    EVP_MD_CTX_free(ctx);
300
#endif // OPENSSL_VERSION_NUMBER >= 0X30000000L
301
0
    ret = true;
302
0
  }
303
304
0
  free(str);
305
306
0
  return ret;
307
0
}
308
309
0
#define PWD_SALT_SIZE (8)
310
311
0
static void readable_string(unsigned char *orig, unsigned char *out, size_t sz) {
312
0
  out[0] = '\0';
313
0
  for (size_t i = 0; i < sz; ++i) {
314
0
    snprintf((char *)(out + (i * 2)), 3, "%02x", (unsigned int)orig[i]);
315
0
  }
316
0
  out[sz * 2] = 0;
317
0
}
318
319
0
static void generate_enc_password(const char *pwd, char *result, const unsigned char *orig_salt) {
320
0
  unsigned char salt[PWD_SALT_SIZE + 1];
321
0
  if (!orig_salt) {
322
0
    generate_random_nonce(salt, PWD_SALT_SIZE);
323
0
  } else {
324
0
    memcpy(salt, orig_salt, PWD_SALT_SIZE);
325
0
    salt[PWD_SALT_SIZE] = 0;
326
0
  }
327
0
  unsigned char rsalt[PWD_SALT_SIZE * 2 + 1];
328
0
  readable_string(salt, rsalt, PWD_SALT_SIZE);
329
0
  result[0] = '$';
330
0
  result[1] = '5';
331
0
  result[2] = '$';
332
0
  memcpy(result + 3, (char *)rsalt, PWD_SALT_SIZE + PWD_SALT_SIZE);
333
0
  result[3 + PWD_SALT_SIZE + PWD_SALT_SIZE] = '$';
334
0
  unsigned char *out = (unsigned char *)(result + 3 + PWD_SALT_SIZE + PWD_SALT_SIZE + 1);
335
0
  {
336
0
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
337
0
#if !defined(OPENSSL_NO_SHA256) && defined(SHA256_DIGEST_LENGTH)
338
0
    EVP_DigestInit(ctx, EVP_sha256());
339
#else
340
    EVP_DigestInit(ctx, EVP_sha1());
341
#endif
342
0
    EVP_DigestUpdate(ctx, salt, PWD_SALT_SIZE);
343
0
    EVP_DigestUpdate(ctx, pwd, strlen(pwd));
344
0
    {
345
0
      unsigned char hash[129];
346
0
      unsigned int keylen = 0;
347
0
      EVP_DigestFinal(ctx, hash, &keylen);
348
0
      readable_string(hash, out, keylen);
349
0
    }
350
0
    EVP_MD_CTX_free(ctx);
351
0
  }
352
0
}
353
354
0
void generate_new_enc_password(const char *pwd, char *result) { generate_enc_password(pwd, result, NULL); }
355
356
0
static bool encrypted_password(const char *pin, unsigned char *salt) {
357
0
  static const size_t min_len = 3 + PWD_SALT_SIZE + PWD_SALT_SIZE + 1 + 32;
358
0
  if (strlen(pin) >= min_len) {
359
0
    if ((pin[0] == '$') && (pin[1] == '5') && (pin[2] == '$') && (pin[3 + PWD_SALT_SIZE + PWD_SALT_SIZE] == '$')) {
360
0
      for (size_t i = 0; i < PWD_SALT_SIZE; ++i) {
361
0
        const char *c = pin + 3 + i + i;
362
0
        char sc[3];
363
0
        sc[0] = c[0];
364
0
        sc[1] = c[1];
365
0
        sc[2] = 0;
366
0
        salt[i] = (unsigned char)strtoul(sc, NULL, 16);
367
0
      }
368
0
      return true;
369
0
    }
370
0
  }
371
0
  return false;
372
0
}
373
374
/* Length-checked constant-time string compare. The length comparison can leak
375
 * the length of the secret, but the byte content is compared in constant time
376
 * via CRYPTO_memcmp so no per-byte timing oracle remains. */
377
0
static bool const_time_str_equal(const char *a, const char *b) {
378
0
  const size_t la = strlen(a);
379
0
  if (la != strlen(b)) {
380
0
    return false;
381
0
  }
382
0
  return CRYPTO_memcmp(a, b, la) == 0;
383
0
}
384
385
0
bool check_password_equal(const char *pin, const char *pwd) {
386
0
  unsigned char salt[PWD_SALT_SIZE];
387
0
  if (!encrypted_password(pwd, salt)) {
388
0
    return const_time_str_equal(pin, pwd);
389
0
  }
390
0
  char enc_pin[257];
391
0
  generate_enc_password(pin, enc_pin, salt);
392
0
  return const_time_str_equal(enc_pin, pwd);
393
0
}
394
395
/////////////////////////////////////////////////////////////////
396
397
static uint32_t ns_crc32(const uint8_t *buffer, uint32_t len);
398
399
/////////////////////////////////////////////////////////////////
400
401
155k
int stun_get_command_message_len_str(const uint8_t *buf, size_t len) {
402
155k
  if (len < STUN_HEADER_LENGTH) {
403
45
    return -1;
404
45
  }
405
406
  /* Validate the size the buffer claims to be */
407
155k
  const size_t bufLen = (size_t)(nswap16(((const uint16_t *)(buf))[1]) + STUN_HEADER_LENGTH);
408
155k
  if (bufLen > len) {
409
2.06k
    return -1;
410
2.06k
  }
411
412
153k
  return bufLen;
413
155k
}
414
415
22.2k
static bool stun_set_command_message_len_str(uint8_t *buf, int len) {
416
22.2k
  if (len < STUN_HEADER_LENGTH) {
417
0
    return false;
418
0
  }
419
22.2k
  ((uint16_t *)buf)[1] = nswap16((uint16_t)(len - STUN_HEADER_LENGTH));
420
22.2k
  return true;
421
22.2k
}
422
423
///////////  Low-level binary //////////////////////////////////////////////
424
425
13.2k
uint16_t stun_make_type(uint16_t method) {
426
13.2k
  method = method & 0x0FFF;
427
13.2k
  return ((method & 0x000F) | ((method & 0x0070) << 1) | ((method & 0x0380) << 2) | ((method & 0x0C00) << 2));
428
13.2k
}
429
430
25.3k
uint16_t stun_get_method_str(const uint8_t *buf, size_t len) {
431
25.3k
  if (!buf || len < 2) {
432
0
    return (uint16_t)-1;
433
0
  }
434
435
25.3k
  const uint16_t tt = nswap16(((const uint16_t *)buf)[0]);
436
437
25.3k
  return (tt & 0x000F) | ((tt & 0x00E0) >> 1) | ((tt & 0x0E00) >> 2) | ((tt & 0x3000) >> 2);
438
25.3k
}
439
440
82.0k
uint16_t stun_get_msg_type_str(const uint8_t *buf, size_t len) {
441
82.0k
  if (!buf || len < 2) {
442
1
    return (uint16_t)-1;
443
1
  }
444
82.0k
  return ((nswap16(((const uint16_t *)buf)[0])) & 0x3FFF);
445
82.0k
}
446
447
57.9k
bool is_channel_msg_str(const uint8_t *buf, size_t blen) {
448
57.9k
  return (buf && blen >= 4 && STUN_VALID_CHANNEL(nswap16(((const uint16_t *)buf)[0])));
449
57.9k
}
450
451
/////////////// message types /////////////////////////////////
452
453
26.7k
bool stun_is_command_message_str(const uint8_t *buf, size_t blen) {
454
26.7k
  if (buf && blen >= STUN_HEADER_LENGTH) {
455
26.7k
    if (!STUN_VALID_CHANNEL(nswap16(((const uint16_t *)buf)[0]))) {
456
26.7k
      if ((((uint8_t)buf[0]) & ((uint8_t)(0xC0))) == 0) {
457
26.6k
        if (nswap32(((const uint32_t *)(buf))[1]) == STUN_MAGIC_COOKIE) {
458
24.1k
          const uint16_t len = nswap16(((const uint16_t *)(buf))[1]);
459
24.1k
          if ((len & 0x0003) == 0) {
460
24.1k
            if ((size_t)(len + STUN_HEADER_LENGTH) == blen) {
461
24.0k
              return true;
462
24.0k
            }
463
24.1k
          }
464
24.1k
        }
465
26.6k
      }
466
26.7k
    }
467
26.7k
  }
468
2.67k
  return false;
469
26.7k
}
470
471
0
bool old_stun_is_command_message_str(const uint8_t *buf, size_t blen, uint32_t *cookie) {
472
0
  if (buf && blen >= STUN_HEADER_LENGTH) {
473
0
    if (!STUN_VALID_CHANNEL(nswap16(((const uint16_t *)buf)[0]))) {
474
0
      if ((((uint8_t)buf[0]) & ((uint8_t)(0xC0))) == 0) {
475
0
        if (nswap32(((const uint32_t *)(buf))[1]) != STUN_MAGIC_COOKIE) {
476
0
          const uint16_t len = nswap16(((const uint16_t *)(buf))[1]);
477
0
          if ((len & 0x0003) == 0) {
478
0
            if ((size_t)(len + STUN_HEADER_LENGTH) == blen) {
479
0
              *cookie = nswap32(((const uint32_t *)(buf))[1]);
480
0
              return true;
481
0
            }
482
0
          }
483
0
        }
484
0
      }
485
0
    }
486
0
  }
487
0
  return false;
488
0
}
489
490
bool stun_is_command_message_full_check_str(const uint8_t *buf, size_t blen, int must_check_fingerprint,
491
0
                                            int *fingerprint_present) {
492
0
  if (!stun_is_command_message_str(buf, blen)) {
493
0
    return false;
494
0
  }
495
0
  stun_attr_ref sar = stun_attr_get_first_by_type_str(buf, blen, STUN_ATTRIBUTE_FINGERPRINT);
496
0
  if (!sar) {
497
0
    if (fingerprint_present) {
498
0
      *fingerprint_present = 0;
499
0
    }
500
0
    if (stun_get_method_str(buf, blen) == STUN_METHOD_BINDING) {
501
0
      return true;
502
0
    }
503
0
    return !must_check_fingerprint;
504
0
  }
505
0
  if (stun_attr_get_len(sar) != 4) {
506
0
    return false;
507
0
  }
508
0
  const uint32_t *fingerprint = (const uint32_t *)stun_attr_get_value(sar);
509
0
  if (!fingerprint) {
510
0
    return !must_check_fingerprint;
511
0
  }
512
0
  const uint32_t crc32len = (uint32_t)((((const uint8_t *)fingerprint) - buf) - 4);
513
0
  const bool ret = (*fingerprint == nswap32(ns_crc32(buf, crc32len) ^ ((uint32_t)FINGERPRINT_XOR)));
514
0
  if (ret && fingerprint_present) {
515
0
    *fingerprint_present = ret;
516
0
  }
517
0
  return ret;
518
0
}
519
520
13.2k
bool stun_is_request_str(const uint8_t *buf, size_t len) {
521
13.2k
  if (is_channel_msg_str(buf, len)) {
522
0
    return false;
523
0
  }
524
13.2k
  return IS_STUN_REQUEST(stun_get_msg_type_str(buf, len));
525
13.2k
}
526
527
13.3k
bool stun_is_success_response_str(const uint8_t *buf, size_t len) {
528
13.3k
  if (is_channel_msg_str(buf, len)) {
529
0
    return false;
530
0
  }
531
13.3k
  return IS_STUN_SUCCESS_RESP(stun_get_msg_type_str(buf, len));
532
13.3k
}
533
534
13.3k
bool stun_is_error_response_str(const uint8_t *buf, size_t len, int *err_code, uint8_t *err_msg, size_t err_msg_size) {
535
13.3k
  if (is_channel_msg_str(buf, len)) {
536
0
    return false;
537
0
  }
538
13.3k
  if (IS_STUN_ERR_RESP(stun_get_msg_type_str(buf, len))) {
539
4.96k
    if (err_code) {
540
4.96k
      stun_attr_ref sar = stun_attr_get_first_by_type_str(buf, len, STUN_ATTRIBUTE_ERROR_CODE);
541
4.96k
      if (sar) {
542
4.89k
        if (stun_attr_get_len(sar) >= 4) {
543
4.89k
          const uint8_t *val = (const uint8_t *)stun_attr_get_value(sar);
544
4.89k
          *err_code = (int)(val[2] * 100 + val[3]);
545
4.89k
          if (err_msg && err_msg_size > 0) {
546
4.89k
            err_msg[0] = 0;
547
4.89k
            if (stun_attr_get_len(sar) > 4) {
548
3.08k
              size_t msg_len = stun_attr_get_len(sar) - 4;
549
3.08k
              if (msg_len > (err_msg_size - 1)) {
550
2
                msg_len = err_msg_size - 1;
551
2
              }
552
3.08k
              memcpy(err_msg, val + 4, msg_len);
553
3.08k
              err_msg[msg_len] = 0;
554
3.08k
            }
555
4.89k
          }
556
4.89k
        }
557
4.89k
      }
558
4.96k
    }
559
4.96k
    return true;
560
4.96k
  }
561
8.35k
  return false;
562
13.3k
}
563
564
bool stun_is_challenge_response_str(const uint8_t *buf, size_t len, int *err_code, uint8_t *err_msg,
565
                                    size_t err_msg_size, uint8_t *realm, uint8_t *nonce, uint8_t *server_name,
566
0
                                    bool *oauth) {
567
0
  const bool ret = stun_is_error_response_str(buf, len, err_code, err_msg, err_msg_size);
568
569
0
  if (ret && (((*err_code) == 401) || ((*err_code) == 438))) {
570
0
    stun_attr_ref sar = stun_attr_get_first_by_type_str(buf, len, STUN_ATTRIBUTE_REALM);
571
0
    if (sar) {
572
0
      bool found_oauth = false;
573
574
0
      const uint8_t *value = stun_attr_get_value(sar);
575
0
      if (value) {
576
0
        size_t vlen = (size_t)stun_attr_get_len(sar);
577
0
        vlen = min(vlen, (size_t)STUN_MAX_REALM_SIZE);
578
0
        memcpy(realm, value, vlen);
579
0
        realm[vlen] = 0;
580
0
        {
581
0
          sar = stun_attr_get_first_by_type_str(buf, len, STUN_ATTRIBUTE_THIRD_PARTY_AUTHORIZATION);
582
0
          if (sar) {
583
0
            value = stun_attr_get_value(sar);
584
0
            if (value) {
585
0
              vlen = (size_t)stun_attr_get_len(sar);
586
0
              vlen = min(vlen, (size_t)STUN_MAX_SERVER_NAME_SIZE);
587
0
              if (vlen > 0) {
588
0
                if (server_name) {
589
0
                  memcpy(server_name, value, vlen);
590
0
                  server_name[vlen] = 0;
591
0
                }
592
0
                found_oauth = true;
593
0
              }
594
0
            }
595
0
          }
596
0
        }
597
598
0
        sar = stun_attr_get_first_by_type_str(buf, len, STUN_ATTRIBUTE_NONCE);
599
0
        if (sar) {
600
0
          value = stun_attr_get_value(sar);
601
0
          if (value) {
602
0
            vlen = (size_t)stun_attr_get_len(sar);
603
0
            vlen = min(vlen, (size_t)STUN_MAX_NONCE_SIZE);
604
0
            memcpy(nonce, value, vlen);
605
0
            nonce[vlen] = 0;
606
0
            if (oauth) {
607
0
              *oauth = found_oauth;
608
0
            }
609
0
            return true;
610
0
          }
611
0
        }
612
0
      }
613
0
    }
614
0
  }
615
616
0
  return false;
617
0
}
618
619
17.1k
bool stun_is_response_str(const uint8_t *buf, size_t len) {
620
17.1k
  if (is_channel_msg_str(buf, len)) {
621
0
    return false;
622
0
  }
623
17.1k
  if (IS_STUN_SUCCESS_RESP(stun_get_msg_type_str(buf, len))) {
624
6.35k
    return true;
625
6.35k
  }
626
10.7k
  if (IS_STUN_ERR_RESP(stun_get_msg_type_str(buf, len))) {
627
6.67k
    return true;
628
6.67k
  }
629
4.10k
  return false;
630
10.7k
}
631
632
119
bool stun_is_indication_str(const uint8_t *buf, size_t len) {
633
119
  if (is_channel_msg_str(buf, len)) {
634
0
    return false;
635
0
  }
636
119
  return IS_STUN_INDICATION(stun_get_msg_type_str(buf, len));
637
119
}
638
639
3.15k
uint16_t stun_make_request(uint16_t method) { return GET_STUN_REQUEST(stun_make_type(method)); }
640
641
287
uint16_t stun_make_indication(uint16_t method) { return GET_STUN_INDICATION(stun_make_type(method)); }
642
643
4.87k
uint16_t stun_make_success_response(uint16_t method) { return GET_STUN_SUCCESS_RESP(stun_make_type(method)); }
644
645
4.87k
uint16_t stun_make_error_response(uint16_t method) { return GET_STUN_ERR_RESP(stun_make_type(method)); }
646
647
//////////////// INIT ////////////////////////////////////////////
648
649
13.2k
void stun_init_buffer_str(uint8_t *buf, size_t *len) {
650
13.2k
  *len = STUN_HEADER_LENGTH;
651
13.2k
  memset(buf, 0, *len);
652
13.2k
}
653
654
11.7k
void stun_init_command_str(uint16_t message_type, uint8_t *buf, size_t *len) {
655
11.7k
  stun_init_buffer_str(buf, len);
656
11.7k
  message_type &= (uint16_t)(0x3FFF);
657
11.7k
  ((uint16_t *)buf)[0] = nswap16(message_type);
658
11.7k
  ((uint16_t *)buf)[1] = 0;
659
11.7k
  ((uint32_t *)buf)[1] = nswap32(STUN_MAGIC_COOKIE);
660
11.7k
  stun_tid_generate_in_message_str(buf, NULL);
661
11.7k
}
662
663
1.45k
void old_stun_init_command_str(uint16_t message_type, uint8_t *buf, size_t *len, uint32_t cookie) {
664
1.45k
  stun_init_buffer_str(buf, len);
665
1.45k
  message_type &= (uint16_t)(0x3FFF);
666
1.45k
  ((uint16_t *)buf)[0] = nswap16(message_type);
667
1.45k
  ((uint16_t *)buf)[1] = 0;
668
1.45k
  ((uint32_t *)buf)[1] = nswap32(cookie);
669
1.45k
  stun_tid_generate_in_message_str(buf, NULL);
670
1.45k
}
671
672
2.87k
void stun_init_request_str(uint16_t method, uint8_t *buf, size_t *len) {
673
2.87k
  stun_init_command_str(stun_make_request(method), buf, len);
674
2.87k
}
675
676
0
void stun_init_indication_str(uint16_t method, uint8_t *buf, size_t *len) {
677
0
  stun_init_command_str(stun_make_indication(method), buf, len);
678
0
}
679
680
4.15k
void stun_init_success_response_str(uint16_t method, uint8_t *buf, size_t *len, stun_tid *id) {
681
4.15k
  stun_init_command_str(stun_make_success_response(method), buf, len);
682
4.15k
  if (id) {
683
4.15k
    stun_tid_message_cpy(buf, id);
684
4.15k
  }
685
4.15k
}
686
687
726
void old_stun_init_success_response_str(uint16_t method, uint8_t *buf, size_t *len, stun_tid *id, uint32_t cookie) {
688
726
  old_stun_init_command_str(stun_make_success_response(method), buf, len, cookie);
689
726
  if (id) {
690
726
    stun_tid_message_cpy(buf, id);
691
726
  }
692
726
}
693
694
90
const uint8_t *get_default_reason(int error_code) {
695
90
  const char *reason = "Unknown error";
696
697
90
  switch (error_code) {
698
42
  case 300:
699
42
    reason = "Try Alternate";
700
42
    break;
701
0
  case 400:
702
0
    reason = "Bad Request";
703
0
    break;
704
0
  case 401:
705
0
    reason = "Unauthorized";
706
0
    break;
707
24
  case 403:
708
24
    reason = "Forbidden";
709
24
    break;
710
0
  case 404:
711
0
    reason = "Not Found";
712
0
    break;
713
0
  case 420:
714
0
    reason = "Unknown Attribute";
715
0
    break;
716
0
  case 437:
717
0
    reason = "Allocation Mismatch";
718
0
    break;
719
0
  case 438:
720
0
    reason = "Stale Nonce";
721
0
    break;
722
0
  case 440:
723
0
    reason = "Address Family not Supported";
724
0
    break;
725
0
  case 441:
726
0
    reason = "Wrong Credentials";
727
0
    break;
728
12
  case 442:
729
12
    reason = "Unsupported Transport Protocol";
730
12
    break;
731
6
  case 443:
732
6
    reason = "Peer Address Family Mismatch";
733
6
    break;
734
0
  case 446:
735
0
    reason = "Connection Already Exists";
736
0
    break;
737
0
  case 447:
738
0
    reason = "Connection Timeout or Failure";
739
0
    break;
740
6
  case 486:
741
6
    reason = "Allocation Quota Reached";
742
6
    break;
743
0
  case 487:
744
0
    reason = "Role Conflict";
745
0
    break;
746
0
  case 500:
747
0
    reason = "Server Error";
748
0
    break;
749
0
  case 508:
750
0
    reason = "Insufficient Capacity";
751
0
    break;
752
0
  default:;
753
90
  };
754
755
90
  return (const uint8_t *)reason;
756
90
}
757
758
static void stun_init_error_response_common_str(uint8_t *buf, size_t *len, uint16_t error_code, const uint8_t *reason,
759
4.87k
                                                stun_tid *id, bool include_reason_string) {
760
761
4.87k
  if (include_reason_string && (!reason || !strcmp((const char *)reason, "Unknown error"))) {
762
90
    reason = get_default_reason(error_code);
763
90
  }
764
765
4.87k
  uint8_t avalue[513];
766
4.87k
  memset(avalue, 0, sizeof(avalue));
767
4.87k
  avalue[0] = 0;
768
4.87k
  avalue[1] = 0;
769
4.87k
  avalue[2] = (uint8_t)(error_code / 100);
770
4.87k
  avalue[3] = (uint8_t)(error_code % 100);
771
4.87k
  if (include_reason_string) {
772
3.43k
    strncpy((char *)(avalue + 4), (const char *)reason, sizeof(avalue) - 4);
773
3.43k
  }
774
4.87k
  avalue[sizeof(avalue) - 1] = 0;
775
4.87k
  int alen = 4 + (int)strlen((const char *)(avalue + 4));
776
777
  //"Manual" padding for compatibility with classic old stun:
778
4.87k
  {
779
4.87k
    const int rem = alen % 4;
780
4.87k
    if (rem) {
781
2.10k
      alen += (4 - rem);
782
2.10k
    }
783
4.87k
  }
784
785
4.87k
  stun_attr_add_str(buf, len, STUN_ATTRIBUTE_ERROR_CODE, (uint8_t *)avalue, alen);
786
4.87k
  if (id) {
787
4.87k
    stun_tid_message_cpy(buf, id);
788
4.87k
  }
789
4.87k
}
790
791
void old_stun_init_error_response_str(uint16_t method, uint8_t *buf, size_t *len, uint16_t error_code,
792
                                      const uint8_t *reason, stun_tid *id, uint32_t cookie,
793
726
                                      bool include_reason_string) {
794
795
726
  old_stun_init_command_str(stun_make_error_response(method), buf, len, cookie);
796
797
726
  stun_init_error_response_common_str(buf, len, error_code, reason, id, include_reason_string);
798
726
}
799
800
void stun_init_error_response_str(uint16_t method, uint8_t *buf, size_t *len, uint16_t error_code,
801
4.15k
                                  const uint8_t *reason, stun_tid *id, bool include_reason_string) {
802
803
4.15k
  stun_init_command_str(stun_make_error_response(method), buf, len);
804
805
4.15k
  stun_init_error_response_common_str(buf, len, error_code, reason, id, include_reason_string);
806
4.15k
}
807
808
/////////// CHANNEL ////////////////////////////////////////////////
809
810
287
bool stun_init_channel_message_str(uint16_t chnumber, uint8_t *buf, size_t *len, int length, bool do_padding) {
811
287
  uint16_t rlen = (uint16_t)length;
812
813
287
  if (length < 0 || (MAX_STUN_MESSAGE_SIZE < (4 + length))) {
814
0
    return false;
815
0
  }
816
287
  ((uint16_t *)(buf))[0] = nswap16(chnumber);
817
287
  ((uint16_t *)(buf))[1] = nswap16((uint16_t)length);
818
819
287
  if (do_padding && (rlen & 0x0003)) {
820
69
    rlen = ((rlen >> 2) + 1) << 2;
821
69
  }
822
823
287
  *len = 4 + rlen;
824
825
287
  return true;
826
287
}
827
828
1.74k
bool stun_is_channel_message_str(const uint8_t *buf, size_t *blen, uint16_t *chnumber, bool mandatory_padding) {
829
1.74k
  uint16_t datalen_header;
830
1.74k
  uint16_t datalen_actual;
831
832
1.74k
  if (!blen || (*blen < 4)) {
833
6
    return false;
834
6
  }
835
836
1.73k
  const uint16_t chn = nswap16(((const uint16_t *)(buf))[0]);
837
1.73k
  if (!STUN_VALID_CHANNEL(chn)) {
838
1.13k
    return false;
839
1.13k
  }
840
841
  /* Clamp to uint16_t range for comparison without mutating the caller's
842
   * *blen — the modification to *blen at the end of this function is
843
   * intentional (it reports actual message length consumed), but clamping
844
   * during validation must not alter the caller's view of the buffer size
845
   * if the function later returns false (issue #1837). */
846
600
  const uint16_t blen16 = (*blen > (uint16_t)-1) ? (uint16_t)-1 : (uint16_t)*blen;
847
600
  datalen_actual = blen16 - 4;
848
600
  datalen_header = ((const uint16_t *)buf)[1];
849
600
  datalen_header = nswap16(datalen_header);
850
851
600
  if (datalen_header > datalen_actual) {
852
24
    return false;
853
24
  }
854
855
576
  if (datalen_header != datalen_actual) {
856
857
    /* maybe there are padding bytes for 32-bit alignment. Mandatory for TCP. Optional for UDP */
858
859
71
    if (datalen_actual & 0x0003) {
860
861
2
      if (mandatory_padding) {
862
1
        return false;
863
1
      } else if (datalen_header == 0) {
864
0
        return false;
865
1
      } else {
866
1
        const uint16_t diff = datalen_actual - datalen_header;
867
1
        if (diff > 3) {
868
1
          return false;
869
1
        }
870
1
      }
871
2
    }
872
71
  }
873
874
574
  *blen = datalen_header + 4;
875
876
574
  if (chnumber) {
877
574
    *chnumber = chn;
878
574
  }
879
880
574
  return true;
881
576
}
882
883
////////// STUN message ///////////////////////////////
884
885
1.00k
static inline bool sheadof(const char *head, const char *full, bool ignore_case) {
886
1.01k
  while (*head) {
887
1.01k
    if (*head != *full) {
888
1.00k
      if (ignore_case && (tolower((unsigned char)*head) == tolower((unsigned char)*full))) {
889
        // OK
890
1.00k
      } else {
891
1.00k
        return false;
892
1.00k
      }
893
1.00k
    }
894
4
    ++head;
895
4
    ++full;
896
4
  }
897
0
  return true;
898
1.00k
}
899
900
0
static inline const char *findstr(const char *hay, size_t slen, const char *needle, bool ignore_case) {
901
0
  const char *ret = NULL;
902
903
0
  if (hay && slen && needle) {
904
0
    const size_t nlen = strlen(needle);
905
0
    if (nlen <= slen) {
906
0
      const size_t smax = slen - nlen + 1;
907
0
      const char *sp = hay;
908
0
      for (size_t i = 0; i < smax; ++i) {
909
0
        if (sheadof(needle, sp + i, ignore_case)) {
910
0
          ret = sp + i;
911
0
          break;
912
0
        }
913
0
      }
914
0
    }
915
0
  }
916
917
0
  return ret;
918
0
}
919
920
1.00k
static inline bool has_prefix(const char *buf, size_t blen, const char *prefix, bool ignore_case) {
921
1.00k
  if (!buf || !prefix) {
922
0
    return false;
923
0
  }
924
925
1.00k
  const size_t prefix_len = strlen(prefix);
926
1.00k
  return (prefix_len <= blen) && sheadof(prefix, buf, ignore_case);
927
1.00k
}
928
929
262
int is_http(const char *s, size_t blen) {
930
262
  if (s && blen >= 12) {
931
252
    if (has_prefix(s, blen, "GET ", false) || has_prefix(s, blen, "POST ", false) ||
932
252
        has_prefix(s, blen, "DELETE ", false) || has_prefix(s, blen, "PUT ", false)) {
933
0
      const char *sp = findstr(s + 4, blen - 4, " HTTP/", false);
934
0
      if (sp) {
935
0
        sp += 6;
936
0
        const size_t diff_blen = sp - s;
937
0
        if (diff_blen + 4 <= blen) {
938
0
          sp = findstr(sp, blen - diff_blen, "\r\n\r\n", false);
939
0
          if (sp) {
940
0
            int ret_len = (int)(sp - s + 4);
941
0
            const char *clheader = "content-length: ";
942
0
            const char *cl = findstr(s, sp - s, clheader, true);
943
0
            if (cl) {
944
0
              const unsigned long clen = strtoul(cl + strlen(clheader), NULL, 10);
945
0
              if (clen > 0 && clen < (0x0FFFFFFF)) {
946
0
                ret_len += (int)clen;
947
0
              }
948
0
            }
949
0
            return ret_len;
950
0
          }
951
0
        }
952
0
      }
953
0
    }
954
252
  }
955
262
  return 0;
956
262
}
957
958
596
int stun_get_message_len_str(uint8_t *buf, size_t blen, int padding, size_t *app_len) {
959
596
  if (buf && blen) {
960
    /* STUN request/response ? */
961
596
    if (buf && blen >= STUN_HEADER_LENGTH) {
962
572
      if (!STUN_VALID_CHANNEL(nswap16(((const uint16_t *)buf)[0]))) {
963
560
        if ((((uint8_t)buf[0]) & ((uint8_t)(0xC0))) == 0) {
964
514
          if (nswap32(((const uint32_t *)(buf))[1]) == STUN_MAGIC_COOKIE) {
965
388
            uint16_t len = nswap16(((const uint16_t *)(buf))[1]);
966
388
            if ((len & 0x0003) == 0) {
967
384
              len += STUN_HEADER_LENGTH;
968
384
              if ((size_t)len <= blen) {
969
334
                *app_len = (size_t)len;
970
334
                return (int)len;
971
334
              }
972
384
            }
973
388
          }
974
514
        }
975
560
      }
976
572
    }
977
978
    // HTTP request ?
979
262
    {
980
262
      const int http_len = is_http(((char *)buf), blen);
981
262
      if ((http_len > 0) && ((size_t)http_len <= blen)) {
982
0
        *app_len = (size_t)http_len;
983
0
        return http_len;
984
0
      }
985
262
    }
986
987
    /* STUN channel ? */
988
262
    if (blen >= 4) {
989
262
      const uint16_t chn = nswap16(((const uint16_t *)(buf))[0]);
990
262
      if (STUN_VALID_CHANNEL(chn)) {
991
992
        /* Use uint32_t to avoid uint16_t truncation overflow when data_len is
993
         * near 0xFFFF: 4 + 0xFFFF = 65539, which wraps to 3 in uint16_t and
994
         * causes TCP framing bypass (CVE candidate, issue #1837). */
995
14
        uint32_t bret = 4u + (uint32_t)nswap16(((const uint16_t *)(buf))[1]);
996
997
14
        *app_len = bret;
998
999
14
        if (padding && (bret & 0x0003u)) {
1000
2
          bret = ((bret >> 2) + 1u) << 2;
1001
2
        }
1002
1003
14
        if (bret <= blen) {
1004
2
          return (int)bret;
1005
2
        }
1006
14
      }
1007
262
    }
1008
262
  }
1009
1010
260
  return -1;
1011
596
}
1012
1013
////////// ALLOCATE ///////////////////////////////////
1014
1015
bool stun_set_allocate_request_str(uint8_t *buf, size_t *len, uint32_t lifetime, bool af4, bool af6, uint8_t transport,
1016
574
                                   bool mobile, const char *rt, int ep) {
1017
1018
574
  stun_init_request_str(STUN_METHOD_ALLOCATE, buf, len);
1019
1020
  // REQUESTED-TRANSPORT
1021
574
  {
1022
574
    uint8_t field[4];
1023
574
    field[0] = transport;
1024
574
    field[1] = 0;
1025
574
    field[2] = 0;
1026
574
    field[3] = 0;
1027
574
    if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, field, sizeof(field))) {
1028
0
      return false;
1029
0
    }
1030
574
  }
1031
1032
  // LIFETIME
1033
574
  {
1034
574
    if (lifetime < 1) {
1035
26
      lifetime = STUN_DEFAULT_ALLOCATE_LIFETIME;
1036
26
    }
1037
574
    uint32_t field = nswap32(lifetime);
1038
574
    if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_LIFETIME, (uint8_t *)(&field), sizeof(field))) {
1039
0
      return false;
1040
0
    }
1041
574
  }
1042
1043
  // MICE
1044
574
  if (mobile) {
1045
287
    if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_MOBILITY_TICKET, (const uint8_t *)"", 0)) {
1046
0
      return false;
1047
0
    }
1048
287
  }
1049
1050
574
  if (ep > -1) {
1051
358
    uint8_t value = ep ? 0x80 : 0x00;
1052
358
    if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_EVEN_PORT, (const uint8_t *)&value, 1)) {
1053
0
      return false;
1054
0
    }
1055
358
  }
1056
1057
  // RESERVATION-TOKEN, EVEN-PORT and DUAL-ALLOCATION are mutually exclusive:
1058
574
  if (rt) {
1059
1060
241
    stun_attr_add_str(buf, len, STUN_ATTRIBUTE_RESERVATION_TOKEN, (const uint8_t *)rt, 8);
1061
1062
333
  } else {
1063
1064
    // ADRESS-FAMILY
1065
333
    if (af4 && !af6) {
1066
74
      uint8_t field[4];
1067
74
      field[0] = (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4;
1068
74
      field[1] = 0;
1069
74
      field[2] = 0;
1070
74
      field[3] = 0;
1071
74
      if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY, field, sizeof(field))) {
1072
0
        return false;
1073
0
      }
1074
74
    }
1075
1076
333
    if (af6 && !af4) {
1077
64
      uint8_t field[4];
1078
64
      field[0] = (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
1079
64
      field[1] = 0;
1080
64
      field[2] = 0;
1081
64
      field[3] = 0;
1082
64
      if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY, field, sizeof(field))) {
1083
0
        return false;
1084
0
      }
1085
64
    }
1086
1087
333
    if (af4 && af6) {
1088
100
      uint8_t field[4];
1089
100
      field[0] = (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
1090
100
      field[1] = 0;
1091
100
      field[2] = 0;
1092
100
      field[3] = 0;
1093
100
      if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_ADDITIONAL_ADDRESS_FAMILY, field, sizeof(field))) {
1094
0
        return false;
1095
0
      }
1096
100
    }
1097
333
  }
1098
1099
574
  return true;
1100
574
}
1101
1102
bool stun_set_allocate_response_str(uint8_t *buf, size_t *len, stun_tid *tid, const ioa_addr *relayed_addr1,
1103
                                    const ioa_addr *relayed_addr2, const ioa_addr *reflexive_addr, uint32_t lifetime,
1104
                                    uint32_t max_lifetime, int error_code, const uint8_t *reason,
1105
2.87k
                                    uint64_t reservation_token, char *mobile_id, bool include_reason_string) {
1106
1107
2.87k
  if (!error_code) {
1108
1109
1.72k
    stun_init_success_response_str(STUN_METHOD_ALLOCATE, buf, len, tid);
1110
1111
1.72k
    if (relayed_addr1) {
1112
1.72k
      if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, relayed_addr1)) {
1113
0
        return false;
1114
0
      }
1115
1.72k
    }
1116
1117
1.72k
    if (relayed_addr2) {
1118
955
      if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, relayed_addr2)) {
1119
0
        return false;
1120
0
      }
1121
955
    }
1122
1123
1.72k
    if (reflexive_addr) {
1124
1.14k
      if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr)) {
1125
0
        return false;
1126
0
      }
1127
1.14k
    }
1128
1129
1.72k
    if (reservation_token) {
1130
1.13k
      reservation_token = nswap64(reservation_token);
1131
1.13k
      stun_attr_add_str(buf, len, STUN_ATTRIBUTE_RESERVATION_TOKEN, (uint8_t *)(&reservation_token), 8);
1132
1.13k
    }
1133
1134
1.72k
    {
1135
1.72k
      if (lifetime < 1) {
1136
660
        lifetime = STUN_DEFAULT_ALLOCATE_LIFETIME;
1137
1.06k
      } else if (lifetime > max_lifetime) {
1138
842
        lifetime = max_lifetime;
1139
842
      }
1140
1141
1.72k
      uint32_t field = nswap32(lifetime);
1142
1.72k
      if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_LIFETIME, (uint8_t *)(&field), sizeof(field))) {
1143
0
        return false;
1144
0
      }
1145
1.72k
    }
1146
1147
1.72k
    if (mobile_id && *mobile_id) {
1148
988
      if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_MOBILITY_TICKET, (uint8_t *)mobile_id, (int)strlen(mobile_id))) {
1149
0
        return false;
1150
0
      }
1151
988
    }
1152
1153
1.72k
  } else {
1154
1.14k
    stun_init_error_response_str(STUN_METHOD_ALLOCATE, buf, len, error_code, reason, tid, include_reason_string);
1155
1.14k
  }
1156
1157
2.87k
  return true;
1158
2.87k
}
1159
1160
/////////////// CHANNEL BIND ///////////////////////////////////////
1161
1162
uint16_t stun_set_channel_bind_request_str(uint8_t *buf, size_t *len, const ioa_addr *peer_addr,
1163
1.72k
                                           uint16_t channel_number) {
1164
1165
1.72k
  if (!STUN_VALID_CHANNEL(channel_number)) {
1166
514
    channel_number = 0x4000 + ((uint16_t)(((uint32_t)turn_random_number()) % (0x7FFF - 0x4000 + 1)));
1167
514
  }
1168
1169
1.72k
  stun_init_request_str(STUN_METHOD_CHANNEL_BIND, buf, len);
1170
1171
1.72k
  if (!stun_attr_add_channel_number_str(buf, len, channel_number)) {
1172
0
    return 0;
1173
0
  }
1174
1175
1.72k
  if (!peer_addr) {
1176
907
    ioa_addr ca;
1177
907
    memset(&ca, 0, sizeof(ioa_addr));
1178
1179
907
    if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &ca)) {
1180
0
      return 0;
1181
0
    }
1182
907
  } else {
1183
815
    if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_PEER_ADDRESS, peer_addr)) {
1184
0
      return 0;
1185
0
    }
1186
815
  }
1187
1188
1.72k
  return channel_number;
1189
1.72k
}
1190
1191
void stun_set_channel_bind_response_str(uint8_t *buf, size_t *len, stun_tid *tid, int error_code, const uint8_t *reason,
1192
1.72k
                                        bool include_reason_string) {
1193
1.72k
  if (!error_code) {
1194
861
    stun_init_success_response_str(STUN_METHOD_CHANNEL_BIND, buf, len, tid);
1195
861
  } else {
1196
861
    stun_init_error_response_str(STUN_METHOD_CHANNEL_BIND, buf, len, error_code, reason, tid, include_reason_string);
1197
861
  }
1198
1.72k
}
1199
1200
/////////////// BINDING ///////////////////////////////////////
1201
1202
574
void stun_set_binding_request_str(uint8_t *buf, size_t *len) { stun_init_request_str(STUN_METHOD_BINDING, buf, len); }
1203
1204
bool stun_set_binding_response_str(uint8_t *buf, size_t *len, stun_tid *tid, const ioa_addr *reflexive_addr,
1205
                                   int error_code, const uint8_t *reason, uint32_t cookie, bool old_stun,
1206
                                   bool stun_backward_compatibility, bool include_reason_string)
1207
1208
4.01k
{
1209
4.01k
  if (!error_code) {
1210
2.00k
    if (!old_stun) {
1211
1.28k
      stun_init_success_response_str(STUN_METHOD_BINDING, buf, len, tid);
1212
1.28k
    } else {
1213
726
      old_stun_init_success_response_str(STUN_METHOD_BINDING, buf, len, tid, cookie);
1214
726
    }
1215
2.00k
    if (!old_stun && reflexive_addr) {
1216
1.28k
      if (!stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, reflexive_addr)) {
1217
0
        return false;
1218
0
      }
1219
1.28k
    }
1220
2.00k
    if (reflexive_addr) {
1221
2.00k
      if (stun_backward_compatibility &&
1222
1.29k
          !stun_attr_add_addr_str(buf, len, STUN_ATTRIBUTE_MAPPED_ADDRESS, reflexive_addr)) {
1223
0
        return false;
1224
0
      }
1225
2.00k
    }
1226
2.00k
  } else if (!old_stun) {
1227
1.28k
    stun_init_error_response_str(STUN_METHOD_BINDING, buf, len, error_code, reason, tid, include_reason_string);
1228
1.28k
  } else {
1229
726
    old_stun_init_error_response_str(STUN_METHOD_BINDING, buf, len, error_code, reason, tid, cookie,
1230
726
                                     include_reason_string);
1231
726
  }
1232
1233
4.01k
  return true;
1234
4.01k
}
1235
1236
0
bool stun_is_binding_request_str(const uint8_t *buf, size_t len, size_t offset) {
1237
0
  if (offset < len) {
1238
0
    buf += offset;
1239
0
    len -= offset;
1240
0
    if (stun_is_command_message_str(buf, len)) {
1241
0
      if (stun_is_request_str(buf, len) && (stun_get_method_str(buf, len) == STUN_METHOD_BINDING)) {
1242
0
        return true;
1243
0
      }
1244
0
    }
1245
0
  }
1246
0
  return false;
1247
0
}
1248
1249
13.2k
bool stun_is_binding_response_str(const uint8_t *buf, size_t len) {
1250
13.2k
  if (stun_is_command_message_str(buf, len) && (stun_get_method_str(buf, len) == STUN_METHOD_BINDING)) {
1251
3.79k
    if (stun_is_response_str(buf, len)) {
1252
3.14k
      return true;
1253
3.14k
    }
1254
3.79k
  }
1255
10.0k
  return false;
1256
13.2k
}
1257
1258
/////////////////////////////// TID ///////////////////////////////
1259
1260
0
bool stun_tid_equals(const stun_tid *id1, const stun_tid *id2) {
1261
0
  if (!id1 || !id2) {
1262
0
    return false;
1263
0
  }
1264
0
  if (id1 == id2) {
1265
0
    return true;
1266
0
  }
1267
0
  for (size_t i = 0; i < STUN_TID_SIZE; ++i) {
1268
0
    if (id1->tsx_id[i] != id2->tsx_id[i]) {
1269
0
      return false;
1270
0
    }
1271
0
  }
1272
0
  return true;
1273
0
}
1274
1275
0
void stun_tid_cpy(stun_tid *id1, const stun_tid *id2) {
1276
0
  if (!id1 || !id2) {
1277
0
    return;
1278
0
  }
1279
0
  memcpy(id1->tsx_id, id2->tsx_id, STUN_TID_SIZE);
1280
0
}
1281
1282
23.2k
static void stun_tid_string_cpy(uint8_t *s, const stun_tid *id) {
1283
23.2k
  if (s && id) {
1284
23.2k
    memcpy(s, id->tsx_id, STUN_TID_SIZE);
1285
23.2k
  }
1286
23.2k
}
1287
1288
22.8k
static void stun_tid_from_string(const uint8_t *s, stun_tid *id) {
1289
22.8k
  if (s && id) {
1290
22.8k
    memcpy(id->tsx_id, s, STUN_TID_SIZE);
1291
22.8k
  }
1292
22.8k
}
1293
1294
22.8k
void stun_tid_from_message_str(const uint8_t *buf, size_t len, stun_tid *id) {
1295
22.8k
  UNUSED_ARG(len);
1296
22.8k
  stun_tid_from_string(buf + 8, id);
1297
22.8k
}
1298
1299
23.2k
void stun_tid_message_cpy(uint8_t *buf, const stun_tid *id) {
1300
23.2k
  if (buf && id) {
1301
23.2k
    stun_tid_string_cpy(buf + 8, id);
1302
23.2k
  }
1303
23.2k
}
1304
1305
13.4k
void stun_tid_generate(stun_tid *id) {
1306
13.4k
  if (id) {
1307
13.4k
    turn_random_tid_size(id->tsx_id);
1308
13.4k
  }
1309
13.4k
}
1310
1311
13.4k
void stun_tid_generate_in_message_str(uint8_t *buf, stun_tid *id) {
1312
13.4k
  stun_tid tmp;
1313
13.4k
  if (!id) {
1314
13.2k
    id = &tmp;
1315
13.2k
  }
1316
13.4k
  stun_tid_generate(id);
1317
13.4k
  stun_tid_message_cpy(buf, id);
1318
13.4k
}
1319
1320
/////////////////// TIME ////////////////////////////////////////////////////////
1321
1322
turn_time_t stun_adjust_allocate_lifetime(turn_time_t lifetime, turn_time_t max_allowed_lifetime,
1323
0
                                          turn_time_t max_lifetime) {
1324
1325
0
  if (!lifetime) {
1326
0
    lifetime = STUN_DEFAULT_ALLOCATE_LIFETIME;
1327
0
  } else if (lifetime < STUN_MIN_ALLOCATE_LIFETIME) {
1328
0
    lifetime = STUN_MIN_ALLOCATE_LIFETIME;
1329
0
  } else if (lifetime > max_allowed_lifetime) {
1330
0
    lifetime = max_allowed_lifetime;
1331
0
  }
1332
1333
0
  if (max_lifetime && (max_lifetime < lifetime)) {
1334
0
    lifetime = max_lifetime;
1335
0
  }
1336
1337
0
  return lifetime;
1338
0
}
1339
1340
////////////// ATTR /////////////////////////////////////////////////////////////
1341
1342
130k
int stun_attr_get_type(stun_attr_ref attr) {
1343
130k
  if (attr) {
1344
130k
    uint16_t val;
1345
130k
    memcpy(&val, attr, sizeof(val));
1346
130k
    return (int)(nswap16(val));
1347
130k
  }
1348
0
  return -1;
1349
130k
}
1350
1351
216k
int stun_attr_get_len(stun_attr_ref attr) {
1352
216k
  if (attr) {
1353
216k
    uint16_t val;
1354
216k
    memcpy(&val, (const uint8_t *)attr + 2, sizeof(val));
1355
216k
    return (int)(nswap16(val));
1356
216k
  }
1357
0
  return -1;
1358
216k
}
1359
1360
20.7k
const uint8_t *stun_attr_get_value(stun_attr_ref attr) {
1361
20.7k
  if (attr) {
1362
20.7k
    uint16_t val;
1363
20.7k
    memcpy(&val, (const uint8_t *)attr + 2, sizeof(val));
1364
20.7k
    const int len = (int)(nswap16(val));
1365
20.7k
    if (len < 1) {
1366
4
      return NULL;
1367
4
    }
1368
20.7k
    return ((const uint8_t *)attr) + 4;
1369
20.7k
  }
1370
0
  return NULL;
1371
20.7k
}
1372
1373
0
int stun_get_requested_address_family(stun_attr_ref attr) {
1374
0
  if (attr) {
1375
0
    uint16_t raw_len;
1376
0
    memcpy(&raw_len, (const uint8_t *)attr + 2, sizeof(raw_len));
1377
0
    const int len = (int)(nswap16(raw_len));
1378
0
    if (len != 4) {
1379
0
      return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_INVALID;
1380
0
    }
1381
0
    const int val = ((const uint8_t *)attr)[4];
1382
0
    switch (val) {
1383
0
    case STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4:
1384
0
    case STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6:
1385
0
      return val;
1386
0
    default:
1387
0
      return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_INVALID;
1388
0
    };
1389
0
  }
1390
0
  return STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_DEFAULT;
1391
0
}
1392
1393
2.00k
uint16_t stun_attr_get_channel_number(stun_attr_ref attr) {
1394
2.00k
  if (attr) {
1395
2.00k
    const uint8_t *value = stun_attr_get_value(attr);
1396
2.00k
    if (value && (stun_attr_get_len(attr) >= 2)) {
1397
2.00k
      const uint16_t cn = nswap16(((const uint16_t *)value)[0]);
1398
2.00k
      if (STUN_VALID_CHANNEL(cn)) {
1399
2.00k
        return cn;
1400
2.00k
      }
1401
2.00k
    }
1402
2.00k
  }
1403
0
  return 0;
1404
2.00k
}
1405
1406
0
band_limit_t stun_attr_get_bandwidth(stun_attr_ref attr) {
1407
0
  if (attr) {
1408
0
    const uint8_t *value = stun_attr_get_value(attr);
1409
0
    if (value && (stun_attr_get_len(attr) >= 4)) {
1410
0
      const uint32_t bps = nswap32(((const uint32_t *)value)[0]);
1411
0
      return (band_limit_t)(bps << 7);
1412
0
    }
1413
0
  }
1414
0
  return 0;
1415
0
}
1416
1417
0
uint64_t stun_attr_get_reservation_token_value(stun_attr_ref attr) {
1418
0
  if (attr) {
1419
0
    const uint8_t *value = stun_attr_get_value(attr);
1420
0
    if (value && (stun_attr_get_len(attr) == 8)) {
1421
0
      uint64_t token;
1422
0
      memcpy(&token, value, sizeof(uint64_t));
1423
0
      return nswap64(token);
1424
0
    }
1425
0
  }
1426
0
  return 0;
1427
0
}
1428
1429
56.4k
bool stun_attr_is_addr(stun_attr_ref attr) {
1430
1431
56.4k
  if (attr) {
1432
56.4k
    switch (stun_attr_get_type(attr)) {
1433
3.76k
    case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS:
1434
7.78k
    case STUN_ATTRIBUTE_XOR_PEER_ADDRESS:
1435
12.1k
    case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS:
1436
13.9k
    case STUN_ATTRIBUTE_MAPPED_ADDRESS:
1437
13.9k
    case STUN_ATTRIBUTE_ALTERNATE_SERVER:
1438
14.0k
    case OLD_STUN_ATTRIBUTE_RESPONSE_ADDRESS:
1439
14.3k
    case OLD_STUN_ATTRIBUTE_SOURCE_ADDRESS:
1440
14.3k
    case OLD_STUN_ATTRIBUTE_CHANGED_ADDRESS:
1441
14.3k
    case OLD_STUN_ATTRIBUTE_REFLECTED_FROM:
1442
14.3k
    case STUN_ATTRIBUTE_RESPONSE_ORIGIN:
1443
14.3k
    case STUN_ATTRIBUTE_OTHER_ADDRESS:
1444
14.3k
      return true;
1445
0
      break;
1446
42.1k
    default:;
1447
56.4k
    };
1448
42.1k
  }
1449
42.1k
  return false;
1450
56.4k
}
1451
1452
0
uint8_t stun_attr_get_even_port(stun_attr_ref attr) {
1453
0
  if (attr) {
1454
0
    const uint8_t *value = stun_attr_get_value(attr);
1455
0
    if (value) {
1456
0
      if ((uint8_t)(value[0]) > 0x7F) {
1457
0
        return 1;
1458
0
      }
1459
0
    }
1460
0
  }
1461
0
  return 0;
1462
0
}
1463
1464
6.97k
stun_attr_ref stun_attr_get_first_by_type_str(const uint8_t *buf, size_t len, uint16_t attr_type) {
1465
6.97k
  stun_attr_ref attr = stun_attr_get_first_str(buf, len);
1466
13.2k
  while (attr) {
1467
12.3k
    if (stun_attr_get_type(attr) == attr_type) {
1468
6.04k
      return attr;
1469
6.04k
    }
1470
6.27k
    attr = stun_attr_get_next_str(buf, len, attr);
1471
6.27k
  }
1472
1473
936
  return NULL;
1474
6.97k
}
1475
1476
90.4k
static stun_attr_ref stun_attr_check_valid(stun_attr_ref attr, size_t remaining) {
1477
90.4k
  if (remaining >= 4) {
1478
    /* Read the size of the attribute */
1479
90.4k
    size_t attrlen = stun_attr_get_len(attr);
1480
90.4k
    remaining -= 4;
1481
1482
    /* Round to boundary */
1483
90.4k
    const uint16_t rem4 = ((uint16_t)attrlen) & 0x0003;
1484
90.4k
    if (rem4) {
1485
11.6k
      attrlen = attrlen + 4 - (int)rem4;
1486
11.6k
    }
1487
1488
    /* Check that there's enough space remaining */
1489
90.4k
    if (attrlen <= remaining) {
1490
88.5k
      return attr;
1491
88.5k
    }
1492
90.4k
  }
1493
1494
1.98k
  return NULL;
1495
90.4k
}
1496
1497
51.1k
stun_attr_ref stun_attr_get_first_str(const uint8_t *buf, size_t len) {
1498
51.1k
  const int bufLen = stun_get_command_message_len_str(buf, len);
1499
51.1k
  if (bufLen > STUN_HEADER_LENGTH) {
1500
40.9k
    stun_attr_ref attr = (stun_attr_ref)(buf + STUN_HEADER_LENGTH);
1501
40.9k
    return stun_attr_check_valid(attr, bufLen - STUN_HEADER_LENGTH);
1502
40.9k
  }
1503
1504
10.1k
  return NULL;
1505
51.1k
}
1506
1507
75.0k
stun_attr_ref stun_attr_get_next_str(const uint8_t *buf, size_t len, stun_attr_ref prev) {
1508
75.0k
  if (!prev) {
1509
0
    return stun_attr_get_first_str(buf, len);
1510
75.0k
  } else {
1511
75.0k
    const uint8_t *end = buf + stun_get_command_message_len_str(buf, len);
1512
75.0k
    int attrlen = stun_attr_get_len(prev);
1513
75.0k
    const uint16_t rem4 = ((uint16_t)attrlen) & 0x0003;
1514
75.0k
    if (rem4) {
1515
9.88k
      attrlen = attrlen + 4 - (int)rem4;
1516
9.88k
    }
1517
    /* Note the order here: operations on attrlen are untrusted as they may overflow */
1518
75.0k
    if (attrlen < end - (const uint8_t *)prev - 4) {
1519
49.5k
      const uint8_t *attr_end = (const uint8_t *)prev + 4 + attrlen;
1520
49.5k
      return stun_attr_check_valid(attr_end, end - attr_end);
1521
49.5k
    }
1522
25.5k
    return NULL;
1523
75.0k
  }
1524
75.0k
}
1525
1526
22.2k
bool stun_attr_add_str(uint8_t *buf, size_t *len, uint16_t attr, const uint8_t *avalue, int alen) {
1527
22.2k
  if (alen < 0) {
1528
0
    alen = 0;
1529
0
  }
1530
22.2k
  uint8_t tmp[1];
1531
22.2k
  if (!avalue) {
1532
0
    alen = 0;
1533
0
    avalue = tmp;
1534
0
  }
1535
22.2k
  const int clen = stun_get_command_message_len_str(buf, *len);
1536
22.2k
  int newlen = clen + 4 + alen;
1537
22.2k
  const int newlenrem4 = newlen & 0x00000003;
1538
22.2k
  int paddinglen = 0;
1539
22.2k
  if (newlenrem4) {
1540
1.88k
    paddinglen = 4 - newlenrem4;
1541
1.88k
    newlen = newlen + paddinglen;
1542
1.88k
  }
1543
1544
22.2k
  if (newlen >= MAX_STUN_MESSAGE_SIZE) {
1545
0
    return false;
1546
0
  }
1547
1548
22.2k
  uint8_t *attr_start = buf + clen;
1549
1550
22.2k
  uint16_t *attr_start_16t = (uint16_t *)attr_start;
1551
1552
22.2k
  stun_set_command_message_len_str(buf, newlen);
1553
22.2k
  *len = newlen;
1554
1555
22.2k
  attr_start_16t[0] = nswap16(attr);
1556
22.2k
  attr_start_16t[1] = nswap16(alen);
1557
22.2k
  if (alen > 0) {
1558
21.9k
    memcpy(attr_start + 4, avalue, alen);
1559
21.9k
  }
1560
1561
  // Write 0 padding to not leak data
1562
22.2k
  memset(attr_start + 4 + alen, 0, paddinglen);
1563
1564
22.2k
  return true;
1565
22.2k
}
1566
1567
8.41k
bool stun_attr_add_addr_str(uint8_t *buf, size_t *len, uint16_t attr_type, const ioa_addr *ca) {
1568
1569
8.41k
  stun_tid tid;
1570
8.41k
  stun_tid_from_message_str(buf, *len, &tid);
1571
1572
8.41k
  int xor_ed = 0;
1573
8.41k
  switch (attr_type) {
1574
2.43k
  case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS:
1575
4.44k
  case STUN_ATTRIBUTE_XOR_PEER_ADDRESS:
1576
7.11k
  case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS:
1577
7.11k
    xor_ed = 1;
1578
7.11k
    break;
1579
1.29k
  default:;
1580
8.41k
  };
1581
1582
8.41k
  ioa_addr public_addr;
1583
8.41k
  map_addr_from_private_to_public(ca, &public_addr);
1584
1585
8.41k
  uint8_t cfield[64];
1586
8.41k
  int clen = 0;
1587
8.41k
  if (stun_addr_encode(&public_addr, cfield, &clen, xor_ed, STUN_MAGIC_COOKIE, tid.tsx_id) < 0) {
1588
0
    return false;
1589
0
  }
1590
1591
8.41k
  if (!stun_attr_add_str(buf, len, attr_type, (uint8_t *)(&cfield), clen)) {
1592
0
    return false;
1593
0
  }
1594
1595
8.41k
  return true;
1596
8.41k
}
1597
1598
bool stun_attr_get_addr_str(const uint8_t *buf, size_t len, stun_attr_ref attr, ioa_addr *ca,
1599
13.8k
                            const ioa_addr *default_addr) {
1600
13.8k
  stun_tid tid;
1601
13.8k
  stun_tid_from_message_str(buf, len, &tid);
1602
13.8k
  ioa_addr public_addr;
1603
1604
13.8k
  addr_set_any(ca);
1605
13.8k
  addr_set_any(&public_addr);
1606
1607
13.8k
  const int attr_type = stun_attr_get_type(attr);
1608
13.8k
  if (attr_type < 0) {
1609
0
    return false;
1610
0
  }
1611
1612
13.8k
  int xor_ed = 0;
1613
13.8k
  switch (attr_type) {
1614
3.72k
  case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS:
1615
7.73k
  case STUN_ATTRIBUTE_XOR_PEER_ADDRESS:
1616
12.1k
  case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS:
1617
12.1k
    xor_ed = 1;
1618
12.1k
    break;
1619
1.69k
  default:;
1620
13.8k
  };
1621
1622
13.8k
  const uint8_t *cfield = stun_attr_get_value(attr);
1623
13.8k
  if (!cfield) {
1624
4
    return false;
1625
4
  }
1626
1627
13.8k
  if (stun_addr_decode(&public_addr, cfield, stun_attr_get_len(attr), xor_ed, STUN_MAGIC_COOKIE, tid.tsx_id) < 0) {
1628
16
    return false;
1629
16
  }
1630
1631
13.8k
  map_addr_from_public_to_private(&public_addr, ca);
1632
1633
13.8k
  if (default_addr && addr_any_no_port(ca) && !addr_any_no_port(default_addr)) {
1634
1.81k
    const uint16_t port = addr_get_port(ca);
1635
1.81k
    addr_cpy(ca, default_addr);
1636
1.81k
    addr_set_port(ca, port);
1637
1.81k
  }
1638
1639
13.8k
  return true;
1640
13.8k
}
1641
1642
bool stun_attr_get_first_addr_str(const uint8_t *buf, size_t len, uint16_t attr_type, ioa_addr *ca,
1643
17.7k
                                  const ioa_addr *default_addr) {
1644
17.7k
  stun_attr_ref attr = stun_attr_get_first_str(buf, len);
1645
1646
46.5k
  while (attr) {
1647
34.2k
    if (stun_attr_is_addr(attr) && (attr_type == stun_attr_get_type(attr))) {
1648
5.41k
      if (stun_attr_get_addr_str(buf, len, attr, ca, default_addr)) {
1649
5.39k
        return true;
1650
5.39k
      }
1651
5.41k
    }
1652
28.8k
    attr = stun_attr_get_next_str(buf, len, attr);
1653
28.8k
  }
1654
1655
12.3k
  return false;
1656
17.7k
}
1657
1658
2.00k
bool stun_attr_add_channel_number_str(uint8_t *buf, size_t *len, uint16_t chnumber) {
1659
1660
2.00k
  uint16_t field[2];
1661
2.00k
  field[0] = nswap16(chnumber);
1662
2.00k
  field[1] = 0;
1663
1664
2.00k
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_CHANNEL_NUMBER, (uint8_t *)(field), sizeof(field));
1665
2.00k
}
1666
1667
0
bool stun_attr_add_bandwidth_str(uint8_t *buf, size_t *len, band_limit_t bps0) {
1668
1669
0
  const uint32_t bps = (uint32_t)(band_limit_t)(bps0 >> 7);
1670
1671
0
  uint32_t field = nswap32(bps);
1672
1673
0
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_NEW_BANDWIDTH, (uint8_t *)(&field), sizeof(field));
1674
0
}
1675
1676
0
bool stun_attr_add_address_error_code(uint8_t *buf, size_t *len, int requested_address_family, int error_code) {
1677
0
  const uint8_t *reason = get_default_reason(error_code);
1678
1679
0
  uint8_t avalue[513];
1680
0
  avalue[0] = (uint8_t)requested_address_family;
1681
0
  avalue[1] = 0;
1682
0
  avalue[2] = (uint8_t)(error_code / 100);
1683
0
  avalue[3] = (uint8_t)(error_code % 100);
1684
0
  strncpy((char *)(avalue + 4), (const char *)reason, sizeof(avalue) - 4);
1685
0
  avalue[sizeof(avalue) - 1] = 0;
1686
0
  int alen = 4 + (int)strlen((const char *)(avalue + 4));
1687
1688
  //"Manual" padding for compatibility with classic old stun:
1689
0
  {
1690
0
    const int rem = alen % 4;
1691
0
    if (rem) {
1692
0
      alen += (4 - rem);
1693
0
    }
1694
0
  }
1695
1696
0
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_ADDRESS_ERROR_CODE, (uint8_t *)avalue, alen);
1697
0
}
1698
1699
13.2k
uint16_t stun_attr_get_first_channel_number_str(const uint8_t *buf, size_t len) {
1700
1701
13.2k
  stun_attr_ref attr = stun_attr_get_first_str(buf, len);
1702
30.8k
  while (attr) {
1703
19.6k
    if (stun_attr_get_type(attr) == STUN_ATTRIBUTE_CHANNEL_NUMBER) {
1704
2.00k
      const uint16_t ret = stun_attr_get_channel_number(attr);
1705
2.00k
      if (STUN_VALID_CHANNEL(ret)) {
1706
2.00k
        return ret;
1707
2.00k
      }
1708
2.00k
    }
1709
17.6k
    attr = stun_attr_get_next_str(buf, len, attr);
1710
17.6k
  }
1711
1712
11.1k
  return 0;
1713
13.2k
}
1714
1715
////////////// FINGERPRINT ////////////////////////////
1716
1717
0
bool stun_attr_add_fingerprint_str(uint8_t *buf, size_t *len) {
1718
0
  uint32_t crc32 = 0;
1719
0
  if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_FINGERPRINT, (uint8_t *)&crc32, 4)) {
1720
0
    return false;
1721
0
  }
1722
0
  crc32 = ns_crc32(buf, (int)*len - 8);
1723
0
  *((uint32_t *)(buf + *len - 4)) = nswap32(crc32 ^ ((uint32_t)FINGERPRINT_XOR));
1724
0
  return true;
1725
0
}
1726
////////////// CRC ///////////////////////////////////////////////
1727
1728
0
#define CRC_MASK 0xFFFFFFFFUL
1729
1730
0
#define UPDATE_CRC(crc, c) crc = crctable[(uint8_t)crc ^ (uint8_t)(c)] ^ (crc >> 8)
1731
1732
static const uint32_t crctable[256] = {
1733
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
1734
    0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
1735
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
1736
    0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1737
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1738
    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
1739
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
1740
    0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1741
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
1742
    0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1743
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
1744
    0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1745
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
1746
    0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
1747
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1748
    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1749
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
1750
    0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
1751
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
1752
    0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1753
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
1754
    0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
1755
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
1756
    0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1757
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1758
    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
1759
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
1760
    0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1761
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1762
};
1763
1764
0
static uint32_t ns_crc32(const uint8_t *buffer, uint32_t len) {
1765
0
  uint32_t crc = CRC_MASK;
1766
0
  while (len--) {
1767
0
    UPDATE_CRC(crc, *buffer++);
1768
0
  }
1769
0
  return (~crc);
1770
0
}
1771
1772
//////////// SASLprep RFC 4013 /////////////////////////////////////////
1773
1774
/* We support only basic ASCII table */
1775
1776
0
bool SASLprep(uint8_t *s) {
1777
0
  if (s) {
1778
0
    uint8_t *strin = s;
1779
0
    uint8_t *strout = s;
1780
0
    for (;;) {
1781
0
      const uint8_t c = *strin;
1782
0
      if (!c) {
1783
0
        *strout = 0;
1784
0
        break;
1785
0
      }
1786
1787
0
      switch (c) {
1788
0
      case 0xAD:
1789
0
        ++strin;
1790
0
        break;
1791
0
      case 0xA0:
1792
0
      case 0x20:
1793
0
        *strout = 0x20;
1794
0
        ++strout;
1795
0
        ++strin;
1796
0
        break;
1797
0
      case 0x7F:
1798
0
        return false;
1799
0
      default:
1800
0
        if (c < 0x1F) {
1801
0
          return false;
1802
0
        }
1803
0
        if (c >= 0x80 && c <= 0x9F) {
1804
0
          return false;
1805
0
        }
1806
0
        *strout = c;
1807
0
        ++strout;
1808
0
        ++strin;
1809
0
      };
1810
0
    }
1811
0
  }
1812
1813
0
  return true;
1814
0
}
1815
1816
//////////////// Message Integrity ////////////////////////////
1817
1818
0
size_t get_hmackey_size(SHATYPE shatype) {
1819
0
  if (shatype == SHATYPE_SHA256) {
1820
0
    return 32;
1821
0
  }
1822
0
  if (shatype == SHATYPE_SHA384) {
1823
0
    return 48;
1824
0
  }
1825
0
  if (shatype == SHATYPE_SHA512) {
1826
0
    return 64;
1827
0
  }
1828
0
  return 16;
1829
0
}
1830
1831
0
void print_bin_func(const char *name, size_t len, const void *s, const char *func) {
1832
0
  printf("<%s>:<%s>:len=%d:[", func, name, (int)len);
1833
0
  for (size_t i = 0; i < len; i++) {
1834
0
    printf("%02x", (int)((const uint8_t *)s)[i]);
1835
0
  }
1836
0
  printf("]\n");
1837
0
}
1838
1839
bool stun_attr_add_integrity_str(turn_credential_type ct, uint8_t *buf, size_t *len, hmackey_t key, password_t pwd,
1840
0
                                 SHATYPE shatype) {
1841
0
  uint8_t hmac[MAXSHASIZE] = {0};
1842
1843
0
  unsigned int shasize;
1844
1845
0
  switch (shatype) {
1846
0
  case SHATYPE_SHA256:
1847
0
    shasize = SHA256SIZEBYTES;
1848
0
    break;
1849
0
  case SHATYPE_SHA384:
1850
0
    shasize = SHA384SIZEBYTES;
1851
0
    break;
1852
0
  case SHATYPE_SHA512:
1853
0
    shasize = SHA512SIZEBYTES;
1854
0
    break;
1855
0
  default:
1856
0
    shasize = SHA1SIZEBYTES;
1857
0
  };
1858
1859
0
  if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, hmac, shasize)) {
1860
0
    return false;
1861
0
  }
1862
1863
0
  if (ct == TURN_CREDENTIALS_SHORT_TERM) {
1864
0
    return stun_calculate_hmac(buf, *len - 4 - shasize, pwd, strlen((char *)pwd), buf + *len - shasize, &shasize,
1865
0
                               shatype);
1866
0
  } else {
1867
0
    return stun_calculate_hmac(buf, *len - 4 - shasize, key, get_hmackey_size(shatype), buf + *len - shasize, &shasize,
1868
0
                               shatype);
1869
0
  }
1870
0
}
1871
1872
bool stun_attr_add_integrity_by_key_str(uint8_t *buf, size_t *len, const uint8_t *uname, const uint8_t *realm,
1873
0
                                        hmackey_t key, const uint8_t *nonce, SHATYPE shatype) {
1874
0
  if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_USERNAME, uname, (int)strlen((const char *)uname))) {
1875
0
    return false;
1876
0
  }
1877
1878
0
  if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_NONCE, nonce, (int)strlen((const char *)nonce))) {
1879
0
    return false;
1880
0
  }
1881
1882
0
  if (!stun_attr_add_str(buf, len, STUN_ATTRIBUTE_REALM, realm, (int)strlen((const char *)realm))) {
1883
0
    return false;
1884
0
  }
1885
1886
0
  password_t p;
1887
0
  return stun_attr_add_integrity_str(TURN_CREDENTIALS_LONG_TERM, buf, len, key, p, shatype);
1888
0
}
1889
1890
bool stun_attr_add_integrity_by_user_str(uint8_t *buf, size_t *len, const uint8_t *uname, const uint8_t *realm,
1891
0
                                         const uint8_t *upwd, const uint8_t *nonce, SHATYPE shatype) {
1892
0
  hmackey_t key;
1893
1894
0
  if (!stun_produce_integrity_key_str(uname, realm, upwd, key, shatype)) {
1895
0
    return false;
1896
0
  }
1897
1898
0
  return stun_attr_add_integrity_by_key_str(buf, len, uname, realm, key, nonce, shatype);
1899
0
}
1900
1901
bool stun_attr_add_integrity_by_user_short_term_str(uint8_t *buf, size_t *len, const uint8_t *uname, password_t pwd,
1902
0
                                                    SHATYPE shatype) {
1903
0
  if (stun_attr_add_str(buf, len, STUN_ATTRIBUTE_USERNAME, uname, (int)strlen((const char *)uname))) {
1904
0
    return false;
1905
0
  }
1906
1907
0
  hmackey_t key;
1908
0
  return stun_attr_add_integrity_str(TURN_CREDENTIALS_SHORT_TERM, buf, len, key, pwd, shatype);
1909
0
}
1910
1911
/*
1912
 * Return -1 if failure, 0 if the integrity is not correct, 1 if OK
1913
 */
1914
int stun_check_message_integrity_by_key_str(turn_credential_type ct, uint8_t *buf, size_t len, hmackey_t key,
1915
0
                                            password_t pwd, SHATYPE shatype) {
1916
0
  stun_attr_ref sar = stun_attr_get_first_by_type_str(buf, len, STUN_ATTRIBUTE_MESSAGE_INTEGRITY);
1917
0
  if (!sar) {
1918
0
    return -1;
1919
0
  }
1920
1921
0
  unsigned int shasize = 0;
1922
0
  switch (stun_attr_get_len(sar)) {
1923
0
  case SHA256SIZEBYTES:
1924
0
    shasize = SHA256SIZEBYTES;
1925
0
    if (shatype != SHATYPE_SHA256) {
1926
0
      return -1;
1927
0
    }
1928
0
    break;
1929
0
  case SHA384SIZEBYTES:
1930
0
    shasize = SHA384SIZEBYTES;
1931
0
    if (shatype != SHATYPE_SHA384) {
1932
0
      return -1;
1933
0
    }
1934
0
    break;
1935
0
  case SHA512SIZEBYTES:
1936
0
    shasize = SHA512SIZEBYTES;
1937
0
    if (shatype != SHATYPE_SHA512) {
1938
0
      return -1;
1939
0
    }
1940
0
    break;
1941
0
  case SHA1SIZEBYTES:
1942
0
    shasize = SHA1SIZEBYTES;
1943
0
    if (shatype != SHATYPE_SHA1) {
1944
0
      return -1;
1945
0
    }
1946
0
    break;
1947
0
  default:
1948
0
    return -1;
1949
0
  };
1950
1951
0
  const int orig_len = stun_get_command_message_len_str(buf, len);
1952
0
  if (orig_len < 0) {
1953
0
    return -1;
1954
0
  }
1955
1956
0
  const int new_len = (int)((const uint8_t *)sar - buf) + 4 + shasize;
1957
0
  if (new_len > orig_len) {
1958
0
    return -1;
1959
0
  }
1960
1961
0
  if (!stun_set_command_message_len_str(buf, new_len)) {
1962
0
    return -1;
1963
0
  }
1964
1965
0
  int res = 0;
1966
0
  uint8_t new_hmac[MAXSHASIZE] = {0};
1967
0
  if (ct == TURN_CREDENTIALS_SHORT_TERM) {
1968
0
    if (!stun_calculate_hmac(buf, (size_t)new_len - 4 - shasize, pwd, strlen((char *)pwd), new_hmac, &shasize,
1969
0
                             shatype)) {
1970
0
      res = -1;
1971
0
    } else {
1972
0
      res = 0;
1973
0
    }
1974
0
  } else {
1975
0
    if (!stun_calculate_hmac(buf, (size_t)new_len - 4 - shasize, key, get_hmackey_size(shatype), new_hmac, &shasize,
1976
0
                             shatype)) {
1977
0
      res = -1;
1978
0
    } else {
1979
0
      res = 0;
1980
0
    }
1981
0
  }
1982
1983
0
  stun_set_command_message_len_str(buf, orig_len);
1984
0
  if (res < 0) {
1985
0
    return -1;
1986
0
  }
1987
1988
0
  const uint8_t *old_hmac = stun_attr_get_value(sar);
1989
0
  if (!old_hmac) {
1990
0
    return -1;
1991
0
  }
1992
1993
  /* Use constant-time comparison: a short-circuiting memcmp leaks the matching prefix
1994
     length via response timing, allowing byte-by-byte HMAC recovery. */
1995
0
  if (0 != CRYPTO_memcmp(old_hmac, new_hmac, shasize)) {
1996
0
    return 0;
1997
0
  }
1998
1999
0
  return +1;
2000
0
}
2001
2002
/*
2003
 * Return -1 if failure, 0 if the integrity is not correct, 1 if OK
2004
 */
2005
int stun_check_message_integrity_str(turn_credential_type ct, uint8_t *buf, size_t len, const uint8_t *uname,
2006
0
                                     const uint8_t *realm, const uint8_t *upwd, SHATYPE shatype) {
2007
0
  hmackey_t key;
2008
0
  password_t pwd;
2009
2010
0
  if (ct == TURN_CREDENTIALS_SHORT_TERM) {
2011
0
    strncpy((char *)pwd, (const char *)upwd, sizeof(password_t) - 1);
2012
0
    pwd[sizeof(password_t) - 1] = 0;
2013
0
  } else if (!stun_produce_integrity_key_str(uname, realm, upwd, key, shatype)) {
2014
0
    return -1;
2015
0
  }
2016
2017
0
  return stun_check_message_integrity_by_key_str(ct, buf, len, key, pwd, shatype);
2018
0
}
2019
2020
/* RFC 5780 */
2021
2022
0
bool stun_attr_get_change_request_str(stun_attr_ref attr, bool *change_ip, bool *change_port) {
2023
0
  if (stun_attr_get_len(attr) == 4) {
2024
0
    const uint8_t *value = stun_attr_get_value(attr);
2025
0
    if (value) {
2026
0
      *change_ip = (value[3] & 0x04);
2027
0
      *change_port = (value[3] & 0x02);
2028
0
      return true;
2029
0
    }
2030
0
  }
2031
0
  return false;
2032
0
}
2033
2034
0
bool stun_attr_add_change_request_str(uint8_t *buf, size_t *len, bool change_ip, bool change_port) {
2035
0
  uint8_t avalue[4] = {0, 0, 0, 0};
2036
2037
0
  if (change_ip) {
2038
0
    if (change_port) {
2039
0
      avalue[3] = 0x06;
2040
0
    } else {
2041
0
      avalue[3] = 0x04;
2042
0
    }
2043
0
  } else if (change_port) {
2044
0
    avalue[3] = 0x02;
2045
0
  }
2046
2047
0
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_CHANGE_REQUEST, avalue, 4);
2048
0
}
2049
2050
0
int stun_attr_get_response_port_str(stun_attr_ref attr) {
2051
0
  if (stun_attr_get_len(attr) >= 2) {
2052
0
    const uint8_t *value = stun_attr_get_value(attr);
2053
0
    if (value) {
2054
0
      return nswap16(((const uint16_t *)value)[0]);
2055
0
    }
2056
0
  }
2057
0
  return -1;
2058
0
}
2059
2060
0
bool stun_attr_add_response_port_str(uint8_t *buf, size_t *len, uint16_t port) {
2061
0
  uint8_t avalue[4] = {0, 0, 0, 0};
2062
0
  uint16_t *port_ptr = (uint16_t *)avalue;
2063
2064
0
  *port_ptr = nswap16(port);
2065
2066
0
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_RESPONSE_PORT, avalue, 4);
2067
0
}
2068
2069
0
int stun_attr_get_padding_len_str(stun_attr_ref attr) {
2070
0
  const int len = stun_attr_get_len(attr);
2071
0
  if (len < 0) {
2072
0
    return -1;
2073
0
  }
2074
0
  return (uint16_t)len;
2075
0
}
2076
2077
0
bool stun_attr_add_padding_str(uint8_t *buf, size_t *len, uint16_t padding_len) {
2078
0
  uint8_t avalue[0xFFFF];
2079
0
  memset(avalue, 0, padding_len);
2080
2081
0
  return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_PADDING, avalue, padding_len);
2082
0
}
2083
2084
/* OAUTH */
2085
2086
0
#define OAUTH_ERROR(...) fprintf(stderr, __VA_ARGS__)
2087
2088
0
static void remove_spaces(char *s) {
2089
0
  char *sfns = s;
2090
0
  while (*sfns) {
2091
0
    if (*sfns != ' ') {
2092
0
      break;
2093
0
    }
2094
0
    ++sfns;
2095
0
  }
2096
0
  if (*sfns) {
2097
0
    if (sfns != s) {
2098
0
      while (*sfns && (*sfns != ' ')) {
2099
0
        *s = *sfns;
2100
0
        ++s;
2101
0
        ++sfns;
2102
0
      };
2103
0
      *s = 0;
2104
0
    } else {
2105
0
      while (*s) {
2106
0
        if (*s == ' ') {
2107
0
          *s = 0;
2108
0
          break;
2109
0
        }
2110
0
        ++s;
2111
0
      }
2112
0
    }
2113
0
  }
2114
0
}
2115
2116
0
static void normalize_algorithm(char *s) {
2117
0
  char c = *s;
2118
0
  while (c) {
2119
0
    if (c == '_') {
2120
0
      *s = '-';
2121
0
    } else if ((c >= 'a') && (c <= 'z')) {
2122
0
      *s = c - 'a' + 'A';
2123
0
    }
2124
0
    ++s;
2125
0
    c = *s;
2126
0
  }
2127
0
}
2128
2129
size_t calculate_enc_key_length(ENC_ALG a);
2130
0
size_t calculate_enc_key_length(ENC_ALG a) {
2131
0
  switch (a) {
2132
0
#if !defined(TURN_NO_GCM)
2133
0
  case A128GCM:
2134
0
    return 16;
2135
0
#endif
2136
0
  default:
2137
0
    break;
2138
0
  };
2139
2140
0
  return 32;
2141
0
}
2142
2143
size_t calculate_auth_key_length(ENC_ALG a);
2144
0
size_t calculate_auth_key_length(ENC_ALG a) {
2145
0
  switch (a) {
2146
0
#if !defined(TURN_NO_GCM)
2147
0
  case A256GCM:
2148
0
  case A128GCM:
2149
0
    return 0;
2150
0
#endif
2151
0
  default:
2152
0
    break;
2153
0
  };
2154
2155
0
  return 0;
2156
0
}
2157
2158
static bool calculate_key(char *key, size_t key_size, char *new_key, size_t new_key_size);
2159
0
static bool calculate_key(char *key, size_t key_size, char *new_key, size_t new_key_size) {
2160
0
  UNUSED_ARG(key_size);
2161
2162
0
  memcpy(new_key, key, new_key_size);
2163
2164
0
  return true;
2165
0
}
2166
2167
0
bool convert_oauth_key_data(const oauth_key_data *oakd0, oauth_key *key, char *err_msg, size_t err_msg_size) {
2168
0
#if !defined(TURN_NO_OAUTH)
2169
0
  if (oakd0 && key) {
2170
2171
0
    oauth_key_data oakd_obj;
2172
0
    memcpy(&oakd_obj, oakd0, sizeof(oauth_key_data));
2173
0
    oauth_key_data *oakd = &oakd_obj;
2174
2175
0
    if (!(oakd->ikm_key_size)) {
2176
0
      if (err_msg) {
2177
0
        snprintf(err_msg, err_msg_size, "key is not defined");
2178
0
      }
2179
0
    }
2180
2181
0
    remove_spaces(oakd->kid);
2182
2183
0
    remove_spaces(oakd->as_rs_alg);
2184
2185
0
    normalize_algorithm(oakd->as_rs_alg);
2186
2187
0
    if (!(oakd->kid[0])) {
2188
0
      if (err_msg) {
2189
0
        snprintf(err_msg, err_msg_size, "KID is not defined");
2190
0
      }
2191
0
      OAUTH_ERROR("KID is not defined\n");
2192
0
      return false;
2193
0
    }
2194
2195
0
    memset(key, 0, sizeof(oauth_key));
2196
2197
0
    STRCPY(key->kid, oakd->kid);
2198
2199
0
    memcpy(key->ikm_key, oakd->ikm_key, sizeof(key->ikm_key));
2200
0
    key->ikm_key_size = oakd->ikm_key_size;
2201
2202
0
    key->timestamp = oakd->timestamp;
2203
0
    key->lifetime = oakd->lifetime;
2204
2205
0
    if (!(key->timestamp)) {
2206
0
      key->timestamp = OAUTH_DEFAULT_TIMESTAMP;
2207
0
    }
2208
0
    if (!(key->lifetime)) {
2209
0
      key->lifetime = OAUTH_DEFAULT_LIFETIME;
2210
0
    }
2211
2212
0
    key->as_rs_alg = ENC_ALG_ERROR;
2213
0
#if !defined(TURN_NO_GCM)
2214
0
    key->as_rs_alg = ENC_ALG_DEFAULT;
2215
0
    if (!strcmp(oakd->as_rs_alg, "A128GCM")) {
2216
0
      key->as_rs_alg = A128GCM;
2217
0
      key->auth_key_size = 0;
2218
0
      key->auth_key[0] = 0;
2219
0
    } else if (!strcmp(oakd->as_rs_alg, "A256GCM")) {
2220
0
      key->as_rs_alg = A256GCM;
2221
0
      key->auth_key_size = 0;
2222
0
      key->auth_key[0] = 0;
2223
0
    } else
2224
0
#endif
2225
0
    {
2226
0
      if (err_msg) {
2227
0
        snprintf(err_msg, err_msg_size, "Wrong oAuth token encryption algorithm: %s (2)\n", oakd->as_rs_alg);
2228
0
      }
2229
0
      OAUTH_ERROR("Wrong oAuth token encryption algorithm: %s (3)\n", oakd->as_rs_alg);
2230
0
      return false;
2231
0
    }
2232
2233
0
#if !defined(TURN_NO_GCM)
2234
2235
0
    key->auth_key_size = calculate_auth_key_length(key->as_rs_alg);
2236
0
    if (key->auth_key_size) {
2237
0
      if (!calculate_key(key->ikm_key, key->ikm_key_size, key->auth_key, key->auth_key_size)) {
2238
0
        return false;
2239
0
      }
2240
0
    }
2241
2242
0
    key->as_rs_key_size = calculate_enc_key_length(key->as_rs_alg);
2243
0
    if (!calculate_key(key->ikm_key, key->ikm_key_size, key->as_rs_key, key->as_rs_key_size)) {
2244
0
      return false;
2245
0
    }
2246
0
#endif
2247
0
  }
2248
2249
0
  return true;
2250
#else
2251
  OAUTH_ERROR("Oauth support not included");
2252
  return false;
2253
#endif
2254
0
}
2255
2256
#if !defined(TURN_NO_OAUTH)
2257
2258
const EVP_CIPHER *get_cipher_type(ENC_ALG enc_alg);
2259
0
const EVP_CIPHER *get_cipher_type(ENC_ALG enc_alg) {
2260
0
  switch (enc_alg) {
2261
0
#if !defined(TURN_NO_GCM)
2262
0
  case A128GCM:
2263
0
    return EVP_aes_128_gcm();
2264
0
  case A256GCM:
2265
0
    return EVP_aes_256_gcm();
2266
0
#endif
2267
0
  default:
2268
0
    break;
2269
0
  }
2270
0
  OAUTH_ERROR("%s: Unsupported enc algorithm: %d\n", __FUNCTION__, (int)enc_alg);
2271
0
  return NULL;
2272
0
}
2273
2274
int my_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
2275
0
int my_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) {
2276
0
  int cycle = 0;
2277
0
  int out_len = 0;
2278
0
  while ((out_len < inl) && (++cycle < 128)) {
2279
0
    int tmp_outl = 0;
2280
0
    unsigned char *ptr = NULL;
2281
0
    if (out) {
2282
0
      ptr = out + out_len;
2283
0
    }
2284
0
    const int ret = EVP_EncryptUpdate(ctx, ptr, &tmp_outl, in + out_len, inl - out_len);
2285
0
    out_len += tmp_outl;
2286
0
    if (ret < 1) {
2287
0
      return ret;
2288
0
    }
2289
0
  }
2290
0
  *outl = out_len;
2291
0
  return 1;
2292
0
}
2293
2294
int my_EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
2295
0
int my_EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) {
2296
0
  int cycle = 0;
2297
0
  int out_len = 0;
2298
0
  while ((out_len < inl) && (++cycle < 128)) {
2299
0
    int tmp_outl = 0;
2300
0
    unsigned char *ptr = NULL;
2301
0
    if (out) {
2302
0
      ptr = out + out_len;
2303
0
    }
2304
0
    const int ret = EVP_DecryptUpdate(ctx, ptr, &tmp_outl, in + out_len, inl - out_len);
2305
0
    out_len += tmp_outl;
2306
0
    if (ret < 1) {
2307
0
      return ret;
2308
0
    }
2309
0
  }
2310
0
  *outl = out_len;
2311
0
  return 1;
2312
0
}
2313
#if !defined(TURN_NO_GCM)
2314
2315
static bool encode_oauth_token_gcm(const uint8_t *server_name, encoded_oauth_token *etoken, const oauth_key *key,
2316
0
                                   const oauth_token *dtoken, const uint8_t *nonce0) {
2317
0
  if (server_name && etoken && key && dtoken && (dtoken->enc_block.key_length <= MAXSHASIZE)) {
2318
2319
0
    unsigned char orig_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
2320
0
    memset(orig_field, 0, sizeof(orig_field));
2321
2322
0
    unsigned char nonce[OAUTH_GCM_NONCE_SIZE];
2323
0
    if (nonce0) {
2324
0
      memcpy(nonce, nonce0, sizeof(nonce));
2325
0
    } else {
2326
0
      generate_random_nonce(nonce, sizeof(nonce));
2327
0
    }
2328
2329
0
    size_t len = 0;
2330
2331
0
    *((uint16_t *)(orig_field + len)) = nswap16(OAUTH_GCM_NONCE_SIZE);
2332
0
    len += 2;
2333
2334
0
    memcpy(orig_field + len, nonce, OAUTH_GCM_NONCE_SIZE);
2335
0
    len += OAUTH_GCM_NONCE_SIZE;
2336
2337
0
    *((uint16_t *)(orig_field + len)) = nswap16(dtoken->enc_block.key_length);
2338
0
    len += 2;
2339
2340
0
    memcpy(orig_field + len, dtoken->enc_block.mac_key, dtoken->enc_block.key_length);
2341
0
    len += dtoken->enc_block.key_length;
2342
2343
0
    uint64_t ts = nswap64(dtoken->enc_block.timestamp);
2344
0
    memcpy((orig_field + len), &ts, sizeof(ts));
2345
0
    len += sizeof(ts);
2346
2347
0
    *((uint32_t *)(orig_field + len)) = nswap32(dtoken->enc_block.lifetime);
2348
0
    len += 4;
2349
2350
0
    const EVP_CIPHER *cipher = get_cipher_type(key->as_rs_alg);
2351
0
    if (!cipher) {
2352
0
      return false;
2353
0
    }
2354
2355
0
    EVP_CIPHER_CTX *ctxp = EVP_CIPHER_CTX_new();
2356
0
    EVP_CIPHER_CTX_init(ctxp);
2357
2358
    /* Initialize the encryption operation. */
2359
0
    if (1 != EVP_EncryptInit_ex(ctxp, cipher, NULL, NULL, NULL)) {
2360
0
      return -1;
2361
0
    }
2362
2363
0
    EVP_CIPHER_CTX_set_padding(ctxp, 1);
2364
2365
    /* Set IV length if default 12 bytes (96 bits) is not appropriate */
2366
0
    if (1 != EVP_CIPHER_CTX_ctrl(ctxp, EVP_CTRL_GCM_SET_IVLEN, OAUTH_GCM_NONCE_SIZE, NULL)) {
2367
0
      return false;
2368
0
    }
2369
2370
    /* Initialize key and IV */
2371
0
    if (1 != EVP_EncryptInit_ex(ctxp, NULL, NULL, (const unsigned char *)key->as_rs_key, nonce)) {
2372
0
      return false;
2373
0
    }
2374
2375
0
    int outl = 0;
2376
0
    const size_t sn_len = strlen((const char *)server_name);
2377
2378
    /* Provide any AAD data. This can be called zero or more times as
2379
     * required
2380
     */
2381
0
    if (1 != my_EVP_EncryptUpdate(ctxp, NULL, &outl, server_name, (int)sn_len)) {
2382
0
      return false;
2383
0
    }
2384
2385
0
    outl = 0;
2386
0
    unsigned char *encoded_field = (unsigned char *)etoken->token;
2387
0
    memcpy(encoded_field, orig_field, OAUTH_GCM_NONCE_SIZE + 2);
2388
0
    encoded_field += OAUTH_GCM_NONCE_SIZE + 2;
2389
0
    unsigned char *start_field = orig_field + OAUTH_GCM_NONCE_SIZE + 2;
2390
0
    len -= OAUTH_GCM_NONCE_SIZE + 2;
2391
2392
0
    if (1 != my_EVP_EncryptUpdate(ctxp, encoded_field, &outl, start_field, (int)len)) {
2393
0
      return -1;
2394
0
    }
2395
2396
0
    int tmp_outl = 0;
2397
0
    EVP_EncryptFinal_ex(ctxp, encoded_field + outl, &tmp_outl);
2398
0
    outl += tmp_outl;
2399
2400
0
    EVP_CIPHER_CTX_ctrl(ctxp, EVP_CTRL_GCM_GET_TAG, OAUTH_GCM_TAG_SIZE, encoded_field + outl);
2401
0
    outl += OAUTH_GCM_TAG_SIZE;
2402
2403
0
    etoken->size = 2 + OAUTH_GCM_NONCE_SIZE + outl;
2404
2405
0
    EVP_CIPHER_CTX_free(ctxp);
2406
2407
0
    return true;
2408
0
  }
2409
0
  return false;
2410
0
}
2411
2412
static bool decode_oauth_token_gcm(const uint8_t *server_name, const encoded_oauth_token *etoken, const oauth_key *key,
2413
0
                                   oauth_token *dtoken) {
2414
0
  if (server_name && etoken && key && dtoken) {
2415
2416
0
    unsigned char snl[2];
2417
0
    memcpy(snl, (const unsigned char *)(etoken->token), 2);
2418
0
    const unsigned char *csnl = snl;
2419
2420
0
    const uint16_t nonce_len = nswap16(*((const uint16_t *)csnl));
2421
2422
0
    if (nonce_len > OAUTH_MAX_NONCE_SIZE) {
2423
0
      OAUTH_ERROR("%s: nonce length too large: %u > %u\n", __FUNCTION__, (unsigned)nonce_len,
2424
0
                  (unsigned)OAUTH_MAX_NONCE_SIZE);
2425
0
      return false;
2426
0
    }
2427
2428
0
    dtoken->enc_block.nonce_length = nonce_len;
2429
2430
0
    const size_t min_encoded_field_size = 2 + 4 + 8 + nonce_len + 2 + OAUTH_GCM_TAG_SIZE + 1;
2431
0
    if (etoken->size < min_encoded_field_size) {
2432
0
      OAUTH_ERROR("%s: token size too small: %d\n", __FUNCTION__, (int)etoken->size);
2433
0
      return false;
2434
0
    }
2435
2436
0
    const unsigned char *encoded_field = (const unsigned char *)(etoken->token + nonce_len + 2);
2437
0
    const unsigned int encoded_field_size = (unsigned int)etoken->size - nonce_len - 2 - OAUTH_GCM_TAG_SIZE;
2438
0
    const unsigned char *nonce = ((const unsigned char *)etoken->token + 2);
2439
0
    memcpy(dtoken->enc_block.nonce, nonce, nonce_len);
2440
2441
0
    unsigned char tag[OAUTH_GCM_TAG_SIZE];
2442
0
    memcpy(tag, ((const unsigned char *)etoken->token) + nonce_len + 2 + encoded_field_size, sizeof(tag));
2443
2444
0
    unsigned char decoded_field[MAX_ENCODED_OAUTH_TOKEN_SIZE];
2445
2446
0
    const EVP_CIPHER *cipher = get_cipher_type(key->as_rs_alg);
2447
0
    if (!cipher) {
2448
0
      OAUTH_ERROR("%s: Cannot find cipher for algorithm: %d\n", __FUNCTION__, (int)key->as_rs_alg);
2449
0
      return false;
2450
0
    }
2451
2452
0
    EVP_CIPHER_CTX *ctxp = EVP_CIPHER_CTX_new();
2453
0
    EVP_CIPHER_CTX_init(ctxp);
2454
    /* Initialize the decryption operation. */
2455
0
    if (1 != EVP_DecryptInit_ex(ctxp, cipher, NULL, NULL, NULL)) {
2456
0
      OAUTH_ERROR("%s: Cannot initialize decryption\n", __FUNCTION__);
2457
0
      return false;
2458
0
    }
2459
2460
    // EVP_CIPHER_CTX_set_padding(&ctx,1);
2461
2462
    /* Set IV length if default 12 bytes (96 bits) is not appropriate */
2463
0
    if (1 != EVP_CIPHER_CTX_ctrl(ctxp, EVP_CTRL_GCM_SET_IVLEN, nonce_len, NULL)) {
2464
0
      OAUTH_ERROR("%s: Cannot set nonce length\n", __FUNCTION__);
2465
0
      return false;
2466
0
    }
2467
2468
    /* Initialize key and IV */
2469
0
    if (1 != EVP_DecryptInit_ex(ctxp, NULL, NULL, (const unsigned char *)key->as_rs_key, nonce)) {
2470
0
      OAUTH_ERROR("%s: Cannot set nonce\n", __FUNCTION__);
2471
0
      return false;
2472
0
    }
2473
2474
    /* Set expected tag value. A restriction in OpenSSL 1.0.1c and earlier
2475
      +         * required the tag before any AAD or ciphertext */
2476
0
    EVP_CIPHER_CTX_ctrl(ctxp, EVP_CTRL_GCM_SET_TAG, OAUTH_GCM_TAG_SIZE, tag);
2477
2478
0
    int outl = 0;
2479
0
    const size_t sn_len = strlen((const char *)server_name);
2480
2481
    /* Provide any AAD data. This can be called zero or more times as
2482
     * required
2483
     */
2484
0
    if (1 != my_EVP_DecryptUpdate(ctxp, NULL, &outl, server_name, (int)sn_len)) {
2485
0
      OAUTH_ERROR("%s: Cannot decrypt update server_name: %s, len=%d\n", __FUNCTION__, server_name, (int)sn_len);
2486
0
      return false;
2487
0
    }
2488
0
    if (1 != my_EVP_DecryptUpdate(ctxp, decoded_field, &outl, encoded_field, (int)encoded_field_size)) {
2489
0
      OAUTH_ERROR("%s: Cannot decrypt update\n", __FUNCTION__);
2490
0
      return false;
2491
0
    }
2492
2493
0
    int tmp_outl = 0;
2494
0
    if (EVP_DecryptFinal_ex(ctxp, decoded_field + outl, &tmp_outl) < 1) {
2495
0
      EVP_CIPHER_CTX_free(ctxp);
2496
0
      OAUTH_ERROR("%s: token integrity check failed\n", __FUNCTION__);
2497
0
      return false;
2498
0
    }
2499
0
    outl += tmp_outl;
2500
2501
0
    EVP_CIPHER_CTX_free(ctxp);
2502
2503
0
    size_t len = 0;
2504
2505
0
    if ((size_t)outl < sizeof(uint16_t)) {
2506
0
      OAUTH_ERROR("%s: decoded token too small: %d\n", __FUNCTION__, (int)outl);
2507
0
      return false;
2508
0
    }
2509
0
    dtoken->enc_block.key_length = nswap16(*((uint16_t *)(decoded_field + len)));
2510
0
    len += sizeof(uint16_t);
2511
2512
0
    if (dtoken->enc_block.key_length > sizeof(dtoken->enc_block.mac_key)) {
2513
0
      OAUTH_ERROR("%s: mac key length too large: %u > %u\n", __FUNCTION__, (unsigned)dtoken->enc_block.key_length,
2514
0
                  (unsigned)sizeof(dtoken->enc_block.mac_key));
2515
0
      return false;
2516
0
    }
2517
2518
0
    if ((size_t)outl < len + dtoken->enc_block.key_length + sizeof(uint64_t) + sizeof(uint32_t)) {
2519
0
      OAUTH_ERROR("%s: decoded token truncated: %d\n", __FUNCTION__, (int)outl);
2520
0
      return false;
2521
0
    }
2522
2523
0
    memcpy(dtoken->enc_block.mac_key, decoded_field + len, dtoken->enc_block.key_length);
2524
0
    len += dtoken->enc_block.key_length;
2525
2526
0
    uint64_t ts;
2527
0
    memcpy(&ts, (decoded_field + len), sizeof(ts));
2528
0
    dtoken->enc_block.timestamp = nswap64(ts);
2529
0
    len += sizeof(ts);
2530
2531
0
    uint32_t lt;
2532
0
    memcpy(&lt, (decoded_field + len), sizeof(lt));
2533
0
    dtoken->enc_block.lifetime = nswap32(lt);
2534
0
    len += sizeof(lt);
2535
2536
0
    return true;
2537
0
  }
2538
0
  return false;
2539
0
}
2540
2541
#endif
2542
2543
#endif
2544
2545
bool encode_oauth_token(const uint8_t *server_name, encoded_oauth_token *etoken, const oauth_key *key,
2546
0
                        const oauth_token *dtoken, const uint8_t *nonce) {
2547
0
#if !defined(TURN_NO_OAUTH)
2548
0
  UNUSED_ARG(nonce);
2549
0
  if (server_name && etoken && key && dtoken) {
2550
0
    switch (key->as_rs_alg) {
2551
0
#if !defined(TURN_NO_GCM)
2552
0
    case A256GCM:
2553
0
    case A128GCM:
2554
0
      return encode_oauth_token_gcm(server_name, etoken, key, dtoken, nonce);
2555
0
#endif
2556
0
    default:
2557
0
      fprintf(stderr, "Unsupported AS_RS algorithm: %d\n", (int)key->as_rs_alg);
2558
0
      break;
2559
0
    };
2560
0
  }
2561
0
  return false;
2562
#else
2563
  OAUTH_ERROR("Oauth support not included");
2564
  return false;
2565
#endif
2566
0
}
2567
2568
bool decode_oauth_token(const uint8_t *server_name, const encoded_oauth_token *etoken, const oauth_key *key,
2569
0
                        oauth_token *dtoken) {
2570
0
#if !defined(TURN_NO_OAUTH)
2571
0
  if (server_name && etoken && key && dtoken) {
2572
0
    switch (key->as_rs_alg) {
2573
0
#if !defined(TURN_NO_GCM)
2574
0
    case A256GCM:
2575
0
    case A128GCM:
2576
0
      return decode_oauth_token_gcm(server_name, etoken, key, dtoken);
2577
0
#endif
2578
0
    default:
2579
0
      fprintf(stderr, "Unsupported AS_RS algorithm: %d\n", (int)key->as_rs_alg);
2580
0
      break;
2581
0
    };
2582
0
  }
2583
0
  return false;
2584
#else
2585
  OAUTH_ERROR("Oauth support not included");
2586
  return false;
2587
#endif
2588
0
}
2589
2590
///////////////////////////////////////////////////////////////