Mercurial > code
view C++/modules/Socket/SocketSsl.cpp @ 388:131ecc6ce7b5
Socket: fix kqueue with new names
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 30 Jun 2015 13:53:40 +0200 |
parents | 743b3a1c71c8 |
children | e292f0fa5395 |
line wrap: on
line source
/* * SocketSsl.cpp -- OpenSSL extension for sockets * * Copyright (c) 2013, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if 0 #include "SocketAddress.h" #include "SocketSsl.h" namespace { inline auto sslMethod(int type) noexcept { if (type == SocketSslOptions::SSLv3) return SSLv3_method(); if (type == SocketSslOptions::TLSv1) return TLSv1_method(); throw std::invalid_argument("unknown method selected"); } inline std::string sslError(int error) { return ERR_reason_error_string(error); } } // !namespace std::mutex SocketAbstractSsl::s_sslMutex; std::atomic<bool> SocketAbstractSsl::s_sslInitialized{false}; SocketSsl::SocketSsl(SocketTcp<Address> sc, SSL_CTX *context, SSL *ssl) : SocketTcp{std::move(*sc)} , m_context{context, SSL_CTX_free} , m_ssl{ssl, SSL_free} { #if !defined(SOCKET_NO_SSL_INIT) if (!s_sslInitialized) { sslInitialize(); } #endif } SocketSsl::SocketSsl(int family, int protocol, SocketSslOptions options) : SocketTcp{family, protocol} , m_context{nullptr, nullptr} , m_ssl{nullptr, nullptr} , m_options{std::move(options)} { #if !defined(SOCKET_NO_SSL_INIT) if (!s_sslInitialized) { sslInitialize(); } #endif m_context = ContextHandle{SSL_CTX_new(sslMethod(m_options.method)), SSL_CTX_free}; m_ssl = SslHandle{SSL_new(m_context.get()), SSL_free}; SSL_set_fd(m_ssl.get(), m_handle); } void SocketSsl::connect(const std::unique_ptr<SocketAddress> &address) { // 1. Standard connect SocketTcp::connect(address); // 2. OpenSSL handshake auto ret = SSL_connect(m_ssl.get()); if (ret <= 0) { auto error = SSL_get_error(m_ssl.get(), ret); if (error == SSL_ERROR_WANT_READ) { throw SocketError(SocketError::WouldBlockRead, "connect", "Operation in progress"); } else if (error == SSL_ERROR_WANT_WRITE) { throw SocketError(SocketError::WouldBlockWrite, "connect", "Operation in progress"); } else { throw SocketError(SocketError::System, "connect", sslError(error)); } } m_state = SocketState::Connected; } std::unique_ptr<SocketTcp> SocketSsl::accept(std::unique_ptr<SocketAddress> &info) { auto client = SocketTcp::accept(info); auto context = SSL_CTX_new(sslMethod(m_options.method)); if (m_options.certificate.size() > 0) SSL_CTX_use_certificate_file(context, m_options.certificate.c_str(), SSL_FILETYPE_PEM); if (m_options.privateKey.size() > 0) SSL_CTX_use_PrivateKey_file(context, m_options.privateKey.c_str(), SSL_FILETYPE_PEM); if (m_options.verify && !SSL_CTX_check_private_key(context)) { throw SocketError(SocketError::System, "accept", "certificate failure"); } // SSL object auto ssl = SSL_new(context); SSL_set_fd(ssl, client->handle()); auto ret = SSL_accept(ssl); if (ret <= 0) { auto error = SSL_get_error(ssl, ret); if (error == SSL_ERROR_WANT_READ) { throw SocketError(SocketError::WouldBlockRead, "accept", "Operation would block"); } else if (error == SSL_ERROR_WANT_WRITE) { throw SocketError(SocketError::WouldBlockWrite, "accept", "Operation would block"); } else { throw SocketError(SocketError::System, "accept", sslError(error)); } } return std::make_unique<SocketSsl>(std::move(client), context, ssl); } unsigned SocketSsl::recv(void *data, unsigned len) { auto nbread = SSL_read(m_ssl.get(), data, len); if (nbread <= 0) { auto error = SSL_get_error(m_ssl.get(), nbread); if (error == SSL_ERROR_WANT_READ) { throw SocketError(SocketError::WouldBlockRead, "recv", "Operation would block"); } else if (error == SSL_ERROR_WANT_WRITE) { throw SocketError(SocketError::WouldBlockWrite, "recv", "Operation would block"); } else { throw SocketError(SocketError::System, "recv", sslError(error)); } } return nbread; } unsigned SocketSsl::send(const void *data, unsigned len) { auto nbread = SSL_write(m_ssl.get(), data, len); if (nbread <= 0) { auto error = SSL_get_error(m_ssl.get(), nbread); if (error == SSL_ERROR_WANT_READ) { throw SocketError(SocketError::WouldBlockRead, "send", "Operation would block"); } else if (error == SSL_ERROR_WANT_WRITE) { throw SocketError(SocketError::WouldBlockWrite, "send", "Operation would block"); } else { throw SocketError(SocketError::System, "send", sslError(error)); } } return nbread; } #endif