#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; } 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; }