Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / tests / mini-dtls-hello-verify.c
1 /*
2  * Copyright (C) 2013 Nikos Mavrogiannopoulos
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
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
49 #include "utils.h"
50
51 static void terminate(void);
52
53 /* This program tests the client hello verify in DTLS
54  */
55
56 static void server_log_func(int level, const char *str)
57 {
58         fprintf(stderr, "server|<%d>| %s", level, str);
59 }
60
61 static void client_log_func(int level, const char *str)
62 {
63         fprintf(stderr, "client|<%d>| %s", level, str);
64 }
65
66 /* A very basic TLS client, with anonymous authentication.
67  */
68
69 #define MAX_BUF 1024
70
71 static ssize_t
72 push(gnutls_transport_ptr_t tr, const void *data, size_t len)
73 {
74         int fd = (long int) tr;
75
76         return send(fd, data, len, 0);
77 }
78
79 static void client(int fd)
80 {
81         int ret;
82         char buffer[MAX_BUF + 1];
83         gnutls_anon_client_credentials_t anoncred;
84         gnutls_session_t session;
85         /* Need to enable anonymous KX specifically. */
86
87         global_init();
88
89         if (debug) {
90                 gnutls_global_set_log_function(client_log_func);
91                 gnutls_global_set_log_level(4711);
92         }
93
94         gnutls_anon_allocate_client_credentials(&anoncred);
95
96         /* Initialize TLS session
97          */
98         gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
99         gnutls_dtls_set_mtu(session, 1500);
100         gnutls_handshake_set_timeout(session, 20 * 1000);
101
102         /* Use default priorities */
103         gnutls_priority_set_direct(session,
104                                    "NONE:+VERS-DTLS-ALL:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
105                                    NULL);
106
107         /* put the anonymous credentials to the current session
108          */
109         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
110
111         gnutls_transport_set_int(session, fd);
112         gnutls_transport_set_push_function(session, push);
113
114         /* Perform the TLS handshake
115          */
116         do {
117                 ret = gnutls_handshake(session);
118         }
119         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
120
121         if (ret < 0) {
122                 fail("client: Handshake failed\n");
123                 gnutls_perror(ret);
124                 exit(1);
125         } else {
126                 if (debug)
127                         success("client: Handshake was completed\n");
128         }
129
130         if (debug)
131                 success("client: TLS version is: %s\n",
132                         gnutls_protocol_get_name
133                         (gnutls_protocol_get_version(session)));
134
135         do {
136                 ret = gnutls_record_recv(session, buffer, MAX_BUF);
137         } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
138
139         if (ret == 0) {
140                 if (debug)
141                         success
142                             ("client: Peer has closed the TLS connection\n");
143                 goto end;
144         } else if (ret < 0) {
145                 fail("client: Error: %s\n", gnutls_strerror(ret));
146                 exit(1);
147         }
148
149         gnutls_bye(session, GNUTLS_SHUT_WR);
150
151       end:
152
153         close(fd);
154
155         gnutls_deinit(session);
156
157         gnutls_anon_free_client_credentials(anoncred);
158
159         gnutls_global_deinit();
160 }
161
162
163 /* These are global */
164 pid_t child;
165
166 static void terminate(void)
167 {
168         int status;
169
170         kill(child, SIGTERM);
171         wait(&status);
172         exit(1);
173 }
174
175 #define CLI_ADDR (void*)"test"
176 #define CLI_ADDR_LEN 4
177
178 static void server(int fd)
179 {
180         int ret, csend = 0;
181         gnutls_anon_server_credentials_t anoncred;
182         char buffer[MAX_BUF + 1];
183         gnutls_datum_t cookie_key;
184         gnutls_dtls_prestate_st prestate;
185         gnutls_session_t session;
186
187         /* this must be called once in the program
188          */
189         global_init();
190
191         if (debug) {
192                 gnutls_global_set_log_function(server_log_func);
193                 gnutls_global_set_log_level(4711);
194         }
195
196         ret = gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE);
197         if (ret < 0) {
198                 fail("Cannot generate key: %s\n", gnutls_strerror(ret));
199                 terminate();
200         }
201
202         gnutls_anon_allocate_server_credentials(&anoncred);
203
204         gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
205         gnutls_handshake_set_timeout(session, 20 * 1000);
206         gnutls_dtls_set_mtu(session, 1500);
207
208         /* avoid calling all the priority functions, since the defaults
209          * are adequate.
210          */
211         gnutls_priority_set_direct(session,
212                                    "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
213                                    NULL);
214
215         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
216
217         gnutls_transport_set_int(session, fd);
218         gnutls_transport_set_push_function(session, push);
219
220         for (;;) {
221                 ret = recv(fd, buffer, sizeof(buffer), MSG_PEEK);
222                 if (ret < 0) {
223                         fail("Cannot receive data\n");
224                         terminate();
225                 }
226
227                 memset(&prestate, 0, sizeof(prestate));
228                 ret =
229                     gnutls_dtls_cookie_verify(&cookie_key, CLI_ADDR,
230                                               CLI_ADDR_LEN, buffer, ret,
231                                               &prestate);
232                 if (ret < 0) {  /* cookie not valid */
233                         if (debug)
234                                 success("Sending hello verify request\n");
235
236                         ret =
237                             gnutls_dtls_cookie_send(&cookie_key, CLI_ADDR,
238                                                     CLI_ADDR_LEN,
239                                                     &prestate,
240                                                     (gnutls_transport_ptr_t)
241                                                     (long) fd, push);
242                         if (ret < 0) {
243                                 fail("Cannot send data\n");
244                                 terminate();
245                         }
246
247                         /* discard peeked data */
248                         recv(fd, buffer, sizeof(buffer), 0);
249                         csend++;
250
251                         if (csend > 2) {
252                                 fail("too many cookies sent\n");
253                                 terminate();
254                         }
255
256                         continue;
257                 }
258
259                 /* success */
260                 break;
261         }
262
263         gnutls_dtls_prestate_set(session, &prestate);
264
265         do {
266                 ret = gnutls_handshake(session);
267         }
268         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
269         if (ret < 0) {
270                 close(fd);
271                 gnutls_deinit(session);
272                 fail("server: Handshake has failed (%s)\n\n",
273                      gnutls_strerror(ret));
274                 terminate();
275         }
276         if (debug)
277                 success("server: Handshake was completed\n");
278
279         if (debug)
280                 success("server: TLS version is: %s\n",
281                         gnutls_protocol_get_name
282                         (gnutls_protocol_get_version(session)));
283
284         /* see the Getting peer's information example */
285         /* print_info(session); */
286
287         do {
288                 ret = gnutls_record_send(session, buffer, sizeof(buffer));
289         } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
290
291         if (ret < 0) {
292                 close(fd);
293                 gnutls_deinit(session);
294                 fail("server: data sending has failed (%s)\n\n",
295                      gnutls_strerror(ret));
296                 terminate();
297         }
298
299
300         /* do not wait for the peer to close the connection.
301          */
302         gnutls_bye(session, GNUTLS_SHUT_WR);
303
304         close(fd);
305         gnutls_deinit(session);
306
307         gnutls_anon_free_server_credentials(anoncred);
308         gnutls_free(cookie_key.data);
309
310         gnutls_global_deinit();
311
312         if (debug)
313                 success("server: finished\n");
314 }
315
316 void doit(void)
317 {
318         int fd[2];
319         int ret;
320
321         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
322         if (ret < 0) {
323                 perror("socketpair");
324                 exit(1);
325         }
326
327         child = fork();
328         if (child < 0) {
329                 perror("fork");
330                 fail("fork");
331                 exit(1);
332         }
333
334         if (child) {
335                 int status;
336                 /* parent */
337
338                 server(fd[0]);
339                 wait(&status);
340                 if (WEXITSTATUS(status) != 0)
341                         fail("Child died with status %d\n",
342                              WEXITSTATUS(status));
343         } else {
344                 close(fd[0]);
345                 client(fd[1]);
346                 exit(0);
347         }
348 }
349
350 #endif                          /* _WIN32 */