Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/tls13/finished.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
#include "gnutls_int.h"
24
#include "errors.h"
25
#include "handshake.h"
26
#include "tls13/finished.h"
27
#include "mem.h"
28
#include "mbuffers.h"
29
#include "secrets.h"
30
31
int _gnutls13_compute_finished(const mac_entry_st *prf, const uint8_t *base_key,
32
             gnutls_buffer_st *handshake_hash_buffer,
33
             void *out)
34
0
{
35
0
  int ret;
36
0
  uint8_t fkey[MAX_HASH_SIZE];
37
0
  uint8_t ts_hash[MAX_HASH_SIZE];
38
39
0
  ret = _tls13_expand_secret2(prf, "finished", 8, NULL, 0, base_key,
40
0
            prf->output_size, fkey);
41
0
  if (ret < 0)
42
0
    return gnutls_assert_val(ret);
43
44
0
  ret = gnutls_hash_fast(MAC_TO_DIG(prf->id), handshake_hash_buffer->data,
45
0
             handshake_hash_buffer->length, ts_hash);
46
0
  if (ret < 0)
47
0
    return gnutls_assert_val(ret);
48
49
0
  ret = gnutls_hmac_fast(prf->id, fkey, prf->output_size, ts_hash,
50
0
             prf->output_size, out);
51
0
  if (ret < 0)
52
0
    return gnutls_assert_val(ret);
53
54
0
  return 0;
55
0
}
56
57
int _gnutls13_recv_finished(gnutls_session_t session)
58
0
{
59
0
  int ret;
60
0
  gnutls_buffer_st buf;
61
0
  uint8_t verifier[MAX_HASH_SIZE];
62
0
  const uint8_t *base_key;
63
0
  unsigned hash_size;
64
65
0
  if (unlikely(session->security_parameters.prf == NULL))
66
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
67
68
0
  hash_size = session->security_parameters.prf->output_size;
69
70
0
  if (!session->internals.initial_negotiation_completed) {
71
0
    if (session->security_parameters.entity == GNUTLS_CLIENT)
72
0
      base_key = session->key.proto.tls13.hs_skey;
73
0
    else
74
0
      base_key = session->key.proto.tls13.hs_ckey;
75
0
  } else {
76
0
    if (session->security_parameters.entity == GNUTLS_CLIENT)
77
0
      base_key = session->key.proto.tls13.ap_skey;
78
0
    else
79
0
      base_key = session->key.proto.tls13.ap_ckey;
80
0
  }
81
82
0
  ret = _gnutls13_compute_finished(
83
0
    session->security_parameters.prf, base_key,
84
0
    &session->internals.handshake_hash_buffer, verifier);
85
0
  if (ret < 0) {
86
0
    gnutls_assert();
87
0
    goto cleanup;
88
0
  }
89
90
0
  ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED, 0,
91
0
             &buf);
92
0
  if (ret < 0)
93
0
    return gnutls_assert_val(ret);
94
95
0
  _gnutls_handshake_log("HSK[%p]: parsing finished\n", session);
96
97
0
  if (buf.length != hash_size) {
98
0
    gnutls_assert();
99
0
    ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
100
0
    goto cleanup;
101
0
  }
102
0
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
103
0
#warning This is unsafe for production builds
104
#else
105
  if (gnutls_memcmp(verifier, buf.data, buf.length) != 0) {
106
    gnutls_assert();
107
    ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
108
    goto cleanup;
109
  }
110
#endif
111
112
0
  ret = 0;
113
0
cleanup:
114
115
0
  _gnutls_buffer_clear(&buf);
116
0
  return ret;
117
0
}
118
119
int _gnutls13_send_finished(gnutls_session_t session, unsigned again)
120
0
{
121
0
  int ret;
122
0
  uint8_t verifier[MAX_HASH_SIZE];
123
0
  mbuffer_st *bufel = NULL;
124
0
  const uint8_t *base_key;
125
0
  unsigned hash_size;
126
127
0
  if (again == 0) {
128
0
    if (unlikely(session->security_parameters.prf == NULL))
129
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
130
131
0
    hash_size = session->security_parameters.prf->output_size;
132
133
0
    if (!session->internals.initial_negotiation_completed) {
134
0
      if (session->security_parameters.entity ==
135
0
          GNUTLS_CLIENT)
136
0
        base_key = session->key.proto.tls13.hs_ckey;
137
0
      else
138
0
        base_key = session->key.proto.tls13.hs_skey;
139
0
    } else {
140
0
      if (session->security_parameters.entity ==
141
0
          GNUTLS_CLIENT)
142
0
        base_key = session->key.proto.tls13.ap_ckey;
143
0
      else
144
0
        base_key = session->key.proto.tls13.ap_skey;
145
0
    }
146
147
0
    ret = _gnutls13_compute_finished(
148
0
      session->security_parameters.prf, base_key,
149
0
      &session->internals.handshake_hash_buffer, verifier);
150
0
    if (ret < 0) {
151
0
      gnutls_assert();
152
0
      goto cleanup;
153
0
    }
154
155
0
    _gnutls_handshake_log("HSK[%p]: sending finished\n", session);
156
157
0
    bufel = _gnutls_handshake_alloc(session, hash_size);
158
0
    if (bufel == NULL)
159
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
160
161
0
    _mbuffer_set_udata_size(bufel, 0);
162
0
    ret = _mbuffer_append_data(bufel, verifier, hash_size);
163
0
    if (ret < 0) {
164
0
      gnutls_assert();
165
0
      goto cleanup;
166
0
    }
167
0
  }
168
169
0
  return _gnutls_send_handshake(session, bufel,
170
0
              GNUTLS_HANDSHAKE_FINISHED);
171
172
0
cleanup:
173
0
  _mbuffer_xfree(&bufel);
174
0
  return ret;
175
0
}