PreVerify/mqtt/paho.mqtt.cpp/ssl_options.cpp
2024-09-09 19:18:28 +08:00

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
}