2 // ssl/old/detail/openssl_context_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
6 // Copyright (c) 2005-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
12 #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
13 #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
19 #include <boost/asio/detail/config.hpp>
22 #include <boost/function.hpp>
23 #include <boost/asio/detail/throw_error.hpp>
24 #include <boost/asio/error.hpp>
25 #include <boost/asio/io_service.hpp>
26 #include <boost/asio/ssl/context_base.hpp>
27 #include <boost/asio/ssl/detail/openssl_init.hpp>
28 #include <boost/asio/ssl/detail/openssl_types.hpp>
30 #include <boost/asio/detail/push_options.hpp>
38 class openssl_context_service
39 : public boost::asio::detail::service_base<openssl_context_service>
42 // The native type of the context.
43 typedef ::SSL_CTX* impl_type;
45 // The type for the password callback function object.
46 typedef boost::function<std::string(std::size_t,
47 context_base::password_purpose)> password_callback_type;
50 openssl_context_service(boost::asio::io_service& io_service)
51 : boost::asio::detail::service_base<openssl_context_service>(io_service)
55 // Destroy all user-defined handler objects owned by the service.
56 void shutdown_service()
60 // Return a null context implementation.
61 static impl_type null()
66 // Create a new context implementation.
67 void create(impl_type& impl, context_base::method m)
71 #if defined(OPENSSL_NO_SSL2)
72 case context_base::sslv2:
73 case context_base::sslv2_client:
74 case context_base::sslv2_server:
75 boost::asio::detail::throw_error(boost::asio::error::invalid_argument);
77 #else // defined(OPENSSL_NO_SSL2)
78 case context_base::sslv2:
79 impl = ::SSL_CTX_new(::SSLv2_method());
81 case context_base::sslv2_client:
82 impl = ::SSL_CTX_new(::SSLv2_client_method());
84 case context_base::sslv2_server:
85 impl = ::SSL_CTX_new(::SSLv2_server_method());
87 #endif // defined(OPENSSL_NO_SSL2)
88 #if defined(OPENSSL_NO_SSL3)
89 case context_base::sslv3:
90 case context_base::sslv3_client:
91 case context_base::sslv3_server:
92 boost::asio::detail::throw_error(boost::asio::error::invalid_argument);
94 #else // defined(OPENSSL_NO_SSL3)
95 case context_base::sslv3:
96 impl = ::SSL_CTX_new(::SSLv3_method());
98 case context_base::sslv3_client:
99 impl = ::SSL_CTX_new(::SSLv3_client_method());
101 case context_base::sslv3_server:
102 impl = ::SSL_CTX_new(::SSLv3_server_method());
104 #endif // defined(OPENSSL_NO_SSL3)
105 case context_base::tlsv1:
106 impl = ::SSL_CTX_new(::TLSv1_method());
108 case context_base::tlsv1_client:
109 impl = ::SSL_CTX_new(::TLSv1_client_method());
111 case context_base::tlsv1_server:
112 impl = ::SSL_CTX_new(::TLSv1_server_method());
114 case context_base::sslv23:
115 impl = ::SSL_CTX_new(::SSLv23_method());
117 case context_base::sslv23_client:
118 impl = ::SSL_CTX_new(::SSLv23_client_method());
120 case context_base::sslv23_server:
121 impl = ::SSL_CTX_new(::SSLv23_server_method());
124 impl = ::SSL_CTX_new(0);
129 // Destroy a context implementation.
130 void destroy(impl_type& impl)
134 if (impl->default_passwd_callback_userdata)
136 password_callback_type* callback =
137 static_cast<password_callback_type*>(
138 impl->default_passwd_callback_userdata);
140 impl->default_passwd_callback_userdata = 0;
143 ::SSL_CTX_free(impl);
148 // Set options on the context.
149 boost::system::error_code set_options(impl_type& impl,
150 context_base::options o, boost::system::error_code& ec)
152 ::SSL_CTX_set_options(impl, o);
154 ec = boost::system::error_code();
158 // Set peer verification mode.
159 boost::system::error_code set_verify_mode(impl_type& impl,
160 context_base::verify_mode v, boost::system::error_code& ec)
162 ::SSL_CTX_set_verify(impl, v, 0);
164 ec = boost::system::error_code();
168 // Load a certification authority file for performing verification.
169 boost::system::error_code load_verify_file(impl_type& impl,
170 const std::string& filename, boost::system::error_code& ec)
172 if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1)
174 ec = boost::asio::error::invalid_argument;
178 ec = boost::system::error_code();
182 // Add a directory containing certification authority files to be used for
183 // performing verification.
184 boost::system::error_code add_verify_path(impl_type& impl,
185 const std::string& path, boost::system::error_code& ec)
187 if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1)
189 ec = boost::asio::error::invalid_argument;
193 ec = boost::system::error_code();
197 // Use a certificate from a file.
198 boost::system::error_code use_certificate_file(impl_type& impl,
199 const std::string& filename, context_base::file_format format,
200 boost::system::error_code& ec)
205 case context_base::asn1:
206 file_type = SSL_FILETYPE_ASN1;
208 case context_base::pem:
209 file_type = SSL_FILETYPE_PEM;
213 ec = boost::asio::error::invalid_argument;
218 if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1)
220 ec = boost::asio::error::invalid_argument;
224 ec = boost::system::error_code();
228 // Use a certificate chain from a file.
229 boost::system::error_code use_certificate_chain_file(impl_type& impl,
230 const std::string& filename, boost::system::error_code& ec)
232 if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1)
234 ec = boost::asio::error::invalid_argument;
238 ec = boost::system::error_code();
242 // Use a private key from a file.
243 boost::system::error_code use_private_key_file(impl_type& impl,
244 const std::string& filename, context_base::file_format format,
245 boost::system::error_code& ec)
250 case context_base::asn1:
251 file_type = SSL_FILETYPE_ASN1;
253 case context_base::pem:
254 file_type = SSL_FILETYPE_PEM;
258 ec = boost::asio::error::invalid_argument;
263 if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1)
265 ec = boost::asio::error::invalid_argument;
269 ec = boost::system::error_code();
273 // Use an RSA private key from a file.
274 boost::system::error_code use_rsa_private_key_file(impl_type& impl,
275 const std::string& filename, context_base::file_format format,
276 boost::system::error_code& ec)
281 case context_base::asn1:
282 file_type = SSL_FILETYPE_ASN1;
284 case context_base::pem:
285 file_type = SSL_FILETYPE_PEM;
289 ec = boost::asio::error::invalid_argument;
294 if (::SSL_CTX_use_RSAPrivateKey_file(
295 impl, filename.c_str(), file_type) != 1)
297 ec = boost::asio::error::invalid_argument;
301 ec = boost::system::error_code();
305 // Use the specified file to obtain the temporary Diffie-Hellman parameters.
306 boost::system::error_code use_tmp_dh_file(impl_type& impl,
307 const std::string& filename, boost::system::error_code& ec)
309 ::BIO* bio = ::BIO_new_file(filename.c_str(), "r");
312 ec = boost::asio::error::invalid_argument;
316 ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0);
320 ec = boost::asio::error::invalid_argument;
325 int result = ::SSL_CTX_set_tmp_dh(impl, dh);
329 ec = boost::asio::error::invalid_argument;
333 ec = boost::system::error_code();
337 static int password_callback(char* buf, int size, int purpose, void* data)
339 using namespace std; // For strncat and strlen.
343 password_callback_type* callback =
344 static_cast<password_callback_type*>(data);
345 std::string passwd = (*callback)(static_cast<std::size_t>(size),
346 purpose ? context_base::for_writing : context_base::for_reading);
348 strncat(buf, passwd.c_str(), size);
355 // Set the password callback.
356 template <typename Password_Callback>
357 boost::system::error_code set_password_callback(impl_type& impl,
358 Password_Callback callback, boost::system::error_code& ec)
360 // Allocate callback function object if not already present.
361 if (impl->default_passwd_callback_userdata)
363 password_callback_type* callback_function =
364 static_cast<password_callback_type*>(
365 impl->default_passwd_callback_userdata);
366 *callback_function = callback;
370 password_callback_type* callback_function =
371 new password_callback_type(callback);
372 impl->default_passwd_callback_userdata = callback_function;
375 // Set the password callback.
376 SSL_CTX_set_default_passwd_cb(impl,
377 &openssl_context_service::password_callback);
379 ec = boost::system::error_code();
384 // Ensure openssl is initialised.
385 boost::asio::ssl::detail::openssl_init<> init_;
388 } // namespace detail
394 #include <boost/asio/detail/pop_options.hpp>
396 #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP