2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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.
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.
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
40 #include <sys/types.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
44 #include <arpa/inet.h>
46 #include <gnutls/gnutls.h>
47 #include <gnutls/dtls.h>
51 static void terminate(void);
53 /* This program tests the rehandshake in DTLS
56 static void server_log_func(int level, const char *str)
58 fprintf(stderr, "server|<%d>| %s", level, str);
61 static void client_log_func(int level, const char *str)
63 fprintf(stderr, "client|<%d>| %s", level, str);
66 /* A very basic TLS client, with anonymous authentication.
70 #define MSG "Hello TLS"
72 gnutls_session_t session;
75 push(gnutls_transport_ptr_t tr, const void *data, size_t len)
77 int fd = (long int) tr;
79 return send(fd, data, len, 0);
82 static void client(int fd, int server_init)
85 char buffer[MAX_BUF + 1];
86 gnutls_anon_client_credentials_t anoncred;
87 /* Need to enable anonymous KX specifically. */
92 gnutls_global_set_log_function(client_log_func);
93 gnutls_global_set_log_level(4711);
96 gnutls_anon_allocate_client_credentials(&anoncred);
98 /* Initialize TLS session
100 gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
101 gnutls_dtls_set_mtu(session, 1500);
103 /* Use default priorities */
104 gnutls_priority_set_direct(session,
105 "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
108 /* put the anonymous credentials to the current session
110 gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
112 gnutls_transport_set_int(session, fd);
113 gnutls_transport_set_push_function(session, push);
115 /* Perform the TLS handshake
118 ret = gnutls_handshake(session);
120 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
123 fail("client: Handshake failed\n");
128 success("client: Handshake was completed\n");
132 success("client: TLS version is: %s\n",
133 gnutls_protocol_get_name
134 (gnutls_protocol_get_version(session)));
139 success("Initiating client rehandshake\n");
141 ret = gnutls_handshake(session);
143 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
146 fail("2nd client gnutls_handshake: %s\n",
147 gnutls_strerror(ret));
152 ret = gnutls_record_recv(session, buffer, MAX_BUF);
153 } while (ret == GNUTLS_E_AGAIN
154 || ret == GNUTLS_E_INTERRUPTED);
160 ("client: Peer has closed the TLS connection\n");
162 } else if (ret < 0) {
163 if (server_init && ret == GNUTLS_E_REHANDSHAKE) {
166 ("Initiating rehandshake due to server request\n");
168 ret = gnutls_handshake(session);
170 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
174 fail("client: Error: %s\n", gnutls_strerror(ret));
180 ret = gnutls_record_send(session, MSG, strlen(MSG));
181 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
182 gnutls_bye(session, GNUTLS_SHUT_WR);
188 gnutls_deinit(session);
190 gnutls_anon_free_client_credentials(anoncred);
192 gnutls_global_deinit();
196 /* These are global */
197 gnutls_anon_server_credentials_t anoncred;
200 static gnutls_session_t initialize_tls_session(void)
202 gnutls_session_t session;
204 gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
205 gnutls_dtls_set_mtu(session, 1500);
207 /* avoid calling all the priority functions, since the defaults
210 gnutls_priority_set_direct(session,
211 "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
214 gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
219 static void terminate(void)
223 kill(child, SIGTERM);
228 static void server(int fd, int server_init)
231 char buffer[MAX_BUF + 1];
232 /* this must be called once in the program
237 gnutls_global_set_log_function(server_log_func);
238 gnutls_global_set_log_level(4711);
241 gnutls_anon_allocate_server_credentials(&anoncred);
243 session = initialize_tls_session();
245 gnutls_transport_set_int(session, fd);
246 gnutls_transport_set_push_function(session, push);
249 ret = gnutls_handshake(session);
251 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
254 gnutls_deinit(session);
255 fail("server: Handshake has failed (%s)\n\n",
256 gnutls_strerror(ret));
260 success("server: Handshake was completed\n");
263 success("server: TLS version is: %s\n",
264 gnutls_protocol_get_name
265 (gnutls_protocol_get_version(session)));
267 /* see the Getting peer's information example */
268 /* print_info(session); */
272 success("server: Sending dummy packet\n");
273 ret = gnutls_rehandshake(session);
275 fail("gnutls_rehandshake: %s\n",
276 gnutls_strerror(ret));
281 success("server: Initiating rehandshake\n");
283 ret = gnutls_handshake(session);
285 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
288 fail("server: 2nd gnutls_handshake: %s\n",
289 gnutls_strerror(ret));
295 memset(buffer, 0, MAX_BUF + 1);
298 ret = gnutls_record_recv(session, buffer, MAX_BUF);
299 } while (ret == GNUTLS_E_AGAIN
300 || ret == GNUTLS_E_INTERRUPTED);
305 ("server: Peer has closed the GnuTLS connection\n");
307 } else if (ret < 0) {
308 if (!server_init && ret == GNUTLS_E_REHANDSHAKE) {
311 ("Initiating rehandshake due to client request\n");
313 ret = gnutls_handshake(session);
316 && gnutls_error_is_fatal(ret) == 0);
321 fail("server: Received corrupted data(%s). Closing...\n", gnutls_strerror(ret));
323 } else if (ret > 0) {
324 /* echo data back to the client
328 gnutls_record_send(session, buffer,
330 } while (ret == GNUTLS_E_AGAIN
331 || ret == GNUTLS_E_INTERRUPTED);
336 /* do not wait for the peer to close the connection.
338 gnutls_bye(session, GNUTLS_SHUT_WR);
341 gnutls_deinit(session);
343 gnutls_anon_free_server_credentials(anoncred);
345 gnutls_global_deinit();
348 success("server: finished\n");
351 static void start(int server_initiated)
356 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
358 perror("socketpair");
373 server(fd[0], server_initiated);
375 if (WEXITSTATUS(status) != 0)
376 fail("Child died with status %d\n",
377 WEXITSTATUS(status));
380 client(fd[1], server_initiated);