summaryrefslogblamecommitdiffstats
path: root/openssl.c
blob: 47acd833b6acdca3c12833f638f798cefb928101 (plain) (tree)
1
2
3
4
5



                             
                                 
















                                                        

                                                                           









                                                                       
                                                  


                                                                                                
                                                             


                   











                                                                       










                                         

















                                                          











                                                                                                                                                          
                       

                                                          




                                                              


























                                                                                                             
#include "openssl.h"
#include "helper.h"

static BOOL initDone = FALSE;
static const EVP_MD *sha1 = NULL;

void ssl_printErrors(char *bailMsg)
{
	unsigned long err;
	while ((err = ERR_get_error())) {
		char *msg = ERR_error_string(err, NULL);
		printf("OpenSSL: %s\n", msg);
	}
	if (bailMsg != NULL) bail(bailMsg);
}

BOOL ssl_init()
{
	if (initDone) return TRUE;
	SSL_load_error_strings();
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	sha1 = EVP_get_digestbyname("sha1");
	if (sha1 == NULL) ssl_printErrors("Could not load SHA-1 digest\n");
	return TRUE;
}

SSL_CTX* ssl_newServerCtx(char *certfile, char *keyfile)
{
	const SSL_METHOD *m = SSLv23_server_method();
	if (m == NULL) ssl_printErrors("newServerCtx: method is NULL");
	SSL_CTX *ctx = SSL_CTX_new(m);
	if (ctx == NULL) ssl_printErrors("newServerCtx: ctx is NULL");
	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
	SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM);
	SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM);
	if (!SSL_CTX_check_private_key(ctx)) ssl_printErrors("Could not load cert/private key");
	SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
	return ctx;
}

SSL_CTX* ssl_newClientCtx()
{
	const SSL_METHOD *m = SSLv23_client_method();
	if (m == NULL) ssl_printErrors("newClientCtx: method is NULL");
	SSL_CTX *ctx = SSL_CTX_new(m);
	if (ctx == NULL) ssl_printErrors("newClientCtx: ctx is NULL");
	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
	SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
	return ctx;
}

SSL *ssl_new(int clientFd, SSL_CTX *ctx)
{
	SSL *ssl = SSL_new(ctx);
	if (ssl == NULL) {
		ssl_printErrors(NULL);
		return NULL;
	}
	if (!SSL_set_fd(ssl, clientFd)) {
		ssl_printErrors(NULL);
		SSL_free(ssl);
		return NULL;
	}
	return ssl;
}

BOOL ssl_acceptClient(epoll_client_t *client)
{
	if (client->sslAccepted) return TRUE;
	int ret = SSL_accept(client->ssl);
	if (ret == 1) {
		client->sslAccepted = TRUE;
		return TRUE;
	}
	if (ret < 0) {
		int err = SSL_get_error(client->ssl, ret);
		if (SSL_BLOCKED(err)) return TRUE;
	}
	return FALSE;
}

BOOL ssl_connectServer(epoll_server_t *server)
{
	if (server->sslConnected) return TRUE;
	int ret = SSL_connect(server->ssl);
	if (ret == 1) {
		if (!ssl_checkCertificateHash(server)) {
			printf("Warning: Fingerprint of %s doesn't match value given in config, refusing to talk to server!\n", server->serverData->addr);
			return FALSE;
		}
		server->sslConnected = TRUE;
		return TRUE;
	}
	if (ret <= 0) {
		int err = SSL_get_error(server->ssl, ret);
		if (SSL_BLOCKED(err)) return TRUE;
		if (err == SSL_ERROR_SSL) {
			ssl_printErrors(NULL);
		} else {
			printf("SSL Unknown error %d\n", err);
		}
	}
	return FALSE;
}

BOOL ssl_checkCertificateHash(epoll_server_t *server)
{
	if (server->ssl == NULL) {
		printf("Bug: Asked to check certificate of non-SSL connection\n");
		return FALSE;
	}
	for (int i = 0; i < FINGERPRINTLEN; ++i) {
		if (server->serverData->fingerprint[i] != 0) {
			unsigned char md[EVP_MAX_MD_SIZE];
			unsigned int n = 20;
			X509 *cert = SSL_get_peer_certificate(server->ssl);
			if (cert == NULL) {
				printf("Warning: Server %s has no certificate!\n", server->serverData->addr);
				return FALSE;
			}
			X509_free(cert);
			X509_digest(cert, sha1, md, &n);
			return n == 20 && memcmp(md, server->serverData->fingerprint, n) == 0;
		}
	}
	return TRUE;
}