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