Skip to content

Commit

Permalink
eclipse-paho#311 Added ALPN protocols to the SSL options
Browse files Browse the repository at this point in the history
  • Loading branch information
fpagliughi committed Dec 26, 2020
1 parent 4c62de4 commit 526f8aa
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 84 deletions.
6 changes: 6 additions & 0 deletions src/mqtt/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ inline std::ostream& operator<<(std::ostream& os, const exception& exc) {

/////////////////////////////////////////////////////////////////////////////

/**
* Exception thrown when an expected server response is missing.
*/
class missing_response : public exception
{
public:
Expand All @@ -178,6 +181,9 @@ class missing_response : public exception

/////////////////////////////////////////////////////////////////////////////

/**
* A timeout exception, particularly from the synchronous client.
*/
class timeout_error : public exception
{
public:
Expand Down
29 changes: 27 additions & 2 deletions src/mqtt/ssl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/// @file ssl_options.h
/// Declaration of MQTT ssl_options class
/// @date Jul 7, 2016
/// @author Guilherme Ferreira
/// @author Frank Pagliughi, Guilherme Ferreira
/////////////////////////////////////////////////////////////////////////////

/*******************************************************************************
Expand Down Expand Up @@ -95,9 +95,13 @@ class ssl_options

/** Error message callback handler */
error_handler errHandler_;

/** PSK callback handler */
psk_handler pskHandler_;

/** ALPN protocol list, in wire format */
std::basic_string<unsigned char> protos_;

/** Callbacks from the C library */
static int on_error(const char *str, size_t len, void *context);
static unsigned on_psk(const char *hint, char *identity, unsigned int max_identity_len,
Expand Down Expand Up @@ -145,7 +149,8 @@ class ssl_options
*/
ssl_options(const string& trustStore, const string& keyStore,
const string& privateKey, const string& privateKeyPassword,
const string& enabledCipherSuites, bool enableServerCertAuth);
const string& enabledCipherSuites, bool enableServerCertAuth,
const std::vector<string> alpnProtos=std::vector<string>());
/**
* Copy constructor.
* @param opt The other options to copy.
Expand Down Expand Up @@ -313,6 +318,18 @@ class ssl_options
* @param cb The callback.
*/
void set_psk_handler(psk_handler cb);
/**
* Gets the list of supported ALPN protocols.
* @return A vector containing the supported ALPN protocols.
*/
std::vector<string> get_alpn_protos() const;
/**
* Sets the list of supported ALPN protolols.
* See:
* https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_alpn_protos.html
* @param protos The list of ALPN protocols to be negotiated.
*/
void set_alpn_protos(const std::vector<string>& protos);
};

/**
Expand Down Expand Up @@ -453,6 +470,14 @@ class ssl_options_builder
opts_.set_psk_handler(cb);
return *this;
}
/**
* Sets the list of supported ALPN protocols.
* @param protos The list of ALPN protocols to be negotiated.
*/
auto alpn_protos(const std::vector<string>& protos) -> self& {
opts_.set_alpn_protos(protos);
return *this;
}
/**
* Finish building the options and return them.
* @return The option struct as built.
Expand Down
96 changes: 85 additions & 11 deletions src/ssl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,34 @@ 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 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 ssl_options& opt)
: opts_(opt.opts_), trustStore_(opt.trustStore_), keyStore_(opt.keyStore_),
privateKey_(opt.privateKey_), privateKeyPassword_(opt.privateKeyPassword_),
enabledCipherSuites_(opt.enabledCipherSuites_)
ssl_options::ssl_options(const ssl_options& other)
: opts_(other.opts_), trustStore_(other.trustStore_), keyStore_(other.keyStore_),
privateKey_(other.privateKey_), privateKeyPassword_(other.privateKeyPassword_),
enabledCipherSuites_(other.enabledCipherSuites_),
errHandler_(other.errHandler_), pskHandler_(other.pskHandler_),
protos_(other.protos_)
{
update_c_struct();
}

ssl_options::ssl_options(ssl_options&& opt)
: opts_(opt.opts_), trustStore_(std::move(opt.trustStore_)),
keyStore_(std::move(opt.keyStore_)), privateKey_(std::move(opt.privateKey_)),
privateKeyPassword_(std::move(opt.privateKeyPassword_)),
enabledCipherSuites_(std::move(opt.enabledCipherSuites_))
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_)),
enabledCipherSuites_(std::move(other.enabledCipherSuites_)),
errHandler_(std::move(other.errHandler_)), pskHandler_(std::move(other.pskHandler_)),
protos_(std::move(other.protos_))
{
update_c_struct();
}
Expand Down Expand Up @@ -82,6 +88,15 @@ void ssl_options::update_c_struct()
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;
}
}

// --------------------------------------------------------------------------
Expand Down Expand Up @@ -144,6 +159,11 @@ ssl_options& ssl_options::operator=(const ssl_options& rhs)
privateKeyPassword_ = rhs.privateKeyPassword_;
enabledCipherSuites_ = rhs.enabledCipherSuites_;

errHandler_ = rhs.errHandler_;
pskHandler_ = rhs.pskHandler_;

protos_ = rhs.protos_;

update_c_struct();
return *this;
}
Expand All @@ -161,6 +181,11 @@ ssl_options& ssl_options::operator=(ssl_options&& rhs)
privateKeyPassword_ = std::move(rhs.privateKeyPassword_);
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;
}
Expand Down Expand Up @@ -236,6 +261,55 @@ void ssl_options::set_psk_handler(psk_handler cb)
}
}

// 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
// end namespace mqtt
}

Loading

0 comments on commit 526f8aa

Please sign in to comment.