]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // ssl/old/detail/openssl_context_service.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
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) | |
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 | ||
12 | #ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP | |
13 | #define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP | |
14 | ||
15 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | |
16 | # pragma once | |
17 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | |
18 | ||
19 | #include <boost/asio/detail/config.hpp> | |
20 | #include <cstring> | |
21 | #include <string> | |
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> | |
29 | ||
30 | #include <boost/asio/detail/push_options.hpp> | |
31 | ||
32 | namespace boost { | |
33 | namespace asio { | |
34 | namespace ssl { | |
35 | namespace old { | |
36 | namespace detail { | |
37 | ||
38 | class openssl_context_service | |
39 | : public boost::asio::detail::service_base<openssl_context_service> | |
40 | { | |
41 | public: | |
42 | // The native type of the context. | |
43 | typedef ::SSL_CTX* impl_type; | |
44 | ||
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; | |
48 | ||
49 | // Constructor. | |
50 | openssl_context_service(boost::asio::io_service& io_service) | |
51 | : boost::asio::detail::service_base<openssl_context_service>(io_service) | |
52 | { | |
53 | } | |
54 | ||
55 | // Destroy all user-defined handler objects owned by the service. | |
56 | void shutdown_service() | |
57 | { | |
58 | } | |
59 | ||
60 | // Return a null context implementation. | |
61 | static impl_type null() | |
62 | { | |
63 | return 0; | |
64 | } | |
65 | ||
66 | // Create a new context implementation. | |
67 | void create(impl_type& impl, context_base::method m) | |
68 | { | |
69 | switch (m) | |
70 | { | |
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); | |
76 | break; | |
77 | #else // defined(OPENSSL_NO_SSL2) | |
78 | case context_base::sslv2: | |
79 | impl = ::SSL_CTX_new(::SSLv2_method()); | |
80 | break; | |
81 | case context_base::sslv2_client: | |
82 | impl = ::SSL_CTX_new(::SSLv2_client_method()); | |
83 | break; | |
84 | case context_base::sslv2_server: | |
85 | impl = ::SSL_CTX_new(::SSLv2_server_method()); | |
86 | break; | |
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); | |
93 | break; | |
94 | #else // defined(OPENSSL_NO_SSL3) | |
95 | case context_base::sslv3: | |
96 | impl = ::SSL_CTX_new(::SSLv3_method()); | |
97 | break; | |
98 | case context_base::sslv3_client: | |
99 | impl = ::SSL_CTX_new(::SSLv3_client_method()); | |
100 | break; | |
101 | case context_base::sslv3_server: | |
102 | impl = ::SSL_CTX_new(::SSLv3_server_method()); | |
103 | break; | |
104 | #endif // defined(OPENSSL_NO_SSL3) | |
105 | case context_base::tlsv1: | |
106 | impl = ::SSL_CTX_new(::TLSv1_method()); | |
107 | break; | |
108 | case context_base::tlsv1_client: | |
109 | impl = ::SSL_CTX_new(::TLSv1_client_method()); | |
110 | break; | |
111 | case context_base::tlsv1_server: | |
112 | impl = ::SSL_CTX_new(::TLSv1_server_method()); | |
113 | break; | |
114 | case context_base::sslv23: | |
115 | impl = ::SSL_CTX_new(::SSLv23_method()); | |
116 | break; | |
117 | case context_base::sslv23_client: | |
118 | impl = ::SSL_CTX_new(::SSLv23_client_method()); | |
119 | break; | |
120 | case context_base::sslv23_server: | |
121 | impl = ::SSL_CTX_new(::SSLv23_server_method()); | |
122 | break; | |
123 | default: | |
124 | impl = ::SSL_CTX_new(0); | |
125 | break; | |
126 | } | |
127 | } | |
128 | ||
129 | // Destroy a context implementation. | |
130 | void destroy(impl_type& impl) | |
131 | { | |
132 | if (impl != null()) | |
133 | { | |
134 | if (impl->default_passwd_callback_userdata) | |
135 | { | |
136 | password_callback_type* callback = | |
137 | static_cast<password_callback_type*>( | |
138 | impl->default_passwd_callback_userdata); | |
139 | delete callback; | |
140 | impl->default_passwd_callback_userdata = 0; | |
141 | } | |
142 | ||
143 | ::SSL_CTX_free(impl); | |
144 | impl = null(); | |
145 | } | |
146 | } | |
147 | ||
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) | |
151 | { | |
152 | ::SSL_CTX_set_options(impl, o); | |
153 | ||
154 | ec = boost::system::error_code(); | |
155 | return ec; | |
156 | } | |
157 | ||
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) | |
161 | { | |
162 | ::SSL_CTX_set_verify(impl, v, 0); | |
163 | ||
164 | ec = boost::system::error_code(); | |
165 | return ec; | |
166 | } | |
167 | ||
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) | |
171 | { | |
172 | if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1) | |
173 | { | |
174 | ec = boost::asio::error::invalid_argument; | |
175 | return ec; | |
176 | } | |
177 | ||
178 | ec = boost::system::error_code(); | |
179 | return ec; | |
180 | } | |
181 | ||
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) | |
186 | { | |
187 | if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1) | |
188 | { | |
189 | ec = boost::asio::error::invalid_argument; | |
190 | return ec; | |
191 | } | |
192 | ||
193 | ec = boost::system::error_code(); | |
194 | return ec; | |
195 | } | |
196 | ||
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) | |
201 | { | |
202 | int file_type; | |
203 | switch (format) | |
204 | { | |
205 | case context_base::asn1: | |
206 | file_type = SSL_FILETYPE_ASN1; | |
207 | break; | |
208 | case context_base::pem: | |
209 | file_type = SSL_FILETYPE_PEM; | |
210 | break; | |
211 | default: | |
212 | { | |
213 | ec = boost::asio::error::invalid_argument; | |
214 | return ec; | |
215 | } | |
216 | } | |
217 | ||
218 | if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1) | |
219 | { | |
220 | ec = boost::asio::error::invalid_argument; | |
221 | return ec; | |
222 | } | |
223 | ||
224 | ec = boost::system::error_code(); | |
225 | return ec; | |
226 | } | |
227 | ||
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) | |
231 | { | |
232 | if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1) | |
233 | { | |
234 | ec = boost::asio::error::invalid_argument; | |
235 | return ec; | |
236 | } | |
237 | ||
238 | ec = boost::system::error_code(); | |
239 | return ec; | |
240 | } | |
241 | ||
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) | |
246 | { | |
247 | int file_type; | |
248 | switch (format) | |
249 | { | |
250 | case context_base::asn1: | |
251 | file_type = SSL_FILETYPE_ASN1; | |
252 | break; | |
253 | case context_base::pem: | |
254 | file_type = SSL_FILETYPE_PEM; | |
255 | break; | |
256 | default: | |
257 | { | |
258 | ec = boost::asio::error::invalid_argument; | |
259 | return ec; | |
260 | } | |
261 | } | |
262 | ||
263 | if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1) | |
264 | { | |
265 | ec = boost::asio::error::invalid_argument; | |
266 | return ec; | |
267 | } | |
268 | ||
269 | ec = boost::system::error_code(); | |
270 | return ec; | |
271 | } | |
272 | ||
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) | |
277 | { | |
278 | int file_type; | |
279 | switch (format) | |
280 | { | |
281 | case context_base::asn1: | |
282 | file_type = SSL_FILETYPE_ASN1; | |
283 | break; | |
284 | case context_base::pem: | |
285 | file_type = SSL_FILETYPE_PEM; | |
286 | break; | |
287 | default: | |
288 | { | |
289 | ec = boost::asio::error::invalid_argument; | |
290 | return ec; | |
291 | } | |
292 | } | |
293 | ||
294 | if (::SSL_CTX_use_RSAPrivateKey_file( | |
295 | impl, filename.c_str(), file_type) != 1) | |
296 | { | |
297 | ec = boost::asio::error::invalid_argument; | |
298 | return ec; | |
299 | } | |
300 | ||
301 | ec = boost::system::error_code(); | |
302 | return ec; | |
303 | } | |
304 | ||
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) | |
308 | { | |
309 | ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); | |
310 | if (!bio) | |
311 | { | |
312 | ec = boost::asio::error::invalid_argument; | |
313 | return ec; | |
314 | } | |
315 | ||
316 | ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); | |
317 | if (!dh) | |
318 | { | |
319 | ::BIO_free(bio); | |
320 | ec = boost::asio::error::invalid_argument; | |
321 | return ec; | |
322 | } | |
323 | ||
324 | ::BIO_free(bio); | |
325 | int result = ::SSL_CTX_set_tmp_dh(impl, dh); | |
326 | ::DH_free(dh); | |
327 | if (result != 1) | |
328 | { | |
329 | ec = boost::asio::error::invalid_argument; | |
330 | return ec; | |
331 | } | |
332 | ||
333 | ec = boost::system::error_code(); | |
334 | return ec; | |
335 | } | |
336 | ||
337 | static int password_callback(char* buf, int size, int purpose, void* data) | |
338 | { | |
339 | using namespace std; // For strncat and strlen. | |
340 | ||
341 | if (data) | |
342 | { | |
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); | |
347 | *buf = '\0'; | |
348 | strncat(buf, passwd.c_str(), size); | |
349 | return strlen(buf); | |
350 | } | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
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) | |
359 | { | |
360 | // Allocate callback function object if not already present. | |
361 | if (impl->default_passwd_callback_userdata) | |
362 | { | |
363 | password_callback_type* callback_function = | |
364 | static_cast<password_callback_type*>( | |
365 | impl->default_passwd_callback_userdata); | |
366 | *callback_function = callback; | |
367 | } | |
368 | else | |
369 | { | |
370 | password_callback_type* callback_function = | |
371 | new password_callback_type(callback); | |
372 | impl->default_passwd_callback_userdata = callback_function; | |
373 | } | |
374 | ||
375 | // Set the password callback. | |
376 | SSL_CTX_set_default_passwd_cb(impl, | |
377 | &openssl_context_service::password_callback); | |
378 | ||
379 | ec = boost::system::error_code(); | |
380 | return ec; | |
381 | } | |
382 | ||
383 | private: | |
384 | // Ensure openssl is initialised. | |
385 | boost::asio::ssl::detail::openssl_init<> init_; | |
386 | }; | |
387 | ||
388 | } // namespace detail | |
389 | } // namespace old | |
390 | } // namespace ssl | |
391 | } // namespace asio | |
392 | } // namespace boost | |
393 | ||
394 | #include <boost/asio/detail/pop_options.hpp> | |
395 | ||
396 | #endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP |