Coverage Report

Created: 2025-03-18 06:55

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