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/key_update.h"
27 #include "mem.h"
28 #include "mbuffers.h"
29 #include "secrets.h"
30 
31 #define KEY_UPDATES_WINDOW 1000
32 #define KEY_UPDATES_PER_WINDOW 8
33 
update_keys(gnutls_session_t session,hs_stage_t stage)34 static int update_keys(gnutls_session_t session, hs_stage_t stage)
35 {
36 	int ret;
37 
38 	ret = _tls13_update_secret(session, session->key.proto.tls13.temp_secret,
39 				   session->key.proto.tls13.temp_secret_size);
40 	if (ret < 0)
41 		return gnutls_assert_val(ret);
42 
43 	_gnutls_epoch_bump(session);
44 	ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT);
45 	if (ret < 0)
46 		return gnutls_assert_val(ret);
47 
48 	/* If we send a key update during early start, only update our
49 	 * write keys */
50 	if (session->internals.recv_state == RECV_STATE_EARLY_START) {
51 		ret = _tls13_write_connection_state_init(session, stage);
52 	} else {
53 		ret = _tls13_connection_state_init(session, stage);
54 	}
55 	if (ret < 0)
56 		return gnutls_assert_val(ret);
57 
58 	return 0;
59 }
60 
_gnutls13_recv_key_update(gnutls_session_t session,gnutls_buffer_st * buf)61 int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf)
62 {
63 	int ret;
64 	struct timespec now;
65 
66 	if (buf->length != 1)
67 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
68 
69 	gnutls_gettime(&now);
70 
71 	/* Roll over the counter if the time window has elapsed */
72 	if (session->internals.key_update_count == 0 ||
73 	    timespec_sub_ms(&now, &session->internals.last_key_update) >
74 	    KEY_UPDATES_WINDOW) {
75 		session->internals.last_key_update = now;
76 		session->internals.key_update_count = 0;
77 	}
78 
79 	if (unlikely(++session->internals.key_update_count >
80 		     KEY_UPDATES_PER_WINDOW)) {
81 		_gnutls_debug_log("reached maximum number of key updates per %d milliseconds (%d)\n",
82 				  KEY_UPDATES_WINDOW,
83 				  KEY_UPDATES_PER_WINDOW);
84 		return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
85 	}
86 
87 	_gnutls_epoch_gc(session);
88 
89 	_gnutls_handshake_log("HSK[%p]: received TLS 1.3 key update (%u)\n",
90 			      session, (unsigned)buf->data[0]);
91 
92 	switch(buf->data[0]) {
93 	case 0:
94 		/* peer updated its key, not requested our key update */
95 		ret = update_keys(session, STAGE_UPD_PEERS);
96 		if (ret < 0)
97 			return gnutls_assert_val(ret);
98 
99 		break;
100 	case 1:
101 		if (session->internals.hsk_flags & HSK_KEY_UPDATE_ASKED) {
102 			/* if we had asked a key update we shouldn't get this
103 			 * reply */
104 			return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
105 		}
106 
107 		/* peer updated its key, requested our key update */
108 		ret = update_keys(session, STAGE_UPD_PEERS);
109 		if (ret < 0)
110 			return gnutls_assert_val(ret);
111 
112 		/* we mark that a key update is schedule, and it
113 		 * will be performed prior to sending the next application
114 		 * message.
115 		 */
116 		if (session->internals.rsend_state == RECORD_SEND_NORMAL)
117 			session->internals.rsend_state = RECORD_SEND_KEY_UPDATE_1;
118 		else if (session->internals.rsend_state == RECORD_SEND_CORKED)
119 			session->internals.rsend_state = RECORD_SEND_CORKED_TO_KU;
120 
121 		break;
122 	default:
123 		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
124 	}
125 
126 	session->internals.hsk_flags &= ~(unsigned)(HSK_KEY_UPDATE_ASKED);
127 
128 	return 0;
129 }
130 
_gnutls13_send_key_update(gnutls_session_t session,unsigned again,unsigned flags)131 int _gnutls13_send_key_update(gnutls_session_t session, unsigned again, unsigned flags /* GNUTLS_KU_* */)
132 {
133 	int ret;
134 	mbuffer_st *bufel = NULL;
135 	uint8_t val;
136 
137 	if (again == 0) {
138 		if (flags & GNUTLS_KU_PEER) {
139 			/* mark that we asked a key update to prevent an
140 			 * infinite ping pong when receiving the reply */
141 			session->internals.hsk_flags |= HSK_KEY_UPDATE_ASKED;
142 			val = 0x01;
143 		} else {
144 			val = 0x00;
145 		}
146 
147 		_gnutls_handshake_log("HSK[%p]: sending key update (%u)\n", session, (unsigned)val);
148 
149 		bufel = _gnutls_handshake_alloc(session, 1);
150 		if (bufel == NULL)
151 			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
152 
153 		_mbuffer_set_udata_size(bufel, 0);
154 		ret = _mbuffer_append_data(bufel, &val, 1);
155 		if (ret < 0) {
156 			gnutls_assert();
157 			goto cleanup;
158 		}
159 
160 	}
161 
162 	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_KEY_UPDATE);
163 
164 cleanup:
165 	_mbuffer_xfree(&bufel);
166 	return ret;
167 }
168 
169 /**
170  * gnutls_session_key_update:
171  * @session: is a #gnutls_session_t type.
172  * @flags: zero of %GNUTLS_KU_PEER
173  *
174  * This function will update/refresh the session keys when the
175  * TLS protocol is 1.3 or better. The peer is notified of the
176  * update by sending a message, so this function should be
177  * treated similarly to gnutls_record_send() --i.e., it may
178  * return %GNUTLS_E_AGAIN or %GNUTLS_E_INTERRUPTED.
179  *
180  * When this flag %GNUTLS_KU_PEER is specified, this function
181  * in addition to updating the local keys, will ask the peer to
182  * refresh its keys too.
183  *
184  * If the negotiated version is not TLS 1.3 or better this
185  * function will return %GNUTLS_E_INVALID_REQUEST.
186  *
187  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
188  *
189  * Since: 3.6.3
190  **/
gnutls_session_key_update(gnutls_session_t session,unsigned flags)191 int gnutls_session_key_update(gnutls_session_t session, unsigned flags)
192 {
193 	int ret;
194 	const version_entry_st *vers = get_version(session);
195 
196 	if (!vers->tls13_sem)
197 		return GNUTLS_E_INVALID_REQUEST;
198 
199 	ret =
200 	    _gnutls13_send_key_update(session, AGAIN(STATE150), flags);
201 	STATE = STATE150;
202 
203 	if (ret < 0) {
204 		gnutls_assert();
205 		return ret;
206 	}
207 	STATE = STATE0;
208 
209 	_gnutls_epoch_gc(session);
210 
211 	/* it was completely sent, update the keys */
212 	ret = update_keys(session, STAGE_UPD_OURS);
213 	if (ret < 0)
214 		return gnutls_assert_val(ret);
215 
216 	return 0;
217 }
218