ssl_context_cp.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #if defined(ASIO2_ENABLE_SSL) || defined(ASIO2_USE_SSL)
  11. #ifndef __ASIO2_SSL_CONTEXT_COMPONENT_HPP__
  12. #define __ASIO2_SSL_CONTEXT_COMPONENT_HPP__
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. #pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include <string>
  17. #include <string_view>
  18. #include <asio2/base/error.hpp>
  19. #include <asio2/base/log.hpp>
  20. namespace asio2::detail
  21. {
  22. // we must pass the "args_t" to this base class.
  23. // can't use derived_t::args_type to get the args_t, beacuse this base class
  24. // is inited before the derived class, the derived_t::args_type has not been
  25. // defined in this base class.
  26. template<class derived_t, class args_t>
  27. class ssl_context_cp : public asio::ssl::context
  28. {
  29. public:
  30. template<typename = void>
  31. ssl_context_cp(asio::ssl::context::method method)
  32. : asio::ssl::context(method)
  33. {
  34. // default_workarounds : SSL_OP_ALL
  35. // All of the above bug workarounds.
  36. // It is usually safe to use SSL_OP_ALL to enable the bug workaround options if
  37. // compatibility with somewhat broken implementations is desired.
  38. // single_dh_use : SSL_OP_SINGLE_DH_USE
  39. // Always create a new key when using temporary / ephemeral
  40. // DH parameters(see ssl_ctx_set_tmp_dh_callback(3)).
  41. // This option must be used to prevent small subgroup attacks,
  42. // when the DH parameters were not generated using "strong"
  43. // primes(e.g.when using DSA - parameters, see dhparam(1)).
  44. // If "strong" primes were used, it is not strictly necessary
  45. // to generate a new DH key during each handshake but it is
  46. // also recommended.
  47. // SSL_OP_SINGLE_DH_USE should therefore be enabled whenever
  48. // temporary / ephemeral DH parameters are used.
  49. if constexpr (args_t::is_server)
  50. {
  51. // set default options
  52. this->set_options(
  53. asio::ssl::context::default_workarounds |
  54. asio::ssl::context::no_sslv2 |
  55. asio::ssl::context::no_sslv3 |
  56. asio::ssl::context::single_dh_use
  57. );
  58. }
  59. else
  60. {
  61. std::ignore = true;
  62. }
  63. }
  64. ~ssl_context_cp() = default;
  65. /**
  66. *
  67. * >> openssl create your certificates and sign them
  68. * ------------------------------------------------------------------------------------------------
  69. * // 1. Generate Server private key
  70. * openssl genrsa -des3 -out server.key 1024
  71. * // 2. Generate Server Certificate Signing Request(CSR)
  72. * openssl req -new -key server.key -out server.csr -config openssl.cnf
  73. * // 3. Generate Client private key
  74. * openssl genrsa -des3 -out client.key 1024
  75. * // 4. Generate Client Certificate Signing Request(CSR)
  76. * openssl req -new -key client.key -out client.csr -config openssl.cnf
  77. * // 5. Generate CA private key
  78. * openssl genrsa -des3 -out ca.key 2048
  79. * // 6. Generate CA Certificate file
  80. * openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -config openssl.cnf
  81. * // 7. Generate Server Certificate file
  82. * openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
  83. * // 8. Generate Client Certificate file
  84. * openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key -config openssl.cnf
  85. * // 9. Generate dhparam file
  86. * openssl dhparam -out dh1024.pem 1024
  87. *
  88. */
  89. /**
  90. * server set_verify_mode :
  91. * "verify_peer", ca_cert_buffer can be empty.
  92. * Whether the client has a certificate or not is ok.
  93. * "verify_fail_if_no_peer_cert", ca_cert_buffer can be empty.
  94. * Whether the client has a certificate or not is ok.
  95. * "verify_peer | verify_fail_if_no_peer_cert", ca_cert_buffer cannot be empty.
  96. * Client must use certificate, otherwise handshake will be failed.
  97. * client set_verify_mode :
  98. * "verify_peer", ca_cert_buffer cannot be empty.
  99. * "verify_none", ca_cert_buffer can be empty.
  100. * private_cert_buffer,private_key_buffer,private_password always cannot be empty.
  101. */
  102. template<typename = void>
  103. inline derived_t& set_cert_buffer(
  104. std::string_view ca_cert_buffer,
  105. std::string_view private_cert_buffer,
  106. std::string_view private_key_buffer,
  107. std::string_view private_password
  108. ) noexcept
  109. {
  110. error_code ec{};
  111. do
  112. {
  113. this->set_password_callback([password = std::string{ private_password }]
  114. (std::size_t max_length, asio::ssl::context_base::password_purpose purpose)->std::string
  115. {
  116. detail::ignore_unused(max_length, purpose);
  117. return password;
  118. }, ec);
  119. if (ec)
  120. break;
  121. ASIO2_ASSERT(!private_cert_buffer.empty() && !private_key_buffer.empty());
  122. this->use_certificate(asio::buffer(private_cert_buffer), asio::ssl::context::pem, ec);
  123. if (ec)
  124. break;
  125. this->use_private_key(asio::buffer(private_key_buffer), asio::ssl::context::pem, ec);
  126. if (ec)
  127. break;
  128. if (!ca_cert_buffer.empty())
  129. {
  130. this->add_certificate_authority(asio::buffer(ca_cert_buffer), ec);
  131. if (ec)
  132. break;
  133. }
  134. } while (false);
  135. set_last_error(ec);
  136. return (static_cast<derived_t&>(*this));
  137. }
  138. /**
  139. * server set_verify_mode :
  140. * "verify_peer", ca_cert_buffer can be empty.
  141. * Whether the client has a certificate or not is ok.
  142. * "verify_fail_if_no_peer_cert", ca_cert_buffer can be empty.
  143. * Whether the client has a certificate or not is ok.
  144. * "verify_peer | verify_fail_if_no_peer_cert", ca_cert_buffer cannot be empty.
  145. * Client must use certificate, otherwise handshake will be failed.
  146. * client set_verify_mode :
  147. * "verify_peer", ca_cert_buffer cannot be empty.
  148. * "verify_none", ca_cert_buffer can be empty.
  149. * private_cert_buffer,private_key_buffer,private_password always cannot be empty.
  150. */
  151. template<typename = void>
  152. inline derived_t& set_cert_file(
  153. const std::string& ca_cert_file,
  154. const std::string& private_cert_file,
  155. const std::string& private_key_file,
  156. const std::string& private_password
  157. ) noexcept
  158. {
  159. error_code ec{};
  160. do
  161. {
  162. this->set_password_callback([password = private_password]
  163. (std::size_t max_length, asio::ssl::context_base::password_purpose purpose)->std::string
  164. {
  165. detail::ignore_unused(max_length, purpose);
  166. return password;
  167. }, ec);
  168. if (ec)
  169. break;
  170. ASIO2_ASSERT(!private_cert_file.empty() && !private_key_file.empty());
  171. this->use_certificate_chain_file(private_cert_file, ec);
  172. if (ec)
  173. break;
  174. this->use_private_key_file(private_key_file, asio::ssl::context::pem, ec);
  175. if (ec)
  176. break;
  177. if (!ca_cert_file.empty())
  178. {
  179. this->load_verify_file(ca_cert_file, ec);
  180. if (ec)
  181. break;
  182. }
  183. } while (false);
  184. set_last_error(ec);
  185. return (static_cast<derived_t&>(*this));
  186. }
  187. /**
  188. * BIO_new_mem_buf -> SSL_CTX_set_tmp_dh
  189. */
  190. inline derived_t& set_dh_buffer(std::string_view dh_buffer) noexcept
  191. {
  192. error_code ec{};
  193. if (!dh_buffer.empty())
  194. this->use_tmp_dh(asio::buffer(dh_buffer), ec);
  195. set_last_error(ec);
  196. return (static_cast<derived_t&>(*this));
  197. }
  198. /**
  199. * BIO_new_file -> SSL_CTX_set_tmp_dh
  200. */
  201. inline derived_t& set_dh_file(const std::string& dh_file) noexcept
  202. {
  203. error_code ec{};
  204. if (!dh_file.empty())
  205. this->use_tmp_dh_file(dh_file, ec);
  206. set_last_error(ec);
  207. return (static_cast<derived_t&>(*this));
  208. }
  209. protected:
  210. };
  211. }
  212. #endif // !__ASIO2_SSL_CONTEXT_COMPONENT_HPP__
  213. #endif