mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-09 16:52:09 +07:00
179 lines
5.1 KiB
C
179 lines
5.1 KiB
C
#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
|