Coverage Report

Created: 2026-05-16 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/nettle/int/tls1-prf.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2017 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
/* Functions for the TLS PRF handling.
24
 */
25
26
#if HAVE_CONFIG_H
27
#include "config.h"
28
#endif
29
30
#include "gnutls_int.h"
31
#include "fips.h"
32
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include <nettle/hmac.h>
37
#include <nettle/memxor.h>
38
#include "int/tls1-prf.h"
39
#include <nettle/sha1.h>
40
#include <nettle/md5.h>
41
#include <nettle/version.h>
42
43
/* The RFC2246 P_hash() function. The mac_ctx is expected to
44
 * be initialized and key set to be the secret key.
45
 */
46
static void P_hash(void *mac_ctx, nettle_hash_update_func *update,
47
       nettle_hash_digest_func *digest, size_t digest_size,
48
       size_t seed_size, const uint8_t *seed, size_t label_size,
49
       const char *label, size_t dst_length, uint8_t *dst)
50
19.0k
{
51
19.0k
  uint8_t Atmp[MAX_HASH_SIZE];
52
19.0k
  ssize_t left;
53
19.0k
  unsigned started = 0;
54
19.0k
  uint8_t tmp[MAX_HASH_SIZE];
55
56
  /* round up */
57
19.0k
  left = dst_length;
58
59
69.5k
  while (left > 0) {
60
50.5k
    if (started == 0) { /* A(0) */
61
19.0k
      update(mac_ctx, label_size,
62
19.0k
             (const uint8_t *)label); /* hash label */
63
19.0k
      update(mac_ctx, seed_size, seed);
64
19.0k
      started = 1;
65
31.4k
    } else {
66
31.4k
      update(mac_ctx, digest_size, Atmp);
67
31.4k
    }
68
#if NETTLE_VERSION_MAJOR >= 4
69
    digest(mac_ctx, Atmp); /* store A(i) */
70
#else
71
50.5k
    digest(mac_ctx, digest_size, Atmp); /* store A(i) */
72
50.5k
#endif
73
74
50.5k
    update(mac_ctx, digest_size, Atmp); /* hash A(i) */
75
50.5k
    update(mac_ctx, label_size,
76
50.5k
           (const uint8_t *)label); /* hash label */
77
50.5k
    update(mac_ctx, seed_size, seed); /* hash seed */
78
79
50.5k
    if (left < (ssize_t)digest_size)
80
15.4k
      digest_size = left;
81
82
#if NETTLE_VERSION_MAJOR >= 4
83
    digest(mac_ctx, tmp);
84
#else
85
50.5k
    digest(mac_ctx, digest_size, tmp);
86
50.5k
#endif
87
50.5k
    memcpy(dst, tmp, digest_size);
88
89
50.5k
    left -= digest_size;
90
50.5k
    dst += digest_size;
91
50.5k
  }
92
93
19.0k
  return;
94
19.0k
}
95
96
int tls10_prf(size_t secret_size, const uint8_t *secret, size_t label_size,
97
        const char *label, size_t seed_size, const uint8_t *seed,
98
        size_t length, uint8_t *dst)
99
5.21k
{
100
5.21k
  int l_s;
101
5.21k
  const uint8_t *s1, *s2;
102
5.21k
  struct hmac_md5_ctx md5_ctx;
103
5.21k
  struct hmac_sha1_ctx sha1_ctx;
104
5.21k
  uint8_t o1[MAX_PRF_BYTES];
105
106
5.21k
  if (length > MAX_PRF_BYTES)
107
0
    return 0;
108
109
5.21k
  l_s = secret_size / 2;
110
5.21k
  s1 = &secret[0];
111
5.21k
  s2 = &secret[l_s];
112
5.21k
  if (secret_size % 2 != 0) {
113
522
    l_s++;
114
522
  }
115
116
5.21k
  hmac_md5_set_key(&md5_ctx, l_s, s1);
117
118
5.21k
  P_hash(&md5_ctx, (nettle_hash_update_func *)hmac_md5_update,
119
5.21k
         (nettle_hash_digest_func *)hmac_md5_digest, MD5_DIGEST_SIZE,
120
5.21k
         seed_size, seed, label_size, label, length, o1);
121
122
5.21k
  hmac_sha1_set_key(&sha1_ctx, l_s, s2);
123
124
5.21k
  P_hash(&sha1_ctx, (nettle_hash_update_func *)hmac_sha1_update,
125
5.21k
         (nettle_hash_digest_func *)hmac_sha1_digest, SHA1_DIGEST_SIZE,
126
5.21k
         seed_size, seed, label_size, label, length, dst);
127
128
5.21k
  memxor(dst, o1, length);
129
130
5.21k
  return 1;
131
5.21k
}
132
133
/*-
134
 * tls12_prf:
135
 * @mac_ctx: a MAC context initialized with key being the secret
136
 * @update: a MAC update function
137
 * @digest: a MAC digest function
138
 * @digest_size: the MAC output size
139
 * @label_size: the size of the label
140
 * @label: the label to apply
141
 * @seed_size: the seed size
142
 * @seed: the seed
143
 * @length: size of desired PRF output
144
 * @dst: the location to store output
145
 *
146
 * The TLS 1.2 Pseudo-Random-Function (PRF).
147
 *
148
 * Returns: zero on failure, non zero on success.
149
 -*/
150
int tls12_prf(void *mac_ctx, nettle_hash_update_func *update,
151
        nettle_hash_digest_func *digest, size_t digest_size,
152
        size_t label_size, const char *label, size_t seed_size,
153
        const uint8_t *seed, size_t length, uint8_t *dst)
154
8.64k
{
155
19.8k
#define MASTER_SECRET "master secret"
156
22.8k
#define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET) - 1)
157
158
8.64k
  P_hash(mac_ctx, update, digest, digest_size, seed_size, seed,
159
8.64k
         label_size, label, length, dst);
160
161
  /* Since May 16, 2023, the use of extended master secret is
162
   * mandatory according to FIPS 140-3 IG D.Q.  Instead of
163
   * allowing the "extended master secret" label specifically,
164
   * we mark the use of non-EMS label, i.e., "master secret" as
165
   * non-approved, because it is still useful to call the
166
   * gnutls_prf_raw function with arbitrary label, e.g., in
167
   * self-tests.
168
   */
169
8.64k
  if (label_size == MASTER_SECRET_SIZE &&
170
5.61k
      memcmp(label, MASTER_SECRET, MASTER_SECRET_SIZE) == 0) {
171
2.63k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
172
6.00k
  } else {
173
6.00k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
174
6.00k
  }
175
176
8.64k
  return 1;
177
8.64k
}