summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nanohttp/nanohttp-ssl.c349
-rw-r--r--nanohttp/nanohttp-ssl.h97
2 files changed, 446 insertions, 0 deletions
diff --git a/nanohttp/nanohttp-ssl.c b/nanohttp/nanohttp-ssl.c
new file mode 100644
index 0000000..a477c3c
--- /dev/null
+++ b/nanohttp/nanohttp-ssl.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2001-2005 Rochester Institute of Technology
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Author: Matt Campbell
+ * Descrip: SSL connection routines
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# else
+typedef unsigned int uint32_t;
+# endif
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <fcntl.h>
+
+#include "nanohttp-ssl.h"
+#include "nanohttp-common.h"
+
+
+#ifdef WIN32
+#include <io.h>
+typedef unsigned int uint32_t;
+#else
+#include <unistd.h>
+#endif
+
+#define MAXCHUNK 1024
+#define HEADER_LEN 5
+char HEADER[HEADER_LEN] = {186, 84, 202, 86, 224};
+static char *pass;
+
+/*
+ * superseed
+ * Creates a 1k random seed and uses it to seed
+ * the SSL random number generator
+ */
+
+void superseed()
+{
+ int buf[256], i;
+
+ srand(time(NULL));
+
+ for(i = 0; i < 256; i++) {
+ buf[i] = rand();
+ } RAND_seed( (unsigned char*)buf, sizeof(buf));
+}
+
+static int pw_cb(char* buf, int num, int rwflag, void *userdata)
+{
+ if( num < (int)strlen(pass) + 1)
+ return(0);
+
+ strcpy(buf, pass);
+ return strlen(pass);
+}
+
+int verify_sn(X509* cert, int who, int nid, char* str)
+{
+ char name[256];
+ char buf[256];
+
+ memset(name, '\0', 256);
+ memset(buf, '\0', 256);
+
+ if(who == CERT_SUBJECT) {
+ X509_NAME_oneline(X509_get_subject_name(cert), name, 256);
+ } else {
+ X509_NAME_oneline(X509_get_issuer_name(cert), name, 256);
+ }
+
+ buf[0] = '/';
+ strcat(buf, OBJ_nid2sn(nid));
+ strcat(buf, "=");
+ strcat(buf, str);
+
+ if(strstr(name, buf)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int verify_cb(int prev_ok, X509_STORE_CTX* ctx)
+{
+ X509* cert = X509_STORE_CTX_get_current_cert(ctx);
+ int depth = X509_STORE_CTX_get_error_depth(ctx);
+ int err = X509_STORE_CTX_get_error(ctx);
+
+ if( err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ){
+ return 1;
+ }
+ if(depth == 0) {
+ return user_verify(cert);
+ } else {
+ return prev_ok;
+ }
+}
+
+int user_verify(X509* cert)
+{
+ //TODO: Make sure that the client is providing a client cert,
+ //or that the Module is providing the Module cert
+ /* connect to anyone */
+ log_verbose1("Validating certificate.");
+ return 1;
+}
+
+SSL_CTX *initialize_ctx(char* keyfile, char* password, char* calist)
+{
+ SSL_CTX* ctx = NULL;
+
+ if(password == NULL) password = "";
+
+
+ /* Global system initialization */
+ log_verbose1( "Initializing library");
+ SSL_library_init();
+ SSL_load_error_strings();
+ ERR_load_crypto_strings();
+ OpenSSL_add_ssl_algorithms();
+
+ /* Create our context*/
+ ctx = SSL_CTX_new( SSLv23_method() );
+
+ if(ctx == NULL) {
+ log_error1( "Cannot create SSL context");
+ return NULL;
+ }
+ log_verbose1( "SSL context created ok");
+
+ /* Load our keys and certificates*/
+ if(keyfile != NULL && password != NULL ){
+
+ 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");
+
+ pass = password;
+ SSL_CTX_set_default_passwd_cb(ctx, pw_cb);
+
+ if( !( SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) ) ) {
+ log_error2( "Couldn't read key file: %s", keyfile);
+ SSL_CTX_free(ctx);
+ return ctx = NULL;
+ }
+
+ log_verbose1("Keyfile read ok");
+ }
+ if( calist != NULL) {
+
+ /* 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;
+ }
+
+ SSL_CTX_set_client_CA_list( ctx, SSL_load_client_CA_file(calist) );
+ log_verbose1("Certificate Authority contacted");
+
+ }
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
+ verify_cb);
+ log_verbose1("Verify callback registered");
+
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF );
+
+
+ /* Load randomness */
+ superseed();
+
+ return ctx;
+}
+
+void log_ssl_error(SSL* ssl, int ret)
+{
+ int errqueue;
+ char errorbuf[256] = "Error: ";
+
+ if(ret == 0) {
+ log_error1("SSL handshake was not successful, contolled shutdown");
+ } else if(ret == -1) {
+ log_error1("SSL handshake was not successful, fatal error at protocol");
+ }
+
+ errqueue = SSL_get_error(ssl, ret);
+
+ switch(errqueue) {
+ 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 */
+
+ 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 */
+
+ log_error1( errorbuf);
+}
+
+SSL* init_ssl(SSL_CTX* ctx, int sock, int type)
+{
+ int ret;
+ int status;
+ SSL* ssl;
+#if 0
+#ifdef WIN32
+ BIO* rbio;
+ BIO* wbio;
+#else
+ BIO* sbio;
+#endif
+#endif
+
+ log_verbose1("Starting SSL Initialization");
+
+ ssl = SSL_new(ctx);
+
+ if(ssl == NULL) {
+ log_error1( "Cannot create new ssl object");
+ return NULL;
+ }
+
+#if 0
+#ifdef WIN32
+ log_error1("Setting up BIO with socket");
+ rbio = BIO_new_socket(sock, BIO_NOCLOSE);
+ if( rbio == NULL ) {
+ log_error1( "BIO_new_socket failed");
+ return NULL;
+ }
+ SSL_set_bio(ssl, rbio, rbio);
+
+#else
+ sbio = BIO_new_socket(sock, BIO_NOCLOSE);
+
+ if( sbio == NULL ) {
+ log_error1( "BIO_new_socket failed");
+ return NULL;
+ }
+ SSL_set_bio(ssl, sbio, sbio);
+#endif
+#endif
+ SSL_set_fd(ssl, sock);
+
+ if(type == SSL_SERVER) {
+ ret = SSL_accept(ssl);
+ if(ret <= 0) {
+ log_error1( "SSL accept error");
+ log_ssl_error(ssl, ret);
+ SSL_free(ssl);
+ return ssl = NULL;
+ } /* if error */
+ } else { /* client */
+ ret = SSL_connect(ssl);
+ if(ret <= 0) {
+ log_error1( "SSL connect error");
+ log_ssl_error(ssl, ret);
+ SSL_free(ssl);
+ return ssl = 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;
+ }
+ */
+ }
+
+ log_verbose1("Completed SSL Initialization");
+ return ssl;
+}
+
+void ssl_cleanup(SSL* ssl)
+{
+ /* does nothing to context */
+
+ if(ssl != NULL) {
+
+ SSL_shutdown(ssl);
+// SSL_clear(ssl);
+ SSL_free(ssl);
+ ssl = NULL;
+ }
+}
+
diff --git a/nanohttp/nanohttp-ssl.h b/nanohttp/nanohttp-ssl.h
new file mode 100644
index 0000000..f6f9219
--- /dev/null
+++ b/nanohttp/nanohttp-ssl.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2001-2005 Rochester Institute of Technology
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Author: Matt Campbell
+ * Contrib:
+ * Descrip: Common ssl routines
+ */
+
+#ifdef TRU64
+#include <arpa/inet.h>
+typedef unsigned int uint32_t;
+#endif
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <openssl/ssl.h>
+
+#ifdef WIN32
+typedef unsigned int uint32_t;
+#else
+#include <unistd.h>
+#endif
+
+#define SSL_SERVER 0
+#define SSL_CLIENT 1
+
+#define CERT_SUBJECT 0
+#define CERT_ISSUER 1
+
+typedef struct Con {
+ SSL* ssl;
+ int sock;
+} Con;
+
+/*
+ * Callback for password checker
+ */
+
+//static int pw_cb(char* buf, int num, int rwflag, void *userdata);
+
+/*
+ * Initialize the context
+ */
+
+SSL_CTX *initialize_ctx(char *keyfile, char *password, char* calist);
+
+/*
+ * Quick function for verifying a portion of the cert
+ * nid is any NID_ defined in <openssl/objects.h>
+ * returns non-zero if everything went ok
+ */
+
+int verify_sn(X509* cert, int who, int nid, char* str);
+
+/*
+ * Called by framework for verify
+ */
+
+//static int verify_cb(int prev_ok, X509_STORE_CTX* ctx);
+
+/*
+ * This function MUST be implemented by user client/server code somewhere
+ */
+
+int user_verify(X509* cert);
+
+/*
+ * Create the ssl socket and return it
+ * pass in the context and an open socket
+ */
+
+SSL* init_ssl(SSL_CTX* ctx, int sock, int type);
+
+/*
+ * Close the ssl connection (socket is still left open)
+ */
+
+void ssl_cleanup();
+
+#endif