/*
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#ifdef HAVE_OPENSSL
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include "monitor.h"
#include "net.h"
#include "ssl.h"
/* -------------------------------------------------------------- Prototypes */
#define SSLERROR ERR_error_string(ERR_get_error(),NULL)
static int unsigned long ssl_thread_id();
static void ssl_mutex_lock(int, int n, const char *, int );
static int verify_init(ssl_server_connection *);
static int verify_callback(int, X509_STORE_CTX *);
static int check_preverify(X509_STORE_CTX *);
static void cleanup_ssl_socket(ssl_connection *);
static void cleanup_ssl_server_socket(ssl_server_connection *);
static int handle_error(int, ssl_connection *);
static int update_ssl_cert_data(ssl_connection *);
static ssl_server_connection *new_ssl_server_connection(char *, char *);
static int start_ssl();
static int allow_self_certification = FALSE;
static int ssl_initialized = FALSE;
static pthread_mutex_t ssl_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t *ssl_mutex_table;
/* ------------------------------------------------------------- Definitions */
/**
* Number of random bytes to obtain
*/
#define RANDOM_BYTES 1024
/**
* The PRIMARY random device selected for seeding the PRNG. We use a
* non-blocking pseudo random device, to generate pseudo entropy.
*/
#define URANDOM_DEVICE "/dev/urandom"
/**
* If a non-blocking device is not found on the system a blocking
* entropy producer is tried instead.
*/
#define RANDOM_DEVICE "/dev/random"
/**
* SSL Socket methods.
*
* @author Christian Hopp <chopp@iei.tu-clausthal.de>
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com>
* @author Martin Pala, <martinp@tildeslash.com>
*
* @version \$Id: ssl.c,v 1.61 2007/07/25 12:54:30 hauk Exp $
*
* @file
*/
/**
* For some of the code I was enlightened by:
*
* An Introduction to OpenSSL Programming, Part I of II
*
* by Eric Rescorla
* Linux Journal 9/2001
* http://www.linuxjournal.com/article.php?sid=4822
*/
/* ------------------------------------------------------------------ Public */
/**
* Embeds a socket in a ssl connection.
* @param socket the socket to be used.
* @return The ssl connection or NULL if an error occured.
*/
int embed_ssl_socket(ssl_connection *ssl, int socket) {
int ssl_error;
time_t ssl_time;
if(!ssl)
return FALSE;
if(!ssl_initialized)
start_ssl();
if(socket >= 0) {
ssl->socket= socket;
} else {
LogError("%s: Socket error!\n", prog);
goto sslerror;
}
if((ssl->handler= SSL_new (ssl->ctx)) == NULL) {
LogError("%s: Cannot initialize the SSL handler -- %s\n", prog, SSLERROR);
goto sslerror;
}
set_noblock(ssl->socket);
if((ssl->socket_bio= BIO_new_socket(ssl->socket, BIO_NOCLOSE)) == NULL) {
LogError("%s: Cannot generate IO buffer -- %s\n", prog, SSLERROR);
goto sslerror;
}
SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio);
ssl_time= time(NULL);
while((ssl_error= SSL_connect (ssl->handler)) < 0) {
if((time(NULL) - ssl_time) > SSL_TIMEOUT) {
LogError("%s: SSL service timeout!\n", prog);
goto sslerror;
}
if(!handle_error(ssl_error, ssl))
goto sslerror;
if(!BIO_should_retry(ssl->socket_bio))
goto sslerror;
}
ssl->cipher= (char *) SSL_get_cipher(ssl->handler);
if(! update_ssl_cert_data(ssl)) {
LogError("%s: Cannot get the SSL server certificate!\n", prog);
goto sslerror;
}
return TRUE;
sslerror:
cleanup_ssl_socket(ssl);
return FALSE;
}
/**
* Compare certificate with given md5 sum
* @param ssl reference to ssl connection
* @param md5sum string of the md5sum to test against
* @return TRUE, if sums do not match FALSE
*/
int check_ssl_md5sum(ssl_connection *ssl, char *md5sum) {
unsigned int i= 0;
ASSERT(md5sum);
while (( i < ssl->cert_md5_len ) &&
( md5sum[2*i] != '\0' ) &&
( md5sum[2*i+1] != '\0' ))
{
unsigned char c=
(md5sum[2*i] > 57 ? md5sum[2*i] - 87 : md5sum[2*i] - 48) * 0x10+
(md5sum[2*i+1] > 57 ? md5sum[2*i+1] - 87 : md5sum[2*i+1] - 48);
if(c != ssl->cert_md5[i])
return FALSE;
i ++;
}
return TRUE;
}
/**
* Closes a ssl connection (ssl socket + net socket)
* @param ssl ssl connection
* @return TRUE, or FALSE if an error has occured.
*/
int close_ssl_socket(ssl_connection *ssl) {
int rv;
if(!ssl)
return FALSE;
if(! (rv= SSL_shutdown(ssl->handler))) {
shutdown(ssl->socket, 1);
rv= SSL_shutdown(ssl->handler);
}
close_socket(ssl->socket);
cleanup_ssl_socket(ssl);
return (rv > 0)?TRUE:FALSE;
}
/**
* Garbage collection for non-reusable parts a ssl connection
* @param ssl ssl connection
*/
void delete_ssl_socket(ssl_connection *ssl) {
if(!ssl)
return;
cleanup_ssl_socket(ssl);
if(ssl->ctx && !ssl->accepted)
SSL_CTX_free(ssl->ctx);
ssl->ctx= NULL;
FREE(ssl);
}
/**
* Initializes a ssl connection for server use.
* @param pemfilename Filename for the key/cert file
* @return An ssl connection, or NULL if an error occured.
*/
ssl_server_connection *init_ssl_server(char *pemfile, char *clientpemfile) {
ssl_server_connection *ssl_server;
ASSERT(pemfile);
if(!ssl_initialized)
start_ssl();
ssl_server = new_ssl_server_connection(pemfile, clientpemfile);
if(!(ssl_server->method= SSLv23_server_method())) {
LogError("%s: Cannot initialize the SSL method -- %s\n", prog, SSLERROR);
goto sslerror;
}
if(!(ssl_server->ctx= SSL_CTX_new(ssl_server->method))) {
LogError("%s: Cannot initialize SSL server certificate handler -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(SSL_CTX_use_certificate_file(ssl_server->ctx, pemfile,
SSL_FILETYPE_PEM) != 1) {
LogError("%s: Cannot initialize SSL server certificate -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile,
SSL_FILETYPE_PEM) != 1) {
LogError("%s: Cannot initialize SSL server private key -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(SSL_CTX_check_private_key(ssl_server->ctx) != 1) {
LogError("%s: The private key doesn't match the certificate public key -- %s\n",
prog, SSLERROR);
goto sslerror;
}
/*
* We need this to force transmission of client certs
*/
if (!verify_init(ssl_server)) {
LogError("%s: Verification engine was not properly initialized -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(ssl_server->clientpemfile) {
STACK_OF(X509_NAME) *stack= SSL_CTX_get_client_CA_list(ssl_server->ctx);
LogInfo("%s: Found %d client certificates\n", prog, sk_X509_NAME_num(stack));
}
return ssl_server;
sslerror:
cleanup_ssl_server_socket(ssl_server);
return NULL;
}
/**
* Deletes a SSL server connection.
* @param ssl_server data for ssl server connection
*/
void delete_ssl_server_socket(ssl_server_connection *ssl_server) {
if(!ssl_server)
return;
cleanup_ssl_server_socket(ssl_server);
if(ssl_server->ctx)
SSL_CTX_free(ssl_server->ctx);
FREE(ssl_server);
}
/**
* Inserts an SSL connection in the connection list of a server.
* @param ssl_server data for ssl server connection
* @return new SSL connection for the connection, or NULL if failed
*/
ssl_connection *insert_accepted_ssl_socket(ssl_server_connection *ssl_server) {
ssl_connection *ssl;
ASSERT(ssl_server);
if(!ssl_initialized)
start_ssl();
NEW(ssl);
ssl->method= NULL;
ssl->handler= NULL;
ssl->cert= NULL;
ssl->cipher= NULL;
ssl->socket= 0;
ssl->next= NULL;
ssl->accepted= FALSE;
ssl->cert_md5= NULL;
ssl->cert_md5_len= 0;
ssl->clientpemfile= NULL;
if(ssl_server->clientpemfile!=NULL)
ssl->clientpemfile= xstrdup(ssl_server->clientpemfile);
LOCK(ssl_mutex);
ssl->prev= NULL;
ssl->next= ssl_server->ssl_conn_list;
if( ssl->next != NULL )
ssl->next->prev= ssl;
END_LOCK;
ssl_server->ssl_conn_list= ssl;
ssl->ctx= ssl_server->ctx;
ssl->accepted= TRUE;
return ssl;
}
/**
* Closes an accepted SSL server connection and deletes it form the
* connection list.
* @param ssl_server data for ssl server connection
* @param ssl data the connection to be deleted
*/
void close_accepted_ssl_socket(ssl_server_connection *ssl_server,
ssl_connection *ssl) {
if(!ssl || !ssl_server)
return;
close_socket(ssl->socket);
LOCK(ssl_mutex);
if(ssl->prev == NULL)
ssl_server->ssl_conn_list= ssl->next;
else
ssl->prev->next= ssl->next;
END_LOCK;
delete_ssl_socket(ssl);
}
/**
* Embeds an accepted server socket in an existing ssl connection.
* @param ssl ssl connection
* @param socket the socket to be used.
* @return TRUE, or FALSE if an error has occured.
*/
int embed_accepted_ssl_socket(ssl_connection *ssl, int socket) {
int ssl_error;
time_t ssl_time;
ASSERT(ssl);
ssl->socket= socket;
if(!ssl_initialized)
start_ssl();
if(!(ssl->handler= SSL_new(ssl->ctx))) {
LogError("%s: Cannot initialize the SSL handler -- %s\n", prog, SSLERROR);
return FALSE;
}
if(socket < 0) {
LogError("%s: Socket error!\n", prog);
return FALSE;
}
set_noblock(ssl->socket);
if(!(ssl->socket_bio= BIO_new_socket(ssl->socket, BIO_NOCLOSE))) {
LogError("%s: Cannot generate IO buffer -- %s\n", prog, SSLERROR);
return FALSE;
}
SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio);
ssl_time= time(NULL);
while((ssl_error= SSL_accept(ssl->handler)) < 0) {
if((time(NULL) - ssl_time) > SSL_TIMEOUT) {
LogError("%s: SSL service timeout!\n", prog);
return FALSE;
}
if(!handle_error(ssl_error, ssl))
return FALSE;
if(!BIO_should_retry(ssl->socket_bio))
return FALSE;
}
ssl->cipher= (char *)SSL_get_cipher(ssl->handler);
if(!update_ssl_cert_data(ssl) && ssl->clientpemfile) {
LogError("%s: The client did not supply a required client certificate!\n",
prog);
return FALSE;
}
if(SSL_get_verify_result(ssl->handler) > 0) {
LogError("%s: Verification of the certificate has failed!\n", prog);
return FALSE;
}
return TRUE;
}
/**
* Send data package though the ssl connection
* @param ssl ssl connection
* @param buffer array containg the data
* @param len size of the data container
* @param timeout Seconds to wait for data to be written
* @return number of bytes transmitted, -1 in case of an error
*/
int send_ssl_socket(ssl_connection *ssl, void *buffer, int len, int timeout) {
int n= 0;
ASSERT(ssl);
do {
n= SSL_write(ssl->handler, buffer, len);
} while(n <= 0 &&
BIO_should_retry(ssl->socket_bio) &&
can_write(ssl->socket, timeout));
return (n > 0)?n:-1;
}
/**
* Receive data package though the ssl connection
* @param ssl ssl connection
* @param buffer array to hold the data
* @param len size of the data container
* @param timeout Seconds to wait for data to be available
* @return number of bytes transmitted, -1 in case of an error
*/
int recv_ssl_socket(ssl_connection *ssl, void *buffer, int len, int timeout) {
int n= 0;
ASSERT(ssl);
do {
n= SSL_read(ssl->handler, buffer, len);
} while(n < 0 &&
BIO_should_retry(ssl->socket_bio) &&
can_read(ssl->socket, timeout));
return (n >= 0)?n:-1;
}
/**
* Stop SSL support library
* @return TRUE, or FALSE if an error has occured.
*/
void stop_ssl() {
if(ssl_initialized) {
int i;
ssl_initialized= FALSE;
ERR_free_strings();
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
for(i= 0; i < CRYPTO_num_locks(); i++)
pthread_mutex_destroy(&ssl_mutex_table[i]);
FREE(ssl_mutex_table);
RAND_cleanup();
}
}
/**
* Configures the ssl engine
*/
void config_ssl(int conf_allow_self_cert) {
allow_self_certification= conf_allow_self_cert;
}
/**
* Generate a new ssl connection
* @return ssl connection container
*/
ssl_connection *new_ssl_connection(char *clientpemfile, int sslversion) {
ssl_connection *ssl;
if(!ssl_initialized)
start_ssl();
NEW(ssl);
ssl->socket_bio= NULL;
ssl->handler= NULL;
ssl->cert= NULL;
ssl->cipher= NULL;
ssl->socket= 0;
ssl->next = NULL;
ssl->accepted = FALSE;
ssl->cert_md5 = NULL;
ssl->cert_md5_len = 0;
ssl->clientpemfile= clientpemfile?xstrdup(clientpemfile):NULL;
switch (sslversion) {
case SSL_VERSION_AUTO:
ssl->method = SSLv23_client_method();
break;
case SSL_VERSION_SSLV2:
ssl->method = SSLv2_client_method();
break;
case SSL_VERSION_SSLV3:
ssl->method = SSLv3_client_method();
break;
case SSL_VERSION_TLS:
ssl->method = TLSv1_client_method();
break;
default:
LogError("%s: Unknown SSL version!\n", prog);
goto sslerror;
}
if(!ssl->method) {
LogError("%s: Cannot initialize SSL method -- %s\n", prog, SSLERROR);
goto sslerror;
}
if(!(ssl->ctx= SSL_CTX_new (ssl->method))) {
LogError("%s: Cannot initialize SSL server certificate handler -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(ssl->clientpemfile) {
if(SSL_CTX_use_certificate_file(ssl->ctx, ssl->clientpemfile,
SSL_FILETYPE_PEM) <= 0) {
LogError("%s: Cannot initialize SSL server certificate -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->clientpemfile,
SSL_FILETYPE_PEM) <= 0) {
LogError("%s: Cannot initialize SSL server private key -- %s\n",
prog, SSLERROR);
goto sslerror;
}
if(!SSL_CTX_check_private_key(ssl->ctx)) {
LogError("%s: Private key does not match the certificate public key -- %s\n",
prog, SSLERROR);
goto sslerror;
}
}
return ssl;
sslerror:
delete_ssl_socket(ssl);
return NULL;
}
/* ----------------------------------------------------------------- Private */
/**
* Init verification of transmitted client certs
*/
static int verify_init(ssl_server_connection *ssl_server) {
struct stat stat_buf;
if(!ssl_server->clientpemfile) {
SSL_CTX_set_verify(ssl_server->ctx, SSL_VERIFY_NONE, NULL);
return TRUE;
}
if(stat(ssl_server->clientpemfile, &stat_buf) == -1) {
LogError("%s: Cannot stat the SSL pem path '%s' -- %s\n",
prog, Run.httpsslclientpem, STRERROR);
return FALSE;
}
if(S_ISDIR(stat_buf.st_mode)) {
if(!SSL_CTX_load_verify_locations(ssl_server->ctx, NULL ,
ssl_server->clientpemfile)) {
LogError("%s: Error setting verify directory to %s -- %s\n",
prog, Run.httpsslclientpem, SSLERROR);
return FALSE;
}
LogInfo("%s: Loaded SSL client pem directory '%s'\n",
prog, ssl_server->clientpemfile);
/* Monit's server cert for cli support */
if(!SSL_CTX_load_verify_locations(ssl_server->ctx, ssl_server->pemfile,
NULL)) {
LogError("%s: Error loading verify certificates from %s -- %s\n",
prog, ssl_server->pemfile, SSLERROR);
return FALSE;
}
LogInfo("%s: Loaded monit's SSL pem server file '%s'\n",
prog, ssl_server->pemfile);
} else if(S_ISREG(stat_buf.st_mode)) {
if(!SSL_CTX_load_verify_locations(ssl_server->ctx,
ssl_server->clientpemfile,
NULL)) {
LogError("%s: Error loading verify certificates from %s -- %s\n",
prog, Run.httpsslclientpem, SSLERROR);
return FALSE;
}
LogInfo("%s: Loaded SSL pem client file '%s'\n",
prog, ssl_server->clientpemfile);
/* Monits server cert for cli support ! */
if(!SSL_CTX_load_verify_locations(ssl_server->ctx, ssl_server->pemfile,
NULL)) {
LogError("%s: Error loading verify certificates from %s -- %s\n",
prog, ssl_server->pemfile, SSLERROR);
return FALSE;
}
LogInfo("%s: Loaded monit's SSL pem server file '%s'\n",
prog, ssl_server->pemfile);
SSL_CTX_set_client_CA_list(ssl_server->ctx,
SSL_load_client_CA_file(ssl_server->clientpemfile));
} else {
LogError("%s: SSL client pem path is no file or directory %s\n",
prog, ssl_server->clientpemfile);
return FALSE;
}
SSL_CTX_set_verify(ssl_server->ctx, SSL_VERIFY_PEER, verify_callback);
return TRUE;
}
/**
* Check the transmitted client certs and a compare with client cert database
*/
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
char subject[STRLEN];
X509_OBJECT found_cert;
X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), subject,
STRLEN-1);
if(!preverify_ok && !check_preverify(ctx))
return 0;
if(ctx->error_depth==0 &&
X509_STORE_get_by_subject(ctx, X509_LU_X509,
X509_get_subject_name(ctx->current_cert),
&found_cert)!=1)
{
LogError("%s: SSL connection rejected. No matching certificate found -- %s\n",
prog, SSLERROR);
return 0;
}
return 1;
}
/**
* Analyse errors found before actual verification
* @return TRUE if successful
*/
static int check_preverify(X509_STORE_CTX *ctx) {
if ((ctx->error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) &&
(ctx->error != X509_V_ERR_INVALID_PURPOSE))
{
/* Remote site specified a certificate, but it's not correct */
LogError("%s: SSL connection rejected because certificate verification has failed -- error %i\n",
prog, ctx->error);
/* Reject connection */
return FALSE;
}
if(allow_self_certification &&
(ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT))
{
/* Let's accept self signed certs for the moment! */
LogInfo("%s: SSL connection accepted with self signed certificate!\n",
prog);
ctx->error=0;
return TRUE;
}
/* Reject connection */
LogError("%s: SSL connection rejected because certificate verification has failed -- error %i!\n",
prog, ctx->error);
return FALSE;
}
/**
* Helper function for the SSL threadding support
* @return current thread number
*/
static int unsigned long ssl_thread_id() {
return ((unsigned long) pthread_self());
}
/**
* Helper function for the SSL threadding support
*/
static void ssl_mutex_lock(int mode, int n, const char *file, int line) {
if(mode & CRYPTO_LOCK)
pthread_mutex_lock( & ssl_mutex_table[n]);
else
pthread_mutex_unlock( & ssl_mutex_table[n]);
}
/**
* Handle errors during read, write, connect and accept
* @return TRUE if non fatal, FALSE if non fatal and retry
*/
static int handle_error(int code, ssl_connection *ssl) {
int ssl_error= SSL_get_error(ssl->handler, code);
switch (ssl_error) {
case SSL_ERROR_WANT_READ:
if(can_read(ssl->socket, SSL_TIMEOUT))
return TRUE;
LogError("%s: Openssl read timeout error!\n", prog);
break;
case SSL_ERROR_WANT_WRITE:
if(can_read(ssl->socket, SSL_TIMEOUT))
return TRUE;
LogError("%s: Openssl write timeout error!\n", prog);
break;
case SSL_ERROR_SYSCALL:
LogError("%s: Openssl syscall error: %s!\n", prog, STRERROR);
break;
case SSL_ERROR_SSL:
LogError("%s: Openssl engine error: %s\n", prog, SSLERROR);
break;
default:
LogError("%s: Openssl error!\n", prog);
break;
}
return FALSE;
}
/**
* Garbage collection for non reusable parts of the ssl connection
* @param ssl ssl connection
*/
static void cleanup_ssl_socket(ssl_connection *ssl) {
if(!ssl)
return;
if(ssl->cert) {
X509_free(ssl->cert);
ssl->cert= NULL;
}
if(ssl->handler) {
SSL_free(ssl->handler);
ssl->handler= NULL;
}
if(ssl->socket_bio) {
/*
* no BIO_free(ssl->socket_bio); necessary, because BIO is freed
* by ssl->handler
*/
ssl->socket_bio= NULL;
}
if(ssl->cert_issuer)
FREE(ssl->cert_issuer);
if(ssl->cert_subject)
FREE(ssl->cert_subject);
if(ssl->cert_md5)
FREE(ssl->cert_md5);
if(ssl->clientpemfile)
FREE(ssl->clientpemfile);
}
/**
* Garbage collection for a SSL server connection.
* @param ssl_server data for ssl server connection
*/
static void cleanup_ssl_server_socket(ssl_server_connection *ssl_server) {
if(!ssl_server)
return;
if(ssl_server->pemfile)
FREE(ssl_server->pemfile);
if(ssl_server->clientpemfile)
FREE(ssl_server->clientpemfile);
while(ssl_server->ssl_conn_list) {
ssl_connection *ssl = ssl_server->ssl_conn_list;
ssl_server->ssl_conn_list = ssl_server->ssl_conn_list->next;
close_accepted_ssl_socket(ssl_server, ssl);
}
}
/**
* Updates some data in the ssl connection
* @param ssl reference to ssl connection
* @return TRUE, if not successful FALSE
*/
static int update_ssl_cert_data(ssl_connection *ssl) {
unsigned char md5[EVP_MAX_MD_SIZE];
ASSERT(ssl);
if(!(ssl->cert = SSL_get_peer_certificate(ssl->handler)))
return FALSE;
ssl->cert_issuer= X509_NAME_oneline (X509_get_issuer_name(ssl->cert), 0, 0);
ssl->cert_subject= X509_NAME_oneline (X509_get_subject_name(ssl->cert), 0, 0);
X509_digest(ssl->cert, EVP_md5(), md5, &ssl->cert_md5_len);
ssl->cert_md5= (unsigned char *)xstrdup((char *)md5);
return TRUE;
}
/**
* Generate a new ssl server connection
* @return ssl server connection container
*/
static ssl_server_connection *new_ssl_server_connection(char * pemfile,
char * clientpemfile) {
ssl_server_connection *ssl_server;
ASSERT(pemfile);
NEW(ssl_server);
ssl_server->ctx= NULL;
ssl_server->method= NULL;
ssl_server->server_socket= 0;
ssl_server->ssl_conn_list= NULL;
ssl_server->pemfile= xstrdup(pemfile);
ssl_server->clientpemfile= clientpemfile?xstrdup(clientpemfile):NULL;
return ssl_server;
}
/**
* Start SSL support library. It has to be run before the SSL support
* can be used.
* @return TRUE, or FALSE if an error has occured.
*/
static int start_ssl() {
if(! ssl_initialized) {
int i;
int locks = CRYPTO_num_locks();
ssl_initialized= TRUE;
ERR_load_crypto_strings();
ssl_mutex_table= xcalloc(locks, sizeof(pthread_mutex_t));
for(i= 0; i < locks; i++)
pthread_mutex_init(&ssl_mutex_table[i], NULL);
CRYPTO_set_id_callback(ssl_thread_id);
CRYPTO_set_locking_callback(ssl_mutex_lock);
SSL_library_init();
if(File_exist(URANDOM_DEVICE)) {
return(RAND_load_file(URANDOM_DEVICE, RANDOM_BYTES)==RANDOM_BYTES);
} else if(File_exist(RANDOM_DEVICE)) {
DEBUG("Gathering entropy from the random device\n");
return(RAND_load_file(RANDOM_DEVICE, RANDOM_BYTES)==RANDOM_BYTES);
}
return FALSE;
}
return TRUE;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1