Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/algorithms/mac.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2017 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include "gnutls_int.h"
25
#include "algorithms.h"
26
#include "errors.h"
27
#include "x509/common.h"
28
#include "c-strcase.h"
29
30
#define MAC_OID_SHA1 "1.2.840.113549.2.7"
31
#define MAC_OID_SHA224 "1.2.840.113549.2.8"
32
#define MAC_OID_SHA256 "1.2.840.113549.2.9"
33
#define MAC_OID_SHA384 "1.2.840.113549.2.10"
34
#define MAC_OID_SHA512 "1.2.840.113549.2.11"
35
#define MAC_OID_GOST_R_3411_94 "1.2.643.2.2.10"
36
#define MAC_OID_STREEBOG_256 "1.2.643.7.1.1.4.1"
37
#define MAC_OID_STREEBOG_512 "1.2.643.7.1.1.4.2"
38
39
static SYSTEM_CONFIG_OR_CONST mac_entry_st hash_algorithms[] = {
40
  { .name = "SHA1",
41
    .oid = HASH_OID_SHA1,
42
    .mac_oid = MAC_OID_SHA1,
43
    .id = GNUTLS_MAC_SHA1,
44
    .output_size = 20,
45
    .key_size = 20,
46
    .block_size = 64 },
47
  { .name = "MD5+SHA1",
48
    .id = GNUTLS_MAC_MD5_SHA1,
49
    .output_size = 36,
50
    .key_size = 36,
51
    .flags = GNUTLS_MAC_FLAG_PREIMAGE_INSECURE,
52
    .block_size = 64 },
53
  { .name = "SHA256",
54
    .oid = HASH_OID_SHA256,
55
    .mac_oid = MAC_OID_SHA256,
56
    .id = GNUTLS_MAC_SHA256,
57
    .output_size = 32,
58
    .key_size = 32,
59
    .block_size = 64 },
60
  { .name = "SHA384",
61
    .oid = HASH_OID_SHA384,
62
    .mac_oid = MAC_OID_SHA384,
63
    .id = GNUTLS_MAC_SHA384,
64
    .output_size = 48,
65
    .key_size = 48,
66
    .block_size = 128 },
67
  { .name = "SHA512",
68
    .oid = HASH_OID_SHA512,
69
    .mac_oid = MAC_OID_SHA512,
70
    .id = GNUTLS_MAC_SHA512,
71
    .output_size = 64,
72
    .key_size = 64,
73
    .block_size = 128 },
74
  { .name = "SHA224",
75
    .oid = HASH_OID_SHA224,
76
    .mac_oid = MAC_OID_SHA224,
77
    .id = GNUTLS_MAC_SHA224,
78
    .output_size = 28,
79
    .key_size = 28,
80
    .block_size = 64 },
81
  { .name = "SHA3-256",
82
    .oid = HASH_OID_SHA3_256,
83
    .id = GNUTLS_MAC_SHA3_256,
84
    .output_size = 32,
85
    .key_size = 32,
86
    .block_size = 136 },
87
  { .name = "SHA3-384",
88
    .oid = HASH_OID_SHA3_384,
89
    .id = GNUTLS_MAC_SHA3_384,
90
    .output_size = 48,
91
    .key_size = 48,
92
    .block_size = 104 },
93
  { .name = "SHA3-512",
94
    .oid = HASH_OID_SHA3_512,
95
    .id = GNUTLS_MAC_SHA3_512,
96
    .output_size = 64,
97
    .key_size = 64,
98
    .block_size = 72 },
99
  { .name = "SHA3-224",
100
    .oid = HASH_OID_SHA3_224,
101
    .id = GNUTLS_MAC_SHA3_224,
102
    .output_size = 28,
103
    .key_size = 28,
104
    .block_size = 144 },
105
  { .name = "UMAC-96",
106
    .id = GNUTLS_MAC_UMAC_96,
107
    .output_size = 12,
108
    .key_size = 16,
109
    .nonce_size = 8 },
110
  { .name = "UMAC-128",
111
    .id = GNUTLS_MAC_UMAC_128,
112
    .output_size = 16,
113
    .key_size = 16,
114
    .nonce_size = 8 },
115
  { .name = "AEAD", .id = GNUTLS_MAC_AEAD, .placeholder = 1 },
116
  { .name = "MD5",
117
    .oid = HASH_OID_MD5,
118
    .id = GNUTLS_MAC_MD5,
119
    .output_size = 16,
120
    .key_size = 16,
121
    .flags = GNUTLS_MAC_FLAG_PREIMAGE_INSECURE,
122
    .block_size = 64 },
123
  { .name = "MD2",
124
    .oid = HASH_OID_MD2,
125
    .flags = GNUTLS_MAC_FLAG_PREIMAGE_INSECURE,
126
    .id = GNUTLS_MAC_MD2 },
127
  { .name = "RIPEMD160",
128
    .oid = HASH_OID_RMD160,
129
    .id = GNUTLS_MAC_RMD160,
130
    .output_size = 20,
131
    .key_size = 20,
132
    .block_size = 64 },
133
  { .name = "GOSTR341194",
134
    .oid = HASH_OID_GOST_R_3411_94,
135
    .mac_oid = MAC_OID_GOST_R_3411_94,
136
    .id = GNUTLS_MAC_GOSTR_94,
137
    .output_size = 32,
138
    .key_size = 32,
139
    .block_size = 32,
140
    .flags = GNUTLS_MAC_FLAG_PREIMAGE_INSECURE },
141
  { .name = "STREEBOG-256",
142
    .oid = HASH_OID_STREEBOG_256,
143
    .mac_oid = MAC_OID_STREEBOG_256,
144
    .id = GNUTLS_MAC_STREEBOG_256,
145
    .output_size = 32,
146
    .key_size = 32,
147
    .block_size = 64 },
148
  { .name = "STREEBOG-512",
149
    .oid = HASH_OID_STREEBOG_512,
150
    .mac_oid = MAC_OID_STREEBOG_512,
151
    .id = GNUTLS_MAC_STREEBOG_512,
152
    .output_size = 64,
153
    .key_size = 64,
154
    .block_size = 64 },
155
  {
156
    .name = "AES-CMAC-128",
157
    .id = GNUTLS_MAC_AES_CMAC_128,
158
    .output_size = 16,
159
    .key_size = 16,
160
  },
161
  { .name = "AES-CMAC-256",
162
    .id = GNUTLS_MAC_AES_CMAC_256,
163
    .output_size = 16,
164
    .key_size = 32 },
165
  { .name = "AES-GMAC-128",
166
    .id = GNUTLS_MAC_AES_GMAC_128,
167
    .output_size = 16,
168
    .key_size = 16,
169
    .nonce_size = 12 },
170
  { .name = "AES-GMAC-192",
171
    .id = GNUTLS_MAC_AES_GMAC_192,
172
    .output_size = 16,
173
    .key_size = 24,
174
    .nonce_size = 12 },
175
  { .name = "AES-GMAC-256",
176
    .id = GNUTLS_MAC_AES_GMAC_256,
177
    .output_size = 16,
178
    .key_size = 32,
179
    .nonce_size = 12 },
180
  { .name = "GOST28147-TC26Z-IMIT",
181
    .id = GNUTLS_MAC_GOST28147_TC26Z_IMIT,
182
    .output_size = 4,
183
    .key_size = 32,
184
    .block_size = 8,
185
    .flags = GNUTLS_MAC_FLAG_CONTINUOUS_MAC },
186
  { .name = "SHAKE-128",
187
    .oid = HASH_OID_SHAKE_128,
188
    .id = GNUTLS_MAC_SHAKE_128,
189
    .block_size = 168,
190
    .flags = GNUTLS_MAC_FLAG_XOF },
191
  { .name = "SHAKE-256",
192
    .oid = HASH_OID_SHAKE_256,
193
    .id = GNUTLS_MAC_SHAKE_256,
194
    .block_size = 136,
195
    .flags = GNUTLS_MAC_FLAG_XOF },
196
  { .name = "OMAC-MAGMA",
197
    .id = GNUTLS_MAC_MAGMA_OMAC,
198
    .output_size = 8,
199
    .key_size = 32,
200
    .block_size = 8 },
201
  { .name = "OMAC-KUZNYECHIK",
202
    .id = GNUTLS_MAC_KUZNYECHIK_OMAC,
203
    .output_size = 16,
204
    .key_size = 32,
205
    .block_size = 16 },
206
  { .name = "PBMAC1", .id = GNUTLS_MAC_PBMAC1, .placeholder = 1 },
207
  { .name = "MAC-NULL", .id = GNUTLS_MAC_NULL },
208
  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
209
};
210
211
#define GNUTLS_HASH_LOOP(b)                               \
212
0
  const mac_entry_st *p;                            \
213
0
  for (p = hash_algorithms; p->name != NULL; p++) { \
214
0
    b;                                        \
215
0
  }
216
217
#define GNUTLS_HASH_ALG_LOOP(a)                    \
218
0
  GNUTLS_HASH_LOOP(if (p->id == algorithm) { \
219
0
    a;                                 \
220
0
    break;                             \
221
0
  })
222
223
const mac_entry_st *_gnutls_mac_to_entry(gnutls_mac_algorithm_t c)
224
0
{
225
0
  GNUTLS_HASH_LOOP(if (c == p->id) return p);
226
227
0
  return NULL;
228
0
}
229
230
/**
231
 * gnutls_mac_get_name:
232
 * @algorithm: is a MAC algorithm
233
 *
234
 * Convert a #gnutls_mac_algorithm_t value to a string.
235
 *
236
 * Returns: a string that contains the name of the specified MAC
237
 *   algorithm, or %NULL.
238
 **/
239
const char *gnutls_mac_get_name(gnutls_mac_algorithm_t algorithm)
240
0
{
241
0
  const char *ret = NULL;
242
243
  /* avoid prefix */
244
0
  GNUTLS_HASH_ALG_LOOP(ret = p->name);
245
246
0
  return ret;
247
0
}
248
249
/**
250
 * gnutls_digest_get_name:
251
 * @algorithm: is a digest algorithm
252
 *
253
 * Convert a #gnutls_digest_algorithm_t value to a string.
254
 *
255
 * Returns: a string that contains the name of the specified digest
256
 *   algorithm, or %NULL.
257
 **/
258
const char *gnutls_digest_get_name(gnutls_digest_algorithm_t algorithm)
259
0
{
260
0
  const char *ret = NULL;
261
262
0
  GNUTLS_HASH_LOOP(if (algorithm == (unsigned)p->id && p->oid != NULL) {
263
0
    ret = p->name;
264
0
    break;
265
0
  });
266
267
0
  return ret;
268
0
}
269
270
/**
271
 * gnutls_digest_get_id:
272
 * @name: is a digest algorithm name
273
 *
274
 * Convert a string to a #gnutls_digest_algorithm_t value.  The names are
275
 * compared in a case insensitive way.
276
 *
277
 * Returns: a #gnutls_digest_algorithm_t id of the specified MAC
278
 *   algorithm string, or %GNUTLS_DIG_UNKNOWN on failure.
279
 **/
280
gnutls_digest_algorithm_t gnutls_digest_get_id(const char *name)
281
0
{
282
0
  gnutls_digest_algorithm_t ret = GNUTLS_DIG_UNKNOWN;
283
284
0
  GNUTLS_HASH_LOOP(if (p->oid != NULL &&
285
0
           c_strcasecmp(p->name, name) == 0) {
286
0
    if (_gnutls_digest_exists((gnutls_digest_algorithm_t)p->id))
287
0
      ret = (gnutls_digest_algorithm_t)p->id;
288
0
    break;
289
0
  });
290
291
0
  return ret;
292
0
}
293
294
/* This is only called by cfg_apply in priority.c, in blocklisting mode. */
295
int _gnutls_digest_mark_insecure(gnutls_digest_algorithm_t dig)
296
0
{
297
0
#ifndef DISABLE_SYSTEM_CONFIG
298
0
  mac_entry_st *p;
299
300
0
  for (p = hash_algorithms; p->name != NULL; p++) {
301
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
302
0
      p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
303
0
      return 0;
304
0
    }
305
0
  }
306
307
0
#endif
308
0
  return GNUTLS_E_INVALID_REQUEST;
309
0
}
310
311
/* This is only called by cfg_apply in priority.c, in allowlisting mode. */
312
void _gnutls_digest_mark_insecure_all(void)
313
0
{
314
0
#ifndef DISABLE_SYSTEM_CONFIG
315
0
  mac_entry_st *p;
316
317
0
  for (p = hash_algorithms; p->name != NULL; p++) {
318
0
    p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE |
319
0
          GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
320
0
  }
321
322
0
#endif
323
0
}
324
325
int _gnutls_digest_set_secure(gnutls_digest_algorithm_t dig,
326
            unsigned int secure)
327
0
{
328
0
#ifndef DISABLE_SYSTEM_CONFIG
329
0
  mac_entry_st *p;
330
331
0
  for (p = hash_algorithms; p->name != NULL; p++) {
332
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
333
0
      if (!(p->flags &
334
0
            GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE)) {
335
0
        return gnutls_assert_val(
336
0
          GNUTLS_E_INVALID_REQUEST);
337
0
      }
338
0
      if (secure) {
339
0
        p->flags &= ~GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
340
0
      } else {
341
0
        p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
342
0
      }
343
0
      return 0;
344
0
    }
345
0
  }
346
347
0
#endif
348
0
  return GNUTLS_E_INVALID_REQUEST;
349
0
}
350
351
unsigned _gnutls_digest_is_insecure(gnutls_digest_algorithm_t dig)
352
0
{
353
0
  const mac_entry_st *p;
354
355
0
  for (p = hash_algorithms; p->name != NULL; p++) {
356
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
357
0
      return p->flags & GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
358
0
    }
359
0
  }
360
361
0
  return 1;
362
0
}
363
364
bool _gnutls_digest_is_insecure2(gnutls_digest_algorithm_t dig, unsigned flags)
365
0
{
366
0
  const mac_entry_st *p;
367
368
0
  for (p = hash_algorithms; p->name != NULL; p++) {
369
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
370
0
      return (p->flags & GNUTLS_MAC_FLAG_PREIMAGE_INSECURE &&
371
0
        !(flags & GNUTLS_MAC_FLAG_ALLOW_INSECURE_REVERTIBLE &&
372
0
          p->flags &
373
0
            GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE));
374
0
    }
375
0
  }
376
377
0
  return true;
378
0
}
379
380
/**
381
 * gnutls_mac_get_id:
382
 * @name: is a MAC algorithm name
383
 *
384
 * Convert a string to a #gnutls_mac_algorithm_t value.  The names are
385
 * compared in a case insensitive way.
386
 *
387
 * Returns: a #gnutls_mac_algorithm_t id of the specified MAC
388
 *   algorithm string, or %GNUTLS_MAC_UNKNOWN on failure.
389
 **/
390
gnutls_mac_algorithm_t gnutls_mac_get_id(const char *name)
391
0
{
392
0
  gnutls_mac_algorithm_t ret = GNUTLS_MAC_UNKNOWN;
393
394
0
  GNUTLS_HASH_LOOP(if (c_strcasecmp(p->name, name) == 0) {
395
0
    if (p->placeholder != 0 || _gnutls_mac_exists(p->id))
396
0
      ret = p->id;
397
0
    break;
398
0
  });
399
400
0
  return ret;
401
0
}
402
403
/**
404
 * gnutls_mac_get_key_size:
405
 * @algorithm: is an encryption algorithm
406
 *
407
 * Returns the size of the MAC key used in TLS.
408
 *
409
 * Returns: length (in bytes) of the given MAC key size, or 0 if the
410
 *   given MAC algorithm is invalid.
411
 **/
412
size_t gnutls_mac_get_key_size(gnutls_mac_algorithm_t algorithm)
413
0
{
414
0
  size_t ret = 0;
415
416
  /* avoid prefix */
417
0
  GNUTLS_HASH_ALG_LOOP(ret = p->key_size);
418
419
0
  return ret;
420
0
}
421
422
/**
423
 * gnutls_mac_get_nonce_size:
424
 * @algorithm: is an encryption algorithm
425
 *
426
 * Returns the size of the nonce used by the MAC in TLS.
427
 *
428
 * Returns: length (in bytes) of the given MAC nonce size, or 0.
429
 *
430
 * Since: 3.2.0
431
 **/
432
size_t gnutls_mac_get_nonce_size(gnutls_mac_algorithm_t algorithm)
433
0
{
434
0
  size_t ret = 0;
435
436
  /* avoid prefix */
437
0
  GNUTLS_HASH_ALG_LOOP(ret = p->nonce_size);
438
439
0
  return ret;
440
0
}
441
442
/**
443
 * gnutls_mac_list:
444
 *
445
 * Get a list of hash algorithms for use as MACs.  Note that not
446
 * necessarily all MACs are supported in TLS cipher suites.
447
 * This function is not thread safe.
448
 *
449
 * Returns: Return a (0)-terminated list of #gnutls_mac_algorithm_t
450
 *   integers indicating the available MACs.
451
 **/
452
const gnutls_mac_algorithm_t *gnutls_mac_list(void)
453
0
{
454
0
  static gnutls_mac_algorithm_t supported_macs[MAX_ALGOS] = { 0 };
455
456
0
  if (supported_macs[0] == 0) {
457
0
    int i = 0;
458
459
0
    GNUTLS_HASH_LOOP(
460
0
      if (p->placeholder != 0 || _gnutls_mac_exists(p->id))
461
0
        supported_macs[i++] = p->id;);
462
0
    supported_macs[i++] = 0;
463
0
  }
464
465
0
  return supported_macs;
466
0
}
467
468
/**
469
 * gnutls_digest_list:
470
 *
471
 * Get a list of hash (digest) algorithms supported by GnuTLS.
472
 *
473
 * This function is not thread safe.
474
 *
475
 * Returns: Return a (0)-terminated list of #gnutls_digest_algorithm_t
476
 *   integers indicating the available digests.
477
 **/
478
const gnutls_digest_algorithm_t *gnutls_digest_list(void)
479
0
{
480
0
  static gnutls_digest_algorithm_t supported_digests[MAX_ALGOS] = { 0 };
481
482
0
  if (supported_digests[0] == 0) {
483
0
    int i = 0;
484
485
0
    GNUTLS_HASH_LOOP(
486
0
      if (p->oid != NULL && (p->placeholder != 0 ||
487
0
                 _gnutls_mac_exists(p->id))) {
488
0
        supported_digests[i++] =
489
0
          (gnutls_digest_algorithm_t)p->id;
490
0
      });
491
0
    supported_digests[i++] = 0;
492
0
  }
493
494
0
  return supported_digests;
495
0
}
496
497
/**
498
 * gnutls_oid_to_digest:
499
 * @oid: is an object identifier
500
 *
501
 * Converts a textual object identifier to a #gnutls_digest_algorithm_t value.
502
 *
503
 * Returns: a #gnutls_digest_algorithm_t id of the specified digest
504
 *   algorithm, or %GNUTLS_DIG_UNKNOWN on failure.
505
 *
506
 * Since: 3.4.3
507
 **/
508
gnutls_digest_algorithm_t gnutls_oid_to_digest(const char *oid)
509
0
{
510
0
  GNUTLS_HASH_LOOP(if (p->oid && strcmp(oid, p->oid) == 0) {
511
0
    if (_gnutls_digest_exists((gnutls_digest_algorithm_t)p->id)) {
512
0
      return (gnutls_digest_algorithm_t)p->id;
513
0
    }
514
0
    break;
515
0
  });
516
517
0
  return GNUTLS_DIG_UNKNOWN;
518
0
}
519
520
/**
521
 * gnutls_oid_to_mac:
522
 * @oid: is an object identifier
523
 *
524
 * Converts a textual object identifier typically from PKCS#5 values to a #gnutls_mac_algorithm_t value.
525
 *
526
 * Returns: a #gnutls_mac_algorithm_t id of the specified digest
527
 *   algorithm, or %GNUTLS_MAC_UNKNOWN on failure.
528
 *
529
 * Since: 3.5.4
530
 **/
531
gnutls_mac_algorithm_t gnutls_oid_to_mac(const char *oid)
532
0
{
533
0
  GNUTLS_HASH_LOOP(if (p->mac_oid && strcmp(oid, p->mac_oid) == 0) {
534
0
    if (_gnutls_mac_exists(p->id)) {
535
0
      return p->id;
536
0
    }
537
0
    break;
538
0
  });
539
540
0
  return GNUTLS_MAC_UNKNOWN;
541
0
}
542
543
/**
544
 * gnutls_digest_get_oid:
545
 * @algorithm: is a digest algorithm
546
 *
547
 * Convert a #gnutls_digest_algorithm_t value to its object identifier.
548
 *
549
 * Returns: a string that contains the object identifier of the specified digest
550
 *   algorithm, or %NULL.
551
 *
552
 * Since: 3.4.3
553
 **/
554
const char *gnutls_digest_get_oid(gnutls_digest_algorithm_t algorithm)
555
0
{
556
0
  GNUTLS_HASH_LOOP(if (algorithm == (unsigned)p->id && p->oid != NULL) {
557
0
    return p->oid;
558
0
  });
559
560
0
  return NULL;
561
0
}
562
563
gnutls_digest_algorithm_t _gnutls_hash_size_to_sha_hash(unsigned int size)
564
0
{
565
0
  if (size == 20)
566
0
    return GNUTLS_DIG_SHA1;
567
0
  else if (size == 28)
568
0
    return GNUTLS_DIG_SHA224;
569
0
  else if (size == 32)
570
0
    return GNUTLS_DIG_SHA256;
571
0
  else if (size == 48)
572
0
    return GNUTLS_DIG_SHA384;
573
0
  else if (size == 64)
574
0
    return GNUTLS_DIG_SHA512;
575
576
0
  return GNUTLS_DIG_UNKNOWN;
577
0
}