Coverage Report

Created: 2024-06-20 06:28

/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
  { .name = "SHAKE-256",
191
    .oid = HASH_OID_SHAKE_256,
192
    .id = GNUTLS_MAC_SHAKE_256,
193
    .block_size = 136 },
194
  { .name = "OMAC-MAGMA",
195
    .id = GNUTLS_MAC_MAGMA_OMAC,
196
    .output_size = 8,
197
    .key_size = 32,
198
    .block_size = 8 },
199
  { .name = "OMAC-KUZNYECHIK",
200
    .id = GNUTLS_MAC_KUZNYECHIK_OMAC,
201
    .output_size = 16,
202
    .key_size = 32,
203
    .block_size = 16 },
204
  { .name = "MAC-NULL", .id = GNUTLS_MAC_NULL },
205
  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
206
};
207
208
#define GNUTLS_HASH_LOOP(b)                               \
209
0
  const mac_entry_st *p;                            \
210
0
  for (p = hash_algorithms; p->name != NULL; p++) { \
211
0
    b;                                        \
212
0
  }
213
214
#define GNUTLS_HASH_ALG_LOOP(a)                    \
215
0
  GNUTLS_HASH_LOOP(if (p->id == algorithm) { \
216
0
    a;                                 \
217
0
    break;                             \
218
0
  })
219
220
const mac_entry_st *_gnutls_mac_to_entry(gnutls_mac_algorithm_t c)
221
0
{
222
0
  GNUTLS_HASH_LOOP(if (c == p->id) return p);
223
224
0
  return NULL;
225
0
}
226
227
/**
228
 * gnutls_mac_get_name:
229
 * @algorithm: is a MAC algorithm
230
 *
231
 * Convert a #gnutls_mac_algorithm_t value to a string.
232
 *
233
 * Returns: a string that contains the name of the specified MAC
234
 *   algorithm, or %NULL.
235
 **/
236
const char *gnutls_mac_get_name(gnutls_mac_algorithm_t algorithm)
237
0
{
238
0
  const char *ret = NULL;
239
240
  /* avoid prefix */
241
0
  GNUTLS_HASH_ALG_LOOP(ret = p->name);
242
243
0
  return ret;
244
0
}
245
246
/**
247
 * gnutls_digest_get_name:
248
 * @algorithm: is a digest algorithm
249
 *
250
 * Convert a #gnutls_digest_algorithm_t value to a string.
251
 *
252
 * Returns: a string that contains the name of the specified digest
253
 *   algorithm, or %NULL.
254
 **/
255
const char *gnutls_digest_get_name(gnutls_digest_algorithm_t algorithm)
256
0
{
257
0
  const char *ret = NULL;
258
259
0
  GNUTLS_HASH_LOOP(if (algorithm == (unsigned)p->id && p->oid != NULL) {
260
0
    ret = p->name;
261
0
    break;
262
0
  });
263
264
0
  return ret;
265
0
}
266
267
/**
268
 * gnutls_digest_get_id:
269
 * @name: is a digest algorithm name
270
 *
271
 * Convert a string to a #gnutls_digest_algorithm_t value.  The names are
272
 * compared in a case insensitive way.
273
 *
274
 * Returns: a #gnutls_digest_algorithm_t id of the specified MAC
275
 *   algorithm string, or %GNUTLS_DIG_UNKNOWN on failure.
276
 **/
277
gnutls_digest_algorithm_t gnutls_digest_get_id(const char *name)
278
0
{
279
0
  gnutls_digest_algorithm_t ret = GNUTLS_DIG_UNKNOWN;
280
281
0
  GNUTLS_HASH_LOOP(if (p->oid != NULL &&
282
0
           c_strcasecmp(p->name, name) == 0) {
283
0
    if (_gnutls_digest_exists((gnutls_digest_algorithm_t)p->id))
284
0
      ret = (gnutls_digest_algorithm_t)p->id;
285
0
    break;
286
0
  });
287
288
0
  return ret;
289
0
}
290
291
/* This is only called by cfg_apply in priority.c, in blocklisting mode. */
292
int _gnutls_digest_mark_insecure(gnutls_digest_algorithm_t dig)
293
0
{
294
0
#ifndef DISABLE_SYSTEM_CONFIG
295
0
  mac_entry_st *p;
296
297
0
  for (p = hash_algorithms; p->name != NULL; p++) {
298
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
299
0
      p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
300
0
      return 0;
301
0
    }
302
0
  }
303
304
0
#endif
305
0
  return GNUTLS_E_INVALID_REQUEST;
306
0
}
307
308
/* This is only called by cfg_apply in priority.c, in allowlisting mode. */
309
void _gnutls_digest_mark_insecure_all(void)
310
0
{
311
0
#ifndef DISABLE_SYSTEM_CONFIG
312
0
  mac_entry_st *p;
313
314
0
  for (p = hash_algorithms; p->name != NULL; p++) {
315
0
    p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE |
316
0
          GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
317
0
  }
318
319
0
#endif
320
0
}
321
322
int _gnutls_digest_set_secure(gnutls_digest_algorithm_t dig,
323
            unsigned int secure)
324
0
{
325
0
#ifndef DISABLE_SYSTEM_CONFIG
326
0
  mac_entry_st *p;
327
328
0
  for (p = hash_algorithms; p->name != NULL; p++) {
329
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
330
0
      if (!(p->flags &
331
0
            GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE)) {
332
0
        return gnutls_assert_val(
333
0
          GNUTLS_E_INVALID_REQUEST);
334
0
      }
335
0
      if (secure) {
336
0
        p->flags &= ~GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
337
0
      } else {
338
0
        p->flags |= GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
339
0
      }
340
0
      return 0;
341
0
    }
342
0
  }
343
344
0
#endif
345
0
  return GNUTLS_E_INVALID_REQUEST;
346
0
}
347
348
unsigned _gnutls_digest_is_insecure(gnutls_digest_algorithm_t dig)
349
0
{
350
0
  const mac_entry_st *p;
351
352
0
  for (p = hash_algorithms; p->name != NULL; p++) {
353
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
354
0
      return p->flags & GNUTLS_MAC_FLAG_PREIMAGE_INSECURE;
355
0
    }
356
0
  }
357
358
0
  return 1;
359
0
}
360
361
bool _gnutls_digest_is_insecure2(gnutls_digest_algorithm_t dig, unsigned flags)
362
0
{
363
0
  const mac_entry_st *p;
364
365
0
  for (p = hash_algorithms; p->name != NULL; p++) {
366
0
    if (p->oid != NULL && p->id == (gnutls_mac_algorithm_t)dig) {
367
0
      return (p->flags & GNUTLS_MAC_FLAG_PREIMAGE_INSECURE &&
368
0
        !(flags & GNUTLS_MAC_FLAG_ALLOW_INSECURE_REVERTIBLE &&
369
0
          p->flags &
370
0
            GNUTLS_MAC_FLAG_PREIMAGE_INSECURE_REVERTIBLE));
371
0
    }
372
0
  }
373
374
0
  return true;
375
0
}
376
377
/**
378
 * gnutls_mac_get_id:
379
 * @name: is a MAC algorithm name
380
 *
381
 * Convert a string to a #gnutls_mac_algorithm_t value.  The names are
382
 * compared in a case insensitive way.
383
 *
384
 * Returns: a #gnutls_mac_algorithm_t id of the specified MAC
385
 *   algorithm string, or %GNUTLS_MAC_UNKNOWN on failure.
386
 **/
387
gnutls_mac_algorithm_t gnutls_mac_get_id(const char *name)
388
0
{
389
0
  gnutls_mac_algorithm_t ret = GNUTLS_MAC_UNKNOWN;
390
391
0
  GNUTLS_HASH_LOOP(if (c_strcasecmp(p->name, name) == 0) {
392
0
    if (p->placeholder != 0 || _gnutls_mac_exists(p->id))
393
0
      ret = p->id;
394
0
    break;
395
0
  });
396
397
0
  return ret;
398
0
}
399
400
/**
401
 * gnutls_mac_get_key_size:
402
 * @algorithm: is an encryption algorithm
403
 *
404
 * Returns the size of the MAC key used in TLS.
405
 *
406
 * Returns: length (in bytes) of the given MAC key size, or 0 if the
407
 *   given MAC algorithm is invalid.
408
 **/
409
size_t gnutls_mac_get_key_size(gnutls_mac_algorithm_t algorithm)
410
0
{
411
0
  size_t ret = 0;
412
413
  /* avoid prefix */
414
0
  GNUTLS_HASH_ALG_LOOP(ret = p->key_size);
415
416
0
  return ret;
417
0
}
418
419
/**
420
 * gnutls_mac_get_nonce_size:
421
 * @algorithm: is an encryption algorithm
422
 *
423
 * Returns the size of the nonce used by the MAC in TLS.
424
 *
425
 * Returns: length (in bytes) of the given MAC nonce size, or 0.
426
 *
427
 * Since: 3.2.0
428
 **/
429
size_t gnutls_mac_get_nonce_size(gnutls_mac_algorithm_t algorithm)
430
0
{
431
0
  size_t ret = 0;
432
433
  /* avoid prefix */
434
0
  GNUTLS_HASH_ALG_LOOP(ret = p->nonce_size);
435
436
0
  return ret;
437
0
}
438
439
/**
440
 * gnutls_mac_list:
441
 *
442
 * Get a list of hash algorithms for use as MACs.  Note that not
443
 * necessarily all MACs are supported in TLS cipher suites.
444
 * This function is not thread safe.
445
 *
446
 * Returns: Return a (0)-terminated list of #gnutls_mac_algorithm_t
447
 *   integers indicating the available MACs.
448
 **/
449
const gnutls_mac_algorithm_t *gnutls_mac_list(void)
450
0
{
451
0
  static gnutls_mac_algorithm_t supported_macs[MAX_ALGOS] = { 0 };
452
453
0
  if (supported_macs[0] == 0) {
454
0
    int i = 0;
455
456
0
    GNUTLS_HASH_LOOP(
457
0
      if (p->placeholder != 0 || _gnutls_mac_exists(p->id))
458
0
        supported_macs[i++] = p->id;);
459
0
    supported_macs[i++] = 0;
460
0
  }
461
462
0
  return supported_macs;
463
0
}
464
465
/**
466
 * gnutls_digest_list:
467
 *
468
 * Get a list of hash (digest) algorithms supported by GnuTLS.
469
 *
470
 * This function is not thread safe.
471
 *
472
 * Returns: Return a (0)-terminated list of #gnutls_digest_algorithm_t
473
 *   integers indicating the available digests.
474
 **/
475
const gnutls_digest_algorithm_t *gnutls_digest_list(void)
476
0
{
477
0
  static gnutls_digest_algorithm_t supported_digests[MAX_ALGOS] = { 0 };
478
479
0
  if (supported_digests[0] == 0) {
480
0
    int i = 0;
481
482
0
    GNUTLS_HASH_LOOP(
483
0
      if (p->oid != NULL && (p->placeholder != 0 ||
484
0
                 _gnutls_mac_exists(p->id))) {
485
0
        supported_digests[i++] =
486
0
          (gnutls_digest_algorithm_t)p->id;
487
0
      });
488
0
    supported_digests[i++] = 0;
489
0
  }
490
491
0
  return supported_digests;
492
0
}
493
494
/**
495
 * gnutls_oid_to_digest:
496
 * @oid: is an object identifier
497
 *
498
 * Converts a textual object identifier to a #gnutls_digest_algorithm_t value.
499
 *
500
 * Returns: a #gnutls_digest_algorithm_t id of the specified digest
501
 *   algorithm, or %GNUTLS_DIG_UNKNOWN on failure.
502
 *
503
 * Since: 3.4.3
504
 **/
505
gnutls_digest_algorithm_t gnutls_oid_to_digest(const char *oid)
506
0
{
507
0
  GNUTLS_HASH_LOOP(if (p->oid && strcmp(oid, p->oid) == 0) {
508
0
    if (_gnutls_digest_exists((gnutls_digest_algorithm_t)p->id)) {
509
0
      return (gnutls_digest_algorithm_t)p->id;
510
0
    }
511
0
    break;
512
0
  });
513
514
0
  return GNUTLS_DIG_UNKNOWN;
515
0
}
516
517
/**
518
 * gnutls_oid_to_mac:
519
 * @oid: is an object identifier
520
 *
521
 * Converts a textual object identifier typically from PKCS#5 values to a #gnutls_mac_algorithm_t value.
522
 *
523
 * Returns: a #gnutls_mac_algorithm_t id of the specified digest
524
 *   algorithm, or %GNUTLS_MAC_UNKNOWN on failure.
525
 *
526
 * Since: 3.5.4
527
 **/
528
gnutls_mac_algorithm_t gnutls_oid_to_mac(const char *oid)
529
0
{
530
0
  GNUTLS_HASH_LOOP(if (p->mac_oid && strcmp(oid, p->mac_oid) == 0) {
531
0
    if (_gnutls_mac_exists(p->id)) {
532
0
      return p->id;
533
0
    }
534
0
    break;
535
0
  });
536
537
0
  return GNUTLS_MAC_UNKNOWN;
538
0
}
539
540
/**
541
 * gnutls_digest_get_oid:
542
 * @algorithm: is a digest algorithm
543
 *
544
 * Convert a #gnutls_digest_algorithm_t value to its object identifier.
545
 *
546
 * Returns: a string that contains the object identifier of the specified digest
547
 *   algorithm, or %NULL.
548
 *
549
 * Since: 3.4.3
550
 **/
551
const char *gnutls_digest_get_oid(gnutls_digest_algorithm_t algorithm)
552
0
{
553
0
  GNUTLS_HASH_LOOP(if (algorithm == (unsigned)p->id && p->oid != NULL) {
554
0
    return p->oid;
555
0
  });
556
557
0
  return NULL;
558
0
}
559
560
gnutls_digest_algorithm_t _gnutls_hash_size_to_sha_hash(unsigned int size)
561
0
{
562
0
  if (size == 20)
563
0
    return GNUTLS_DIG_SHA1;
564
0
  else if (size == 28)
565
0
    return GNUTLS_DIG_SHA224;
566
0
  else if (size == 32)
567
0
    return GNUTLS_DIG_SHA256;
568
0
  else if (size == 48)
569
0
    return GNUTLS_DIG_SHA384;
570
0
  else if (size == 64)
571
0
    return GNUTLS_DIG_SHA512;
572
573
0
  return GNUTLS_DIG_UNKNOWN;
574
0
}