#include "internal.h" #if !defined(NO_SSL) // set_ssl_option() function updates this array. // It loads SSL library dynamically and changes NULLs to the actual addresses // of respective functions. The macros above (like SSL_connect()) are really // just calling these functions indirectly via the pointer. static struct ssl_func ssl_sw[] = { {"SSL_free", NULL}, {"SSL_accept", NULL}, {"SSL_connect", NULL}, {"SSL_read", NULL}, {"SSL_write", NULL}, {"SSL_get_error", NULL}, {"SSL_set_fd", NULL}, {"SSL_new", NULL}, {"SSL_CTX_new", NULL}, {"SSLv23_server_method", NULL}, {"SSL_library_init", NULL}, {"SSL_CTX_use_PrivateKey_file", NULL}, {"SSL_CTX_use_certificate_file",NULL}, {"SSL_CTX_set_default_passwd_cb",NULL}, {"SSL_CTX_free", NULL}, {"SSL_load_error_strings", NULL}, {"SSL_CTX_use_certificate_chain_file", NULL}, {"SSLv23_client_method", NULL}, {"SSL_pending", NULL}, {"SSL_CTX_set_verify", NULL}, {"SSL_shutdown", NULL}, {NULL, NULL} }; // Similar array as ssl_sw. These functions could be located in different lib. static struct ssl_func crypto_sw[] = { {"CRYPTO_num_locks", NULL}, {"CRYPTO_set_locking_callback", NULL}, {"CRYPTO_set_id_callback", NULL}, {"ERR_get_error", NULL}, {"ERR_error_string", NULL}, {NULL, NULL} }; static pthread_mutex_t *ssl_mutexes; static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) { return (conn->ssl = SSL_new(s)) != NULL && SSL_set_fd(conn->ssl, conn->client.sock) == 1 && func(conn->ssl) == 1; } // Return OpenSSL error message static const char *ssl_error(void) { unsigned long err; err = ERR_get_error(); return err == 0 ? "" : ERR_error_string(err, NULL); } static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line) { (void) line; (void) file; if (mode & 1) { // 1 is CRYPTO_LOCK (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]); } else { (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]); } } static unsigned long ssl_id_callback(void) { return (unsigned long) pthread_self(); } #if !defined(NO_SSL_DL) static int load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw) { union {void *p; void (*fp)(void);} u; void *dll_handle; struct ssl_func *fp; if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) { cry(fc(ctx), "%s: cannot load %s", __func__, dll_name); return 0; } for (fp = sw; fp->name != NULL; fp++) { #ifdef _WIN32 // GetProcAddress() returns pointer to function u.fp = (void (*)(void)) dlsym(dll_handle, fp->name); #else // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to // function pointers. We need to use a union to make a cast. u.p = dlsym(dll_handle, fp->name); #endif // _WIN32 if (u.fp == NULL) { cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name); return 0; } else { fp->ptr = u.fp; } } return 1; } #endif // NO_SSL_DL // Dynamically load SSL library. Set up ctx->ssl_ctx pointer. static int set_ssl_option(struct mg_context *ctx) { int i, size; const char *pem; // If PEM file is not specified and the init_ssl callback // is not specified, skip SSL initialization. if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL) { // MG_INIT_SSL // ctx->callbacks.init_ssl == NULL) { return 1; } #if !defined(NO_SSL_DL) if (!load_dll(ctx, SSL_LIB, ssl_sw) || !load_dll(ctx, CRYPTO_LIB, crypto_sw)) { return 0; } #endif // NO_SSL_DL // Initialize SSL library SSL_library_init(); SSL_load_error_strings(); if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error()); return 0; } // If user callback returned non-NULL, that means that user callback has // set up certificate itself. In this case, skip sertificate setting. // MG_INIT_SSL if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 || SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) { cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error()); return 0; } if (pem != NULL) { (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem); } // Initialize locking callbacks, needed for thread safety. // http://www.openssl.org/support/faq.html#PROG1 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) { cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); return 0; } for (i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_init(&ssl_mutexes[i], NULL); } CRYPTO_set_locking_callback(&ssl_locking_callback); CRYPTO_set_id_callback(&ssl_id_callback); return 1; } static void uninitialize_ssl(struct mg_context *ctx) { int i; if (ctx->ssl_ctx != NULL) { CRYPTO_set_locking_callback(NULL); for (i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_destroy(&ssl_mutexes[i]); } CRYPTO_set_locking_callback(NULL); CRYPTO_set_id_callback(NULL); } } #endif // !NO_SSL