added X.509 parameters to the daemon struct

added https daemon creation functionality
https file server example [overriding existing echo server]
This commit is contained in:
lv-426
2008-06-02 02:11:51 +00:00
parent 1a951599f1
commit 2132000306
6 changed files with 339 additions and 70 deletions
+194 -67
View File
@@ -20,7 +20,17 @@
/**
* @file https_server_example.c
* @brief a simple echo server using TLS. echo input from client until 'exit' message is received.
* @brief a simple https file server using TLS.
*
* This example assumes the existence of a private key file named "key.pem"
* and a server certificate file named "cert.pem". File path for these should be
* provided as command-line arguments. 'certtool' may be used to generate these if
* missing.
*
* Access server with your browser of choice or with curl :
*
* curl --insecure --tlsv1 --ciphers AES256-SHA <url>
*
* @author LV-426
*/
@@ -35,64 +45,76 @@
#include <string.h>
#include <stdio.h>
#include <gnutls/gnutls.h>
#include <gcrypt.h>
#define DH_BITS 1024
#define MAX_BUF 1024
/* server credintials */
gnutls_anon_server_credentials_t anoncred;
#define BUF_SIZE 1024
#define MAX_URL_LEN 255
/* server Diffie-Hellman parameters */
static gnutls_dh_params_t dh_params;
#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
// TODO remove if unused
#define CAFILE "ca.pem"
#define CRLFILE "crl.pem"
/* Generate Diffie Hellman parameters - for use with DHE kx algorithms. */
static int
generate_dh_params (void)
{
gnutls_dh_params_init (&dh_params);
gnutls_dh_params_generate2 (dh_params, DH_BITS);
return 0;
}
#define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>"
gnutls_session_t
initialize_tls_session (void)
initialize_tls_session (struct MHD_Connection *connection)
{
gnutls_session_t session;
gnutls_init (&session, GNUTLS_SERVER);
gnutls_priority_set_direct (session, "NORMAL:+ANON-DH", NULL);
/* sets cipher priorities */
gnutls_priority_set (session, connection->daemon->priority_cache);
gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
gnutls_dh_set_prime_bits (session, DH_BITS);
/* set needed credentials for certificate authentication. */
gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE,
connection->daemon->x509_cret);
return session;
}
/* Accept Policy Callback */
static int
TLS_echo (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *upload_data,
const char *version, unsigned int *upload_data_size, void **ptr)
file_reader (void *cls, size_t pos, char *buf, int max)
{
FILE *file = cls;
fseek (file, pos, SEEK_SET);
return fread (buf, 1, max, file);
}
/* HTTPS access handler call back */
static int
https_ahc (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *upload_data,
const char *version, unsigned int *upload_data_size, void **ptr)
{
/* loopback HTTP socket */
int loopback_sd, err;
ssize_t ret;
struct sockaddr_in servaddr4;
const struct sockaddr *servaddr;
struct sockaddr_in loopback_sa;
socklen_t addrlen;
gnutls_session_t session;
static int aptr;
struct MHD_Response *response;
char buffer[MAX_BUF + 1];
int ret;
char buffer[BUF_SIZE];
printf ("accepted connection from %d\n", connection->addr->sin_addr);
session = initialize_tls_session ();
session = initialize_tls_session (connection);
gnutls_transport_set_ptr (session, connection->socket_fd);
ret = gnutls_handshake (session);
if (ret < 0)
{
/* set connection as closed */
@@ -106,77 +128,182 @@ TLS_echo (void *cls,
printf ("TLS Handshake completed\n");
connection->state = MHDS_HANDSHAKE_COMPLETE;
/* simple echo loop. message encryption/decryption is acheived through 'gnutls_record_send'
* & gnutls_record_recv calls. */
/* initialize loopback socket */
loopback_sd = socket (AF_INET, SOCK_STREAM, 0);
memset (&loopback_sa, '\0', sizeof (loopback_sa));
loopback_sa.sin_family = AF_INET;
// TODO solve magic number issue - the http's daemons port must be shared with the https daemon - rosolve data sharing point
loopback_sa.sin_port = htons (50000);
inet_pton (AF_INET, "127.0.0.1", &loopback_sa.sin_addr);
/* connect loopback socket */
err = connect (loopback_sd, (struct sockaddr *) &loopback_sa,
sizeof (loopback_sa));
if (err < 0)
{
// TODO err handle
fprintf (stderr, "Error : failed to create TLS loopback socket\n");
exit (1);
}
/*
* This loop pipes data received through the TLS tunnel into the loopback connection.
* message encryption/decryption is acheived via 'gnutls_record_send' & gnutls_record_recv calls.
*/
memset (buffer, 0, BUF_SIZE);
if (gnutls_record_recv (session, buffer, BUF_SIZE) < 0)
{
fprintf (stderr, "\n*** Received corrupted "
"data(%d). Closing the connection.\n\n", ret);
connection->socket_fd = -1;
gnutls_deinit (session);
return MHD_NO;
}
if (write (loopback_sd, buffer, BUF_SIZE) < 0)
{
printf ("failed to write to TLS loopback socket\n");
connection->socket_fd = -1;
gnutls_deinit (session);
return MHD_NO;
}
for (;;)
{
memset (buffer, 0, MAX_BUF + 1);
ret = gnutls_record_recv (session, buffer, MAX_BUF);
memset (buffer, 0, BUF_SIZE);
ret = read (loopback_sd, buffer, BUF_SIZE);
if (ret < 0)
{
fprintf (stderr, "\n*** Received corrupted "
"data(%d). Closing the connection.\n\n", ret);
printf ("failed to read from TLS loopback socket\n");
break;
}
else if (ret >= 0)
if (ret == 0)
{
if (strcmp (buffer, "exit") == 0)
{
printf ("\n- Peer has closed the GNUTLS connection\n");
break;
}
else
{
/* echo data back to the client */
gnutls_record_send (session, buffer, strlen (buffer));
}
break;
}
/* echo data back to the client */
ret = gnutls_record_send (session, buffer, ret);
if (ret < 0)
{
printf ("failed to write to TLS socket\n");
break;
}
}
printf ("\n");
/* mark connection as closed */
connection->socket_fd = -1;
gnutls_deinit (session);
return MHD_YES;
}
/* HTTP access handler call back */
static int
http_ahc (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *upload_data,
const char *version, unsigned int *upload_data_size, void **ptr)
{
static int aptr;
static char full_url[MAX_URL_LEN];
struct MHD_Response *response;
int ret;
FILE *file;
struct stat buf;
if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
return MHD_NO; /* unexpected method */
if (&aptr != *ptr)
{
/* do never respond on first call */
*ptr = &aptr;
return MHD_YES;
}
*ptr = NULL; /* reset when done */
/* assemble full url */
strcpy (full_url, connection->daemon->doc_root);
strncat (full_url, url,
MAX_URL_LEN - strlen (connection->daemon->doc_root) - 1);
file = fopen (full_url, "r");
if (file == NULL)
{
response = MHD_create_response_from_data (strlen (PAGE_NOT_FOUND),
(void *) PAGE_NOT_FOUND,
MHD_NO, MHD_NO);
ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
MHD_destroy_response (response);
}
else
{
stat (&url[1], &buf);
response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */
&file_reader, file,
(MHD_ContentReaderFreeCallback)
& fclose);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
}
return ret;
}
int
main (int argc, char *const *argv)
{
struct MHD_Daemon *daemon;
char keyfile[255] = KEYFILE;
char certfile[255] = CERTFILE;
struct MHD_Daemon *HTTP_daemon;
struct MHD_Daemon *TLS_daemon;
/* look for HTTPS port argument */
if (argc < 4)
/* look for HTTPS arguments */
if (argc < 5)
{
printf ("Usage : %s HTTP-PORT SECONDS-TO-RUN HTTPS-PORT\n", argv[0]);
printf
("Usage : %s HTTP-PORT SECONDS-TO-RUN HTTPS-PORT X.509_FILE_PATH\n",
argv[0]);
return 1;
}
gnutls_global_init ();
// TODO check if this is truly necessary - disallow usage of the blocking /dev/random */
// gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
gnutls_anon_allocate_server_credentials (&anoncred);
HTTP_daemon =
MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
atoi (argv[1]), NULL, NULL, &http_ahc, MHD_OPTION_END);
generate_dh_params ();
if (HTTP_daemon == NULL)
{
printf ("Error: failed to start HTTP_daemon");
return 1;
}
gnutls_anon_set_server_dh_params (anoncred, dh_params);
TLS_daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
| MHD_USE_DEBUG | MHD_USE_SSL,
atoi (argv[3]), NULL, NULL, &TLS_echo, NULL,
TLS_daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG
| MHD_USE_SSL, atoi (argv[3]),
NULL,
NULL, &https_ahc,
NULL, MHD_OPTION_CONNECTION_TIMEOUT, 256,
MHD_OPTION_HTTPS_KEY_PATH, argv[4],
MHD_OPTION_HTTPS_CERT_PATH, argv[4],
MHD_OPTION_END);
if (TLS_daemon == NULL)
return 1;
{
printf ("Error: failed to start TLS_daemon");
return 1;
}
sleep (atoi (argv[2]));
MHD_stop_daemon (daemon);
MHD_stop_daemon (HTTP_daemon);
gnutls_anon_free_server_credentials (anoncred);
MHD_stop_daemon (TLS_daemon);
gnutls_global_deinit ();
return 0;
}