ssl_options.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /////////////////////////////////////////////////////////////////////////////
  2. /// @file ssl_options.h
  3. /// Declaration of MQTT ssl_options class
  4. /// @date Jul 7, 2016
  5. /// @author Frank Pagliughi, Guilherme Ferreira
  6. /////////////////////////////////////////////////////////////////////////////
  7. /*******************************************************************************
  8. * Copyright (c) 2016-2024 Frank Pagliughi <fpagliughi@mindspring.com>
  9. * Copyright (c) 2016 Guilherme Ferreira <guilherme.maciel.ferreira@gmail.com>
  10. *
  11. * All rights reserved. This program and the accompanying materials
  12. * are made available under the terms of the Eclipse Public License v2.0
  13. * and Eclipse Distribution License v1.0 which accompany this distribution.
  14. *
  15. * The Eclipse Public License is available at
  16. * http://www.eclipse.org/legal/epl-v20.html
  17. * and the Eclipse Distribution License is available at
  18. * http://www.eclipse.org/org/documents/edl-v10.php.
  19. *
  20. * Contributors:
  21. * Guilherme Ferreira - initial implementation and documentation
  22. * Frank Pagliughi - added copy & move operations
  23. * Frank Pagliughi - upgraded compatibility to Paho C 1.3
  24. *******************************************************************************/
  25. #ifndef __mqtt_ssl_options_h
  26. #define __mqtt_ssl_options_h
  27. #include <functional>
  28. #include <vector>
  29. #include "MQTTAsync.h"
  30. #include "mqtt/message.h"
  31. #include "mqtt/platform.h"
  32. #include "mqtt/topic.h"
  33. #include "mqtt/types.h"
  34. namespace mqtt {
  35. /////////////////////////////////////////////////////////////////////////////
  36. /**
  37. * Holds the set of SSL options for connection.
  38. */
  39. class ssl_options
  40. {
  41. public:
  42. /** Smart/shared pointer to an object of this class. */
  43. using ptr_t = std::shared_ptr<ssl_options>;
  44. /** Smart/shared pointer to a const object of this class. */
  45. using const_ptr_t = std::shared_ptr<const ssl_options>;
  46. /** Unique pointer to an object of this class. */
  47. using unique_ptr_t = std::unique_ptr<ssl_options>;
  48. /** Handler type for error message callbacks */
  49. using error_handler = std::function<void(const string& errMsg)>;
  50. /**
  51. * Handler type for TLS-PSK option callback.
  52. * On success, the callback should return the length of the PSK (in
  53. * bytes). On failure, it should throw or return zero.
  54. */
  55. using psk_handler = std::function<unsigned(
  56. const string& hint, char* identity, size_t max_identity_len, unsigned char* psk,
  57. size_t max_psk_len
  58. )>;
  59. private:
  60. /** The default C struct */
  61. static constexpr MQTTAsync_SSLOptions DFLT_C_STRUCT MQTTAsync_SSLOptions_initializer;
  62. /** The underlying C SSL options */
  63. MQTTAsync_SSLOptions opts_{DFLT_C_STRUCT};
  64. /**
  65. * The file containing the public digital certificates trusted by
  66. * the client.
  67. */
  68. string trustStore_;
  69. /** The file containing the public certificate chain of the client. */
  70. string keyStore_;
  71. /** The file containing the client's private key. */
  72. string privateKey_;
  73. /** The password to load the client's privateKey if encrypted. */
  74. string privateKeyPassword_;
  75. /** Path to a directory containing CA certificates in PEM format */
  76. string caPath_;
  77. /**
  78. * The list of cipher suites that the client will present to the
  79. * server during the SSL handshake.
  80. */
  81. string enabledCipherSuites_;
  82. /** Error message callback handler */
  83. error_handler errHandler_;
  84. /** PSK callback handler */
  85. psk_handler pskHandler_;
  86. /** ALPN protocol list, in wire format */
  87. std::vector<unsigned char> protos_;
  88. /** Callbacks from the C library */
  89. static int on_error(const char* str, size_t len, void* context);
  90. static unsigned on_psk(
  91. const char* hint, char* identity, unsigned int max_identity_len, unsigned char* psk,
  92. unsigned int max_psk_len, void* context
  93. );
  94. /** The connect options has special access */
  95. friend class connect_options;
  96. /**
  97. * Gets a pointer to the C-language NUL-terminated strings for the
  98. * struct.
  99. * @note In the SSL options, by default, the Paho C treats nullptr char
  100. * arrays as unset values, so we keep that semantic and only set those
  101. * char arrays if the string is non-empty.
  102. * @param str The C++ string object.
  103. * @return Pointer to a NUL terminated string. This is only valid until
  104. * the next time the string is updated.
  105. */
  106. const char* c_str(const string& str) { return str.empty() ? nullptr : str.c_str(); }
  107. /**
  108. * Updates the underlying C structure to match our strings.
  109. */
  110. void update_c_struct();
  111. public:
  112. /**
  113. * Constructs a new MqttConnectOptions object using the default values.
  114. */
  115. ssl_options() {}
  116. /**
  117. * Argument constructor.
  118. * @param trustStore The file containing the public digital certificates
  119. * trusted by the client.
  120. * @param keyStore The file containing the public certificate chain of the
  121. * client.
  122. * @param privateKey The file containing the client's private key.
  123. * @param privateKeyPassword The password to load the client's privateKey
  124. * if encrypted.
  125. * @param enabledCipherSuites The list of cipher suites that the client
  126. * will present to the server during the SSL handshake.
  127. * @param enableServerCertAuth True/False option to enable verification of
  128. * the server certificate
  129. * @param alpnProtos The ALPN protocols to try.
  130. */
  131. ssl_options(
  132. const string& trustStore, const string& keyStore, const string& privateKey,
  133. const string& privateKeyPassword, const string& enabledCipherSuites,
  134. bool enableServerCertAuth,
  135. const std::vector<string> alpnProtos = std::vector<string>()
  136. );
  137. /**
  138. * Argument constructor.
  139. * @param trustStore The file containing the public digital certificates
  140. * trusted by the client.
  141. * @param keyStore The file containing the public certificate chain of
  142. * the client.
  143. * @param privateKey The file containing the client's private key.
  144. * @param privateKeyPassword The password to load the client's
  145. * privateKey if encrypted.
  146. * @param caPath The name of a directory containing CA certificates in
  147. * PEM format.
  148. * @param enabledCipherSuites The list of cipher suites that the client
  149. * will present to the server during the SSL
  150. * handshake.
  151. * @param enableServerCertAuth True/False option to enable verification
  152. * of the server certificate
  153. * @param alpnProtos The ALPN protocols to try.
  154. */
  155. ssl_options(
  156. const string& trustStore, const string& keyStore, const string& privateKey,
  157. const string& privateKeyPassword, const string& caPath,
  158. const string& enabledCipherSuites, bool enableServerCertAuth,
  159. const std::vector<string> alpnProtos = std::vector<string>()
  160. );
  161. /**
  162. * Copy constructor.
  163. * @param opt The other options to copy.
  164. */
  165. ssl_options(const ssl_options& opt);
  166. /**
  167. * Move constructor.
  168. * @param opt The other options to move to this one.
  169. */
  170. ssl_options(ssl_options&& opt);
  171. /**
  172. * Copy assignment.
  173. * @param opt The other options to copy.
  174. * @return A reference to this object.
  175. */
  176. ssl_options& operator=(const ssl_options& opt);
  177. /**
  178. * Move assignment.
  179. * @param opt The other options to move to this one.
  180. * @return A reference to this object.
  181. */
  182. ssl_options& operator=(ssl_options&& opt);
  183. /**
  184. * Expose the underlying C struct for the unit tests.
  185. */
  186. #if defined(UNIT_TESTS)
  187. const MQTTAsync_SSLOptions& c_struct() const { return opts_; }
  188. #endif
  189. /**
  190. * Returns the file containing the public digital certificates trusted by
  191. * the client.
  192. * @return string
  193. */
  194. string get_trust_store() const { return trustStore_; }
  195. /**
  196. * Returns the file containing the public certificate chain of the client.
  197. * @return string
  198. */
  199. string get_key_store() const { return keyStore_; }
  200. /**
  201. * Gets the name of file containing the client's private key.
  202. * @return The name of file containing the client's private key.
  203. */
  204. string get_private_key() const { return privateKey_; }
  205. /**
  206. * Gets the password to load the client's privateKey if encrypted.
  207. * @return The password to load the client's privateKey if encrypted.
  208. */
  209. string get_private_key_password() const { return privateKeyPassword_; }
  210. /**
  211. * Returns the list of cipher suites that the client will present to the
  212. * server during the SSL handshake.
  213. * @return string
  214. */
  215. string get_enabled_cipher_suites() const { return enabledCipherSuites_; }
  216. /**
  217. * Returns the true/false to enable verification of the server certificate .
  218. * @return bool
  219. */
  220. bool get_enable_server_cert_auth() const { return to_bool(opts_.enableServerCertAuth); }
  221. /**
  222. * Sets the file containing the public digital certificates trusted by
  223. * the client.
  224. * @param trustStore The file in PEM format containing the public
  225. * digital certificates trusted by the client.
  226. */
  227. void set_trust_store(const string& trustStore);
  228. /**
  229. * Sets the file containing the public certificate chain of the client.
  230. * @param keyStore The file in PEM format containing the public
  231. * certificate chain of the client. It may also include
  232. * the client's private key.
  233. */
  234. void set_key_store(const string& keyStore);
  235. /**
  236. * Sets the file containing the client's private key.
  237. * @param privateKey If not included in the sslKeyStore, this is the
  238. * file in PEM format containing the client's private
  239. * key.
  240. */
  241. void set_private_key(const string& privateKey);
  242. /**
  243. * Sets the password to load the client's privateKey if encrypted.
  244. * @param privateKeyPassword The password to load the privateKey if
  245. * encrypted.
  246. */
  247. void set_private_key_password(const string& privateKeyPassword);
  248. /**
  249. * Sets the list of cipher suites that the client will present to the server
  250. * during the SSL handshake.
  251. * @param enabledCipherSuites The list of cipher suites that the client
  252. * will present to the server during the SSL
  253. * handshake. For a full explanation of the
  254. * cipher list format, please see the OpenSSL
  255. * on-line documentation:
  256. * https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html
  257. * If this setting is omitted, its default
  258. * value will be "ALL", that is, all the
  259. * cipher suites -excluding those offering no
  260. * encryption- will be considered. This
  261. * setting can be used to set an SSL
  262. * anonymous connection (empty string value,
  263. * for instance).
  264. */
  265. void set_enabled_cipher_suites(const string& enabledCipherSuites);
  266. /**
  267. * Enables or disables verification of the server certificate.
  268. * @param enableServerCertAuth enable/disable verification of the server
  269. * certificate
  270. */
  271. void set_enable_server_cert_auth(bool enableServerCertAuth);
  272. /**
  273. * Gets the requested SSL/TLS version.
  274. * @return The requested SSL/TLS version.
  275. */
  276. int get_ssl_version() const { return opts_.sslVersion; }
  277. /**
  278. * Set the SSL/TLS version to use.
  279. *
  280. * @param ver The desired SSL/TLS version. Specify one of:
  281. * @li MQTT_SSL_VERSION_DEFAULT (0)
  282. * @li MQTT_SSL_VERSION_TLS_1_0 (1)
  283. * @li MQTT_SSL_VERSION_TLS_1_1 (2)
  284. * @li MQTT_SSL_VERSION_TLS_1_2 (3)
  285. */
  286. void set_ssl_version(int ver) { opts_.sslVersion = ver; }
  287. /**
  288. * Determines whether it will carry out post-connect checks, including
  289. * that a certificate matches the given host name.
  290. * @return Whether it will carry out post-connect checks.
  291. */
  292. bool get_verify() const { return to_bool(opts_.verify); }
  293. /**
  294. * Sets whether it should carry out post-connect checks, including that
  295. * a certificate matches the given host name.
  296. * @param v Whether it should carry out post-connect checks.
  297. */
  298. void set_verify(bool v) { opts_.verify = to_int(v); }
  299. /**
  300. * Gets the path to a directory containing CA certificates in PEM
  301. * format.
  302. *
  303. * @return Path to a directory containing CA certificates in PEM format,
  304. * if set. If this isn't set, returns an empty string.
  305. */
  306. string get_ca_path() const { return caPath_; }
  307. string ca_path() const { return caPath_; }
  308. /**
  309. * Sets the path to a directory containing CA certificates in PEM
  310. * format.
  311. *
  312. * @param path Path to a directory containing CA certificates in PEM
  313. * format.
  314. */
  315. void set_ca_path(const string& path);
  316. void ca_path(const string& path) { set_ca_path(path); }
  317. /**
  318. * Registers the error message callback handler.
  319. * @param cb The callback to receive error messages.
  320. */
  321. void set_error_handler(error_handler cb);
  322. /**
  323. * Registers a callback handler to set the TLS-PSK options.
  324. * See: OpenSSL SSL_CTX_set_psk_client_callback()
  325. * @param cb The callback.
  326. */
  327. void set_psk_handler(psk_handler cb);
  328. /**
  329. * Gets the list of supported ALPN protocols.
  330. * @return A vector containing the supported ALPN protocols.
  331. */
  332. std::vector<string> get_alpn_protos() const;
  333. /**
  334. * Sets the list of supported ALPN protocols.
  335. * See:
  336. * https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_alpn_protos.html
  337. * @param protos The list of ALPN protocols to be negotiated.
  338. */
  339. void set_alpn_protos(const std::vector<string>& protos);
  340. };
  341. /**
  342. * Shared pointer to the ssl options class.
  343. */
  344. using ssl_options_ptr = ssl_options::ptr_t;
  345. /**
  346. * Unique pointer to the ssl options class.
  347. */
  348. using ssl_options_unique_ptr = ssl_options::unique_ptr_t;
  349. /////////////////////////////////////////////////////////////////////////////
  350. /**
  351. * Class to build the SSL options for connections.
  352. */
  353. class ssl_options_builder
  354. {
  355. /** The underlying options */
  356. ssl_options opts_;
  357. public:
  358. /** This class */
  359. using self = ssl_options_builder;
  360. /**
  361. * Default constructor.
  362. */
  363. ssl_options_builder() {}
  364. /**
  365. * Sets the file containing the public digital certificates trusted by
  366. * the client.
  367. * @param store The file in PEM format containing the public digital
  368. * certificates trusted by the client.
  369. */
  370. auto trust_store(const string& store) -> self& {
  371. opts_.set_trust_store(store);
  372. return *this;
  373. }
  374. /**
  375. * Sets the file containing the public certificate chain of the client.
  376. * @param store The file in PEM format containing the public certificate
  377. * chain of the client. It may also include the client's
  378. * private key.
  379. */
  380. auto key_store(const string& store) -> self& {
  381. opts_.set_key_store(store);
  382. return *this;
  383. }
  384. /**
  385. * Sets the file containing the client's private key.
  386. * @param key If not included in the sslKeyStore, this is the file in
  387. * PEM format containing the client's private key.
  388. */
  389. auto private_key(const string& key) -> self& {
  390. opts_.set_private_key(key);
  391. return *this;
  392. }
  393. /**
  394. * Sets the password to load the client's privateKey if encrypted.
  395. * @param passwd The password to load the privateKey if encrypted.
  396. */
  397. auto private_keypassword(const string& passwd) -> self& {
  398. opts_.set_private_key_password(passwd);
  399. return *this;
  400. }
  401. /**
  402. * Sets the list of cipher suites that the client will present to the server
  403. * during the SSL handshake.
  404. * @param suites The list of cipher suites that the client will present to
  405. * the server during the SSL handshake. For a full
  406. * explanation of the cipher list format, please see the
  407. * OpenSSL on-line documentation:
  408. * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT
  409. * If this setting is omitted, its default value will be
  410. * "ALL", that is, all the cipher suites -excluding those
  411. * offering no encryption- will be considered. This setting
  412. * can be used to set an SSL anonymous connection (empty
  413. * string value, for instance).
  414. */
  415. auto enabled_cipher_suites(const string& suites) -> self& {
  416. opts_.set_enabled_cipher_suites(suites);
  417. return *this;
  418. }
  419. /**
  420. * Enables or disables verification of the server certificate.
  421. * @param on enable/disable verification of the server certificate
  422. */
  423. auto enable_server_cert_auth(bool on) -> self& {
  424. opts_.set_enable_server_cert_auth(on);
  425. return *this;
  426. }
  427. /**
  428. * Set the SSL/TLS version to use.
  429. *
  430. * @param ver The desired SSL/TLS version. Specify one of:
  431. * @li MQTT_SSL_VERSION_DEFAULT (0)
  432. * @li MQTT_SSL_VERSION_TLS_1_0 (1)
  433. * @li MQTT_SSL_VERSION_TLS_1_1 (2)
  434. * @li MQTT_SSL_VERSION_TLS_1_2 (3)
  435. */
  436. auto ssl_version(int ver) -> self& {
  437. opts_.set_ssl_version(ver);
  438. return *this;
  439. }
  440. /**
  441. * Sets whether it should carry out post-connect checks, including that
  442. * a certificate matches the given host name.
  443. * @param on Whether it should carry out post-connect checks.
  444. */
  445. auto verify(bool on = true) -> self& {
  446. opts_.set_verify(on);
  447. return *this;
  448. }
  449. /**
  450. * Sets the path to a directory containing CA certificates in PEM format.
  451. * @param path Path to a directory containing CA certificates in PEM
  452. * format.
  453. */
  454. auto ca_path(const string& path) -> self& {
  455. opts_.ca_path(path);
  456. return *this;
  457. }
  458. /**
  459. * Registers an error callback handler.
  460. * @param cb The callback to receive error messages.
  461. */
  462. auto error_handler(ssl_options::error_handler cb) -> self& {
  463. opts_.set_error_handler(cb);
  464. return *this;
  465. }
  466. /**
  467. * Registers a callback handler to set the TLS-PSK options.
  468. * See: OpenSSL SSL_CTX_set_psk_client_callback()
  469. * @param cb The callback.
  470. */
  471. auto psk_handler(ssl_options::psk_handler cb) -> self& {
  472. opts_.set_psk_handler(cb);
  473. return *this;
  474. }
  475. /**
  476. * Sets the list of supported ALPN protocols.
  477. * @param protos The list of ALPN protocols to be negotiated.
  478. */
  479. auto alpn_protos(const std::vector<string>& protos) -> self& {
  480. opts_.set_alpn_protos(protos);
  481. return *this;
  482. }
  483. /**
  484. * Finish building the options and return them.
  485. * @return The option struct as built.
  486. */
  487. ssl_options finalize() { return opts_; }
  488. };
  489. /////////////////////////////////////////////////////////////////////////////
  490. } // namespace mqtt
  491. #endif // __mqtt_ssl_options_h