mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-29 04:09:31 +03:00
add support for SNI
This commit is contained in:
1 parent
00a9277f49
commit
9889fd9eee
14 files changed
+700
-102
No files matched your search
@@ -19,6 +19,7 @@ check_PROGRAMS = \
|
||||
test_tls_authentication \
|
||||
test_https_multi_daemon \
|
||||
test_https_get \
|
||||
test_https_sni \
|
||||
test_https_get_select \
|
||||
test_https_get_parallel \
|
||||
test_https_get_parallel_threads \
|
||||
@@ -32,6 +33,7 @@ TESTS = \
|
||||
test_tls_options \
|
||||
test_https_multi_daemon \
|
||||
test_https_get \
|
||||
test_https_sni \
|
||||
test_https_get_select \
|
||||
test_https_get_parallel \
|
||||
test_https_get_parallel_threads \
|
||||
@@ -113,6 +115,14 @@ test_https_get_LDADD = \
|
||||
$(top_builddir)/src/microhttpd/libmicrohttpd.la \
|
||||
@LIBCURL@ -lgnutls @LIBGCRYPT_LIBS@
|
||||
|
||||
test_https_sni_SOURCES = \
|
||||
test_https_sni.c \
|
||||
tls_test_common.c
|
||||
test_https_sni_LDADD = \
|
||||
$(top_builddir)/src/testcurl/libcurl_version_check.a \
|
||||
$(top_builddir)/src/microhttpd/libmicrohttpd.la \
|
||||
@LIBCURL@ -lgnutls @LIBGCRYPT_LIBS@
|
||||
|
||||
test_https_get_select_SOURCES = \
|
||||
test_https_get_select.c \
|
||||
tls_test_common.c
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICWTCCAcICCQDc4McLp7j56DANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJa
|
||||
WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
|
||||
cyBQdHkgTHRkMQ4wDAYDVQQDDAVob3N0MTEZMBcGCSqGSIb3DQEJARYKdGVzdEBo
|
||||
b3N0MTAgFw0xMzExMTcxNTE2MzdaGA8yMTEzMTAyNDE1MTYzN1owcDELMAkGA1UE
|
||||
BhMCWloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
|
||||
ZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFaG9zdDExGTAXBgkqhkiG9w0BCQEWCnRl
|
||||
c3RAaG9zdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKxYiRUzfQnekQn3
|
||||
6e+hP/mt/JEkiFzX5TV+E19ue2v4tc7lf+SoLEk2dVt5tGQkHjIGeFFNwCLrgXoi
|
||||
h3KfP4R1IYe7NFbM+lFVwPceF3inJ75dZD80BxaXQANeh0yC/DhaVJUFNaof2S4+
|
||||
7xd8zTL6M11gME+XmR8uaDvW7EBtAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAf62m
|
||||
Nstj9p9u8T5A5fRnJWfoglH/zfm7IHzht0Wi047O3NFZJ0pOPqV97HuErUA5oBGg
|
||||
qswnyRGyGMcvL08Bki7Q6NkY7K0ON3lq+ofTkIAHlOKMF+Y/otbjuIDHBfo63tmE
|
||||
uOcr8XDQGu9R0cfh+qLgicJQd/8cFBhxsL0ls6I=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQCsWIkVM30J3pEJ9+nvoT/5rfyRJIhc1+U1fhNfbntr+LXO5X/k
|
||||
qCxJNnVbebRkJB4yBnhRTcAi64F6Iodynz+EdSGHuzRWzPpRVcD3Hhd4pye+XWQ/
|
||||
NAcWl0ADXodMgvw4WlSVBTWqH9kuPu8XfM0y+jNdYDBPl5kfLmg71uxAbQIDAQAB
|
||||
AoGBAJvq9QmjLSnymtCj4pYSEai2iNpebKdiAlEkoC4j67DArupgohWhN398ryt0
|
||||
rYgzTMYBKHSVnI969AYkmtlNzM1yNckRQb/G/tWrkl9re28y2nbAExtHbvLoTk2C
|
||||
a/EEl1Op+JZNzLoSje7IQMVZoArD3d4aUbfux4XzlO2eRNmZAkEA2pV49QgcOTOJ
|
||||
PrR5cgekonNdeMtkbZm9dhxgDk9IsYkC0iOxjn/IbeCQN3wuTQ5/yLoiiQ/CQ8w5
|
||||
JndF/XpICwJBAMnY37BSRb+XKZeJWP0yjqyFJwzHXkh6IsoSF2OOXSixdiMpthLh
|
||||
IPzvo6Qxsnha4VvwuDxljHzQFPgMT//CTGcCQQDMs9S+LKU50JDEX4Goj43X8RBl
|
||||
cp0Poz3yYap3XDqowLYalADRgcvzUq3cuHgoA98Z3W9ASrjUg2o2ItcyBhV3AkAK
|
||||
bCBgwl7Hnc6P/I+Tw2CKl/WEO2cq5uOU+4opodg9maw39JdqMiW56cXRXJ+Sh17L
|
||||
mIpq0/OFHll21WvsEORRAkAnDDn/vmW25PSxPVY7tKKJCCkmtBeLQpySfpDgBF+O
|
||||
QvvokKs2COivc50rmOYNvD1WSsAOspdaSoZUgFw5ikti
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICWTCCAcICCQCJ9nhDYTUBKjANBgkqhkiG9w0BAQUFADBwMQswCQYDVQQGEwJa
|
||||
WjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
|
||||
cyBQdHkgTHRkMQ4wDAYDVQQDDAVob3N0MjEZMBcGCSqGSIb3DQEJARYKdGVzdEBo
|
||||
b3N0MjAgFw0xMzExMTcxNTE2NDNaGA8yMTEzMTAyNDE1MTY0M1owcDELMAkGA1UE
|
||||
BhMCWloxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
|
||||
ZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFaG9zdDIxGTAXBgkqhkiG9w0BCQEWCnRl
|
||||
c3RAaG9zdDIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVK8QKMvU96iNL2
|
||||
66PKm6xXw9NPHDn+o1TLF1CQRxXMrBYUrObk0961+3n3Z3BXOFHKfSV4E55CpVyz
|
||||
D1Wcadlt3B9z3ke3HOi0lEa1xNJTMQK/QT3Fx/NURmNg5s9HAsqY4ocb9KHaF5Ex
|
||||
0TgC0L0aRP0cK1x2TgPEHBNcgGl9AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEXOi
|
||||
9rSmVrTN5olIdowctr1vWbGwRCjCnAFXDsqakcDASNthr15LB5kr/mrA3olJjbZh
|
||||
o+JDvWMY6FN8r1QXW0RL9/obbHxtJpwvAmYVMY9jrR8Rpo38p4RfXlN85g3q9PVx
|
||||
5IGLaOqLf4hSnKArFL/fzXwxX9b5HBCKlXfiuqM=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQC1SvECjL1PeojS9uujypusV8PTTxw5/qNUyxdQkEcVzKwWFKzm
|
||||
5NPetft592dwVzhRyn0leBOeQqVcsw9VnGnZbdwfc95HtxzotJRGtcTSUzECv0E9
|
||||
xcfzVEZjYObPRwLKmOKHG/Sh2heRMdE4AtC9GkT9HCtcdk4DxBwTXIBpfQIDAQAB
|
||||
AoGAR5Do6TfDt69IefdNeCAQKg2PWUg+fUpfEacGciAyX5GnUSQiSReF58HxHumi
|
||||
ZL+ZlPgZRQRMwknO23Q4FnSjd66A3E9iHLqkWxRFJWME6E7zgtBrIjctnNu9uYM9
|
||||
cw4R6qmXOL7C5sK00KXF2ep8+s+JjrZz61o85QnGGRYA94ECQQDbG6f1B8NKY9T1
|
||||
1GDR/++rJbdTVQlZQcKSXMumpU6V3mEV0O9GkYaZzoYvWa3kx6c0np4karrm3QWa
|
||||
u5E0q1YdAkEA09FPcmzVvIR0+sMWca8QJ/tJUxD6qYo8vLOpO4wt4iTPhGBEU+Q5
|
||||
cgXmde3/plVsp0vYxK/NG5XZkoC1fbuC4QJATRGxRlLwsl3jLoUBeVxY5Q5jKYCj
|
||||
xS2ITwss5vUGa1jJNW9EesH9YmRudoFI1UwU2EFixtRz4Xik3ARV0vzhUQJAfabT
|
||||
50ASxqMYtczW2peMEPurMqCG4d4ES7iUMqPkcBuAErn8rntbbH19igWmOyi/rLp8
|
||||
m6jiFnQdPiAmCbEbYQJAFAKiQl2ZOe3gkSh8MaQilD8Ppog6rod4SQiSmRNsDWPi
|
||||
IxqXneaGDWhzynC9xr4SwuJ9D5VxW1phNyiveDuYXw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
This file is part of libmicrohttpd
|
||||
(C) 2013 Christian Grothoff
|
||||
|
||||
libmicrohttpd is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3, or (at your
|
||||
option) any later version.
|
||||
|
||||
libmicrohttpd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libmicrohttpd; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_https_sni.c
|
||||
* @brief Testcase for libmicrohttpd HTTPS with SNI operations
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "microhttpd.h"
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <curl/curl.h>
|
||||
#include <gcrypt.h>
|
||||
#include "tls_test_common.h"
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
/* This test only works with GnuTLS >= 3.0 */
|
||||
#if GNUTLS_VERSION_MAJOR >= 3
|
||||
|
||||
#include <gnutls/abstract.h>
|
||||
|
||||
/**
|
||||
* A hostname, server key and certificate.
|
||||
*/
|
||||
struct Hosts
|
||||
{
|
||||
struct Hosts *next;
|
||||
const char *hostname;
|
||||
gnutls_pcert_st pcrt;
|
||||
gnutls_privkey_t key;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Linked list of supported TLDs and respective certificates.
|
||||
*/
|
||||
static struct Hosts *hosts;
|
||||
|
||||
/* Load the certificate and the private key.
|
||||
* (This code is largely taken from GnuTLS).
|
||||
*/
|
||||
static void
|
||||
load_keys(const char *hostname,
|
||||
const char *CERT_FILE,
|
||||
const char *KEY_FILE)
|
||||
{
|
||||
int ret;
|
||||
gnutls_datum_t data;
|
||||
struct Hosts *host;
|
||||
|
||||
host = malloc (sizeof (struct Hosts));
|
||||
host->hostname = hostname;
|
||||
host->next = hosts;
|
||||
hosts = host;
|
||||
|
||||
ret = gnutls_load_file (CERT_FILE, &data);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"*** Error loading certificate file %s.\n",
|
||||
CERT_FILE);
|
||||
exit (1);
|
||||
}
|
||||
ret =
|
||||
gnutls_pcert_import_x509_raw (&host->pcrt, &data, GNUTLS_X509_FMT_PEM,
|
||||
0);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"*** Error loading certificate file: %s\n",
|
||||
gnutls_strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
gnutls_free (data.data);
|
||||
|
||||
ret = gnutls_load_file (KEY_FILE, &data);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"*** Error loading key file %s.\n",
|
||||
KEY_FILE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gnutls_privkey_init (&host->key);
|
||||
ret =
|
||||
gnutls_privkey_import_x509_raw (host->key,
|
||||
&data, GNUTLS_X509_FMT_PEM,
|
||||
NULL, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"*** Error loading key file: %s\n",
|
||||
gnutls_strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
gnutls_free (data.data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param session the session we are giving a cert for
|
||||
* @param req_ca_dn NULL on server side
|
||||
* @param nreqs length of req_ca_dn, and thus 0 on server side
|
||||
* @param pk_algos NULL on server side
|
||||
* @param pk_algos_length 0 on server side
|
||||
* @param pcert list of certificates (to be set)
|
||||
* @param pcert_length length of pcert (to be set)
|
||||
* @param pkey the private key (to be set)
|
||||
*/
|
||||
static int
|
||||
sni_callback (gnutls_session_t session,
|
||||
const gnutls_datum_t* req_ca_dn,
|
||||
int nreqs,
|
||||
const gnutls_pk_algorithm_t* pk_algos,
|
||||
int pk_algos_length,
|
||||
gnutls_pcert_st** pcert,
|
||||
unsigned int *pcert_length,
|
||||
gnutls_privkey_t * pkey)
|
||||
{
|
||||
char name[256];
|
||||
size_t name_len;
|
||||
struct Hosts *host;
|
||||
unsigned int type;
|
||||
|
||||
name_len = sizeof (name);
|
||||
if (GNUTLS_E_SUCCESS !=
|
||||
gnutls_server_name_get (session,
|
||||
name,
|
||||
&name_len,
|
||||
&type,
|
||||
0 /* index */))
|
||||
return -1;
|
||||
for (host = hosts; NULL != host; host = host->next)
|
||||
if (0 == strncmp (name, host->hostname, name_len))
|
||||
break;
|
||||
if (NULL == host)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Need certificate for %.*s\n",
|
||||
(int) name_len,
|
||||
name);
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
fprintf (stderr,
|
||||
"Returning certificate for %.*s\n",
|
||||
(int) name_len,
|
||||
name);
|
||||
#endif
|
||||
*pkey = host->key;
|
||||
*pcert_length = 1;
|
||||
*pcert = &host->pcrt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* perform a HTTP GET request via SSL/TLS */
|
||||
static int
|
||||
do_get (const char *url)
|
||||
{
|
||||
CURL *c;
|
||||
struct CBC cbc;
|
||||
CURLcode errornum;
|
||||
size_t len;
|
||||
struct curl_slist *dns_info;
|
||||
|
||||
len = strlen (test_data);
|
||||
if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
|
||||
{
|
||||
fprintf (stderr, MHD_E_MEM);
|
||||
return -1;
|
||||
}
|
||||
cbc.size = len;
|
||||
cbc.pos = 0;
|
||||
|
||||
c = curl_easy_init ();
|
||||
#if DEBUG_HTTPS_TEST
|
||||
curl_easy_setopt (c, CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
curl_easy_setopt (c, CURLOPT_URL, url);
|
||||
curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L);
|
||||
curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L);
|
||||
curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer);
|
||||
curl_easy_setopt (c, CURLOPT_FILE, &cbc);
|
||||
|
||||
/* perform peer authentication */
|
||||
/* TODO merge into send_curl_req */
|
||||
curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
dns_info = curl_slist_append (NULL, "host1:4233:127.0.0.1");
|
||||
dns_info = curl_slist_append (dns_info, "host2:4233:127.0.0.1");
|
||||
curl_easy_setopt (c, CURLOPT_RESOLVE, dns_info);
|
||||
curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
|
||||
|
||||
/* NOTE: use of CONNECTTIMEOUT without also
|
||||
setting NOSIGNAL results in really weird
|
||||
crashes on my system! */
|
||||
curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
|
||||
if (CURLE_OK != (errornum = curl_easy_perform (c)))
|
||||
{
|
||||
fprintf (stderr, "curl_easy_perform failed: `%s'\n",
|
||||
curl_easy_strerror (errornum));
|
||||
curl_easy_cleanup (c);
|
||||
free (cbc.buf);
|
||||
curl_slist_free_all (dns_info);
|
||||
return errornum;
|
||||
}
|
||||
|
||||
curl_easy_cleanup (c);
|
||||
curl_slist_free_all (dns_info);
|
||||
if (memcmp (cbc.buf, test_data, len) != 0)
|
||||
{
|
||||
fprintf (stderr, "Error: local file & received file differ.\n");
|
||||
free (cbc.buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (cbc.buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
unsigned int error_count = 0;
|
||||
struct MHD_Daemon *d;
|
||||
|
||||
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
|
||||
#ifdef GCRYCTL_INITIALIZATION_FINISHED
|
||||
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
#endif
|
||||
if (0 != curl_global_init (CURL_GLOBAL_ALL))
|
||||
{
|
||||
fprintf (stderr, "Error: %s\n", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
load_keys ("host1", "host1.crt", "host1.key");
|
||||
load_keys ("host2", "host2.crt", "host2.key");
|
||||
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | MHD_USE_DEBUG,
|
||||
4233,
|
||||
NULL, NULL,
|
||||
&http_ahc, NULL,
|
||||
MHD_OPTION_HTTPS_CERT_CALLBACK, &sni_callback,
|
||||
MHD_OPTION_END);
|
||||
if (d == NULL)
|
||||
{
|
||||
fprintf (stderr, MHD_E_SERVER_INIT);
|
||||
return -1;
|
||||
}
|
||||
error_count += do_get ("https://host1:4233/");
|
||||
error_count += do_get ("https://host2:4233/");
|
||||
|
||||
MHD_stop_daemon (d);
|
||||
curl_global_cleanup ();
|
||||
return error_count != 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int main ()
|
||||
{
|
||||
fprintf (stderr,
|
||||
"SNI not supported by GnuTLS < 3.0\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user