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