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