Merge branch 'upstream' into tizen
[platform/upstream/gnutls.git] / tests / custom-urls.c
1 /*
2  * Copyright (C) 2014 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/abstract.h>
48 #include <gnutls/urls.h>
49 #include <signal.h>
50
51 #include "utils.h"
52
53 static void terminate(void);
54
55 /* This program tests the registration of custom URL strings.
56  */
57
58 static void server_log_func(int level, const char *str)
59 {
60         fprintf(stderr, "server|<%d>| %s", level, str);
61 }
62
63 static unsigned char server_cert_pem[] =
64     "-----BEGIN CERTIFICATE-----\n"
65     "MIICVjCCAcGgAwIBAgIERiYdMTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n"
66     "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTIxWhcNMDgwNDE3MTMyOTIxWjA3MRsw\n"
67     "GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz\n"
68     "Lm9yZzCBnDALBgkqhkiG9w0BAQEDgYwAMIGIAoGA17pcr6MM8C6pJ1aqU46o63+B\n"
69     "dUxrmL5K6rce+EvDasTaDQC46kwTHzYWk95y78akXrJutsoKiFV1kJbtple8DDt2\n"
70     "DZcevensf9Op7PuFZKBroEjOd35znDET/z3IrqVgbtm2jFqab7a+n2q9p/CgMyf1\n"
71     "tx2S5Zacc1LWn9bIjrECAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAAMBoGA1UdEQQT\n"
72     "MBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8B\n"
73     "Af8EBQMDB6AAMB0GA1UdDgQWBBTrx0Vu5fglyoyNgw106YbU3VW0dTAfBgNVHSME\n"
74     "GDAWgBTpPBz7rZJu5gakViyi4cBTJ8jylTALBgkqhkiG9w0BAQUDgYEAaFEPTt+7\n"
75     "bzvBuOf7+QmeQcn29kT6Bsyh1RHJXf8KTk5QRfwp6ogbp94JQWcNQ/S7YDFHglD1\n"
76     "AwUNBRXwd3riUsMnsxgeSDxYBfJYbDLeohNBsqaPDJb7XailWbMQKfAbFQ8cnOxg\n"
77     "rOKLUQRWJ0K3HyXRMhbqjdLIaQiCvQLuizo=\n" "-----END CERTIFICATE-----\n";
78
79 const gnutls_datum_t server_cert = { server_cert_pem,
80         sizeof(server_cert_pem)
81 };
82
83 static unsigned char server_key_pem[] =
84     "-----BEGIN RSA PRIVATE KEY-----\n"
85     "MIICXAIBAAKBgQDXulyvowzwLqknVqpTjqjrf4F1TGuYvkrqtx74S8NqxNoNALjq\n"
86     "TBMfNhaT3nLvxqResm62ygqIVXWQlu2mV7wMO3YNlx696ex/06ns+4VkoGugSM53\n"
87     "fnOcMRP/PciupWBu2baMWppvtr6far2n8KAzJ/W3HZLllpxzUtaf1siOsQIDAQAB\n"
88     "AoGAYAFyKkAYC/PYF8e7+X+tsVCHXppp8AoP8TEZuUqOZz/AArVlle/ROrypg5kl\n"
89     "8YunrvUdzH9R/KZ7saNZlAPLjZyFG9beL/am6Ai7q7Ma5HMqjGU8kTEGwD7K+lbG\n"
90     "iomokKMOl+kkbY/2sI5Czmbm+/PqLXOjtVc5RAsdbgvtmvkCQQDdV5QuU8jap8Hs\n"
91     "Eodv/tLJ2z4+SKCV2k/7FXSKWe0vlrq0cl2qZfoTUYRnKRBcWxc9o92DxK44wgPi\n"
92     "oMQS+O7fAkEA+YG+K9e60sj1K4NYbMPAbYILbZxORDecvP8lcphvwkOVUqbmxOGh\n"
93     "XRmTZUuhBrJhJKKf6u7gf3KWlPl6ShKEbwJASC118cF6nurTjuLf7YKARDjNTEws\n"
94     "qZEeQbdWYINAmCMj0RH2P0mvybrsXSOD5UoDAyO7aWuqkHGcCLv6FGG+qwJAOVqq\n"
95     "tXdUucl6GjOKKw5geIvRRrQMhb/m5scb+5iw8A4LEEHPgGiBaF5NtJZLALgWfo5n\n"
96     "hmC8+G8F0F78znQtPwJBANexu+Tg5KfOnzSILJMo3oXiXhf5PqXIDmbN0BKyCKAQ\n"
97     "LfkcEcUbVfmDaHpvzwY9VEaoMOKVLitETXdNSxVpvWM=\n"
98     "-----END RSA PRIVATE KEY-----\n";
99
100 const gnutls_datum_t server_key = { server_key_pem,
101         sizeof(server_key_pem)
102 };
103
104 static int url_import_key(gnutls_privkey_t pkey, const char *url, unsigned flags)
105 {
106         if (strcmp(url, "myurl:key") != 0) {
107                 fail("unexpected key url: %s\n", url);
108                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
109         }
110         return gnutls_privkey_import_x509_raw(pkey, &server_key, GNUTLS_X509_FMT_PEM, NULL, 0);
111 }
112
113 static int url_import_crt(gnutls_x509_crt_t crt, const char *url, unsigned flags)
114 {
115         if (strcmp(url, "myurl:cert") != 0) {
116                 abort();
117                 fail("unexpected cert url: %s\n", url);
118                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
119         }
120         return gnutls_x509_crt_import(crt, &server_cert, GNUTLS_X509_FMT_PEM);
121 }
122
123 /* A very basic TLS client, with anonymous authentication.
124  */
125
126 static void client(int fd)
127 {
128         int ret;
129         gnutls_anon_client_credentials_t anoncred;
130         gnutls_certificate_credentials_t x509_cred;
131         gnutls_session_t session;
132         /* Need to enable anonymous KX specifically. */
133
134         gnutls_anon_allocate_client_credentials(&anoncred);
135         gnutls_certificate_allocate_credentials(&x509_cred);
136
137         /* Initialize TLS session
138          */
139         gnutls_init(&session, GNUTLS_CLIENT);
140
141         /* Use default priorities */
142         gnutls_priority_set_direct(session, "NORMAL", NULL);
143
144         /* put the anonymous credentials to the current session
145          */
146         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
147         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
148
149         gnutls_transport_set_int(session, fd);
150
151         /* Perform the TLS handshake
152          */
153         do {
154                 ret = gnutls_handshake(session);
155         }
156         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
157
158         if (ret < 0) {
159                 fail("client: Handshake failed\n");
160                 gnutls_perror(ret);
161                 exit(1);
162         } else {
163                 if (debug)
164                         success("client: Handshake was completed\n");
165         }
166
167         if (debug)
168                 success("client: TLS version is: %s\n",
169                         gnutls_protocol_get_name
170                         (gnutls_protocol_get_version(session)));
171
172         gnutls_bye(session, GNUTLS_SHUT_WR);
173
174         close(fd);
175
176         gnutls_deinit(session);
177
178         gnutls_anon_free_client_credentials(anoncred);
179         gnutls_certificate_free_credentials(x509_cred);
180
181         gnutls_global_deinit();
182 }
183
184 /* These are global */
185 pid_t child;
186
187 static void terminate(void)
188 {
189         kill(child, SIGTERM);
190         exit(1);
191 }
192
193 static void server(int fd)
194 {
195         int ret;
196         gnutls_session_t session;
197         gnutls_anon_server_credentials_t anoncred;
198         gnutls_certificate_credentials_t x509_cred;
199
200         /* this must be called once in the program
201          */
202         gnutls_certificate_allocate_credentials(&x509_cred);
203         ret = gnutls_certificate_set_x509_key_file(x509_cred, "nomyurl:cert", "nomyurl:key",
204                                                   GNUTLS_X509_FMT_PEM);
205         if (ret != GNUTLS_E_FILE_ERROR) {
206                 fail("server: gnutls_certificate_set_x509_key_file unexpected error (%s)\n\n",
207                      gnutls_strerror(ret));
208                 terminate();
209         }
210
211         ret = gnutls_certificate_set_x509_key_file(x509_cred, "myurl:cert", "myurl:key",
212                                                   GNUTLS_X509_FMT_PEM);
213         if (ret < 0) {
214                 fail("server: gnutls_certificate_set_x509_key_file (%s)\n\n",
215                      gnutls_strerror(ret));
216                 terminate();
217         }
218
219         gnutls_anon_allocate_server_credentials(&anoncred);
220
221         gnutls_init(&session, GNUTLS_SERVER);
222
223         /* avoid calling all the priority functions, since the defaults
224          * are adequate.
225          */
226         gnutls_priority_set_direct(session, "NORMAL", NULL);
227
228         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
229         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
230
231         gnutls_transport_set_int(session, fd);
232
233         do {
234                 ret = gnutls_handshake(session);
235         }
236         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
237         if (ret < 0) {
238                 close(fd);
239                 gnutls_deinit(session);
240                 fail("server: Handshake has failed (%s)\n\n",
241                      gnutls_strerror(ret));
242                 terminate();
243         }
244         if (debug)
245                 success("server: Handshake was completed\n");
246
247         if (debug)
248                 success("server: TLS version is: %s\n",
249                         gnutls_protocol_get_name
250                         (gnutls_protocol_get_version(session)));
251
252         /* do not wait for the peer to close the connection.
253          */
254         gnutls_bye(session, GNUTLS_SHUT_WR);
255
256         close(fd);
257         gnutls_deinit(session);
258
259         gnutls_anon_free_server_credentials(anoncred);
260         gnutls_certificate_free_credentials(x509_cred);
261
262         gnutls_global_deinit();
263
264         if (debug)
265                 success("server: finished\n");
266 }
267
268 const gnutls_custom_url_st custom_url_st = {
269         .name = "myurl:",
270         .name_size = sizeof("myurl:")-1,
271         .import_key = url_import_key,
272         .import_crt = url_import_crt
273 };
274
275 static void start(void)
276 {
277         int fd[2];
278         int ret;
279
280         global_init();
281
282         if (debug) {
283                 gnutls_global_set_log_function(server_log_func);
284                 gnutls_global_set_log_level(3);
285         }
286
287         ret = gnutls_register_custom_url(&custom_url_st);
288         if (ret < 0) {
289                 fail("error registering: %s\n", gnutls_strerror(ret));
290                 exit(1);
291         }
292
293         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
294         if (ret < 0) {
295                 perror("socketpair");
296                 exit(1);
297         }
298
299         child = fork();
300         if (child < 0) {
301                 perror("fork");
302                 fail("fork");
303                 exit(1);
304         }
305
306         if (child) {
307                 /* parent */
308                 close(fd[0]);
309                 client(fd[1]);
310                 kill(child, SIGTERM);
311         } else {
312                 close(fd[1]);
313                 server(fd[0]);
314                 exit(0);
315         }
316 }
317
318 static void ch_handler(int sig)
319 {
320         int status;
321         wait(&status);
322         if (WEXITSTATUS(status) != 0 ||
323             (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) {
324                 if (WIFSIGNALED(status))
325                         fail("Child died with sigsegv\n");
326                 else
327                         fail("Child died with status %d\n",
328                              WEXITSTATUS(status));
329                 terminate();
330         }
331         return;
332 }
333
334 void doit(void)
335 {
336         signal(SIGCHLD, ch_handler);
337         signal(SIGPIPE, SIG_IGN);
338
339         start();
340 }
341
342 #endif                          /* _WIN32 */