$search
00001 // 00002 // openssl_context_service.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com 00006 // Copyright (c) 2005-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00007 // 00008 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00010 // 00011 00012 #ifndef ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP 00013 #define ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP 00014 00015 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00016 # pragma once 00017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00018 00019 #include "asio/detail/push_options.hpp" 00020 00021 #include "asio/detail/push_options.hpp" 00022 #include <cstring> 00023 #include <string> 00024 #include <boost/function.hpp> 00025 #include "asio/detail/pop_options.hpp" 00026 00027 #include "asio/error.hpp" 00028 #include "asio/io_service.hpp" 00029 #include "asio/detail/service_base.hpp" 00030 #include "asio/ssl/context_base.hpp" 00031 #include "asio/ssl/detail/openssl_init.hpp" 00032 #include "asio/ssl/detail/openssl_types.hpp" 00033 00034 namespace asio { 00035 namespace ssl { 00036 namespace detail { 00037 00038 class openssl_context_service 00039 : public asio::detail::service_base<openssl_context_service> 00040 { 00041 public: 00042 // The native type of the context. 00043 typedef ::SSL_CTX* impl_type; 00044 00045 // The type for the password callback function object. 00046 typedef boost::function<std::string(std::size_t, 00047 context_base::password_purpose)> password_callback_type; 00048 00049 // Constructor. 00050 openssl_context_service(asio::io_service& io_service) 00051 : asio::detail::service_base<openssl_context_service>(io_service) 00052 { 00053 } 00054 00055 // Destroy all user-defined handler objects owned by the service. 00056 void shutdown_service() 00057 { 00058 } 00059 00060 // Return a null context implementation. 00061 static impl_type null() 00062 { 00063 return 0; 00064 } 00065 00066 // Create a new context implementation. 00067 void create(impl_type& impl, context_base::method m) 00068 { 00069 ::SSL_METHOD* ssl_method = 0; 00070 switch (m) 00071 { 00072 case context_base::sslv2: 00073 ssl_method = ::SSLv2_method(); 00074 break; 00075 case context_base::sslv2_client: 00076 ssl_method = ::SSLv2_client_method(); 00077 break; 00078 case context_base::sslv2_server: 00079 ssl_method = ::SSLv2_server_method(); 00080 break; 00081 case context_base::sslv3: 00082 ssl_method = ::SSLv3_method(); 00083 break; 00084 case context_base::sslv3_client: 00085 ssl_method = ::SSLv3_client_method(); 00086 break; 00087 case context_base::sslv3_server: 00088 ssl_method = ::SSLv3_server_method(); 00089 break; 00090 case context_base::tlsv1: 00091 ssl_method = ::TLSv1_method(); 00092 break; 00093 case context_base::tlsv1_client: 00094 ssl_method = ::TLSv1_client_method(); 00095 break; 00096 case context_base::tlsv1_server: 00097 ssl_method = ::TLSv1_server_method(); 00098 break; 00099 case context_base::sslv23: 00100 ssl_method = ::SSLv23_method(); 00101 break; 00102 case context_base::sslv23_client: 00103 ssl_method = ::SSLv23_client_method(); 00104 break; 00105 case context_base::sslv23_server: 00106 ssl_method = ::SSLv23_server_method(); 00107 break; 00108 default: 00109 break; 00110 } 00111 impl = ::SSL_CTX_new(ssl_method); 00112 } 00113 00114 // Destroy a context implementation. 00115 void destroy(impl_type& impl) 00116 { 00117 if (impl != null()) 00118 { 00119 if (impl->default_passwd_callback_userdata) 00120 { 00121 password_callback_type* callback = 00122 static_cast<password_callback_type*>( 00123 impl->default_passwd_callback_userdata); 00124 delete callback; 00125 impl->default_passwd_callback_userdata = 0; 00126 } 00127 00128 ::SSL_CTX_free(impl); 00129 impl = null(); 00130 } 00131 } 00132 00133 // Set options on the context. 00134 asio::error_code set_options(impl_type& impl, 00135 context_base::options o, asio::error_code& ec) 00136 { 00137 ::SSL_CTX_set_options(impl, o); 00138 00139 ec = asio::error_code(); 00140 return ec; 00141 } 00142 00143 // Set peer verification mode. 00144 asio::error_code set_verify_mode(impl_type& impl, 00145 context_base::verify_mode v, asio::error_code& ec) 00146 { 00147 ::SSL_CTX_set_verify(impl, v, 0); 00148 00149 ec = asio::error_code(); 00150 return ec; 00151 } 00152 00153 // Load a certification authority file for performing verification. 00154 asio::error_code load_verify_file(impl_type& impl, 00155 const std::string& filename, asio::error_code& ec) 00156 { 00157 if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1) 00158 { 00159 ec = asio::error::invalid_argument; 00160 return ec; 00161 } 00162 00163 ec = asio::error_code(); 00164 return ec; 00165 } 00166 00167 // Add a directory containing certification authority files to be used for 00168 // performing verification. 00169 asio::error_code add_verify_path(impl_type& impl, 00170 const std::string& path, asio::error_code& ec) 00171 { 00172 if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1) 00173 { 00174 ec = asio::error::invalid_argument; 00175 return ec; 00176 } 00177 00178 ec = asio::error_code(); 00179 return ec; 00180 } 00181 00182 // Use a certificate from a file. 00183 asio::error_code use_certificate_file(impl_type& impl, 00184 const std::string& filename, context_base::file_format format, 00185 asio::error_code& ec) 00186 { 00187 int file_type; 00188 switch (format) 00189 { 00190 case context_base::asn1: 00191 file_type = SSL_FILETYPE_ASN1; 00192 break; 00193 case context_base::pem: 00194 file_type = SSL_FILETYPE_PEM; 00195 break; 00196 default: 00197 { 00198 ec = asio::error::invalid_argument; 00199 return ec; 00200 } 00201 } 00202 00203 if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1) 00204 { 00205 ec = asio::error::invalid_argument; 00206 return ec; 00207 } 00208 00209 ec = asio::error_code(); 00210 return ec; 00211 } 00212 00213 // Use a certificate chain from a file. 00214 asio::error_code use_certificate_chain_file(impl_type& impl, 00215 const std::string& filename, asio::error_code& ec) 00216 { 00217 if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1) 00218 { 00219 ec = asio::error::invalid_argument; 00220 return ec; 00221 } 00222 00223 ec = asio::error_code(); 00224 return ec; 00225 } 00226 00227 // Use a private key from a file. 00228 asio::error_code use_private_key_file(impl_type& impl, 00229 const std::string& filename, context_base::file_format format, 00230 asio::error_code& ec) 00231 { 00232 int file_type; 00233 switch (format) 00234 { 00235 case context_base::asn1: 00236 file_type = SSL_FILETYPE_ASN1; 00237 break; 00238 case context_base::pem: 00239 file_type = SSL_FILETYPE_PEM; 00240 break; 00241 default: 00242 { 00243 ec = asio::error::invalid_argument; 00244 return ec; 00245 } 00246 } 00247 00248 if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1) 00249 { 00250 ec = asio::error::invalid_argument; 00251 return ec; 00252 } 00253 00254 ec = asio::error_code(); 00255 return ec; 00256 } 00257 00258 // Use an RSA private key from a file. 00259 asio::error_code use_rsa_private_key_file(impl_type& impl, 00260 const std::string& filename, context_base::file_format format, 00261 asio::error_code& ec) 00262 { 00263 int file_type; 00264 switch (format) 00265 { 00266 case context_base::asn1: 00267 file_type = SSL_FILETYPE_ASN1; 00268 break; 00269 case context_base::pem: 00270 file_type = SSL_FILETYPE_PEM; 00271 break; 00272 default: 00273 { 00274 ec = asio::error::invalid_argument; 00275 return ec; 00276 } 00277 } 00278 00279 if (::SSL_CTX_use_RSAPrivateKey_file( 00280 impl, filename.c_str(), file_type) != 1) 00281 { 00282 ec = asio::error::invalid_argument; 00283 return ec; 00284 } 00285 00286 ec = asio::error_code(); 00287 return ec; 00288 } 00289 00290 // Use the specified file to obtain the temporary Diffie-Hellman parameters. 00291 asio::error_code use_tmp_dh_file(impl_type& impl, 00292 const std::string& filename, asio::error_code& ec) 00293 { 00294 ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); 00295 if (!bio) 00296 { 00297 ec = asio::error::invalid_argument; 00298 return ec; 00299 } 00300 00301 ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); 00302 if (!dh) 00303 { 00304 ::BIO_free(bio); 00305 ec = asio::error::invalid_argument; 00306 return ec; 00307 } 00308 00309 ::BIO_free(bio); 00310 int result = ::SSL_CTX_set_tmp_dh(impl, dh); 00311 ::DH_free(dh); 00312 if (result != 1) 00313 { 00314 ec = asio::error::invalid_argument; 00315 return ec; 00316 } 00317 00318 ec = asio::error_code(); 00319 return ec; 00320 } 00321 00322 static int password_callback(char* buf, int size, int purpose, void* data) 00323 { 00324 using namespace std; // For strncat and strlen. 00325 00326 if (data) 00327 { 00328 password_callback_type* callback = 00329 static_cast<password_callback_type*>(data); 00330 std::string passwd = (*callback)(static_cast<std::size_t>(size), 00331 purpose ? context_base::for_writing : context_base::for_reading); 00332 *buf = '\0'; 00333 strncat(buf, passwd.c_str(), size); 00334 return strlen(buf); 00335 } 00336 00337 return 0; 00338 } 00339 00340 // Set the password callback. 00341 template <typename Password_Callback> 00342 asio::error_code set_password_callback(impl_type& impl, 00343 Password_Callback callback, asio::error_code& ec) 00344 { 00345 // Allocate callback function object if not already present. 00346 if (impl->default_passwd_callback_userdata) 00347 { 00348 password_callback_type* callback_function = 00349 static_cast<password_callback_type*>( 00350 impl->default_passwd_callback_userdata); 00351 *callback_function = callback; 00352 } 00353 else 00354 { 00355 password_callback_type* callback_function = 00356 new password_callback_type(callback); 00357 impl->default_passwd_callback_userdata = callback_function; 00358 } 00359 00360 // Set the password callback. 00361 SSL_CTX_set_default_passwd_cb(impl, 00362 &openssl_context_service::password_callback); 00363 00364 ec = asio::error_code(); 00365 return ec; 00366 } 00367 00368 private: 00369 // Ensure openssl is initialised. 00370 openssl_init<> init_; 00371 }; 00372 00373 } // namespace detail 00374 } // namespace ssl 00375 } // namespace asio 00376 00377 #include "asio/detail/pop_options.hpp" 00378 00379 #endif // ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP