Merge branch 'upstream' into tizen
[platform/upstream/gnutls.git] / tests / mini-dtls-fork.c
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 #include <stdint.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <gnutls/gnutls.h>
33 #include <gnutls/dtls.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #ifndef _WIN32
37 # include <netinet/in.h>
38 # include <sys/types.h>
39 # include <sys/socket.h>
40 # include <sys/wait.h>
41 #endif
42 #include "utils.h"
43
44 #ifdef _WIN32
45
46 void doit(void)
47 {
48         exit(77);
49 }
50
51 #else
52
53 /* These are global */
54 pid_t child;
55
56 static void terminate(void)
57 {
58         int status;
59
60         kill(child, SIGTERM);
61         wait(&status);
62         exit(1);
63 }
64
65 /* Tests whether we can send and receive from different processes
66  * using DTLS, either as server or client. DTLS is a superset of
67  * TLS, so correct behavior under fork means TLS would operate too.
68  */
69
70 const char *side = "";
71
72 static void tls_log_func(int level, const char *str)
73 {
74         fprintf(stderr, "%s|<%d>| %s", side, level, str);
75 }
76
77 static unsigned char server_cert_pem[] =
78   "-----BEGIN CERTIFICATE-----\n"
79   "MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\n"
80   "A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\n"
81   "MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\n"
82   "A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\n"
83   "CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\n"
84   "2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\n"
85   "BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\n"
86   "PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\n"
87   "clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\n"
88   "CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\n"
89   "C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\n"
90   "fGa5kHvHARBPc8YAIVIqDvHH1Q==\n"
91   "-----END CERTIFICATE-----\n";
92
93 const gnutls_datum_t server_cert = { server_cert_pem,
94         sizeof(server_cert_pem)
95 };
96
97 static unsigned char server_key_pem[] =
98   "-----BEGIN EC PRIVATE KEY-----\n"
99   "MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\n"
100   "AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\n"
101   "6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\n"
102   "-----END EC PRIVATE KEY-----\n";
103
104 const gnutls_datum_t server_key = { server_key_pem,
105         sizeof(server_key_pem)
106 };
107
108 #define MSG "hello1111"
109 #define MSG2 "xxxxxxxxxxxx"
110
111 static
112 void do_fork_stuff(gnutls_session_t session)
113 {
114         pid_t pid;
115         int ret;
116         char buf[64];
117
118         /* separate sending from receiving */
119         pid = fork();
120         if (pid == -1) {
121                 exit(1);
122         } else if (pid != 0) {
123                 if (debug)
124                         success("client: TLS version is: %s\n",
125                                 gnutls_protocol_get_name
126                                 (gnutls_protocol_get_version(session)));
127                 sec_sleep(1);
128                 /* the server should reflect our messages */
129                 ret = gnutls_record_recv(session, buf, sizeof(buf));
130                 if (ret != sizeof(MSG)-1 || memcmp(buf, MSG, sizeof(MSG)-1) != 0) {
131                         fail("client: recv failed: %s\n", gnutls_strerror(ret));
132                         exit(1);
133                 }
134
135                 if (debug) {
136                         fprintf(stderr, "client received: %.*s\n", ret, buf);
137                 }
138
139                 ret = gnutls_record_recv(session, buf, sizeof(buf));
140                 if (ret != sizeof(MSG2)-1 || memcmp(buf, MSG2, sizeof(MSG2)-1) != 0) {
141                         fail("client: recv2 failed: %s\n", gnutls_strerror(ret));
142                         exit(1);
143                 }
144
145                 if (debug) {
146                         fprintf(stderr, "client received: %.*s\n", ret, buf);
147                 }
148
149                 ret = gnutls_record_recv(session, buf, sizeof(buf));
150                 if (ret != 0) {
151                         fail("client: recv3 failed: %s\n", gnutls_strerror(ret));
152                         exit(1);
153                 }
154         } else if (pid == 0) { /* child */
155                 ret = gnutls_record_send(session, MSG, sizeof(MSG)-1);
156                 if (ret != sizeof(MSG)-1) {
157                         fail("client: send failed: %s\n", gnutls_strerror(ret));
158                         exit(1);
159                 }
160
161                 ret = gnutls_record_send(session, MSG2, sizeof(MSG2)-1);
162                 if (ret != sizeof(MSG2)-1) {
163                         fail("client: send2 failed: %s\n", gnutls_strerror(ret));
164                         exit(1);
165                 }
166                 sec_sleep(2);
167                 gnutls_bye(session, GNUTLS_SHUT_WR);
168         }
169 }
170
171 static void do_reflect_stuff(gnutls_session_t session)
172 {
173         char buf[64];
174         unsigned buf_size;
175         int ret;
176
177         do {
178                 ret = gnutls_record_recv(session, buf, sizeof(buf));
179                 if (ret < 0) {
180                         fail("server: recv failed: %s\n", gnutls_strerror(ret));
181                         terminate();
182                 }
183
184                 if (ret == 0)
185                         break;
186
187                 buf_size = ret;
188                 if (debug) {
189                         fprintf(stderr, "server received: %.*s\n", buf_size, buf);
190                 }
191
192                 ret = gnutls_record_send(session, buf, buf_size);
193                 if (ret < 0) {
194                         fail("server: send failed: %s\n", gnutls_strerror(ret));
195                         terminate();
196                 }
197         } while(1);
198
199         /* do not wait for the peer to close the connection.
200          */
201         gnutls_bye(session, GNUTLS_SHUT_WR);
202 }
203
204 static void client(int fd, unsigned do_fork)
205 {
206         int ret;
207         gnutls_certificate_credentials_t x509_cred;
208         gnutls_session_t session;
209         /* Need to enable anonymous KX specifically. */
210
211         global_init();
212
213         if (debug) {
214                 side = "client";
215                 gnutls_global_set_log_function(tls_log_func);
216                 gnutls_global_set_log_level(4711);
217         }
218
219         gnutls_certificate_allocate_credentials(&x509_cred);
220
221         /* Initialize TLS session
222          */
223         gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
224         gnutls_dtls_set_mtu(session, 1500);
225         gnutls_dtls_set_timeouts(session, 6 * 1000, 60 * 1000);
226         //gnutls_transport_set_push_function(session, push);
227
228         /* Use default priorities */
229         gnutls_priority_set_direct(session,
230                                    "NONE:+VERS-DTLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ECDHE-ECDSA:+CURVE-ALL",
231                                    NULL);
232
233         /* put the anonymous credentials to the current session
234          */
235         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
236
237         gnutls_transport_set_int(session, fd);
238
239         /* Perform the TLS handshake
240          */
241         do {
242                 ret = gnutls_handshake(session);
243         }
244         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
245
246         if (ret < 0) {
247                 fail("client: Handshake failed\n");
248                 gnutls_perror(ret);
249                 exit(1);
250         } else {
251                 if (debug)
252                         success("client: Handshake was completed\n");
253         }
254
255         if (do_fork)
256                 do_fork_stuff(session);
257         else
258                 do_reflect_stuff(session);
259
260         close(fd);
261
262         gnutls_deinit(session);
263
264         gnutls_certificate_free_credentials(x509_cred);
265
266         gnutls_global_deinit();
267         exit(0);
268 }
269
270
271 static void server(int fd, unsigned do_fork)
272 {
273         int ret;
274         gnutls_certificate_credentials_t x509_cred;
275         gnutls_session_t session;
276
277         /* this must be called once in the program
278          */
279         global_init();
280
281 #if 0
282         if (debug) {
283                 side = "server";
284                 gnutls_global_set_log_function(tls_log_func);
285                 gnutls_global_set_log_level(4711);
286         }
287 #endif
288
289         gnutls_certificate_allocate_credentials(&x509_cred);
290         gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert,
291                                             &server_key,
292                                             GNUTLS_X509_FMT_PEM);
293
294         gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
295         gnutls_dtls_set_timeouts(session, 5 * 1000, 60 * 1000);
296         gnutls_dtls_set_mtu(session, 400);
297
298         /* avoid calling all the priority functions, since the defaults
299          * are adequate.
300          */
301         gnutls_priority_set_direct(session,
302                                    "NONE:+VERS-DTLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ECDHE-ECDSA:+CURVE-ALL",
303                                    NULL);
304
305         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
306
307         gnutls_transport_set_int(session, fd);
308
309         do {
310                 ret = gnutls_handshake(session);
311         } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
312         if (ret < 0) {
313                 close(fd);
314                 gnutls_deinit(session);
315                 fail("server: Handshake has failed (%s)\n\n",
316                      gnutls_strerror(ret));
317                 terminate();
318         }
319         if (debug)
320                 success("server: Handshake was completed\n");
321
322         if (debug)
323                 success("server: TLS version is: %s\n",
324                         gnutls_protocol_get_name
325                         (gnutls_protocol_get_version(session)));
326
327         if (do_fork)
328                 do_fork_stuff(session);
329         else
330                 do_reflect_stuff(session);
331
332
333         close(fd);
334         gnutls_deinit(session);
335
336         gnutls_certificate_free_credentials(x509_cred);
337
338         gnutls_global_deinit();
339
340         if (debug)
341                 success("server: finished\n");
342 }
343
344 static
345 void run(unsigned do_fork)
346 {
347         int fd[2];
348         int ret;
349
350         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
351         if (ret < 0) {
352                 perror("socketpair");
353                 exit(1);
354         }
355
356         child = fork();
357         if (child < 0) {
358                 perror("fork");
359                 fail("fork");
360                 exit(1);
361         }
362
363         if (child) {
364                 int status;
365                 /* parent */
366
367                 close(fd[1]);
368                 client(fd[0], do_fork);
369                 wait(&status);
370                 if (WEXITSTATUS(status) != 0)
371                         fail("Child died with status %d\n",
372                              WEXITSTATUS(status));
373         } else {
374                 close(fd[0]);
375                 server(fd[1], 1-do_fork);
376                 exit(0);
377         }
378 }
379
380 void doit(void)
381 {
382         signal(SIGPIPE, SIG_IGN);
383         run(0);
384         run(1);
385 }
386 #endif                          /* _WIN32 */