1 /*
2  * Copyright (C) 2015 Red Hat, Inc.
3  *
4  * Author: 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 General Public License
19  * along with GnuTLS; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 
30 #if defined(_WIN32)
31 
main()32 int main()
33 {
34 	exit(77);
35 }
36 
37 #else
38 
39 #include <string.h>
40 #include <sys/types.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <sys/wait.h>
44 #include <arpa/inet.h>
45 #include <unistd.h>
46 #include <gnutls/gnutls.h>
47 #include <gnutls/dtls.h>
48 #include <signal.h>
49 #include <assert.h>
50 
51 #include "utils.h"
52 #include "cert-common.h"
53 
54 static void terminate(void);
55 
56 /* This program tests whether EtM is negotiated as expected.
57  */
58 
server_log_func(int level,const char * str)59 static void server_log_func(int level, const char *str)
60 {
61 	fprintf(stderr, "server|<%d>| %s", level, str);
62 }
63 
client_log_func(int level,const char * str)64 static void client_log_func(int level, const char *str)
65 {
66 	fprintf(stderr, "client|<%d>| %s", level, str);
67 }
68 
69 /* A very basic TLS client, with anonymous authentication.
70  */
71 
72 #define MAX_BUF 1024
73 
client(int fd,const char * prio,unsigned etm)74 static void client(int fd, const char *prio, unsigned etm)
75 {
76 	int ret;
77 	char buffer[MAX_BUF + 1];
78 	gnutls_anon_client_credentials_t anoncred;
79 	gnutls_certificate_credentials_t x509_cred;
80 	gnutls_session_t session;
81 	/* Need to enable anonymous KX specifically. */
82 
83 	global_init();
84 
85 	if (debug) {
86 		gnutls_global_set_log_function(client_log_func);
87 		gnutls_global_set_log_level(7);
88 	}
89 
90 	gnutls_anon_allocate_client_credentials(&anoncred);
91 	gnutls_certificate_allocate_credentials(&x509_cred);
92 
93 	/* Initialize TLS session
94 	 */
95 	gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_DATAGRAM);
96 
97 	/* Use default priorities */
98 	assert(gnutls_priority_set_direct(session, prio, NULL)>=0);
99 
100 	/* put the anonymous credentials to the current session
101 	 */
102 	gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
103 	gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
104 
105 	gnutls_transport_set_int(session, fd);
106 
107 	/* Perform the TLS handshake
108 	 */
109 	do {
110 		ret = gnutls_handshake(session);
111 	}
112 	while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
113 
114 	if (ret < 0) {
115 		fail("client: Handshake failed\n");
116 		gnutls_perror(ret);
117 		exit(1);
118 	} else {
119 		if (debug)
120 			success("client: Handshake was completed\n");
121 	}
122 
123 	if (debug)
124 		success("client: TLS version is: %s\n",
125 			gnutls_protocol_get_name
126 			(gnutls_protocol_get_version(session)));
127 
128 	if (etm != 0 && gnutls_session_etm_status(session) == 0) {
129 		fail("client: EtM was not negotiated with %s!\n", prio);
130 		exit(1);
131 	} else if (etm == 0 && gnutls_session_etm_status(session) != 0) {
132 		fail("client: EtM was negotiated with %s!\n", prio);
133 		exit(1);
134 	}
135 
136 	if (etm != 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) == 0)) {
137 		fail("client: EtM was not negotiated with %s!\n", prio);
138 		exit(1);
139 	} else if (etm == 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) != 0)) {
140 		fail("client: EtM was negotiated with %s!\n", prio);
141 		exit(1);
142 	}
143 
144 	do {
145 		do {
146 			ret = gnutls_record_recv(session, buffer, MAX_BUF);
147 		} while (ret == GNUTLS_E_AGAIN
148 			 || ret == GNUTLS_E_INTERRUPTED);
149 	} while (ret > 0);
150 
151 	if (ret == 0) {
152 		if (debug)
153 			success
154 			    ("client: Peer has closed the TLS connection\n");
155 		goto end;
156 	} else if (ret < 0) {
157 		if (ret != 0) {
158 			fail("client: Error: %s\n", gnutls_strerror(ret));
159 			exit(1);
160 		}
161 	}
162 
163 	gnutls_bye(session, GNUTLS_SHUT_WR);
164 
165       end:
166 
167 	close(fd);
168 
169 	gnutls_deinit(session);
170 
171 	gnutls_anon_free_client_credentials(anoncred);
172 	gnutls_certificate_free_credentials(x509_cred);
173 
174 	gnutls_global_deinit();
175 }
176 
177 
178 /* These are global */
179 pid_t child;
180 
terminate(void)181 static void terminate(void)
182 {
183 	kill(child, SIGTERM);
184 	exit(1);
185 }
186 
server(int fd,const char * prio,unsigned etm)187 static void server(int fd, const char *prio, unsigned etm)
188 {
189 	int ret;
190 	char buffer[MAX_BUF + 1];
191 	gnutls_session_t session;
192 	gnutls_anon_server_credentials_t anoncred;
193 	gnutls_certificate_credentials_t x509_cred;
194 	unsigned to_send = sizeof(buffer)/4;
195 
196 	/* this must be called once in the program
197 	 */
198 	global_init();
199 	memset(buffer, 0, sizeof(buffer));
200 
201 	if (debug) {
202 		gnutls_global_set_log_function(server_log_func);
203 		gnutls_global_set_log_level(4711);
204 	}
205 
206 	gnutls_certificate_allocate_credentials(&x509_cred);
207 	gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert,
208 					    &server_key,
209 					    GNUTLS_X509_FMT_PEM);
210 
211 	gnutls_anon_allocate_server_credentials(&anoncred);
212 
213 	gnutls_init(&session, GNUTLS_SERVER|GNUTLS_DATAGRAM);
214 
215 	/* avoid calling all the priority functions, since the defaults
216 	 * are adequate.
217 	 */
218 	assert(gnutls_priority_set_direct(session, prio, NULL) >= 0);
219 
220 	gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
221 	gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
222 
223 	gnutls_transport_set_int(session, fd);
224 
225 	do {
226 		ret = gnutls_handshake(session);
227 	} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
228 	if (ret < 0) {
229 		close(fd);
230 		gnutls_deinit(session);
231 		fail("server: Handshake has failed (%s)\n\n",
232 		     gnutls_strerror(ret));
233 		terminate();
234 	}
235 
236 	if (etm != 0 && gnutls_session_etm_status(session) == 0) {
237 		fail("server: EtM was not negotiated with %s!\n", prio);
238 		exit(1);
239 	} else if (etm == 0 && gnutls_session_etm_status(session) != 0) {
240 		fail("server: EtM was negotiated with %s!\n", prio);
241 		exit(1);
242 	}
243 
244 	if (etm != 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) == 0)) {
245 		fail("server: EtM was not negotiated with %s!\n", prio);
246 		exit(1);
247 	} else if (etm == 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) != 0)) {
248 		fail("server: EtM was negotiated with %s!\n", prio);
249 		exit(1);
250 	}
251 
252 	if (debug)
253 		success("server: Handshake was completed\n");
254 
255 	if (debug)
256 		success("server: TLS version is: %s\n",
257 			gnutls_protocol_get_name
258 			(gnutls_protocol_get_version(session)));
259 
260 	do {
261 		do {
262 			ret =
263 			    gnutls_record_send(session, buffer,
264 						sizeof(buffer));
265 		} while (ret == GNUTLS_E_AGAIN
266 			 || ret == GNUTLS_E_INTERRUPTED);
267 
268 		if (ret < 0) {
269 			fail("Error sending %d byte packet: %s\n", to_send,
270 			     gnutls_strerror(ret));
271 			terminate();
272 		}
273 		to_send++;
274 	}
275 	while (to_send < 64);
276 
277 	to_send = -1;
278 	/* do not wait for the peer to close the connection.
279 	 */
280 	gnutls_bye(session, GNUTLS_SHUT_WR);
281 
282 	close(fd);
283 	gnutls_deinit(session);
284 
285 	gnutls_anon_free_server_credentials(anoncred);
286 	gnutls_certificate_free_credentials(x509_cred);
287 
288 	gnutls_global_deinit();
289 
290 	if (debug)
291 		success("server: finished\n");
292 }
293 
start(const char * prio,unsigned etm)294 static void start(const char *prio, unsigned etm)
295 {
296 	int fd[2];
297 	int ret;
298 
299 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
300 	if (ret < 0) {
301 		perror("socketpair");
302 		exit(1);
303 	}
304 
305 	child = fork();
306 	if (child < 0) {
307 		perror("fork");
308 		fail("fork");
309 		exit(1);
310 	}
311 
312 	if (child) {
313 		/* parent */
314 		close(fd[1]);
315 		server(fd[0], prio, etm);
316 		kill(child, SIGTERM);
317 	} else {
318 		close(fd[0]);
319 		client(fd[1], prio, etm);
320 		exit(0);
321 	}
322 }
323 
324 #define AES_CBC "NONE:+VERS-DTLS1.0:-CIPHER-ALL:+AES-128-CBC:+SHA1:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
325 #define AES_CBC_SHA256 "NONE:+VERS-DTLS1.2:-CIPHER-ALL:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA256:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
326 #define AES_GCM "NONE:+VERS-DTLS1.2:-CIPHER-ALL:+RSA:+AES-128-GCM:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
327 
ch_handler(int sig)328 static void ch_handler(int sig)
329 {
330 	int status;
331 	wait(&status);
332 	check_wait_status(status);
333 	return;
334 }
335 
doit(void)336 void doit(void)
337 {
338 	signal(SIGCHLD, ch_handler);
339 
340 	start(AES_CBC, 1);
341 	start(AES_CBC_SHA256, 1);
342 	start(AES_GCM, 0);
343 }
344 
345 #endif				/* _WIN32 */
346