remove p11-kit in gnutls.spec file
[platform/upstream/gnutls.git] / tests / resume-dtls.c
1 /*
2  * Copyright (C) 2004-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2013 Adam Sampson <ats@offog.org>
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * GnuTLS is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * GnuTLS is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with GnuTLS; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 /* Parts copied from GnuTLS example programs. */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #if defined(_WIN32)
34
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 #endif
48 #include <unistd.h>
49 #include <gnutls/gnutls.h>
50
51 #include "utils.h"
52
53 static void wrap_db_init(void);
54 static void wrap_db_deinit(void);
55 static int wrap_db_store(void *dbf, gnutls_datum_t key,
56                          gnutls_datum_t data);
57 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key);
58 static int wrap_db_delete(void *dbf, gnutls_datum_t key);
59
60 #define TLS_SESSION_CACHE 50
61
62 struct params_res {
63         const char *desc;
64         int enable_db;
65         int enable_session_ticket_server;
66         int enable_session_ticket_client;
67         int expect_resume;
68 };
69
70 pid_t child;
71
72 struct params_res resume_tests[] = {
73         {"try to resume from db", 50, 0, 0, 1},
74         {"try to resume from session ticket", 0, 1, 1, 1},
75         {"try to resume from session ticket (server only)", 0, 1, 0, 0},
76         {"try to resume from session ticket (client only)", 0, 0, 1, 0},
77         {NULL, -1}
78 };
79
80 /* A very basic TLS client, with anonymous authentication.
81  */
82
83 #define SESSIONS 2
84 #define MAX_BUF 5*1024
85 #define MSG "Hello TLS"
86
87 static void tls_log_func(int level, const char *str)
88 {
89         fprintf(stderr, "%s |<%d>| %s", child ? "server" : "client", level,
90                 str);
91 }
92
93 static void client(int sds[], struct params_res *params)
94 {
95         int ret, ii;
96         gnutls_session_t session;
97         char buffer[MAX_BUF + 1];
98         gnutls_anon_client_credentials_t anoncred;
99         /* Need to enable anonymous KX specifically. */
100
101         /* variables used in session resuming
102          */
103         int t;
104         gnutls_datum_t session_data;
105
106         if (debug) {
107                 gnutls_global_set_log_function(tls_log_func);
108                 gnutls_global_set_log_level(3);
109         }
110         global_init();
111
112         gnutls_anon_allocate_client_credentials(&anoncred);
113
114         for (t = 0; t < SESSIONS; t++) {
115                 int sd = sds[t];
116
117                 /* Initialize TLS session
118                  */
119                 gnutls_init(&session,
120                             GNUTLS_CLIENT | GNUTLS_DATAGRAM |
121                             GNUTLS_NO_EXTENSIONS);
122
123                 /* Use default priorities */
124                 gnutls_priority_set_direct(session,
125                                            "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH",
126                                            NULL);
127
128                 /* put the anonymous credentials to the current session
129                  */
130                 gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
131
132                 if (params->enable_session_ticket_client)
133                         gnutls_session_ticket_enable_client(session);
134
135                 if (t > 0) {
136                         /* if this is not the first time we connect */
137                         gnutls_session_set_data(session, session_data.data,
138                                                 session_data.size);
139                         gnutls_free(session_data.data);
140                 }
141
142                 gnutls_transport_set_int(session, sd);
143
144                 /* Perform the TLS handshake
145                  */
146                 gnutls_handshake_set_timeout(session, 20 * 1000);
147                 do {
148                         ret = gnutls_handshake(session);
149                 } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
150
151                 if (ret < 0) {
152                         gnutls_perror(ret);
153                         fail("client: Handshake failed\n");
154                         goto end;
155                 } else {
156                         if (debug)
157                                 success
158                                     ("client: Handshake was completed\n");
159                 }
160
161                 if (t == 0) {   /* the first time we connect */
162                         /* get the session data size */
163                         ret =
164                             gnutls_session_get_data2(session,
165                                                      &session_data);
166                         if (ret < 0)
167                                 fail("Getting resume data failed\n");
168                 } else {        /* the second time we connect */
169
170                         /* check if we actually resumed the previous session */
171                         if (gnutls_session_is_resumed(session) != 0) {
172                                 if (params->expect_resume) {
173                                         if (debug)
174                                                 success
175                                                     ("- Previous session was resumed\n");
176                                 } else
177                                         fail("- Previous session was resumed\n");
178                         } else {
179                                 if (params->expect_resume) {
180                                         fail("*** Previous session was NOT resumed\n");
181                                 } else {
182                                         if (debug)
183                                                 success
184                                                     ("*** Previous session was NOT resumed (expected)\n");
185                                 }
186                         }
187                 }
188
189                 gnutls_record_send(session, MSG, strlen(MSG));
190
191                 ret = gnutls_record_recv(session, buffer, MAX_BUF);
192                 if (ret == 0) {
193                         if (debug)
194                                 success
195                                     ("client: Peer has closed the TLS connection\n");
196                         goto end;
197                 } else if (ret < 0) {
198                         fail("client: Error: %s\n", gnutls_strerror(ret));
199                         goto end;
200                 }
201
202                 if (debug) {
203                         printf("- Received %d bytes: ", ret);
204                         for (ii = 0; ii < ret; ii++) {
205                                 fputc(buffer[ii], stdout);
206                         }
207                         fputs("\n", stdout);
208                 }
209
210                 gnutls_bye(session, GNUTLS_SHUT_RDWR);
211
212                 close(sd);
213
214                 gnutls_deinit(session);
215         }
216
217       end:
218         gnutls_anon_free_client_credentials(anoncred);
219 }
220
221 /* This is a sample TLS 1.0 echo server, for anonymous authentication only.
222  */
223
224 #define DH_BITS 1024
225
226 /* These are global */
227 gnutls_anon_server_credentials_t anoncred;
228 static gnutls_datum_t session_ticket_key = { NULL, 0 };
229
230 static gnutls_session_t initialize_tls_session(struct params_res *params)
231 {
232         gnutls_session_t session;
233
234         gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
235
236         /* avoid calling all the priority functions, since the defaults
237          * are adequate.
238          */
239         gnutls_priority_set_direct(session,
240                                    "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-DH",
241                                    NULL);
242
243         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
244
245         gnutls_dh_set_prime_bits(session, DH_BITS);
246
247         if (params->enable_db) {
248                 gnutls_db_set_retrieve_function(session, wrap_db_fetch);
249                 gnutls_db_set_remove_function(session, wrap_db_delete);
250                 gnutls_db_set_store_function(session, wrap_db_store);
251                 gnutls_db_set_ptr(session, NULL);
252         }
253
254         if (params->enable_session_ticket_server)
255                 gnutls_session_ticket_enable_server(session,
256                                                     &session_ticket_key);
257
258         return session;
259 }
260
261 static gnutls_dh_params_t dh_params;
262
263 static int generate_dh_params(void)
264 {
265         const gnutls_datum_t p3 = { (void *) pkcs3, strlen(pkcs3) };
266         /* Generate Diffie-Hellman parameters - for use with DHE
267          * kx algorithms. These should be discarded and regenerated
268          * once a day, once a week or once a month. Depending on the
269          * security requirements.
270          */
271         gnutls_dh_params_init(&dh_params);
272         return gnutls_dh_params_import_pkcs3(dh_params, &p3,
273                                              GNUTLS_X509_FMT_PEM);
274 }
275
276 int err, ret;
277 char topbuf[512];
278 gnutls_session_t session;
279 char buffer[MAX_BUF + 1];
280 int optval = 1;
281
282 static void global_stop(void)
283 {
284         if (debug)
285                 success("global stop\n");
286
287         gnutls_anon_free_server_credentials(anoncred);
288
289         gnutls_dh_params_deinit(dh_params);
290
291         gnutls_global_deinit();
292 }
293
294 static void server(int sds[], struct params_res *params)
295 {
296         size_t t;
297
298         /* this must be called once in the program, it is mostly for the server.
299          */
300         if (debug) {
301                 gnutls_global_set_log_function(tls_log_func);
302                 gnutls_global_set_log_level(3);
303         }
304
305         global_init();
306         gnutls_anon_allocate_server_credentials(&anoncred);
307
308         if (debug)
309                 success("Launched, generating DH parameters...\n");
310
311         generate_dh_params();
312
313         gnutls_anon_set_server_dh_params(anoncred, dh_params);
314
315         if (params->enable_db) {
316                 wrap_db_init();
317         }
318
319         if (params->enable_session_ticket_server)
320                 gnutls_session_ticket_key_generate(&session_ticket_key);
321
322         for (t = 0; t < SESSIONS; t++) {
323                 int sd = sds[t];
324
325                 session = initialize_tls_session(params);
326
327                 gnutls_transport_set_int(session, sd);
328                 gnutls_handshake_set_timeout(session, 20 * 1000);
329                 
330                 do {
331                         ret = gnutls_handshake(session);
332                 } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
333                 if (ret < 0) {
334                         close(sd);
335                         gnutls_deinit(session);
336                         kill(child, SIGTERM);
337                         fail("server: Handshake has failed (%s)\n\n",
338                              gnutls_strerror(ret));
339                         return;
340                 }
341                 if (debug)
342                         success("server: Handshake was completed\n");
343
344                 /* see the Getting peer's information example */
345                 /* print_info(session); */
346
347                 for (;;) {
348                         memset(buffer, 0, MAX_BUF + 1);
349                         ret = gnutls_record_recv(session, buffer, MAX_BUF);
350
351                         if (ret == 0) {
352                                 if (debug)
353                                         success
354                                             ("server: Peer has closed the GnuTLS connection\n");
355                                 break;
356                         } else if (ret < 0) {
357                                 kill(child, SIGTERM);
358                                 fail("server: Received corrupted data(%d). Closing...\n", ret);
359                                 break;
360                         } else if (ret > 0) {
361                                 /* echo data back to the client
362                                  */
363                                 gnutls_record_send(session, buffer,
364                                                    strlen(buffer));
365                         }
366                 }
367                 /* do not wait for the peer to close the connection.
368                  */
369                 gnutls_bye(session, GNUTLS_SHUT_WR);
370
371                 close(sd);
372
373                 gnutls_deinit(session);
374         }
375
376         if (params->enable_db) {
377                 wrap_db_deinit();
378         }
379
380         gnutls_free(session_ticket_key.data);
381         session_ticket_key.data = NULL;
382
383         if (debug)
384                 success("server: finished\n");
385 }
386
387 void doit(void)
388 {
389         int i;
390
391         for (i = 0; resume_tests[i].desc; i++) {
392                 int client_sds[SESSIONS], server_sds[SESSIONS];
393                 int j;
394
395                 printf("%s\n", resume_tests[i].desc);
396
397                 for (j = 0; j < SESSIONS; j++) {
398                         int sockets[2];
399
400                         err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
401                         if (err == -1) {
402                                 perror("socketpair");
403                                 fail("socketpair failed\n");
404                                 return;
405                         }
406
407                         server_sds[j] = sockets[0];
408                         client_sds[j] = sockets[1];
409                 }
410
411                 child = fork();
412                 if (child < 0) {
413                         perror("fork");
414                         fail("fork");
415                         return;
416                 }
417
418                 if (child) {
419                         int status;
420                         /* parent */
421                         server(server_sds, &resume_tests[i]);
422                         wait(&status);
423                         if (WEXITSTATUS(status) > 0)
424                                 error_count++;
425                         global_stop();
426
427                         if (error_count)
428                                 exit(1);
429
430                 } else {
431                         client(client_sds, &resume_tests[i]);
432                         gnutls_global_deinit();
433                         if (error_count)
434                                 exit(1);
435                         exit(0);
436                 }
437         }
438 }
439
440 /* Functions and other stuff needed for session resuming.
441  * This is done using a very simple list which holds session ids
442  * and session data.
443  */
444
445 #define MAX_SESSION_ID_SIZE 32
446 #define MAX_SESSION_DATA_SIZE 1024
447
448 typedef struct {
449         unsigned char session_id[MAX_SESSION_ID_SIZE];
450         unsigned int session_id_size;
451
452         char session_data[MAX_SESSION_DATA_SIZE];
453         int session_data_size;
454 } CACHE;
455
456 static CACHE *cache_db;
457 static int cache_db_ptr = 0;
458
459 static void wrap_db_init(void)
460 {
461
462         /* allocate cache_db */
463         cache_db = calloc(1, TLS_SESSION_CACHE * sizeof(CACHE));
464 }
465
466 static void wrap_db_deinit(void)
467 {
468         free(cache_db);
469         cache_db = NULL;
470         return;
471 }
472
473 static int
474 wrap_db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
475 {
476         if (debug)
477                 success("resume db storing... (%d-%d)\n", key.size,
478                         data.size);
479
480         if (debug) {
481                 unsigned int i;
482                 printf("key:\n");
483                 for (i = 0; i < key.size; i++) {
484                         printf("%02x ", key.data[i] & 0xFF);
485                         if ((i + 1) % 16 == 0)
486                                 printf("\n");
487                 }
488                 printf("\n");
489                 printf("data:\n");
490                 for (i = 0; i < data.size; i++) {
491                         printf("%02x ", data.data[i] & 0xFF);
492                         if ((i + 1) % 16 == 0)
493                                 printf("\n");
494                 }
495                 printf("\n");
496         }
497
498         if (cache_db == NULL)
499                 return -1;
500
501         if (key.size > MAX_SESSION_ID_SIZE)
502                 return -1;
503
504         if (data.size > MAX_SESSION_DATA_SIZE)
505                 return -1;
506
507         memcpy(cache_db[cache_db_ptr].session_id, key.data, key.size);
508         cache_db[cache_db_ptr].session_id_size = key.size;
509
510         memcpy(cache_db[cache_db_ptr].session_data, data.data, data.size);
511         cache_db[cache_db_ptr].session_data_size = data.size;
512
513         cache_db_ptr++;
514         cache_db_ptr %= TLS_SESSION_CACHE;
515
516         return 0;
517 }
518
519 static gnutls_datum_t wrap_db_fetch(void *dbf, gnutls_datum_t key)
520 {
521         gnutls_datum_t res = { NULL, 0 };
522         int i;
523
524         if (debug)
525                 success("resume db fetch... (%d)\n", key.size);
526         if (debug) {
527                 unsigned int i;
528                 printf("key:\n");
529                 for (i = 0; i < key.size; i++) {
530                         printf("%02x ", key.data[i] & 0xFF);
531                         if ((i + 1) % 16 == 0)
532                                 printf("\n");
533                 }
534                 printf("\n");
535         }
536
537         if (cache_db == NULL)
538                 return res;
539
540         for (i = 0; i < TLS_SESSION_CACHE; i++) {
541                 if (key.size == cache_db[i].session_id_size &&
542                     memcmp(key.data, cache_db[i].session_id,
543                            key.size) == 0) {
544                         if (debug)
545                                 success
546                                     ("resume db fetch... return info\n");
547
548                         res.size = cache_db[i].session_data_size;
549
550                         res.data = gnutls_malloc(res.size);
551                         if (res.data == NULL)
552                                 return res;
553
554                         memcpy(res.data, cache_db[i].session_data,
555                                res.size);
556
557                         if (debug) {
558                                 unsigned int i;
559                                 printf("data:\n");
560                                 for (i = 0; i < res.size; i++) {
561                                         printf("%02x ",
562                                                res.data[i] & 0xFF);
563                                         if ((i + 1) % 16 == 0)
564                                                 printf("\n");
565                                 }
566                                 printf("\n");
567                         }
568
569                         return res;
570                 }
571         }
572
573         if (debug)
574                 success("resume db fetch... NOT FOUND\n");
575         return res;
576 }
577
578 static int wrap_db_delete(void *dbf, gnutls_datum_t key)
579 {
580         int i;
581
582         if (cache_db == NULL)
583                 return -1;
584
585         for (i = 0; i < TLS_SESSION_CACHE; i++) {
586                 if (key.size == cache_db[i].session_id_size &&
587                     memcmp(key.data, cache_db[i].session_id,
588                            key.size) == 0) {
589
590                         cache_db[i].session_id_size = 0;
591                         cache_db[i].session_data_size = 0;
592
593                         return 0;
594                 }
595         }
596
597         return -1;
598
599 }
600
601 #endif                          /* _WIN32 */