Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / tests / mini-handshake-timeout.c
1 /*
2  * Copyright (C) 2012 Free Software Foundation, 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 <string.h>
30
31 #if defined(_WIN32)
32
33 int main()
34 {
35         exit(77);
36 }
37
38 #else
39
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
50 #include "utils.h"
51
52 /* This program tests whether the handshake timeout value is enforced.
53  */
54
55 static void server_log_func(int level, const char *str)
56 {
57         fprintf(stderr, "server|<%d>| %s", level, str);
58 }
59
60 static void client_log_func(int level, const char *str)
61 {
62         fprintf(stderr, "client|<%d>| %s", level, str);
63 }
64
65 /* A very basic TLS client, with anonymous authentication.
66  */
67
68 static void client(int fd, int wait)
69 {
70         int ret;
71         gnutls_anon_client_credentials_t anoncred;
72         gnutls_session_t session;
73         /* Need to enable anonymous KX specifically. */
74
75         global_init();
76
77         if (debug) {
78                 gnutls_global_set_log_function(client_log_func);
79                 gnutls_global_set_log_level(4711);
80         }
81
82         gnutls_anon_allocate_client_credentials(&anoncred);
83
84         /* Initialize TLS session
85          */
86         gnutls_init(&session, GNUTLS_CLIENT);
87         gnutls_handshake_set_timeout(session, 20 * 1000);
88
89         /* Use default priorities */
90         gnutls_priority_set_direct(session, "NORMAL:+ANON-ECDH", NULL);
91
92         /* put the anonymous credentials to the current session
93          */
94         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
95
96         gnutls_transport_set_int(session, fd);
97
98         /* Perform the TLS handshake
99          */
100         do {
101                 ret = gnutls_handshake(session);
102         }
103         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
104
105         gnutls_deinit(session);
106         gnutls_anon_free_client_credentials(anoncred);
107         gnutls_global_deinit();
108
109         if (ret < 0) {
110                 if (ret != GNUTLS_E_TIMEDOUT || wait == 0) {
111                         if (debug)
112                                 fail("client: unexpected error: %s\n",
113                                      gnutls_strerror(ret));
114                         exit(1);
115                 }
116                 if (debug)
117                         success("client: expected timeout occured\n");
118                 return;
119         } else {
120                 if (wait != 0) {
121                         fail("client: handshake was completed unexpectedly\n");
122                         gnutls_perror(ret);
123                         exit(1);
124                 }
125         }
126
127         return;
128 }
129
130 static void initialize_tls_session(gnutls_session_t * session)
131 {
132         gnutls_init(session, GNUTLS_SERVER);
133
134         /* avoid calling all the priority functions, since the defaults
135          * are adequate.
136          */
137         gnutls_priority_set_direct(*session, "NORMAL:+ANON-ECDH", NULL);
138 }
139
140 static void server(int fd, int wait)
141 {
142         int ret;
143         gnutls_session_t session;
144         gnutls_anon_server_credentials_t anoncred;
145
146         /* this must be called once in the program
147          */
148         global_init();
149
150         if (debug) {
151                 gnutls_global_set_log_function(server_log_func);
152                 gnutls_global_set_log_level(4711);
153         }
154
155         gnutls_anon_allocate_server_credentials(&anoncred);
156
157         initialize_tls_session(&session);
158         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
159
160         gnutls_transport_set_int(session, fd);
161
162         if (wait) {
163                 sec_sleep(25);
164         } else {
165                 do {
166                         ret = gnutls_handshake(session);
167                 }
168                 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
169
170                 if (ret == 0)
171                         gnutls_bye(session, GNUTLS_SHUT_RDWR);
172         }
173
174         gnutls_deinit(session);
175         gnutls_anon_free_server_credentials(anoncred);
176         gnutls_global_deinit();
177 }
178
179 static void start(int wait)
180 {
181         int fd[2];
182         int ret;
183         pid_t child;
184
185         if (debug && wait)
186                 fprintf(stderr, "\nWill test timeout\n");
187
188         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
189         if (ret < 0) {
190                 perror("socketpair");
191                 exit(1);
192         }
193
194         child = fork();
195         if (child < 0) {
196                 perror("fork");
197                 fail("fork");
198                 exit(1);
199         }
200
201         if (child) {
202                 /* parent */
203                 close(fd[1]);
204                 server(fd[0], wait);
205                 close(fd[0]);
206         } else {
207                 close(fd[0]);
208                 client(fd[1], wait);
209                 close(fd[1]);
210                 exit(0);
211         }
212 }
213
214 static void ch_handler(int sig)
215 {
216         int status = 0;
217         wait(&status);
218         if (WEXITSTATUS(status) != 0)
219                 fail("Child died with status %d\n", WEXITSTATUS(status));
220         return;
221 }
222
223 void doit(void)
224 {
225         signal(SIGCHLD, ch_handler);
226         signal(SIGPIPE, SIG_IGN);
227
228         /* make sure that normal handshake occurs */
229         start(0);
230
231         /* check the handshake with an expected timeout */
232         start(1);
233 }
234
235 #endif                          /* _WIN32 */