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