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