Coverage Report

Created: 2026-03-31 07:20

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
0
{
51
0
  uint8_t Atmp[MAX_HASH_SIZE];
52
0
  ssize_t left;
53
0
  unsigned started = 0;
54
0
  uint8_t tmp[MAX_HASH_SIZE];
55
56
  /* round up */
57
0
  left = dst_length;
58
59
0
  while (left > 0) {
60
0
    if (started == 0) { /* A(0) */
61
0
      update(mac_ctx, label_size,
62
0
             (const uint8_t *)label); /* hash label */
63
0
      update(mac_ctx, seed_size, seed);
64
0
      started = 1;
65
0
    } else {
66
0
      update(mac_ctx, digest_size, Atmp);
67
0
    }
68
#if NETTLE_VERSION_MAJOR >= 4
69
    digest(mac_ctx, Atmp); /* store A(i) */
70
#else
71
0
    digest(mac_ctx, digest_size, Atmp); /* store A(i) */
72
0
#endif
73
74
0
    update(mac_ctx, digest_size, Atmp); /* hash A(i) */
75
0
    update(mac_ctx, label_size,
76
0
           (const uint8_t *)label); /* hash label */
77
0
    update(mac_ctx, seed_size, seed); /* hash seed */
78
79
0
    if (left < (ssize_t)digest_size)
80
0
      digest_size = left;
81
82
#if NETTLE_VERSION_MAJOR >= 4
83
    digest(mac_ctx, tmp);
84
#else
85
0
    digest(mac_ctx, digest_size, tmp);
86
0
#endif
87
0
    memcpy(dst, tmp, digest_size);
88
89
0
    left -= digest_size;
90
0
    dst += digest_size;
91
0
  }
92
93
0
  return;
94
0
}
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
0
{
100
0
  int l_s;
101
0
  const uint8_t *s1, *s2;
102
0
  struct hmac_md5_ctx md5_ctx;
103
0
  struct hmac_sha1_ctx sha1_ctx;
104
0
  uint8_t o1[MAX_PRF_BYTES];
105
106
0
  if (length > MAX_PRF_BYTES)
107
0
    return 0;
108
109
0
  l_s = secret_size / 2;
110
0
  s1 = &secret[0];
111
0
  s2 = &secret[l_s];
112
0
  if (secret_size % 2 != 0) {
113
0
    l_s++;
114
0
  }
115
116
0
  hmac_md5_set_key(&md5_ctx, l_s, s1);
117
118
0
  P_hash(&md5_ctx, (nettle_hash_update_func *)hmac_md5_update,
119
0
         (nettle_hash_digest_func *)hmac_md5_digest, MD5_DIGEST_SIZE,
120
0
         seed_size, seed, label_size, label, length, o1);
121
122
0
  hmac_sha1_set_key(&sha1_ctx, l_s, s2);
123
124
0
  P_hash(&sha1_ctx, (nettle_hash_update_func *)hmac_sha1_update,
125
0
         (nettle_hash_digest_func *)hmac_sha1_digest, SHA1_DIGEST_SIZE,
126
0
         seed_size, seed, label_size, label, length, dst);
127
128
0
  memxor(dst, o1, length);
129
130
0
  return 1;
131
0
}
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
0
{
155
0
#define MASTER_SECRET "master secret"
156
0
#define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET) - 1)
157
158
0
  P_hash(mac_ctx, update, digest, digest_size, seed_size, seed,
159
0
         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
0
  if (label_size == MASTER_SECRET_SIZE &&
170
0
      memcmp(label, MASTER_SECRET, MASTER_SECRET_SIZE) == 0) {
171
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
172
0
  } else {
173
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
174
0
  }
175
176
0
  return 1;
177
0
}