/src/gnutls/lib/tls13/post_handshake.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 | | /* Functions that relate to the TLS handshake procedure. |
24 | | */ |
25 | | |
26 | | #include "gnutls_int.h" |
27 | | #include "errors.h" |
28 | | #include "dh.h" |
29 | | #include "debug.h" |
30 | | #include "algorithms.h" |
31 | | #include "cipher.h" |
32 | | #include "buffers.h" |
33 | | #include "mbuffers.h" |
34 | | #include "kx.h" |
35 | | #include "handshake.h" |
36 | | #include "num.h" |
37 | | #include "hash_int.h" |
38 | | #include "db.h" |
39 | | #include "hello_ext.h" |
40 | | #include "supplemental.h" |
41 | | #include "auth.h" |
42 | | #include "sslv2_compat.h" |
43 | | #include <auth/cert.h> |
44 | | #include "constate.h" |
45 | | #include <record.h> |
46 | | #include <state.h> |
47 | | #include <random.h> |
48 | | #include <dtls.h> |
49 | | #include "tls13/certificate_request.h" |
50 | | #include "tls13/certificate_verify.h" |
51 | | #include "tls13/certificate.h" |
52 | | #include "tls13/finished.h" |
53 | | |
54 | | #undef AGAIN |
55 | 0 | #define AGAIN(x) ((x)==(REAUTH_STATE)) |
56 | | |
57 | | /* |
58 | | * _gnutls13_reauth_client |
59 | | * This function performs the client side of the post-handshake authentication |
60 | | */ |
61 | | static |
62 | | int _gnutls13_reauth_client(gnutls_session_t session) |
63 | 0 | { |
64 | 0 | int ret = 0; |
65 | 0 | size_t tmp; |
66 | |
|
67 | 0 | if (!session->internals.initial_negotiation_completed) |
68 | 0 | return gnutls_assert_val(GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE); |
69 | | |
70 | 0 | if (!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)) |
71 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
72 | | |
73 | 0 | if (session->internals.reauth_buffer.length == 0) |
74 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
75 | | |
76 | 0 | switch (REAUTH_STATE) { |
77 | 0 | case REAUTH_STATE0: |
78 | | |
79 | | /* restore handshake transcript */ |
80 | 0 | _gnutls_buffer_reset(&session->internals.handshake_hash_buffer); |
81 | 0 | ret = |
82 | 0 | gnutls_buffer_append_data(&session-> |
83 | 0 | internals.handshake_hash_buffer, |
84 | 0 | session-> |
85 | 0 | internals.post_handshake_hash_buffer. |
86 | 0 | data, |
87 | 0 | session-> |
88 | 0 | internals.post_handshake_hash_buffer.length); |
89 | 0 | if (ret < 0) |
90 | 0 | return gnutls_assert_val(ret); |
91 | | |
92 | | /* append the previously received certificate request message, to the |
93 | | * transcript. */ |
94 | 0 | ret = |
95 | 0 | gnutls_buffer_append_data(&session-> |
96 | 0 | internals.handshake_hash_buffer, |
97 | 0 | session->internals. |
98 | 0 | reauth_buffer.data, |
99 | 0 | session->internals. |
100 | 0 | reauth_buffer.length); |
101 | 0 | if (ret < 0) |
102 | 0 | return gnutls_assert_val(ret); |
103 | | |
104 | 0 | session->internals.handshake_hash_buffer_prev_len = |
105 | 0 | session->internals.handshake_hash_buffer.length; |
106 | | |
107 | | /* skip the reauth buffer handshake message headers */ |
108 | 0 | ret = |
109 | 0 | _gnutls_buffer_pop_prefix32(&session-> |
110 | 0 | internals.reauth_buffer, &tmp, |
111 | 0 | 0); |
112 | 0 | if (ret < 0) |
113 | 0 | return gnutls_assert_val(ret); |
114 | |
|
115 | 0 | FALLTHROUGH; |
116 | 0 | case REAUTH_STATE1: |
117 | 0 | ret = _gnutls13_recv_certificate_request_int(session, |
118 | 0 | &session->internals.reauth_buffer); |
119 | 0 | REAUTH_STATE = REAUTH_STATE1; |
120 | 0 | IMED_RET("recv certificate request", ret, 0); |
121 | 0 | FALLTHROUGH; |
122 | 0 | case REAUTH_STATE2: |
123 | 0 | ret = _gnutls13_send_certificate(session, AGAIN(REAUTH_STATE2)); |
124 | 0 | REAUTH_STATE = REAUTH_STATE2; |
125 | 0 | IMED_RET("send certificate", ret, 0); |
126 | 0 | FALLTHROUGH; |
127 | 0 | case REAUTH_STATE3: |
128 | 0 | ret = |
129 | 0 | _gnutls13_send_certificate_verify(session, |
130 | 0 | AGAIN(REAUTH_STATE3)); |
131 | 0 | REAUTH_STATE = REAUTH_STATE3; |
132 | 0 | IMED_RET("send certificate verify", ret, 0); |
133 | 0 | FALLTHROUGH; |
134 | 0 | case REAUTH_STATE4: |
135 | 0 | ret = _gnutls13_send_finished(session, AGAIN(REAUTH_STATE4)); |
136 | 0 | REAUTH_STATE = REAUTH_STATE4; |
137 | 0 | IMED_RET("send finished", ret, 0); |
138 | 0 | break; |
139 | 0 | default: |
140 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
141 | 0 | } |
142 | | |
143 | 0 | _gnutls_handshake_hash_buffers_clear(session); |
144 | 0 | _gnutls_buffer_reset(&session->internals.reauth_buffer); |
145 | 0 | REAUTH_STATE = REAUTH_STATE0; |
146 | |
|
147 | 0 | return 0; |
148 | 0 | } |
149 | | |
150 | | /* |
151 | | * _gnutls13_reauth_server |
152 | | * This function does the server stuff of the post-handshake authentication. |
153 | | */ |
154 | | static |
155 | | int _gnutls13_reauth_server(gnutls_session_t session) |
156 | 0 | { |
157 | 0 | int ret = 0; |
158 | |
|
159 | 0 | if (session->security_parameters.post_handshake_auth == 0 || |
160 | 0 | (!(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH))) |
161 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
162 | | |
163 | 0 | if (session->internals.send_cert_req == 0) { |
164 | 0 | _gnutls_debug_log |
165 | 0 | ("You need to call gnutls_certificate_server_set_request to enable post handshake auth\n"); |
166 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
167 | 0 | } |
168 | | |
169 | 0 | switch (REAUTH_STATE) { |
170 | 0 | case REAUTH_STATE0: |
171 | | /* restore handshake transcript */ |
172 | 0 | _gnutls_buffer_reset(&session->internals.handshake_hash_buffer); |
173 | 0 | ret = |
174 | 0 | gnutls_buffer_append_data(&session-> |
175 | 0 | internals.handshake_hash_buffer, |
176 | 0 | session-> |
177 | 0 | internals.post_handshake_hash_buffer. |
178 | 0 | data, |
179 | 0 | session-> |
180 | 0 | internals.post_handshake_hash_buffer.length); |
181 | 0 | if (ret < 0) |
182 | 0 | return gnutls_assert_val(ret); |
183 | | |
184 | 0 | session->internals.handshake_hash_buffer_prev_len = |
185 | 0 | session->internals.handshake_hash_buffer.length; |
186 | |
|
187 | 0 | FALLTHROUGH; |
188 | 0 | case REAUTH_STATE1: |
189 | 0 | ret = |
190 | 0 | _gnutls13_send_certificate_request(session, |
191 | 0 | AGAIN(REAUTH_STATE1)); |
192 | 0 | REAUTH_STATE = REAUTH_STATE1; |
193 | 0 | IMED_RET("send certificate request", ret, 0); |
194 | 0 | FALLTHROUGH; |
195 | 0 | case REAUTH_STATE2: |
196 | | /* here we should tolerate application data */ |
197 | 0 | ret = _gnutls13_recv_certificate(session); |
198 | 0 | REAUTH_STATE = REAUTH_STATE2; |
199 | 0 | IMED_RET("recv certificate", ret, 0); |
200 | 0 | FALLTHROUGH; |
201 | 0 | case REAUTH_STATE3: |
202 | 0 | ret = _gnutls13_recv_certificate_verify(session); |
203 | 0 | REAUTH_STATE = REAUTH_STATE3; |
204 | 0 | IMED_RET("recv certificate verify", ret, 0); |
205 | 0 | FALLTHROUGH; |
206 | 0 | case REAUTH_STATE4: |
207 | 0 | ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT); |
208 | 0 | REAUTH_STATE = REAUTH_STATE4; |
209 | 0 | if (ret < 0) |
210 | 0 | return gnutls_assert_val(ret); |
211 | 0 | FALLTHROUGH; |
212 | 0 | case REAUTH_STATE5: |
213 | 0 | ret = _gnutls13_recv_finished(session); |
214 | 0 | REAUTH_STATE = REAUTH_STATE5; |
215 | 0 | IMED_RET("recv finished", ret, 0); |
216 | 0 | break; |
217 | 0 | default: |
218 | 0 | return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); |
219 | 0 | } |
220 | | |
221 | 0 | _gnutls_handshake_hash_buffers_clear(session); |
222 | 0 | REAUTH_STATE = REAUTH_STATE0; |
223 | |
|
224 | 0 | return 0; |
225 | 0 | } |
226 | | |
227 | | /** |
228 | | * gnutls_reauth: |
229 | | * @session: is a #gnutls_session_t type. |
230 | | * @flags: must be zero |
231 | | * |
232 | | * This function performs the post-handshake authentication |
233 | | * for TLS 1.3. The post-handshake authentication is initiated by the server |
234 | | * by calling this function. Clients respond when %GNUTLS_E_REAUTH_REQUEST |
235 | | * has been seen while receiving data. |
236 | | * |
237 | | * The non-fatal errors expected by this function are: |
238 | | * %GNUTLS_E_INTERRUPTED, %GNUTLS_E_AGAIN, as well as |
239 | | * %GNUTLS_E_GOT_APPLICATION_DATA when called on server side. |
240 | | * |
241 | | * The former two interrupt the authentication procedure due to the transport |
242 | | * layer being interrupted, and the latter because there were pending data prior |
243 | | * to peer initiating the re-authentication. The server should read/process that |
244 | | * data as unauthenticated and retry calling gnutls_reauth(). |
245 | | * |
246 | | * When this function is called under TLS1.2 or earlier or the peer didn't |
247 | | * advertise post-handshake auth, it always fails with |
248 | | * %GNUTLS_E_INVALID_REQUEST. The verification of the received peers certificate |
249 | | * is delegated to the session or credentials verification callbacks. A |
250 | | * server can check whether post handshake authentication is supported |
251 | | * by the client by checking the session flags with gnutls_session_get_flags(). |
252 | | * |
253 | | * Prior to calling this function in server side, the function |
254 | | * gnutls_certificate_server_set_request() must be called setting expectations |
255 | | * for the received certificate (request or require). If none are set |
256 | | * this function will return with %GNUTLS_E_INVALID_REQUEST. |
257 | | * |
258 | | * Note that post handshake authentication is available irrespective |
259 | | * of the initial negotiation type (PSK or certificate). In all cases |
260 | | * however, certificate credentials must be set to the session prior |
261 | | * to calling this function. |
262 | | * |
263 | | * Returns: %GNUTLS_E_SUCCESS on a successful authentication, otherwise a negative error code. |
264 | | **/ |
265 | | int gnutls_reauth(gnutls_session_t session, unsigned int flags) |
266 | 0 | { |
267 | 0 | const version_entry_st *vers = get_version(session); |
268 | |
|
269 | 0 | if (unlikely(!vers->tls13_sem)) |
270 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
271 | | |
272 | 0 | if (session->security_parameters.entity == GNUTLS_SERVER) |
273 | 0 | return _gnutls13_reauth_server(session); |
274 | 0 | else |
275 | 0 | return _gnutls13_reauth_client(session); |
276 | 0 | } |