Coverage Report

Created: 2026-09-28 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/secrets.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
/* TLS 1.3 secret key derivation handling.
24
 */
25
26
#include "config.h"
27
#include "crypto-api.h"
28
#include "fips.h"
29
#include "gnutls_int.h"
30
#include "secrets.h"
31
32
/* HKDF-Extract(0,0) or HKDF-Extract(0, PSK) */
33
int _tls13_init_secret(gnutls_session_t session, const uint8_t *psk,
34
           size_t psk_size)
35
0
{
36
0
  session->key.proto.tls13.temp_secret_size =
37
0
    session->security_parameters.prf->output_size;
38
39
0
  return _tls13_init_secret2(session->security_parameters.prf, psk,
40
0
           psk_size,
41
0
           session->key.proto.tls13.temp_secret);
42
0
}
43
44
int _tls13_init_secret2(const mac_entry_st *prf, const uint8_t *psk,
45
      size_t psk_size, void *out)
46
0
{
47
0
  uint8_t buf[128] = { 0 };
48
0
  uint8_t salt[MAX_HASH_SIZE] = { 0 };
49
50
0
  if (unlikely(prf == NULL))
51
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
52
53
  /* when no PSK, use the zero-value */
54
0
  if (psk == NULL) {
55
0
    psk_size = prf->output_size;
56
0
    if (unlikely(psk_size >= sizeof(buf)))
57
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
58
0
    psk = (uint8_t *)buf;
59
0
  }
60
61
  /* passing an empty salt trips FIPS indicator, so pass real zeroes */
62
0
  memset(salt, 0, prf->output_size);
63
0
  return gnutls_hmac_fast(prf->id, salt, prf->output_size, psk, psk_size,
64
0
        out);
65
0
}
66
67
/* HKDF-Extract(Prev-Secret, key) */
68
int _tls13_update_secret(gnutls_session_t session, const uint8_t *key,
69
       size_t key_size)
70
0
{
71
0
  gnutls_datum_t _key;
72
0
  gnutls_datum_t salt;
73
0
  int ret;
74
75
0
  _key.data = (void *)key;
76
0
  _key.size = key_size;
77
0
  salt.data = (void *)session->key.proto.tls13.temp_secret;
78
0
  salt.size = session->key.proto.tls13.temp_secret_size;
79
80
0
  ret = _gnutls_hkdf_extract(session->security_parameters.prf->id, &_key,
81
0
           &salt, session->key.proto.tls13.temp_secret);
82
0
  if (ret < 0)
83
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
84
0
  else
85
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
86
87
0
  return ret;
88
0
}
89
90
/* Derive-Secret(Secret, Label, Messages) */
91
int _tls13_derive_secret2(const mac_entry_st *prf, const char *label,
92
        unsigned label_size, const uint8_t *tbh,
93
        size_t tbh_size, const uint8_t secret[MAX_HASH_SIZE],
94
        void *out)
95
0
{
96
0
  uint8_t digest[MAX_HASH_SIZE];
97
0
  int ret;
98
0
  unsigned digest_size;
99
100
0
  if (unlikely(prf == NULL))
101
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
102
0
  if (unlikely(label_size >= sizeof(digest)))
103
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
104
105
0
  digest_size = prf->output_size;
106
0
  ret = gnutls_hash_fast((gnutls_digest_algorithm_t)prf->id, tbh,
107
0
             tbh_size, digest);
108
0
  if (ret < 0)
109
0
    return gnutls_assert_val(ret);
110
111
0
  return _tls13_expand_secret2(prf, label, label_size, digest,
112
0
             digest_size, secret, digest_size, out);
113
0
}
114
115
/* Derive-Secret(Secret, Label, Messages) */
116
int _tls13_derive_secret(gnutls_session_t session, const char *label,
117
       unsigned label_size, const uint8_t *tbh,
118
       size_t tbh_size, const uint8_t secret[MAX_HASH_SIZE],
119
       void *out)
120
0
{
121
0
  if (unlikely(session->security_parameters.prf == NULL))
122
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
123
124
0
  return _tls13_derive_secret2(session->security_parameters.prf, label,
125
0
             label_size, tbh, tbh_size, secret, out);
126
0
}
127
128
/* HKDF-Expand-Label(Secret, Label, HashValue, Length) */
129
int _tls13_expand_secret2(const mac_entry_st *prf, const char *label,
130
        unsigned label_size, const uint8_t *msg,
131
        size_t msg_size, const uint8_t secret[MAX_HASH_SIZE],
132
        unsigned out_size, void *out)
133
0
{
134
0
  uint8_t tmp[256] = "tls13 ";
135
0
  gnutls_buffer_st str;
136
0
  gnutls_datum_t key;
137
0
  gnutls_datum_t info;
138
0
  int ret;
139
140
0
  if (unlikely(label_size >= sizeof(tmp) - 6))
141
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
142
143
0
  _gnutls_buffer_init(&str);
144
145
0
  ret = _gnutls_buffer_append_uint16(&str, out_size);
146
0
  if (ret < 0) {
147
0
    gnutls_assert();
148
0
    goto cleanup;
149
0
  }
150
151
0
  memcpy(&tmp[6], label, label_size);
152
0
  ret = _gnutls_buffer_append_data_prefix8(&str, tmp, label_size + 6);
153
0
  if (ret < 0) {
154
0
    gnutls_assert();
155
0
    goto cleanup;
156
0
  }
157
158
0
  ret = _gnutls_buffer_append_data_prefix8(&str, msg, msg_size);
159
0
  if (ret < 0) {
160
0
    gnutls_assert();
161
0
    goto cleanup;
162
0
  }
163
164
0
  key.data = (void *)secret;
165
0
  key.size = _gnutls_mac_get_algo_len(mac_to_entry(prf->id));
166
0
  info.data = str.data;
167
0
  info.size = str.length;
168
169
0
  ret = _gnutls_hkdf_expand(prf->id, &key, &info, out, out_size);
170
0
  if (ret < 0) {
171
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
172
0
    gnutls_assert();
173
0
    goto cleanup;
174
0
  } else {
175
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
176
0
  }
177
178
#if 0
179
  _gnutls_hard_log("INT: hkdf label: %d,%s\n",
180
       out_size,
181
       _gnutls_bin2hex(str.data, str.length,
182
           (char *)tmp, sizeof(tmp), NULL));
183
  _gnutls_hard_log("INT: secret expanded for '%.*s': %d,%s\n",
184
       (int)label_size, label, out_size,
185
       _gnutls_bin2hex(out, out_size,
186
           (char *)tmp, sizeof(tmp), NULL));
187
#endif
188
189
0
  ret = 0;
190
0
cleanup:
191
0
  _gnutls_buffer_clear(&str);
192
0
  return ret;
193
0
}
194
195
int _tls13_expand_secret(gnutls_session_t session, const char *label,
196
       unsigned label_size, const uint8_t *msg,
197
       size_t msg_size, const uint8_t secret[MAX_HASH_SIZE],
198
       unsigned out_size, void *out)
199
0
{
200
0
  if (unlikely(session->security_parameters.prf == NULL))
201
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
202
203
0
  return _tls13_expand_secret2(session->security_parameters.prf, label,
204
0
             label_size, msg, msg_size, secret,
205
0
             out_size, out);
206
0
}