aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/https/test_https_sni.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/https/test_https_sni.c')
-rw-r--r--src/testcurl/https/test_https_sni.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/testcurl/https/test_https_sni.c b/src/testcurl/https/test_https_sni.c
new file mode 100644
index 00000000..408d4c10
--- /dev/null
+++ b/src/testcurl/https/test_https_sni.c
@@ -0,0 +1,289 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2013 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file test_https_sni.c
23 * @brief Testcase for libmicrohttpd HTTPS with SNI operations
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "microhttpd.h"
28#include <limits.h>
29#include <sys/stat.h>
30#include <curl/curl.h>
31#include <gcrypt.h>
32#include "tls_test_common.h"
33#include <gnutls/gnutls.h>
34
35/* This test only works with GnuTLS >= 3.0 */
36#if GNUTLS_VERSION_MAJOR >= 3
37
38#include <gnutls/abstract.h>
39
40/**
41 * A hostname, server key and certificate.
42 */
43struct Hosts
44{
45 struct Hosts *next;
46 const char *hostname;
47 gnutls_pcert_st pcrt;
48 gnutls_privkey_t key;
49};
50
51
52/**
53 * Linked list of supported TLDs and respective certificates.
54 */
55static struct Hosts *hosts;
56
57/* Load the certificate and the private key.
58 * (This code is largely taken from GnuTLS).
59 */
60static void
61load_keys(const char *hostname,
62 const char *CERT_FILE,
63 const char *KEY_FILE)
64{
65 int ret;
66 gnutls_datum_t data;
67 struct Hosts *host;
68
69 host = malloc (sizeof (struct Hosts));
70 host->hostname = hostname;
71 host->next = hosts;
72 hosts = host;
73
74 ret = gnutls_load_file (CERT_FILE, &data);
75 if (ret < 0)
76 {
77 fprintf (stderr,
78 "*** Error loading certificate file %s.\n",
79 CERT_FILE);
80 exit (1);
81 }
82 ret =
83 gnutls_pcert_import_x509_raw (&host->pcrt, &data, GNUTLS_X509_FMT_PEM,
84 0);
85 if (ret < 0)
86 {
87 fprintf (stderr,
88 "*** Error loading certificate file: %s\n",
89 gnutls_strerror (ret));
90 exit (1);
91 }
92 gnutls_free (data.data);
93
94 ret = gnutls_load_file (KEY_FILE, &data);
95 if (ret < 0)
96 {
97 fprintf (stderr,
98 "*** Error loading key file %s.\n",
99 KEY_FILE);
100 exit (1);
101 }
102
103 gnutls_privkey_init (&host->key);
104 ret =
105 gnutls_privkey_import_x509_raw (host->key,
106 &data, GNUTLS_X509_FMT_PEM,
107 NULL, 0);
108 if (ret < 0)
109 {
110 fprintf (stderr,
111 "*** Error loading key file: %s\n",
112 gnutls_strerror (ret));
113 exit (1);
114 }
115 gnutls_free (data.data);
116}
117
118
119
120/**
121 * @param session the session we are giving a cert for
122 * @param req_ca_dn NULL on server side
123 * @param nreqs length of req_ca_dn, and thus 0 on server side
124 * @param pk_algos NULL on server side
125 * @param pk_algos_length 0 on server side
126 * @param pcert list of certificates (to be set)
127 * @param pcert_length length of pcert (to be set)
128 * @param pkey the private key (to be set)
129 */
130static int
131sni_callback (gnutls_session_t session,
132 const gnutls_datum_t* req_ca_dn,
133 int nreqs,
134 const gnutls_pk_algorithm_t* pk_algos,
135 int pk_algos_length,
136 gnutls_pcert_st** pcert,
137 unsigned int *pcert_length,
138 gnutls_privkey_t * pkey)
139{
140 char name[256];
141 size_t name_len;
142 struct Hosts *host;
143 unsigned int type;
144
145 name_len = sizeof (name);
146 if (GNUTLS_E_SUCCESS !=
147 gnutls_server_name_get (session,
148 name,
149 &name_len,
150 &type,
151 0 /* index */))
152 return -1;
153 for (host = hosts; NULL != host; host = host->next)
154 if (0 == strncmp (name, host->hostname, name_len))
155 break;
156 if (NULL == host)
157 {
158 fprintf (stderr,
159 "Need certificate for %.*s\n",
160 (int) name_len,
161 name);
162 return -1;
163 }
164#if 0
165 fprintf (stderr,
166 "Returning certificate for %.*s\n",
167 (int) name_len,
168 name);
169#endif
170 *pkey = host->key;
171 *pcert_length = 1;
172 *pcert = &host->pcrt;
173 return 0;
174}
175
176
177/* perform a HTTP GET request via SSL/TLS */
178static int
179do_get (const char *url)
180{
181 CURL *c;
182 struct CBC cbc;
183 CURLcode errornum;
184 size_t len;
185 struct curl_slist *dns_info;
186
187 len = strlen (test_data);
188 if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
189 {
190 fprintf (stderr, MHD_E_MEM);
191 return -1;
192 }
193 cbc.size = len;
194 cbc.pos = 0;
195
196 c = curl_easy_init ();
197#if DEBUG_HTTPS_TEST
198 curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
199#endif
200 curl_easy_setopt (c, CURLOPT_URL, url);
201 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
202 curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L);
203 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L);
204 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
205 curl_easy_setopt (c, CURLOPT_FILE, &cbc);
206
207 /* perform peer authentication */
208 /* TODO merge into send_curl_req */
209 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
210 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 2);
211 dns_info = curl_slist_append (NULL, "host1:4233:127.0.0.1");
212 dns_info = curl_slist_append (dns_info, "host2:4233:127.0.0.1");
213 curl_easy_setopt (c, CURLOPT_RESOLVE, dns_info);
214 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
215
216 /* NOTE: use of CONNECTTIMEOUT without also
217 setting NOSIGNAL results in really weird
218 crashes on my system! */
219 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
220 if (CURLE_OK != (errornum = curl_easy_perform (c)))
221 {
222 fprintf (stderr, "curl_easy_perform failed: `%s'\n",
223 curl_easy_strerror (errornum));
224 curl_easy_cleanup (c);
225 free (cbc.buf);
226 curl_slist_free_all (dns_info);
227 return errornum;
228 }
229
230 curl_easy_cleanup (c);
231 curl_slist_free_all (dns_info);
232 if (memcmp (cbc.buf, test_data, len) != 0)
233 {
234 fprintf (stderr, "Error: local file & received file differ.\n");
235 free (cbc.buf);
236 return -1;
237 }
238
239 free (cbc.buf);
240 return 0;
241}
242
243
244int
245main (int argc, char *const *argv)
246{
247 unsigned int error_count = 0;
248 struct MHD_Daemon *d;
249
250 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
251#ifdef GCRYCTL_INITIALIZATION_FINISHED
252 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
253#endif
254 if (0 != curl_global_init (CURL_GLOBAL_ALL))
255 {
256 fprintf (stderr, "Error: %s\n", strerror (errno));
257 return -1;
258 }
259 load_keys ("host1", "host1.crt", "host1.key");
260 load_keys ("host2", "host2.crt", "host2.key");
261 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | MHD_USE_DEBUG,
262 4233,
263 NULL, NULL,
264 &http_ahc, NULL,
265 MHD_OPTION_HTTPS_CERT_CALLBACK, &sni_callback,
266 MHD_OPTION_END);
267 if (d == NULL)
268 {
269 fprintf (stderr, MHD_E_SERVER_INIT);
270 return -1;
271 }
272 error_count += do_get ("https://host1:4233/");
273 error_count += do_get ("https://host2:4233/");
274
275 MHD_stop_daemon (d);
276 curl_global_cleanup ();
277 return error_count != 0;
278}
279
280
281#else
282
283int main ()
284{
285 fprintf (stderr,
286 "SNI not supported by GnuTLS < 3.0\n");
287 return 0;
288}
289#endif