1 /*
2  * Copyright (C) 2017 Red Hat, Inc.
3  *
4  * Author: Thierry Quemerais, Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * GnuTLS is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GnuTLS 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  * 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 /* This program tests whether a cookie sent by the server is repeated
23  * by the gnutls client. */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #if defined(_WIN32)
33 
34 /* socketpair isn't supported on Win32. */
main(int argc,char ** argv)35 int main(int argc, char **argv)
36 {
37 	exit(77);
38 }
39 
40 #else
41 
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #if !defined(_WIN32)
46 #include <sys/wait.h>
47 #include <signal.h>
48 #endif
49 #include <unistd.h>
50 #include <gnutls/gnutls.h>
51 #include <assert.h>
52 
53 #include "utils.h"
54 #include "cert-common.h"
55 
56 const char *side = "";
57 
tls_log_func(int level,const char * str)58 static void tls_log_func(int level, const char *str)
59 {
60 	fprintf(stderr, "%s|<%d>| %s", side, level, str);
61 }
62 
63 static int TLSEXT_TYPE_server_sent		= 0;
64 static int TLSEXT_TYPE_server_received		= 0;
65 
66 static const unsigned char ext_data[] =
67 {
68 	0x00,
69 	0x03,
70 	0xFE,
71 	0xED,
72 	0xFF
73 };
74 
ext_recv_server_cookie(gnutls_session_t session,const unsigned char * buf,size_t buflen)75 static int ext_recv_server_cookie(gnutls_session_t session, const unsigned char *buf, size_t buflen)
76 {
77 	if (buflen != sizeof(ext_data))
78 		fail("ext_recv_server_params: Invalid input buffer length\n");
79 
80 	if (memcmp(buf, ext_data, sizeof(ext_data)) != 0)
81 		fail("ext_recv_server_params: Invalid input buffer data\n");
82 
83 	TLSEXT_TYPE_server_received = 1;
84 
85 	return 0; //Success
86 }
87 
ext_send_server_cookie(gnutls_session_t session,gnutls_buffer_t extdata)88 static int ext_send_server_cookie(gnutls_session_t session, gnutls_buffer_t extdata)
89 {
90 	if (gnutls_ext_get_current_msg(session) == GNUTLS_EXT_FLAG_HRR) {
91 		TLSEXT_TYPE_server_sent = 1;
92 
93 		gnutls_buffer_append_data(extdata, ext_data, sizeof(ext_data));
94 		return sizeof(ext_data);
95 	}
96 	return 0;
97 }
98 
client(int sd)99 static void client(int sd)
100 {
101 	int ret;
102 	gnutls_session_t session;
103 	gnutls_certificate_credentials_t clientx509cred;
104 
105 	global_init();
106 	gnutls_global_set_log_function(tls_log_func);
107 	if (debug)
108 		gnutls_global_set_log_level(4711);
109 
110 	side = "client";
111 
112 	gnutls_certificate_allocate_credentials(&clientx509cred);
113 
114 	/* Initialize TLS session
115 	 */
116 	gnutls_init(&session, GNUTLS_CLIENT);
117 
118 	/* Use default priorities */
119 	assert(gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3",
120 				   NULL)>=0);
121 
122 	/* put the anonymous credentials to the current session
123 	 */
124 	gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
125 				clientx509cred);
126 
127 	gnutls_transport_set_int(session, sd);
128 	gnutls_handshake_set_timeout(session, 20 * 1000);
129 
130 	/* Perform the TLS handshake
131 	 */
132 	ret = gnutls_handshake(session);
133 
134 	if (ret < 0) {
135 		fail("client: Handshake failed: %s\n", gnutls_strerror(ret));
136 		goto end;
137 	} else {
138 		if (debug)
139 			success("client: Handshake was completed\n");
140 	}
141 
142 	gnutls_bye(session, GNUTLS_SHUT_WR);
143 
144 end:
145 	close(sd);
146 
147 	gnutls_deinit(session);
148 
149 	gnutls_certificate_free_credentials(clientx509cred);
150 
151 	gnutls_global_deinit();
152 }
153 
server(int sd)154 static void server(int sd)
155 {
156 	gnutls_certificate_credentials_t serverx509cred;
157 	int ret;
158 	gnutls_session_t session;
159 
160 	/* this must be called once in the program
161 	 */
162 	global_init();
163 	gnutls_global_set_log_function(tls_log_func);
164 	if (debug)
165 		gnutls_global_set_log_level(4711);
166 
167 	side = "server";
168 
169 	gnutls_certificate_allocate_credentials(&serverx509cred);
170 	gnutls_certificate_set_x509_key_mem(serverx509cred,
171 					    &server_cert, &server_key,
172 					    GNUTLS_X509_FMT_PEM);
173 
174 	gnutls_init(&session, GNUTLS_SERVER);
175 
176 
177 	/* force a hello retry request by disabling all the groups that are
178 	 * enabled by default. */
179 	assert(gnutls_priority_set_direct(session,
180 					  "NORMAL:-VERS-ALL:+VERS-TLS1.3:"
181 					  "-GROUP-SECP256R1:-GROUP-X25519:-GROUP-FFDHE2048",
182 					  NULL)>=0);
183 
184 	gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
185 				serverx509cred);
186 
187 	ret = gnutls_session_ext_register(session, "cookie_server", 44, GNUTLS_EXT_TLS, ext_recv_server_cookie, ext_send_server_cookie,
188 					  NULL, NULL, NULL,
189 					  GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_HRR|GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL|GNUTLS_EXT_FLAG_IGNORE_CLIENT_REQUEST);
190 	if (ret != 0)
191 		fail("server: cannot register: %s", gnutls_strerror(ret));
192 
193 	gnutls_transport_set_int(session, sd);
194 	gnutls_handshake_set_timeout(session, 20 * 1000);
195 
196 	ret = gnutls_handshake(session);
197 	if (ret < 0) {
198 		fail("server: Handshake has failed: %s\n\n",
199 		     gnutls_strerror(ret));
200 		goto end;
201 	}
202 	if (debug)
203 		success("server: Handshake was completed\n");
204 
205 	if (TLSEXT_TYPE_server_sent != 1)
206 		fail("server: extension not properly sent\n");
207 
208 	if (TLSEXT_TYPE_server_received != 1)
209 		fail("server: extension not properly received\n");
210 
211 	/* do not wait for the peer to close the connection.
212 	 */
213 	gnutls_bye(session, GNUTLS_SHUT_WR);
214 
215 end:
216 	close(sd);
217 	gnutls_deinit(session);
218 
219 	gnutls_certificate_free_credentials(serverx509cred);
220 
221 	gnutls_global_deinit();
222 
223 	if (debug)
224 		success("server: finished\n");
225 }
226 
doit(void)227 void doit(void)
228 {
229 	pid_t child;
230 	int sockets[2];
231 	int err;
232 
233 	signal(SIGPIPE, SIG_IGN);
234 
235 	err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
236 	if (err == -1) {
237 		perror("socketpair");
238 		fail("socketpair failed\n");
239 		return;
240 	}
241 
242 	TLSEXT_TYPE_server_sent	= 0;
243 	TLSEXT_TYPE_server_received = 0;
244 
245 	child = fork();
246 	if (child < 0) {
247 		perror("fork");
248 		fail("fork");
249 		return;
250 	}
251 
252 	if (child) {
253 		int status = 0;
254 		/* parent */
255 		close(sockets[1]);
256 		server(sockets[0]);
257 		wait(&status);
258 	} else {
259 		close(sockets[0]);
260 		client(sockets[1]);
261 		exit(0);
262 	}
263 }
264 
265 #endif				/* _WIN32 */
266