/****************************************************************** * $Id: nanohttp-ssl.c,v 1.24 2006/04/17 12:26:17 mrcsys Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2001-2005 Rochester Institute of Technology * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Author: Matt Campbell ******************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_IO_H #include #endif #ifdef HAVE_SSL #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #endif #include "nanohttp-common.h" #include "nanohttp-socket.h" #include "nanohttp-ssl.h" #ifdef HAVE_SSL static char *certificate = NULL; static char *certpass = ""; static char *ca_list = NULL; static SSL_CTX *context = NULL; static int enabled = 0; int (*_hssl_verify_cert) (X509 * cert) = _hssl_dummy_verify_cert; static void _hssl_superseed (void) { int buf[256], i; srand (time (NULL)); for (i = 0; i < 256; i++) { 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 error"; } } static int _hssl_password_callback(char *buf, int num, int rwflag, void *userdata) { int ret; ret = strlen(certpass); if (num < ret + 1) return 0; strcpy(buf, certpass); return ret; } 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); return strstr(name, buf) ? 1 : 0; } void hssl_set_hssl_verify_cert( int func(X509 * cert) ){ _hssl_verify_cert = func; } static int _hssl_dummy_verify_cert(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; } static int _hssl_cert_verify_callback(int prev_ok, X509_STORE_CTX * ctx) { /* if ((X509_STORE_CTX_get_error(ctx) = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)) { log_verbose1("Self signed cert in chain"); return 1; } */ log_verbose2 ("Cert depth = %d", X509_STORE_CTX_get_error_depth(ctx) ); if (X509_STORE_CTX_get_error_depth(ctx) == 0) { return _hssl_verify_cert(X509_STORE_CTX_get_current_cert(ctx)); } else { log_verbose1 ("Cert ok (prev)"); return prev_ok; } } static void _hssl_parse_arguments(int argc, char **argv) { int i; for (i=1; isock); if ((ret = SSL_connect(ssl)) <= 0) { herror_t err; 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; } /* 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 herror_new("hssl_client_ssl", HSSL_ERROR_CERTIFICATE, "No certificate provided"); } 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_verbose1 ("SSL client initialization completed"); sock->ssl = ssl; return H_OK; } herror_t hssl_server_ssl(hsocket_t *sock) { SSL *ssl; int ret; if (!enabled) return H_OK; log_verbose2("Starting SSL initialization for socket %d", sock->sock); if (!(ssl = SSL_new(context))) { 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 ((ret = SSL_accept(ssl)) <= 0) { 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; } sock->ssl = ssl; return H_OK; } void hssl_cleanup(hsocket_t *sock) { if (sock->ssl) { SSL_shutdown (sock->ssl); SSL_free (sock->ssl); sock->ssl = NULL; } 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) { 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 { 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; /* log_verbose4("sock->sock=%d, sock->ssl=%p, len=%li", sock->sock, sock->ssl, len); */ 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; } #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