353 lines
9.1 KiB
C++
353 lines
9.1 KiB
C++
/*******************************************************************************
|
|
* Copyright (c) 2016 Guilherme Ferreira <guilherme.maciel.ferreira@gmail.com>
|
|
* Copyright (c) 2016-2021 Frank Pagliughi <fpagliughi@mindspring.com>
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v2.0
|
|
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
*
|
|
* The Eclipse Public License is available at
|
|
* http://www.eclipse.org/legal/epl-v20.html
|
|
* and the Eclipse Distribution License is available at
|
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
*
|
|
* Contributors:
|
|
* Guilherme Ferreira - initial implementation and documentation
|
|
* Frank Pagliughi - added copy & move operations
|
|
*******************************************************************************/
|
|
|
|
#include "mqtt/ssl_options.h"
|
|
#include <utility>
|
|
#include <cstring>
|
|
|
|
namespace mqtt {
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
PAHO_MQTTPP_EXPORT const MQTTAsync_SSLOptions ssl_options::DFLT_C_STRUCT
|
|
= MQTTAsync_SSLOptions_initializer;
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
ssl_options::ssl_options() : opts_(DFLT_C_STRUCT)
|
|
{
|
|
}
|
|
|
|
ssl_options::ssl_options(const string& trustStore, const string& keyStore,
|
|
const string& privateKey, const string& privateKeyPassword,
|
|
const string& enabledCipherSuites, bool enableServerCertAuth,
|
|
const std::vector<string> alpnProtos /*=std::vector<string>()*/)
|
|
: opts_(DFLT_C_STRUCT),
|
|
trustStore_(trustStore),
|
|
keyStore_(keyStore),
|
|
privateKey_(privateKey),
|
|
privateKeyPassword_(privateKeyPassword),
|
|
enabledCipherSuites_(enabledCipherSuites)
|
|
{
|
|
set_alpn_protos(alpnProtos);
|
|
update_c_struct();
|
|
opts_.enableServerCertAuth = enableServerCertAuth;
|
|
}
|
|
|
|
ssl_options::ssl_options(const string& trustStore, const string& keyStore,
|
|
const string& privateKey, const string& privateKeyPassword,
|
|
const string& caPath,
|
|
const string& enabledCipherSuites, bool enableServerCertAuth,
|
|
const std::vector<string> alpnProtos /*=std::vector<string>()*/)
|
|
: opts_(DFLT_C_STRUCT),
|
|
trustStore_(trustStore),
|
|
keyStore_(keyStore),
|
|
privateKey_(privateKey),
|
|
privateKeyPassword_(privateKeyPassword),
|
|
caPath_(caPath),
|
|
enabledCipherSuites_(enabledCipherSuites)
|
|
{
|
|
set_alpn_protos(alpnProtos);
|
|
update_c_struct();
|
|
opts_.enableServerCertAuth = enableServerCertAuth;
|
|
}
|
|
|
|
ssl_options::ssl_options(const ssl_options& other)
|
|
: opts_(other.opts_),
|
|
trustStore_(other.trustStore_),
|
|
keyStore_(other.keyStore_),
|
|
privateKey_(other.privateKey_),
|
|
privateKeyPassword_(other.privateKeyPassword_),
|
|
caPath_(other.caPath_),
|
|
enabledCipherSuites_(other.enabledCipherSuites_),
|
|
errHandler_(other.errHandler_),
|
|
pskHandler_(other.pskHandler_),
|
|
protos_(other.protos_)
|
|
{
|
|
update_c_struct();
|
|
}
|
|
|
|
ssl_options::ssl_options(ssl_options&& other)
|
|
: opts_(other.opts_),
|
|
trustStore_(std::move(other.trustStore_)),
|
|
keyStore_(std::move(other.keyStore_)),
|
|
privateKey_(std::move(other.privateKey_)),
|
|
privateKeyPassword_(std::move(other.privateKeyPassword_)),
|
|
caPath_(std::move(other.caPath_)),
|
|
enabledCipherSuites_(std::move(other.enabledCipherSuites_)),
|
|
errHandler_(std::move(other.errHandler_)),
|
|
pskHandler_(std::move(other.pskHandler_)),
|
|
protos_(std::move(other.protos_))
|
|
{
|
|
update_c_struct();
|
|
}
|
|
|
|
void ssl_options::update_c_struct()
|
|
{
|
|
opts_.trustStore = c_str(trustStore_);
|
|
opts_.keyStore = c_str(keyStore_);
|
|
opts_.privateKey = c_str(privateKey_);
|
|
opts_.privateKeyPassword = c_str(privateKeyPassword_);
|
|
opts_.CApath = c_str(caPath_);
|
|
opts_.enabledCipherSuites = c_str(enabledCipherSuites_);
|
|
|
|
if (errHandler_) {
|
|
opts_.ssl_error_cb = &ssl_options::on_error;
|
|
opts_.ssl_error_context = this;
|
|
}
|
|
else {
|
|
opts_.ssl_error_cb = nullptr;
|
|
opts_.ssl_error_context = nullptr;
|
|
}
|
|
|
|
if (pskHandler_) {
|
|
opts_.ssl_psk_cb = &ssl_options::on_psk;
|
|
opts_.ssl_psk_context = this;
|
|
}
|
|
else {
|
|
opts_.ssl_psk_cb = nullptr;
|
|
opts_.ssl_psk_context = nullptr;
|
|
}
|
|
|
|
if (!protos_.empty()) {
|
|
opts_.protos = protos_.data();
|
|
opts_.protos_len = unsigned(protos_.length());
|
|
}
|
|
else {
|
|
opts_.protos = nullptr;
|
|
opts_.protos_len = 0;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
int ssl_options::on_error(const char *str, size_t len, void *context)
|
|
{
|
|
try {
|
|
if (context && str && len > 0) {
|
|
string errMsg { str, len };
|
|
|
|
ssl_options* opts = static_cast<ssl_options*>(context);
|
|
auto& errHandler = opts->errHandler_;
|
|
|
|
if (errHandler)
|
|
errHandler(errMsg);
|
|
|
|
return MQTTASYNC_SUCCESS;
|
|
}
|
|
}
|
|
catch (...) {}
|
|
|
|
return MQTTASYNC_FAILURE;
|
|
}
|
|
|
|
unsigned ssl_options::on_psk(const char *hint, char *identity, unsigned max_identity_len,
|
|
unsigned char *psk, unsigned max_psk_len, void *context)
|
|
{
|
|
unsigned ret = 0;
|
|
|
|
try {
|
|
if (context) {
|
|
auto hintStr = (hint) ? string(hint) : string();
|
|
|
|
ssl_options* opts = static_cast<ssl_options*>(context);
|
|
auto& pskHandler = opts->pskHandler_;
|
|
|
|
if (pskHandler) {
|
|
ret = pskHandler(hintStr, identity, size_t(max_identity_len),
|
|
psk, size_t(max_psk_len));
|
|
}
|
|
}
|
|
}
|
|
catch (...) {}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
ssl_options& ssl_options::operator=(const ssl_options& rhs)
|
|
{
|
|
if (&rhs == this)
|
|
return *this;
|
|
|
|
opts_ = rhs.opts_;
|
|
|
|
trustStore_ = rhs.trustStore_;
|
|
keyStore_ = rhs.keyStore_;
|
|
privateKey_ = rhs.privateKey_;
|
|
privateKeyPassword_ = rhs.privateKeyPassword_;
|
|
caPath_ = rhs.caPath_;
|
|
enabledCipherSuites_ = rhs.enabledCipherSuites_;
|
|
|
|
errHandler_ = rhs.errHandler_;
|
|
pskHandler_ = rhs.pskHandler_;
|
|
|
|
protos_ = rhs.protos_;
|
|
|
|
update_c_struct();
|
|
return *this;
|
|
}
|
|
|
|
ssl_options& ssl_options::operator=(ssl_options&& rhs)
|
|
{
|
|
if (&rhs == this)
|
|
return *this;
|
|
|
|
opts_ = rhs.opts_;
|
|
|
|
trustStore_ = std::move(rhs.trustStore_);
|
|
keyStore_ = std::move(rhs.keyStore_);
|
|
privateKey_ = std::move(rhs.privateKey_);
|
|
privateKeyPassword_ = std::move(rhs.privateKeyPassword_);
|
|
caPath_ = std::move(rhs.caPath_);
|
|
enabledCipherSuites_ = std::move(rhs.enabledCipherSuites_);
|
|
|
|
errHandler_ = std::move(rhs.errHandler_);
|
|
pskHandler_ = std::move(rhs.pskHandler_);
|
|
|
|
protos_ = std::move(rhs.protos_);
|
|
|
|
update_c_struct();
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
void ssl_options::set_trust_store(const string& trustStore)
|
|
{
|
|
trustStore_ = trustStore;
|
|
opts_.trustStore = c_str(trustStore_);
|
|
}
|
|
|
|
void ssl_options::set_key_store(const string& keyStore)
|
|
{
|
|
keyStore_ = keyStore;
|
|
opts_.keyStore = c_str(keyStore_);
|
|
}
|
|
|
|
void ssl_options::set_private_key(const string& privateKey)
|
|
{
|
|
privateKey_ = privateKey;
|
|
opts_.privateKey = c_str(privateKey_);
|
|
}
|
|
|
|
void ssl_options::set_private_key_password(const string& privateKeyPassword)
|
|
{
|
|
privateKeyPassword_ = privateKeyPassword;
|
|
opts_.privateKeyPassword = c_str(privateKeyPassword_);
|
|
}
|
|
|
|
void ssl_options::set_enabled_cipher_suites(const string& enabledCipherSuites)
|
|
{
|
|
enabledCipherSuites_ = enabledCipherSuites;
|
|
opts_.enabledCipherSuites = c_str(enabledCipherSuites_);
|
|
}
|
|
|
|
void ssl_options::set_enable_server_cert_auth(bool enableServerCertAuth)
|
|
{
|
|
opts_.enableServerCertAuth = to_int(enableServerCertAuth);
|
|
}
|
|
|
|
void ssl_options::set_ca_path(const string& path)
|
|
{
|
|
caPath_ = path;
|
|
opts_.CApath = c_str(caPath_);
|
|
}
|
|
|
|
void ssl_options::set_error_handler(error_handler cb)
|
|
{
|
|
errHandler_ = cb;
|
|
|
|
if (errHandler_) {
|
|
opts_.ssl_error_cb = &ssl_options::on_error;
|
|
opts_.ssl_error_context = this;
|
|
}
|
|
else {
|
|
opts_.ssl_error_cb = nullptr;
|
|
opts_.ssl_error_context = nullptr;
|
|
}
|
|
}
|
|
|
|
void ssl_options::set_psk_handler(psk_handler cb)
|
|
{
|
|
pskHandler_ = cb;
|
|
|
|
if (pskHandler_) {
|
|
opts_.ssl_psk_cb = &ssl_options::on_psk;
|
|
opts_.ssl_psk_context = this;
|
|
}
|
|
else {
|
|
opts_.ssl_psk_cb = nullptr;
|
|
opts_.ssl_psk_context = nullptr;
|
|
}
|
|
}
|
|
|
|
// Gets the list of ALPN protocols.
|
|
// To do so, it must recover the strings from the wire format.
|
|
std::vector<string> ssl_options::get_alpn_protos() const
|
|
{
|
|
std::vector<string> protos;
|
|
size_t i = 0, n = protos_.length();
|
|
|
|
while (i < n) {
|
|
size_t sn = protos_[i++];
|
|
if (i+sn > n) break;
|
|
|
|
string s;
|
|
s.reserve(sn);
|
|
|
|
sn += i;
|
|
while (i < sn)
|
|
s.push_back(char(protos_[i++]));
|
|
protos.push_back(std::move(s));
|
|
}
|
|
return protos;
|
|
}
|
|
|
|
// Converts the vector of names into the binary string in wire format.
|
|
// This is a single string uf unsigned characters with each protocol
|
|
// prepended by a byte of its length.
|
|
void ssl_options::set_alpn_protos(const std::vector<string>& protos)
|
|
{
|
|
using uchar = unsigned char;
|
|
|
|
if (!protos.empty()) {
|
|
std::basic_string<uchar> protoBin;
|
|
for (const auto& proto : protos) {
|
|
protoBin.push_back(uchar(proto.length()));
|
|
for (const char c : proto)
|
|
protoBin.push_back(uchar(c));
|
|
}
|
|
protos_ = std::move(protoBin);
|
|
|
|
opts_.protos = protos_.data();
|
|
opts_.protos_len = unsigned(protos_.length());
|
|
}
|
|
else {
|
|
protos_ = std::basic_string<uchar>();
|
|
opts_.protos = nullptr;
|
|
opts_.protos_len = 0;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// end namespace mqtt
|
|
}
|
|
|