tls.c 2.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
 * Copyright 2016,      Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
 */

/**
 * TLS support functions
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>

#include "tls.h"

#include "logging.h"
#define CATMODULE "tls"

#ifdef HAVE_OPENSSL
struct tls_ctx_tag {
    size_t refc;
    SSL_CTX *ctx;
};

void       tls_initialize(void)
{
    SSL_load_error_strings(); /* readable error messages */
    SSL_library_init(); /* initialize library */
}
void       tls_shutdown(void)
{
}

tls_ctx_t *tls_ctx_new(const char *cert_file, const char *key_file, const char *cipher_list)
{
    tls_ctx_t *ctx;
    SSL_METHOD *method;
    long ssl_opts;

    if (!cert_file || !key_file || !cipher_list)
        return NULL;

    ctx = calloc(1, sizeof(*ctx));
    if (!ctx)
        return NULL;

    method = SSLv23_server_method();

    ctx->refc = 1;
    ctx->ctx = SSL_CTX_new(method);

    ssl_opts = SSL_CTX_get_options(ctx->ctx);
#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ctx->ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
#else
    SSL_CTX_set_options(ctx->ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
#endif

    do {
        if (SSL_CTX_use_certificate_chain_file(ctx->ctx, cert_file) <= 0) {
            ICECAST_LOG_WARN("Invalid cert file %s", cert_file);
            break;
        }
        if (SSL_CTX_use_PrivateKey_file(ctx->ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
            ICECAST_LOG_WARN("Invalid private key file %s", key_file);
            break;
        }
        if (!SSL_CTX_check_private_key(ctx->ctx)) {
            ICECAST_LOG_ERROR("Invalid %s - Private key does not match cert public key", key_file);
            break;
        }
        if (SSL_CTX_set_cipher_list(ctx->ctx, cipher_list) <= 0) {
            ICECAST_LOG_WARN("Invalid cipher list: %s", cipher_list);
        }
        ICECAST_LOG_INFO("Certificate found at %s", cert_file);
        ICECAST_LOG_INFO("Using ciphers %s", cipher_list);
        return ctx;
    } while (0);

    ICECAST_LOG_INFO("Can not setup TLS.");
    tls_ctx_unref(ctx);
    return NULL;
}

void       tls_ctx_ref(tls_ctx_t *ctx)
{
    if (!ctx)
        return;

    ctx->refc++;
}

void       tls_ctx_unref(tls_ctx_t *ctx)
{
    if (!ctx)
        return;

    ctx->refc--;

    if (ctx->refc)
        return;

    if (ctx->ctx)
        SSL_CTX_free(ctx->ctx);

    free(ctx);
}

SSL       *tls_ctx_SSL_new(tls_ctx_t *ctx)
{
    if (!ctx)
        return NULL;
    return SSL_new(ctx->ctx);
}
#else
void       tls_initialize(void)
{
}
void       tls_shutdown(void)
{
}

tls_ctx_t *tls_ctx_new(const char *cert_file, const char *key_file, const char *cipher_list)
{
    return NULL;
}
void       tls_ctx_ref(tls_ctx_t *ctx)
{
}
void       tls_ctx_unref(tls_ctx_t *ctx)
{
}
#endif