00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00043 typedef ::SSL_CTX* impl_type;
00044
00045
00046 typedef boost::function<std::string(std::size_t,
00047 context_base::password_purpose)> password_callback_type;
00048
00049
00050 openssl_context_service(asio::io_service& io_service)
00051 : asio::detail::service_base<openssl_context_service>(io_service)
00052 {
00053 }
00054
00055
00056 void shutdown_service()
00057 {
00058 }
00059
00060
00061 static impl_type null()
00062 {
00063 return 0;
00064 }
00065
00066
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
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
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
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
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
00168
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
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
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
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
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
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;
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
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
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
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
00370 openssl_init<> init_;
00371 };
00372
00373 }
00374 }
00375 }
00376
00377 #include "asio/detail/pop_options.hpp"
00378
00379 #endif // ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP