diff options
Diffstat (limited to 'nanohttp/nanohttp-ssl.c')
-rw-r--r-- | nanohttp/nanohttp-ssl.c | 521 |
1 files changed, 307 insertions, 214 deletions
diff --git a/nanohttp/nanohttp-ssl.c b/nanohttp/nanohttp-ssl.c index 63bf0f7..a365e64 100644 --- a/nanohttp/nanohttp-ssl.c +++ b/nanohttp/nanohttp-ssl.c @@ -1,4 +1,7 @@ -/* +/************************************************************************* + * $Id: nanohttp-ssl.c,v 1.18 2006/03/06 13:37:38 m0gg Exp $ + * + * CSOAP Project: A http client/server library in C * Copyright (C) 2001-2005 Rochester Institute of Technology * * This program is free software; you can redistribute it and/or modify @@ -21,9 +24,6 @@ * Descrip: SSL connection routines */ -/* Enter only if --with-ssl was specified to the configure script */ -#ifdef HAVE_SSL - #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -36,16 +36,6 @@ #include <netinet/in.h> #endif -#if HAVE_INTTYPES_H -#include <inttypes.h> -#else -# if HAVE_STDINT_H -# include <stdint.h> -# else -typedef unsigned int uint32_t; -# endif -#endif - #ifdef HAVE_STRING_H #include <string.h> #endif @@ -54,6 +44,10 @@ typedef unsigned int uint32_t; #include <stdlib.h> #endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + #ifdef HAVE_TIME_H #include <time.h> #endif @@ -66,12 +60,11 @@ typedef unsigned int uint32_t; #include <unistd.h> #endif -#ifdef WIN32 +#ifdef HAVE_IO_H #include <io.h> -typedef unsigned int uint32_t; -#else #endif +#ifdef HAVE_SSL #ifdef HAVE_OPENSSL_RAND_H #include <openssl/rand.h> #endif @@ -79,24 +72,25 @@ typedef unsigned int uint32_t; #ifdef HAVE_OPENSSL_ERR_H #include <openssl/err.h> #endif +#endif #include "nanohttp-common.h" #include "nanohttp-socket.h" #include "nanohttp-ssl.h" -#define MAXCHUNK 1024 -#define HEADER_LEN 5 -char HEADER[HEADER_LEN] = { 186, 84, 202, 86, 224 }; -static char *pass; +#ifdef HAVE_SSL -/* - * superseed - * Creates a 1k random seed and uses it to seed - * the SSL random number generator - */ +static char *certificate = NULL; +static char *certpass = NULL; +static char *ca_list = NULL; +static SSL_CTX *context = NULL; -void -superseed () +static int enabled = 0; +static int initialized = 0; + + +static void +_hssl_superseed (void) { int buf[256], i; @@ -107,18 +101,47 @@ superseed () buf[i] = rand (); } RAND_seed ((unsigned char *) buf, sizeof (buf)); + + return; } + +static char * +_hssl_get_error(SSL *ssl, int ret) +{ + switch(SSL_get_error(ssl, ret)) + { + case SSL_ERROR_NONE: + return "None"; + case SSL_ERROR_ZERO_RETURN: + return "Zero return"; + case SSL_ERROR_WANT_READ: + return "Want read"; + case SSL_ERROR_WANT_WRITE: + return "Want write"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "Want x509 lookup"; + case SSL_ERROR_SYSCALL: + return "Syscall failed"; + case SSL_ERROR_SSL: + return "SSL error"; + default: + return "Unkown"; + } +} + + static int pw_cb (char *buf, int num, int rwflag, void *userdata) { - if (num < (int) strlen (pass) + 1) + if (num < (int) strlen (certpass) + 1) return (0); - strcpy (buf, pass); - return strlen (pass); + strcpy(buf, certpass); + return strlen(certpass); } + int verify_sn (X509 * cert, int who, int nid, char *str) { @@ -152,6 +175,7 @@ verify_sn (X509 * cert, int who, int nid, char *str) } } + #ifdef NOUSER_VERIFY static int user_verify (X509 * cert) @@ -190,262 +214,331 @@ verify_cb (int prev_ok, X509_STORE_CTX * ctx) #endif } -void -start_ssl( void ) + +static void +_hssl_parse_arguments(int argc, char **argv) +{ + + int i; + + for (i=1; i<argc; i++) + { + if (!strcmp(argv[i-1], NHTTP_ARG_CERT)) + { + certificate = argv[i]; + } + else if (!strcmp(argv[i-1], NHTTP_ARG_CERTPASS)) + { + certpass = argv[i]; + } + else if (!strcmp(argv[i-1], NHTTP_ARG_CA)) + { + ca_list = argv[i]; + } + else if (!strcmp(argv[i-1], NHTTP_ARG_HTTPS)) + { + enabled = 1; + } + } + + return; +} + + +static void +_hssl_library_init(void) { /* Global system initialization */ log_verbose1 ("Initializing library"); - SSL_library_init (); - SSL_load_error_strings (); - ERR_load_crypto_strings (); - OpenSSL_add_ssl_algorithms (); + + SSL_library_init(); + + SSL_load_error_strings(); + ERR_load_crypto_strings(); + + OpenSSL_add_ssl_algorithms(); + + initialized = 1; return; } -SSL_CTX * -initialize_ctx (const char *keyfile, const char *password, const char *calist) + +static herror_t +hssl_context_init(void) { - SSL_CTX *ctx = NULL; + log_verbose3("enabled=%i, certificate=%p", enabled, certificate); + + if (!enabled || !certificate) + return H_OK; - if (password == NULL) - password = ""; + if (certpass == NULL) + certpass = ""; /* Create our context */ - ctx = SSL_CTX_new (SSLv23_method ()); - - if (ctx == NULL) + if (!(context = SSL_CTX_new(SSLv23_method()))) { log_error1 ("Cannot create SSL context"); - return NULL; + return herror_new("hssl_context_init", HSSL_ERROR_CONTEXT, "Unable to create SSL context"); } - log_verbose1 ("SSL context created ok"); - /* Load our keys and certificates */ - if (keyfile != NULL && password != NULL) + if (!(SSL_CTX_use_certificate_file (context, certificate, SSL_FILETYPE_PEM))) { + SSL_CTX_free(context); + log_error2 ("Cannot read certificate file: \"%s\"", certificate); + return herror_new("hssl_context_init", HSSL_ERROR_CERTIFICATE, "Unable to use SSL certificate \"%s\"", certificate); + } - if (!(SSL_CTX_use_certificate_file (ctx, keyfile, SSL_FILETYPE_PEM))) - { - log_error2 ("Couldn't read certificate file: %s", keyfile); - SSL_CTX_free (ctx); - return ctx = NULL; - } - - log_verbose1 ("Certificate file read ok"); + SSL_CTX_set_default_passwd_cb(context, pw_cb); - pass = strdup(password); - SSL_CTX_set_default_passwd_cb (ctx, pw_cb); + if (!(SSL_CTX_use_PrivateKey_file(context, certificate, SSL_FILETYPE_PEM))) + { + SSL_CTX_free(context); + log_error2 ("Cannot read key file: \"%s\"", certificate); + return herror_new("hssl_context_init", HSSL_ERROR_PEM, "Unable to use private key"); + } - if (!(SSL_CTX_use_PrivateKey_file (ctx, keyfile, SSL_FILETYPE_PEM))) + if (ca_list != NULL && *ca_list != '\0') + { + if (!(SSL_CTX_load_verify_locations(context, ca_list, NULL))) { - log_error2 ("Couldn't read key file: %s", keyfile); - SSL_CTX_free (ctx); - return ctx = NULL; + SSL_CTX_free(context); + log_error2 ("Cannot read CA list: \"%s\"", ca_list); + return herror_new("hssl_context_init", HSSL_ERROR_CA_LIST, "Unable to read certification authorities \"%s\""); } - log_verbose1 ("Keyfile read ok"); + SSL_CTX_set_client_CA_list (context, SSL_load_client_CA_file (ca_list)); + log_verbose1 ("Certification authority contacted"); } - if (calist != NULL && *calist != '\0') - { + SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_cb); - /* Load the CAs we trust */ - if (!(SSL_CTX_load_verify_locations (ctx, calist, NULL))) - { - log_error2 ("Couldn't read CA list: %s", calist); - SSL_CTX_free (ctx); - return ctx = NULL; - } + log_verbose1("Verify callback registered"); + + SSL_CTX_set_mode(context, SSL_MODE_AUTO_RETRY); + + SSL_CTX_set_session_cache_mode(context, SSL_SESS_CACHE_OFF); + + _hssl_superseed(); + + return H_OK; +} - SSL_CTX_set_client_CA_list (ctx, SSL_load_client_CA_file (calist)); - log_verbose1 ("Certificate Authority contacted"); +static void +_hssl_context_destroy(void) +{ + if (context) + { + SSL_CTX_free(context); + context = NULL; } - SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, - verify_cb); - log_verbose1 ("Verify callback registered"); + return; +} - SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_OFF); +herror_t +hssl_module_init(int argc, char **argv) +{ + _hssl_parse_arguments(argc, argv); - /* Load randomness */ - superseed (); + if (!initialized) + { + if (enabled) + { + _hssl_library_init(); + log_verbose1("SSL enabled"); + } + else + { + log_verbose1("SSL _not_ enabled"); + } + } - return ctx; + return hssl_context_init(); } + void -log_ssl_error (SSL * ssl, int ret) +hssl_module_destroy(void) { - int errqueue; - char errorbuf[256] = "Error: "; + _hssl_context_destroy(); - if (ret == 0) + return; +} + + +herror_t +hssl_client_ssl(hsocket_t *sock) +{ + SSL *ssl; + int ret; + + log_verbose1 ("Starting SSL client initialization"); + + if (!(ssl = SSL_new(context))) { - log_error1 ("SSL handshake was not successful, contolled shutdown"); + log_error1("Cannot create new SSL object"); + return herror_new("hssl_client_ssl", HSSL_ERROR_CLIENT, "SSL_new failed"); } - else if (ret == -1) + + SSL_set_fd (ssl, sock->sock); + + if ((ret = SSL_connect(ssl)) <= 0) { - log_error1 ("SSL handshake was not successful, fatal error at protocol"); - } + herror_t err; - errqueue = SSL_get_error (ssl, ret); + log_error2 ("SSL connect error (%s)", _hssl_get_error(ssl, -1)); + err = herror_new("hssl_client_ssl", HSSL_ERROR_CONNECT, "SSL_connect failed (%s)", _hssl_get_error(ssl, ret)); + SSL_free (ssl); + return err; + } - switch (errqueue) + /* SSL_connect should take care of this for us. + if (SSL_get_peer_certificate(ssl) == NULL) { - case SSL_ERROR_NONE: - strcat (errorbuf, "None"); - break; - case SSL_ERROR_ZERO_RETURN: - strcat (errorbuf, "Zero return"); - break; - case SSL_ERROR_WANT_READ: - strcat (errorbuf, "Want read"); - break; - case SSL_ERROR_WANT_WRITE: - strcat (errorbuf, "Want write"); - break; - case SSL_ERROR_WANT_X509_LOOKUP: - strcat (errorbuf, "Want x509 lookup"); - break; - case SSL_ERROR_SYSCALL: - strcat (errorbuf, "Syscall:"); - if (ret == 0) - { - strcat (errorbuf, "Protocol violation"); - } - else if (ret == -1) - { - strcat (errorbuf, "BIO reported an I/O error"); - } - else - { - strcat (errorbuf, "Unknown syscall error"); - } /* if */ + log_error1("No certificate provided"); + SSL_free(ssl); + return herror_new("hssl_client_ssl", HSSL_ERROR_CERTIFICATE, "No certificate provided"); + } - break; - case SSL_ERROR_SSL: - strcat (errorbuf, "SSL library"); - while ((errqueue = ERR_get_error())) - { - log_error2 ("SSL %s", ERR_error_string (errqueue, NULL)); - } - break; - } /* switch code */ + if (SSL_get_verify_result(ssl) != X509_V_OK) + { + log_error1("Certificate did not verify"); + SSL_free(ssl); + return herror_new("hssl_client_ssl", HSSL_ERROR_CERTIFICATE, "Verfiy certificate failed"); + } */ - log_error1 (errorbuf); + log_verbose1 ("SSL client initialization completed"); + + /* XXX: why??? + if ((status = hsocket_block(sock, sock->block)) != H_OK) + { + log_error2("Cannot make socket non-blocking (%s)", herror_message(status)); + SSL_free(ssl); + return status; + } */ + + sock->ssl = ssl; + + return H_OK; } -SSL * -init_ssl (SSL_CTX * ctx, int sock, int type) + +herror_t +hssl_server_ssl(hsocket_t *sock) { - int ret; SSL *ssl; -#if 0 -#ifdef WIN32 - BIO *rbio; - BIO *wbio; -#else - BIO *sbio; -#endif -#endif + int ret; - log_verbose1 ("Starting SSL Initialization"); + if (!enabled) + return H_OK; - ssl = SSL_new (ctx); + log_verbose2("Starting SSL initialization for socket %d", sock->sock); - if (ssl == NULL) + if (!(ssl = SSL_new(context))) { - log_error1 ("Cannot create new ssl object"); - return NULL; + log_warn1("SSL_new failed"); + return herror_new("hssl_server_ssl", HSSL_ERROR_SERVER, "Cannot create SSL object"); } + SSL_set_fd(ssl, sock->sock); -#if 0 -#ifdef WIN32 - log_error1 ("Setting up BIO with socket"); - rbio = BIO_new_socket (sock, BIO_NOCLOSE); - if (rbio == NULL) + if ((ret = SSL_accept(ssl)) <= 0) { - log_error1 ("BIO_new_socket failed"); - return NULL; + herror_t err; + + log_error2 ("SSL_accept failed (%s)", _hssl_get_error(ssl, ret)); + + err = herror_new("hssl_server_ssl", HSSL_ERROR_SERVER, "SSL_accept failed (%s)", _hssl_get_error(ssl, ret)); + SSL_free (ssl); + + return err; } - SSL_set_bio (ssl, rbio, rbio); -#else - sbio = BIO_new_socket (sock, BIO_NOCLOSE); + sock->ssl = ssl; - if (sbio == NULL) + return H_OK; +} + + +void +hssl_cleanup(hsocket_t *sock) +{ + + if (sock->ssl) { - log_error1 ("BIO_new_socket failed"); - return NULL; + SSL_shutdown (sock->ssl); + SSL_free (sock->ssl); + sock->ssl = NULL; } - SSL_set_bio (ssl, sbio, sbio); -#endif -#endif - SSL_set_fd (ssl, sock); - if (type == SSL_SERVER) + return; +} + + +herror_t hssl_read(hsocket_t *sock, char *buf, size_t len, size_t *received) +{ + int count; + + log_verbose4("sock->sock=%d sock->ssl=%p, len=%li", sock->sock, sock->ssl, len); + + if (sock->ssl) { - hsocket_t sock_t; - sock_t.sock = sock; - hsocket_block (sock_t, 1); - ret = SSL_accept (ssl); - hsocket_block (sock_t, 0); - if (ret <= 0) - { - log_error1 ("SSL accept error"); - log_ssl_error (ssl, ret); - SSL_free (ssl); - return NULL; - } /* if error */ + if ((count = SSL_read(sock->ssl, buf, len)) == -1) + return herror_new("SSL_read", HSOCKET_ERROR_RECEIVE, "SSL_read failed (%s)", _hssl_get_error(sock->ssl, count)); } else - { /* client */ - ret = SSL_connect (ssl); - if (ret <= 0) - { - log_error1 ("SSL connect error"); - log_ssl_error (ssl, ret); - SSL_free (ssl); - return NULL; - } /* if error */ - /* SSL_connect should take care of this for us. - if(SSL_get_peer_certificate(ssl) == NULL) { log_error1( "No - certificate provided"); SSL_free(ssl); return ssl = NULL; } - if(SSL_get_verify_result(ssl) != X509_V_OK) { log_error1( "Certificate - did not verify"); SSL_free(ssl); return ssl = NULL; } */ + { + if ((count = recv(sock->sock, buf, len, 0)) == -1) + return herror_new("hssl_read", HSOCKET_ERROR_RECEIVE, "recv failed (%s)", strerror(errno)); } + *received = count; - log_verbose1 ("Completed SSL Initialization"); - return ssl; + return H_OK; } -void -ssl_cleanup (SSL * ssl) + +herror_t hssl_write(hsocket_t *sock, const char *buf, size_t len, size_t *sent) { - /* does nothing to context */ + int count; - if (ssl != NULL) - { + log_verbose4("sock->sock=%d, sock->ssl=%p, len=%li", sock->sock, sock->ssl, len); - SSL_shutdown (ssl); -// SSL_clear(ssl); - SSL_free (ssl); - ssl = NULL; + if (sock->ssl) + { + if ((count = SSL_write(sock->ssl, buf, len)) == -1) + return herror_new("SSL_write", HSOCKET_ERROR_SEND, "SSL_write failed (%s)", _hssl_get_error(sock->ssl, count)); + } + else + { + if ((count = send(sock->sock, buf, len, 0)) == -1) + return herror_new("hssl_write", HSOCKET_ERROR_SEND, "send failed (%s)", strerror(errno)); } + *sent = count; + + return H_OK; } -int -ssl_checkFatal( SSL *ssl, int status ){ - switch (SSL_get_error(ssl, status)) { - case SSL_ERROR_ZERO_RETURN: - case SSL_ERROR_SSL: - case SSL_ERROR_SYSCALL: - return 1; - break; - default: - return 0; - } +#else + +herror_t hssl_read(hsocket_t *sock, char *buf, size_t len, size_t *received) +{ + int count; + + if ((count = recv(sock->sock, buf, len, 0)) == -1) + return herror_new("hssl_read", HSOCKET_ERROR_RECEIVE, "recv failed (%s)", strerror(errno)); + *received = count; + return H_OK; +} + + +herror_t hssl_write(hsocket_t *sock, const char *buf, size_t len, size_t *sent) +{ + int count; + + if ((count = send(sock->sock, buf, len, 0)) == -1) + return herror_new("hssl_write", HSOCKET_ERROR_SEND, "send failed (%s)", strerror(errno)); + *sent = count; + return H_OK; } -#endif /* end of ifdef HAVE_SSL */ +#endif |