MySQLHandlerFactory.cpp 4.5 KB
Newer Older
A
Amos Bird 已提交
1 2
#include <Common/config.h>
#if USE_POCO_NETSSL
Y
Yuriy 已提交
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
#include <Common/OpenSSLHelpers.h>
#include <Poco/Crypto/X509Certificate.h>
#include <Poco/Net/SSLManager.h>
#include <Poco/Net/TCPServerConnectionFactory.h>
#include <Poco/Util/Application.h>
#include <common/logger_useful.h>
#include <ext/scope_guard.h>
#include "IServer.h"
#include "MySQLHandler.h"
#include "MySQLHandlerFactory.h"

namespace DB
{

namespace ErrorCodes
{
    extern const int CANNOT_OPEN_FILE;
    extern const int NO_ELEMENTS_IN_CONFIG;
    extern const int OPENSSL_ERROR;
    extern const int SYSTEM_ERROR;
}

MySQLHandlerFactory::MySQLHandlerFactory(IServer & server_)
    : server(server_)
    , log(&Logger::get("MySQLHandlerFactory"))
{
    try
    {
        Poco::Net::SSLManager::instance().defaultServerContext();
    }
    catch (...)
    {
        LOG_INFO(log, "Failed to create SSL context. SSL will be disabled. Error: " << getCurrentExceptionMessage(false));
        ssl_enabled = false;
    }

    /// Reading rsa keys for SHA256 authentication plugin.
    try
    {
        readRSAKeys();
    }
    catch (...)
    {
        LOG_WARNING(log, "Failed to read RSA keys. Error: " << getCurrentExceptionMessage(false));
        generateRSAKeys();
    }
}

void MySQLHandlerFactory::readRSAKeys()
{
    const Poco::Util::LayeredConfiguration & config = Poco::Util::Application::instance().config();
    String certificateFileProperty = "openSSL.server.certificateFile";
    String privateKeyFileProperty = "openSSL.server.privateKeyFile";

    if (!config.has(certificateFileProperty))
        throw Exception("Certificate file is not set.", ErrorCodes::NO_ELEMENTS_IN_CONFIG);

    if (!config.has(privateKeyFileProperty))
        throw Exception("Private key file is not set.", ErrorCodes::NO_ELEMENTS_IN_CONFIG);

    {
        String certificateFile = config.getString(certificateFileProperty);
        FILE * fp = fopen(certificateFile.data(), "r");
        if (fp == nullptr)
            throw Exception("Cannot open certificate file: " + certificateFile + ".", ErrorCodes::CANNOT_OPEN_FILE);
        SCOPE_EXIT(fclose(fp));

        X509 * x509 = PEM_read_X509(fp, nullptr, nullptr, nullptr);
        SCOPE_EXIT(X509_free(x509));
        if (x509 == nullptr)
            throw Exception("Failed to read PEM certificate from " + certificateFile + ". Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);

        EVP_PKEY * p = X509_get_pubkey(x509);
        if (p == nullptr)
            throw Exception("Failed to get RSA key from X509. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);
        SCOPE_EXIT(EVP_PKEY_free(p));

        public_key.reset(EVP_PKEY_get1_RSA(p));
        if (public_key.get() == nullptr)
            throw Exception("Failed to get RSA key from ENV_PKEY. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);
    }

    {
        String privateKeyFile = config.getString(privateKeyFileProperty);

        FILE * fp = fopen(privateKeyFile.data(), "r");
        if (fp == nullptr)
            throw Exception ("Cannot open private key file " + privateKeyFile + ".", ErrorCodes::CANNOT_OPEN_FILE);
        SCOPE_EXIT(fclose(fp));

        private_key.reset(PEM_read_RSAPrivateKey(fp, nullptr, nullptr, nullptr));
Y
Yuriy 已提交
94
        if (!private_key)
Y
Yuriy 已提交
95 96 97 98 99 100 101
            throw Exception("Failed to read RSA private key from " + privateKeyFile + ". Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);
    }
}

void MySQLHandlerFactory::generateRSAKeys()
{
    LOG_INFO(log, "Generating new RSA key.");
Y
Yuriy 已提交
102 103
    public_key.reset(RSA_new());
    if (!public_key)
Y
Yuriy 已提交
104 105 106 107 108 109 110
        throw Exception("Failed to allocate RSA key. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);

    BIGNUM * e = BN_new();
    if (!e)
        throw Exception("Failed to allocate BIGNUM. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);
    SCOPE_EXIT(BN_free(e));

Y
Yuriy 已提交
111
    if (!BN_set_word(e, 65537) || !RSA_generate_key_ex(public_key.get(), 2048, e, nullptr))
Y
Yuriy 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
        throw Exception("Failed to generate RSA key. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);

    private_key.reset(RSAPrivateKey_dup(public_key.get()));
    if (!private_key)
        throw Exception("Failed to copy RSA key. Error: " + getOpenSSLErrors(), ErrorCodes::OPENSSL_ERROR);
}

Poco::Net::TCPServerConnection * MySQLHandlerFactory::createConnection(const Poco::Net::StreamSocket & socket)
{
    size_t connection_id = last_connection_id++;
    LOG_TRACE(log, "MySQL connection. Id: " << connection_id << ". Address: " << socket.peerAddress().toString());
    return new MySQLHandler(server, socket, *public_key, *private_key, ssl_enabled, connection_id);
}

}
A
Amos Bird 已提交
127
#endif