Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/prf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2002-2015 Free Software Foundation, Inc.
3
 * Copyright (C) 2014-2015 Nikos Mavrogiannopoulos
4
 * Copyright (C) 2016-2017 Red Hat, Inc.
5
 *
6
 * Author: Nikos Mavrogiannopoulos
7
 *
8
 * This file is part of GnuTLS.
9
 *
10
 * The GnuTLS is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public License
12
 * as published by the Free Software Foundation; either version 2.1 of
13
 * the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful, but
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
22
 *
23
 */
24
25
/* Functions for the TLS PRF handling.
26
 */
27
28
#include "gnutls_int.h"
29
#include "errors.h"
30
#include "handshake.h"
31
#include "secrets.h"
32
#include <num.h>
33
#include <state.h>
34
#include <algorithms.h>
35
36
/**
37
 * gnutls_prf_raw:
38
 * @session: is a #gnutls_session_t type.
39
 * @label_size: length of the @label variable.
40
 * @label: label used in PRF computation, typically a short string.
41
 * @seed_size: length of the @seed variable.
42
 * @seed: optional extra data to seed the PRF with.
43
 * @outsize: size of pre-allocated output buffer to hold the output.
44
 * @out: pre-allocated buffer to hold the generated data.
45
 *
46
 * Apply the TLS Pseudo-Random-Function (PRF) on the master secret
47
 * and the provided data.
48
 *
49
 * The @label variable usually contains a string denoting the purpose
50
 * for the generated data.  The @seed usually contains data such as the
51
 * client and server random, perhaps together with some additional
52
 * data that is added to guarantee uniqueness of the output for a
53
 * particular purpose.
54
 *
55
 * Because the output is not guaranteed to be unique for a particular
56
 * session unless @seed includes the client random and server random
57
 * fields (the PRF would output the same data on another connection
58
 * resumed from the first one), it is not recommended to use this
59
 * function directly.  The gnutls_prf() function seeds the PRF with the
60
 * client and server random fields directly, and is recommended if you
61
 * want to generate pseudo random data unique for each session.
62
 *
63
 * Note: This function will only operate under TLS versions prior to 1.3.
64
 * In TLS1.3 the use of PRF is replaced with HKDF and the generic
65
 * exporters like gnutls_prf_rfc5705() should be used instead. Under
66
 * TLS1.3 this function returns %GNUTLS_E_INVALID_REQUEST.
67
 *
68
 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
69
 **/
70
int
71
gnutls_prf_raw(gnutls_session_t session,
72
         size_t label_size,
73
         const char *label,
74
         size_t seed_size, const char *seed, size_t outsize, char *out)
75
0
{
76
0
  int ret;
77
0
  const version_entry_st *vers = get_version(session);
78
79
0
  if (vers && vers->tls13_sem)
80
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
81
82
0
  if (session->security_parameters.prf == NULL)
83
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
84
85
0
  ret = _gnutls_prf_raw(session->security_parameters.prf->id,
86
0
            GNUTLS_MASTER_SIZE,
87
0
            session->security_parameters.master_secret,
88
0
            label_size, label, seed_size, (uint8_t *) seed,
89
0
            outsize, out);
90
91
0
  return ret;
92
0
}
93
94
static int
95
_tls13_derive_exporter(const mac_entry_st * prf,
96
           gnutls_session_t session,
97
           size_t label_size, const char *label,
98
           size_t context_size, const char *context,
99
           size_t outsize, char *out, bool early)
100
0
{
101
0
  uint8_t secret[MAX_HASH_SIZE];
102
0
  uint8_t digest[MAX_HASH_SIZE];
103
0
  unsigned digest_size = prf->output_size;
104
0
  int ret;
105
106
0
  ret = _tls13_derive_secret2(prf, label, label_size, NULL, 0,
107
0
            session->key.proto.tls13.ap_expkey, secret);
108
0
  if (ret < 0)
109
0
    return gnutls_assert_val(ret);
110
111
0
  ret = gnutls_hash_fast((gnutls_digest_algorithm_t) prf->id,
112
0
             context, context_size, digest);
113
0
  if (ret < 0)
114
0
    return gnutls_assert_val(ret);
115
116
0
  return _tls13_expand_secret2(prf,
117
0
             EXPORTER_LABEL, sizeof(EXPORTER_LABEL) - 1,
118
0
             digest, digest_size, secret, outsize, out);
119
0
}
120
121
/**
122
 * gnutls_prf_rfc5705:
123
 * @session: is a #gnutls_session_t type.
124
 * @label_size: length of the @label variable.
125
 * @label: label used in PRF computation, typically a short string.
126
 * @context_size: length of the @extra variable.
127
 * @context: optional extra data to seed the PRF with.
128
 * @outsize: size of pre-allocated output buffer to hold the output.
129
 * @out: pre-allocated buffer to hold the generated data.
130
 *
131
 * Exports keying material from TLS/DTLS session to an application, as
132
 * specified in RFC5705.
133
 *
134
 * In the TLS versions prior to 1.3, it applies the TLS
135
 * Pseudo-Random-Function (PRF) on the master secret and the provided
136
 * data, seeded with the client and server random fields.
137
 *
138
 * In TLS 1.3, it applies HKDF on the exporter master secret derived
139
 * from the master secret.
140
 *
141
 * The @label variable usually contains a string denoting the purpose
142
 * for the generated data.
143
 *
144
 * The @context variable can be used to add more data to the seed, after
145
 * the random variables.  It can be used to make sure the
146
 * generated output is strongly connected to some additional data
147
 * (e.g., a string used in user authentication). 
148
 *
149
 * The output is placed in @out, which must be pre-allocated.
150
 *
151
 * Note that, to provide the RFC5705 context, the @context variable
152
 * must be non-null.
153
 *
154
 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
155
 *
156
 * Since: 3.4.4
157
 **/
158
int
159
gnutls_prf_rfc5705(gnutls_session_t session,
160
       size_t label_size, const char *label,
161
       size_t context_size, const char *context,
162
       size_t outsize, char *out)
163
0
{
164
0
  const version_entry_st *vers = get_version(session);
165
0
  int ret;
166
167
0
  if (session->security_parameters.prf == NULL)
168
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
169
170
0
  if (vers && vers->tls13_sem) {
171
0
    ret = _tls13_derive_exporter(session->security_parameters.prf,
172
0
               session,
173
0
               label_size, label,
174
0
               context_size, context,
175
0
               outsize, out, 0);
176
0
  } else {
177
0
    char *pctx = NULL;
178
179
0
    if (context != NULL && context_size > 65535) {
180
0
      gnutls_assert();
181
0
      return GNUTLS_E_INVALID_REQUEST;
182
0
    }
183
184
0
    if (context != NULL) {
185
0
      pctx = gnutls_malloc(context_size + 2);
186
0
      if (!pctx) {
187
0
        gnutls_assert();
188
0
        return GNUTLS_E_MEMORY_ERROR;
189
0
      }
190
191
0
      memcpy(pctx + 2, context, context_size);
192
0
      _gnutls_write_uint16(context_size, (void *)pctx);
193
0
      context_size += 2;
194
0
    }
195
196
0
    ret = gnutls_prf(session, label_size, label, 0,
197
0
         context_size, pctx, outsize, out);
198
199
0
    gnutls_free(pctx);
200
0
  }
201
202
0
  return ret;
203
0
}
204
205
/**
206
 * gnutls_prf_early:
207
 * @session: is a #gnutls_session_t type.
208
 * @label_size: length of the @label variable.
209
 * @label: label used in PRF computation, typically a short string.
210
 * @context_size: length of the @extra variable.
211
 * @context: optional extra data to seed the PRF with.
212
 * @outsize: size of pre-allocated output buffer to hold the output.
213
 * @out: pre-allocated buffer to hold the generated data.
214
 *
215
 * This function is similar to gnutls_prf_rfc5705(), but only works in
216
 * TLS 1.3 or later to export early keying material.
217
 *
218
 * Note that the keying material is only available after the
219
 * ClientHello message is processed and before the application traffic
220
 * keys are established.  Therefore this function shall be called in a
221
 * handshake hook function for %GNUTLS_HANDSHAKE_CLIENT_HELLO.
222
 *
223
 * The @label variable usually contains a string denoting the purpose
224
 * for the generated data.
225
 *
226
 * The @context variable can be used to add more data to the seed, after
227
 * the random variables.  It can be used to make sure the
228
 * generated output is strongly connected to some additional data
229
 * (e.g., a string used in user authentication).
230
 *
231
 * The output is placed in @out, which must be pre-allocated.
232
 *
233
 * Note that, to provide the RFC5705 context, the @context variable
234
 * must be non-null.
235
 *
236
 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
237
 *
238
 * Since: 3.6.8
239
 **/
240
int
241
gnutls_prf_early(gnutls_session_t session,
242
     size_t label_size, const char *label,
243
     size_t context_size, const char *context,
244
     size_t outsize, char *out)
245
0
{
246
0
  if (session->internals.initial_negotiation_completed ||
247
0
      session->key.binders[0].prf == NULL)
248
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
249
250
0
  return _tls13_derive_exporter(session->key.binders[0].prf, session,
251
0
              label_size, label,
252
0
              context_size, context, outsize, out, 1);
253
0
}
254
255
/**
256
 * gnutls_prf:
257
 * @session: is a #gnutls_session_t type.
258
 * @label_size: length of the @label variable.
259
 * @label: label used in PRF computation, typically a short string.
260
 * @server_random_first: non-zero if server random field should be first in seed
261
 * @extra_size: length of the @extra variable.
262
 * @extra: optional extra data to seed the PRF with.
263
 * @outsize: size of pre-allocated output buffer to hold the output.
264
 * @out: pre-allocated buffer to hold the generated data.
265
 *
266
 * Applies the TLS Pseudo-Random-Function (PRF) on the master secret
267
 * and the provided data, seeded with the client and server random fields.
268
 * For the key expansion specified in RFC5705 see gnutls_prf_rfc5705().
269
 *
270
 * The @label variable usually contains a string denoting the purpose
271
 * for the generated data.  The @server_random_first indicates whether
272
 * the client random field or the server random field should be first
273
 * in the seed.  Non-zero indicates that the server random field is first,
274
 * 0 that the client random field is first.
275
 *
276
 * The @extra variable can be used to add more data to the seed, after
277
 * the random variables.  It can be used to make sure the
278
 * generated output is strongly connected to some additional data
279
 * (e.g., a string used in user authentication).
280
 *
281
 * The output is placed in @out, which must be pre-allocated.
282
 *
283
 * Note: This function produces identical output with gnutls_prf_rfc5705()
284
 * when @server_random_first is set to 0 and @extra is %NULL. Under TLS1.3
285
 * this function will only operate when these conditions are true, or otherwise
286
 * return %GNUTLS_E_INVALID_REQUEST.
287
 *
288
 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
289
 **/
290
int
291
gnutls_prf(gnutls_session_t session,
292
     size_t label_size,
293
     const char *label,
294
     int server_random_first,
295
     size_t extra_size, const char *extra, size_t outsize, char *out)
296
0
{
297
0
  int ret;
298
0
  uint8_t *seed;
299
0
  const version_entry_st *vers = get_version(session);
300
0
  size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size;
301
302
0
  if (vers && vers->tls13_sem) {
303
0
    if (extra == NULL && server_random_first == 0)
304
0
      return gnutls_prf_rfc5705(session, label_size, label,
305
0
              extra_size, extra, outsize,
306
0
              out);
307
0
    else
308
0
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
309
0
  }
310
311
0
  if (session->security_parameters.prf == NULL)
312
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
313
314
0
  seed = gnutls_malloc(seedsize);
315
0
  if (!seed) {
316
0
    gnutls_assert();
317
0
    return GNUTLS_E_MEMORY_ERROR;
318
0
  }
319
320
0
  memcpy(seed, server_random_first ?
321
0
         session->security_parameters.server_random :
322
0
         session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
323
0
  memcpy(seed + GNUTLS_RANDOM_SIZE,
324
0
         server_random_first ? session->security_parameters.
325
0
         client_random : session->security_parameters.server_random,
326
0
         GNUTLS_RANDOM_SIZE);
327
328
0
  if (extra && extra_size) {
329
0
    memcpy(seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size);
330
0
  }
331
332
0
  ret =
333
0
      _gnutls_prf_raw(session->security_parameters.prf->id,
334
0
          GNUTLS_MASTER_SIZE,
335
0
          session->security_parameters.master_secret,
336
0
          label_size, label, seedsize, seed, outsize, out);
337
338
0
  gnutls_free(seed);
339
340
0
  return ret;
341
0
}