PageRenderTime 28ms CodeModel.GetById 58ms RepoModel.GetById 0ms app.codeStats 0ms

/boost/asio/ssl/impl/context.ipp

https://github.com/gimlism/boost-svn
C++ Header | 527 lines | 444 code | 73 blank | 10 comment | 38 complexity | 62a52e9961e553028fbf400decf31c30 MD5 | raw file
  1. //
  2. // ssl/impl/context.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
  6. // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef BOOST_ASIO_SSL_IMPL_CONTEXT_IPP
  12. #define BOOST_ASIO_SSL_IMPL_CONTEXT_IPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include <boost/asio/detail/config.hpp>
  17. #if !defined(BOOST_ASIO_ENABLE_OLD_SSL)
  18. # include <cstring>
  19. # include <boost/asio/detail/throw_error.hpp>
  20. # include <boost/asio/error.hpp>
  21. # include <boost/asio/ssl/context.hpp>
  22. # include <boost/asio/ssl/error.hpp>
  23. #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL)
  24. #include <boost/asio/detail/push_options.hpp>
  25. namespace boost {
  26. namespace asio {
  27. namespace ssl {
  28. #if !defined(BOOST_ASIO_ENABLE_OLD_SSL)
  29. context::context(context::method m)
  30. : handle_(0)
  31. {
  32. switch (m)
  33. {
  34. #if defined(OPENSSL_NO_SSL2)
  35. case context::sslv2:
  36. case context::sslv2_client:
  37. case context::sslv2_server:
  38. boost::asio::detail::throw_error(
  39. boost::asio::error::invalid_argument, "context");
  40. break;
  41. #else // defined(OPENSSL_NO_SSL2)
  42. case context::sslv2:
  43. handle_ = ::SSL_CTX_new(::SSLv2_method());
  44. break;
  45. case context::sslv2_client:
  46. handle_ = ::SSL_CTX_new(::SSLv2_client_method());
  47. break;
  48. case context::sslv2_server:
  49. handle_ = ::SSL_CTX_new(::SSLv2_server_method());
  50. break;
  51. #endif // defined(OPENSSL_NO_SSL2)
  52. case context::sslv3:
  53. handle_ = ::SSL_CTX_new(::SSLv3_method());
  54. break;
  55. case context::sslv3_client:
  56. handle_ = ::SSL_CTX_new(::SSLv3_client_method());
  57. break;
  58. case context::sslv3_server:
  59. handle_ = ::SSL_CTX_new(::SSLv3_server_method());
  60. break;
  61. case context::tlsv1:
  62. handle_ = ::SSL_CTX_new(::TLSv1_method());
  63. break;
  64. case context::tlsv1_client:
  65. handle_ = ::SSL_CTX_new(::TLSv1_client_method());
  66. break;
  67. case context::tlsv1_server:
  68. handle_ = ::SSL_CTX_new(::TLSv1_server_method());
  69. break;
  70. case context::sslv23:
  71. handle_ = ::SSL_CTX_new(::SSLv23_method());
  72. break;
  73. case context::sslv23_client:
  74. handle_ = ::SSL_CTX_new(::SSLv23_client_method());
  75. break;
  76. case context::sslv23_server:
  77. handle_ = ::SSL_CTX_new(::SSLv23_server_method());
  78. break;
  79. default:
  80. handle_ = ::SSL_CTX_new(0);
  81. break;
  82. }
  83. if (handle_ == 0)
  84. {
  85. boost::system::error_code ec(::ERR_get_error(),
  86. boost::asio::error::get_ssl_category());
  87. boost::asio::detail::throw_error(ec, "context");
  88. }
  89. }
  90. context::context(boost::asio::io_service&, context::method m)
  91. : handle_(0)
  92. {
  93. context tmp(m);
  94. handle_ = tmp.handle_;
  95. tmp.handle_ = 0;
  96. }
  97. #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  98. context::context(context&& other)
  99. {
  100. handle_ = other.handle_;
  101. other.handle_ = 0;
  102. }
  103. context& context::operator=(context&& other)
  104. {
  105. context tmp(BOOST_ASIO_MOVE_CAST(context)(*this));
  106. handle_ = other.handle_;
  107. other.handle_ = 0;
  108. return *this;
  109. }
  110. #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  111. context::~context()
  112. {
  113. if (handle_)
  114. {
  115. if (handle_->default_passwd_callback_userdata)
  116. {
  117. detail::password_callback_base* callback =
  118. static_cast<detail::password_callback_base*>(
  119. handle_->default_passwd_callback_userdata);
  120. delete callback;
  121. handle_->default_passwd_callback_userdata = 0;
  122. }
  123. if (SSL_CTX_get_app_data(handle_))
  124. {
  125. detail::verify_callback_base* callback =
  126. static_cast<detail::verify_callback_base*>(
  127. SSL_CTX_get_app_data(handle_));
  128. delete callback;
  129. SSL_CTX_set_app_data(handle_, 0);
  130. }
  131. ::SSL_CTX_free(handle_);
  132. }
  133. }
  134. context::native_handle_type context::native_handle()
  135. {
  136. return handle_;
  137. }
  138. context::impl_type context::impl()
  139. {
  140. return handle_;
  141. }
  142. void context::set_options(context::options o)
  143. {
  144. boost::system::error_code ec;
  145. set_options(o, ec);
  146. boost::asio::detail::throw_error(ec, "set_options");
  147. }
  148. boost::system::error_code context::set_options(
  149. context::options o, boost::system::error_code& ec)
  150. {
  151. ::SSL_CTX_set_options(handle_, o);
  152. ec = boost::system::error_code();
  153. return ec;
  154. }
  155. void context::set_verify_mode(verify_mode v)
  156. {
  157. boost::system::error_code ec;
  158. set_verify_mode(v, ec);
  159. boost::asio::detail::throw_error(ec, "set_verify_mode");
  160. }
  161. boost::system::error_code context::set_verify_mode(
  162. verify_mode v, boost::system::error_code& ec)
  163. {
  164. ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_));
  165. ec = boost::system::error_code();
  166. return ec;
  167. }
  168. void context::load_verify_file(const std::string& filename)
  169. {
  170. boost::system::error_code ec;
  171. load_verify_file(filename, ec);
  172. boost::asio::detail::throw_error(ec, "load_verify_file");
  173. }
  174. boost::system::error_code context::load_verify_file(
  175. const std::string& filename, boost::system::error_code& ec)
  176. {
  177. if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1)
  178. {
  179. ec = boost::system::error_code(::ERR_get_error(),
  180. boost::asio::error::get_ssl_category());
  181. return ec;
  182. }
  183. ec = boost::system::error_code();
  184. return ec;
  185. }
  186. void context::set_default_verify_paths()
  187. {
  188. boost::system::error_code ec;
  189. set_default_verify_paths(ec);
  190. boost::asio::detail::throw_error(ec, "set_default_verify_paths");
  191. }
  192. boost::system::error_code context::set_default_verify_paths(
  193. boost::system::error_code& ec)
  194. {
  195. if (::SSL_CTX_set_default_verify_paths(handle_) != 1)
  196. {
  197. ec = boost::system::error_code(::ERR_get_error(),
  198. boost::asio::error::get_ssl_category());
  199. return ec;
  200. }
  201. ec = boost::system::error_code();
  202. return ec;
  203. }
  204. void context::add_verify_path(const std::string& path)
  205. {
  206. boost::system::error_code ec;
  207. add_verify_path(path, ec);
  208. boost::asio::detail::throw_error(ec, "add_verify_path");
  209. }
  210. boost::system::error_code context::add_verify_path(
  211. const std::string& path, boost::system::error_code& ec)
  212. {
  213. if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1)
  214. {
  215. ec = boost::system::error_code(::ERR_get_error(),
  216. boost::asio::error::get_ssl_category());
  217. return ec;
  218. }
  219. ec = boost::system::error_code();
  220. return ec;
  221. }
  222. void context::use_certificate_file(
  223. const std::string& filename, file_format format)
  224. {
  225. boost::system::error_code ec;
  226. use_certificate_file(filename, format, ec);
  227. boost::asio::detail::throw_error(ec, "use_certificate_file");
  228. }
  229. boost::system::error_code context::use_certificate_file(
  230. const std::string& filename, file_format format,
  231. boost::system::error_code& ec)
  232. {
  233. int file_type;
  234. switch (format)
  235. {
  236. case context_base::asn1:
  237. file_type = SSL_FILETYPE_ASN1;
  238. break;
  239. case context_base::pem:
  240. file_type = SSL_FILETYPE_PEM;
  241. break;
  242. default:
  243. {
  244. ec = boost::asio::error::invalid_argument;
  245. return ec;
  246. }
  247. }
  248. if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1)
  249. {
  250. ec = boost::system::error_code(::ERR_get_error(),
  251. boost::asio::error::get_ssl_category());
  252. return ec;
  253. }
  254. ec = boost::system::error_code();
  255. return ec;
  256. }
  257. void context::use_certificate_chain_file(const std::string& filename)
  258. {
  259. boost::system::error_code ec;
  260. use_certificate_chain_file(filename, ec);
  261. boost::asio::detail::throw_error(ec, "use_certificate_chain_file");
  262. }
  263. boost::system::error_code context::use_certificate_chain_file(
  264. const std::string& filename, boost::system::error_code& ec)
  265. {
  266. if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1)
  267. {
  268. ec = boost::system::error_code(::ERR_get_error(),
  269. boost::asio::error::get_ssl_category());
  270. return ec;
  271. }
  272. ec = boost::system::error_code();
  273. return ec;
  274. }
  275. void context::use_private_key_file(
  276. const std::string& filename, context::file_format format)
  277. {
  278. boost::system::error_code ec;
  279. use_private_key_file(filename, format, ec);
  280. boost::asio::detail::throw_error(ec, "use_private_key_file");
  281. }
  282. boost::system::error_code context::use_private_key_file(
  283. const std::string& filename, context::file_format format,
  284. boost::system::error_code& ec)
  285. {
  286. int file_type;
  287. switch (format)
  288. {
  289. case context_base::asn1:
  290. file_type = SSL_FILETYPE_ASN1;
  291. break;
  292. case context_base::pem:
  293. file_type = SSL_FILETYPE_PEM;
  294. break;
  295. default:
  296. {
  297. ec = boost::asio::error::invalid_argument;
  298. return ec;
  299. }
  300. }
  301. if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1)
  302. {
  303. ec = boost::system::error_code(::ERR_get_error(),
  304. boost::asio::error::get_ssl_category());
  305. return ec;
  306. }
  307. ec = boost::system::error_code();
  308. return ec;
  309. }
  310. void context::use_rsa_private_key_file(
  311. const std::string& filename, context::file_format format)
  312. {
  313. boost::system::error_code ec;
  314. use_rsa_private_key_file(filename, format, ec);
  315. boost::asio::detail::throw_error(ec, "use_rsa_private_key_file");
  316. }
  317. boost::system::error_code context::use_rsa_private_key_file(
  318. const std::string& filename, context::file_format format,
  319. boost::system::error_code& ec)
  320. {
  321. int file_type;
  322. switch (format)
  323. {
  324. case context_base::asn1:
  325. file_type = SSL_FILETYPE_ASN1;
  326. break;
  327. case context_base::pem:
  328. file_type = SSL_FILETYPE_PEM;
  329. break;
  330. default:
  331. {
  332. ec = boost::asio::error::invalid_argument;
  333. return ec;
  334. }
  335. }
  336. if (::SSL_CTX_use_RSAPrivateKey_file(
  337. handle_, filename.c_str(), file_type) != 1)
  338. {
  339. ec = boost::system::error_code(::ERR_get_error(),
  340. boost::asio::error::get_ssl_category());
  341. return ec;
  342. }
  343. ec = boost::system::error_code();
  344. return ec;
  345. }
  346. void context::use_tmp_dh_file(const std::string& filename)
  347. {
  348. boost::system::error_code ec;
  349. use_tmp_dh_file(filename, ec);
  350. boost::asio::detail::throw_error(ec, "use_tmp_dh_file");
  351. }
  352. boost::system::error_code context::use_tmp_dh_file(
  353. const std::string& filename, boost::system::error_code& ec)
  354. {
  355. ::BIO* bio = ::BIO_new_file(filename.c_str(), "r");
  356. if (!bio)
  357. {
  358. ec = boost::asio::error::invalid_argument;
  359. return ec;
  360. }
  361. ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0);
  362. if (!dh)
  363. {
  364. ::BIO_free(bio);
  365. ec = boost::asio::error::invalid_argument;
  366. return ec;
  367. }
  368. ::BIO_free(bio);
  369. int result = ::SSL_CTX_set_tmp_dh(handle_, dh);
  370. ::DH_free(dh);
  371. if (result != 1)
  372. {
  373. ec = boost::system::error_code(::ERR_get_error(),
  374. boost::asio::error::get_ssl_category());
  375. return ec;
  376. }
  377. ec = boost::system::error_code();
  378. return ec;
  379. }
  380. boost::system::error_code context::do_set_verify_callback(
  381. detail::verify_callback_base* callback, boost::system::error_code& ec)
  382. {
  383. if (SSL_CTX_get_app_data(handle_))
  384. {
  385. delete static_cast<detail::verify_callback_base*>(
  386. SSL_CTX_get_app_data(handle_));
  387. }
  388. SSL_CTX_set_app_data(handle_, callback);
  389. ::SSL_CTX_set_verify(handle_,
  390. ::SSL_CTX_get_verify_mode(handle_),
  391. &context::verify_callback_function);
  392. ec = boost::system::error_code();
  393. return ec;
  394. }
  395. int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx)
  396. {
  397. if (ctx)
  398. {
  399. if (SSL* ssl = static_cast<SSL*>(
  400. ::X509_STORE_CTX_get_ex_data(
  401. ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))
  402. {
  403. if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl))
  404. {
  405. if (SSL_CTX_get_app_data(handle))
  406. {
  407. detail::verify_callback_base* callback =
  408. static_cast<detail::verify_callback_base*>(
  409. SSL_CTX_get_app_data(handle));
  410. verify_context verify_ctx(ctx);
  411. return callback->call(preverified != 0, verify_ctx) ? 1 : 0;
  412. }
  413. }
  414. }
  415. }
  416. return 0;
  417. }
  418. boost::system::error_code context::do_set_password_callback(
  419. detail::password_callback_base* callback, boost::system::error_code& ec)
  420. {
  421. if (handle_->default_passwd_callback_userdata)
  422. delete static_cast<detail::password_callback_base*>(
  423. handle_->default_passwd_callback_userdata);
  424. handle_->default_passwd_callback_userdata = callback;
  425. SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function);
  426. ec = boost::system::error_code();
  427. return ec;
  428. }
  429. int context::password_callback_function(
  430. char* buf, int size, int purpose, void* data)
  431. {
  432. using namespace std; // For strncat and strlen.
  433. if (data)
  434. {
  435. detail::password_callback_base* callback =
  436. static_cast<detail::password_callback_base*>(data);
  437. std::string passwd = callback->call(static_cast<std::size_t>(size),
  438. purpose ? context_base::for_writing : context_base::for_reading);
  439. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
  440. strcpy_s(buf, size, passwd.c_str());
  441. #else
  442. *buf = '\0';
  443. strncat(buf, passwd.c_str(), size);
  444. #endif
  445. return strlen(buf);
  446. }
  447. return 0;
  448. }
  449. #endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL)
  450. } // namespace ssl
  451. } // namespace asio
  452. } // namespace boost
  453. #include <boost/asio/detail/pop_options.hpp>
  454. #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_IPP