1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/net/SslStream.h"
8
9 #if !TD_EMSCRIPTEN
10 #include "td/utils/common.h"
11 #include "td/utils/crypto.h"
12 #include "td/utils/logging.h"
13 #include "td/utils/misc.h"
14 #include "td/utils/port/IPAddress.h"
15 #include "td/utils/port/wstring_convert.h"
16 #include "td/utils/SliceBuilder.h"
17 #include "td/utils/Status.h"
18 #include "td/utils/Time.h"
19
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/ssl.h>
23 #include <openssl/x509.h>
24 #include <openssl/x509v3.h>
25
26 #include <cstring>
27 #include <memory>
28 #include <mutex>
29 #include <unordered_map>
30
31 #if TD_PORT_WINDOWS
32 #include <wincrypt.h>
33 #endif
34
35 namespace td {
36
37 namespace detail {
38 namespace {
39 #if OPENSSL_VERSION_NUMBER < 0x10100000L
BIO_get_data(BIO * b)40 void *BIO_get_data(BIO *b) {
41 return b->ptr;
42 }
BIO_set_data(BIO * b,void * ptr)43 void BIO_set_data(BIO *b, void *ptr) {
44 b->ptr = ptr;
45 }
BIO_set_init(BIO * b,int init)46 void BIO_set_init(BIO *b, int init) {
47 b->init = init;
48 }
49
BIO_get_new_index()50 int BIO_get_new_index() {
51 return 0;
52 }
BIO_meth_new(int type,const char * name)53 BIO_METHOD *BIO_meth_new(int type, const char *name) {
54 auto res = new BIO_METHOD();
55 std::memset(res, 0, sizeof(*res));
56 return res;
57 }
58
BIO_meth_set_write(BIO_METHOD * biom,int (* bwrite)(BIO *,const char *,int))59 int BIO_meth_set_write(BIO_METHOD *biom, int (*bwrite)(BIO *, const char *, int)) {
60 biom->bwrite = bwrite;
61 return 1;
62 }
BIO_meth_set_read(BIO_METHOD * biom,int (* bread)(BIO *,char *,int))63 int BIO_meth_set_read(BIO_METHOD *biom, int (*bread)(BIO *, char *, int)) {
64 biom->bread = bread;
65 return 1;
66 }
BIO_meth_set_ctrl(BIO_METHOD * biom,long (* ctrl)(BIO *,int,long,void *))67 int BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl)(BIO *, int, long, void *)) {
68 biom->ctrl = ctrl;
69 return 1;
70 }
BIO_meth_set_create(BIO_METHOD * biom,int (* create)(BIO *))71 int BIO_meth_set_create(BIO_METHOD *biom, int (*create)(BIO *)) {
72 biom->create = create;
73 return 1;
74 }
BIO_meth_set_destroy(BIO_METHOD * biom,int (* destroy)(BIO *))75 int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy)(BIO *)) {
76 biom->destroy = destroy;
77 return 1;
78 }
79 #endif
80
strm_create(BIO * b)81 int strm_create(BIO *b) {
82 BIO_set_init(b, 1);
83 return 1;
84 }
85
strm_destroy(BIO * b)86 int strm_destroy(BIO *b) {
87 return 1;
88 }
89
90 int strm_read(BIO *b, char *buf, int len);
91
92 int strm_write(BIO *b, const char *buf, int len);
93
strm_ctrl(BIO * b,int cmd,long num,void * ptr)94 long strm_ctrl(BIO *b, int cmd, long num, void *ptr) {
95 switch (cmd) {
96 case BIO_CTRL_FLUSH:
97 return 1;
98 case BIO_CTRL_PUSH:
99 case BIO_CTRL_POP:
100 return 0;
101 default:
102 LOG(FATAL) << b << " " << cmd << " " << num << " " << ptr;
103 }
104 return 1;
105 }
106
BIO_s_sslstream()107 BIO_METHOD *BIO_s_sslstream() {
108 static BIO_METHOD *result = [] {
109 BIO_METHOD *res = BIO_meth_new(BIO_get_new_index(), "td::SslStream helper bio");
110 BIO_meth_set_write(res, strm_write);
111 BIO_meth_set_read(res, strm_read);
112 BIO_meth_set_create(res, strm_create);
113 BIO_meth_set_destroy(res, strm_destroy);
114 BIO_meth_set_ctrl(res, strm_ctrl);
115 return res;
116 }();
117 return result;
118 }
119
verify_callback(int preverify_ok,X509_STORE_CTX * ctx)120 int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
121 if (!preverify_ok) {
122 char buf[256];
123 X509_NAME_oneline(X509_get_subject_name(X509_STORE_CTX_get_current_cert(ctx)), buf, 256);
124
125 int err = X509_STORE_CTX_get_error(ctx);
126 auto warning = PSTRING() << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err)
127 << ":depth=" << X509_STORE_CTX_get_error_depth(ctx) << ":" << Slice(buf, std::strlen(buf));
128 double now = Time::now();
129
130 static std::mutex warning_mutex;
131 {
132 std::lock_guard<std::mutex> lock(warning_mutex);
133 static std::unordered_map<std::string, double> next_warning_time;
134 double &next = next_warning_time[warning];
135 if (next <= now) {
136 next = now + 300; // one warning per 5 minutes
137 LOG(WARNING) << warning;
138 }
139 }
140 }
141
142 return preverify_ok;
143 }
144
145 using SslCtx = std::shared_ptr<SSL_CTX>;
146
147 struct SslHandleDeleter {
operator ()td::detail::__anon81d0eed30111::SslHandleDeleter148 void operator()(SSL *ssl_handle) {
149 if (SSL_is_init_finished(ssl_handle)) {
150 clear_openssl_errors("Before SSL_shutdown");
151 SSL_set_quiet_shutdown(ssl_handle, 1);
152 SSL_shutdown(ssl_handle);
153 clear_openssl_errors("After SSL_shutdown");
154 }
155 SSL_free(ssl_handle);
156 }
157 };
158
159 using SslHandle = std::unique_ptr<SSL, SslHandleDeleter>;
160
do_create_ssl_ctx(CSlice cert_file,SslStream::VerifyPeer verify_peer)161 Result<SslCtx> do_create_ssl_ctx(CSlice cert_file, SslStream::VerifyPeer verify_peer) {
162 auto ssl_method =
163 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
164 TLS_client_method();
165 #else
166 SSLv23_client_method();
167 #endif
168 if (ssl_method == nullptr) {
169 return create_openssl_error(-6, "Failed to create an SSL client method");
170 }
171 auto ssl_ctx = SSL_CTX_new(ssl_method);
172 if (!ssl_ctx) {
173 return create_openssl_error(-7, "Failed to create an SSL context");
174 }
175 auto ssl_ctx_ptr = SslCtx(ssl_ctx, SSL_CTX_free);
176 long options = 0;
177 #ifdef SSL_OP_NO_SSLv2
178 options |= SSL_OP_NO_SSLv2;
179 #endif
180 #ifdef SSL_OP_NO_SSLv3
181 options |= SSL_OP_NO_SSLv3;
182 #endif
183 SSL_CTX_set_options(ssl_ctx, options);
184 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
185 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
186 #endif
187 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
188
189 if (cert_file.empty()) {
190 #if TD_PORT_WINDOWS
191 LOG(DEBUG) << "Begin to load system store";
192 auto flags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
193 HCERTSTORE system_store =
194 CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, HCRYPTPROV_LEGACY(), flags,
195 static_cast<const void *>(to_wstring("ROOT").ok().c_str()));
196
197 if (system_store) {
198 X509_STORE *store = X509_STORE_new();
199
200 for (PCCERT_CONTEXT cert_context = CertEnumCertificatesInStore(system_store, nullptr); cert_context != nullptr;
201 cert_context = CertEnumCertificatesInStore(system_store, cert_context)) {
202 const unsigned char *in = cert_context->pbCertEncoded;
203 X509 *x509 = d2i_X509(nullptr, &in, static_cast<long>(cert_context->cbCertEncoded));
204 if (x509 != nullptr) {
205 if (X509_STORE_add_cert(store, x509) != 1) {
206 auto error_code = ERR_peek_error();
207 auto error = create_openssl_error(-20, "Failed to add certificate");
208 if (ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
209 LOG(ERROR) << error;
210 } else {
211 LOG(INFO) << error;
212 }
213 }
214
215 X509_free(x509);
216 } else {
217 LOG(ERROR) << create_openssl_error(-21, "Failed to load X509 certificate");
218 }
219 }
220
221 CertCloseStore(system_store, 0);
222
223 SSL_CTX_set_cert_store(ssl_ctx, store);
224 LOG(DEBUG) << "End to load system store";
225 } else {
226 LOG(ERROR) << create_openssl_error(-22, "Failed to open system certificate store");
227 }
228 #else
229 if (SSL_CTX_set_default_verify_paths(ssl_ctx) == 0) {
230 auto error = create_openssl_error(-8, "Failed to load default verify paths");
231 if (verify_peer == SslStream::VerifyPeer::On) {
232 return std::move(error);
233 } else {
234 LOG(ERROR) << error;
235 }
236 }
237 #endif
238 } else {
239 if (SSL_CTX_load_verify_locations(ssl_ctx, cert_file.c_str(), nullptr) == 0) {
240 return create_openssl_error(-8, "Failed to set custom certificate file");
241 }
242 }
243
244 if (verify_peer == SslStream::VerifyPeer::On) {
245 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
246
247 constexpr int DEFAULT_VERIFY_DEPTH = 10;
248 SSL_CTX_set_verify_depth(ssl_ctx, DEFAULT_VERIFY_DEPTH);
249 } else {
250 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);
251 }
252
253 string cipher_list;
254 if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.empty() ? "DEFAULT" : cipher_list.c_str()) == 0) {
255 return create_openssl_error(-9, PSLICE() << "Failed to set cipher list \"" << cipher_list << '"');
256 }
257
258 return std::move(ssl_ctx_ptr);
259 }
260
get_default_ssl_ctx()261 Result<SslCtx> get_default_ssl_ctx() {
262 static auto ctx = do_create_ssl_ctx("", SslStream::VerifyPeer::On);
263 if (ctx.is_error()) {
264 return ctx.error().clone();
265 }
266
267 return ctx.ok();
268 }
269
get_default_unverified_ssl_ctx()270 Result<SslCtx> get_default_unverified_ssl_ctx() {
271 static auto ctx = do_create_ssl_ctx("", SslStream::VerifyPeer::Off);
272 if (ctx.is_error()) {
273 return ctx.error().clone();
274 }
275
276 return ctx.ok();
277 }
278
create_ssl_ctx(CSlice cert_file,SslStream::VerifyPeer verify_peer)279 Result<SslCtx> create_ssl_ctx(CSlice cert_file, SslStream::VerifyPeer verify_peer) {
280 if (cert_file.empty()) {
281 if (verify_peer == SslStream::VerifyPeer::On) {
282 return get_default_ssl_ctx();
283 } else {
284 return get_default_unverified_ssl_ctx();
285 }
286 }
287 return do_create_ssl_ctx(cert_file, verify_peer);
288 }
289
290 } // namespace
291
292 class SslStreamImpl {
293 public:
init(CSlice host,CSlice cert_file,SslStream::VerifyPeer verify_peer,bool check_ip_address_as_host)294 Status init(CSlice host, CSlice cert_file, SslStream::VerifyPeer verify_peer, bool check_ip_address_as_host) {
295 static bool init_openssl = [] {
296 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
297 return OPENSSL_init_ssl(0, nullptr) != 0;
298 #else
299 OpenSSL_add_all_algorithms();
300 SSL_load_error_strings();
301 return OpenSSL_add_ssl_algorithms() != 0;
302 #endif
303 }();
304 CHECK(init_openssl);
305
306 clear_openssl_errors("Before SslFd::init");
307
308 TRY_RESULT(ssl_ctx, create_ssl_ctx(cert_file, verify_peer));
309
310 auto ssl_handle = SslHandle(SSL_new(ssl_ctx.get()));
311 if (!ssl_handle) {
312 return create_openssl_error(-13, "Failed to create an SSL handle");
313 }
314
315 auto r_ip_address = IPAddress::get_ip_address(host);
316
317 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
318 X509_VERIFY_PARAM *param = SSL_get0_param(ssl_handle.get());
319 X509_VERIFY_PARAM_set_hostflags(param, 0);
320 if (r_ip_address.is_ok() && !check_ip_address_as_host) {
321 LOG(DEBUG) << "Set verification IP address to " << r_ip_address.ok().get_ip_str();
322 X509_VERIFY_PARAM_set1_ip_asc(param, r_ip_address.ok().get_ip_str().c_str());
323 } else {
324 LOG(DEBUG) << "Set verification host to " << host;
325 X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0);
326 }
327 #else
328 #warning DANGEROUS! HTTPS HOST WILL NOT BE CHECKED. INSTALL OPENSSL >= 1.0.2 OR IMPLEMENT HTTPS HOST CHECK MANUALLY
329 #endif
330
331 auto *bio = BIO_new(BIO_s_sslstream());
332 BIO_set_data(bio, static_cast<void *>(this));
333 SSL_set_bio(ssl_handle.get(), bio, bio);
334
335 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
336 if (r_ip_address.is_error()) { // IP address must not be send as SNI
337 LOG(DEBUG) << "Set SNI host name to " << host;
338 auto host_str = host.str();
339 SSL_set_tlsext_host_name(ssl_handle.get(), MutableCSlice(host_str).begin());
340 }
341 #endif
342 SSL_set_connect_state(ssl_handle.get());
343
344 ssl_handle_ = std::move(ssl_handle);
345
346 return Status::OK();
347 }
348
read_byte_flow()349 ByteFlowInterface &read_byte_flow() {
350 return read_flow_;
351 }
write_byte_flow()352 ByteFlowInterface &write_byte_flow() {
353 return write_flow_;
354 }
flow_read(MutableSlice slice)355 size_t flow_read(MutableSlice slice) {
356 return read_flow_.read(slice);
357 }
flow_write(Slice slice)358 size_t flow_write(Slice slice) {
359 return write_flow_.write(slice);
360 }
361
362 private:
363 SslHandle ssl_handle_;
364
365 friend class SslReadByteFlow;
366 friend class SslWriteByteFlow;
367
write(Slice slice)368 Result<size_t> write(Slice slice) {
369 clear_openssl_errors("Before SslFd::write");
370 auto size = SSL_write(ssl_handle_.get(), slice.data(), static_cast<int>(slice.size()));
371 if (size <= 0) {
372 return process_ssl_error(size);
373 }
374 return size;
375 }
376
read(MutableSlice slice)377 Result<size_t> read(MutableSlice slice) {
378 clear_openssl_errors("Before SslFd::read");
379 auto size = SSL_read(ssl_handle_.get(), slice.data(), static_cast<int>(slice.size()));
380 if (size <= 0) {
381 return process_ssl_error(size);
382 }
383 return size;
384 }
385
386 class SslReadByteFlow final : public ByteFlowBase {
387 public:
SslReadByteFlow(SslStreamImpl * stream)388 explicit SslReadByteFlow(SslStreamImpl *stream) : stream_(stream) {
389 }
loop()390 bool loop() final {
391 auto to_read = output_.prepare_append();
392 auto r_size = stream_->read(to_read);
393 if (r_size.is_error()) {
394 finish(r_size.move_as_error());
395 return false;
396 }
397 auto size = r_size.move_as_ok();
398 if (size == 0) {
399 return false;
400 }
401 output_.confirm_append(size);
402 return true;
403 }
404
read(MutableSlice data)405 size_t read(MutableSlice data) {
406 return input_->advance(min(data.size(), input_->size()), data);
407 }
408
409 private:
410 SslStreamImpl *stream_;
411 };
412
413 class SslWriteByteFlow final : public ByteFlowBase {
414 public:
SslWriteByteFlow(SslStreamImpl * stream)415 explicit SslWriteByteFlow(SslStreamImpl *stream) : stream_(stream) {
416 }
loop()417 bool loop() final {
418 auto to_write = input_->prepare_read();
419 auto r_size = stream_->write(to_write);
420 if (r_size.is_error()) {
421 finish(r_size.move_as_error());
422 return false;
423 }
424 auto size = r_size.move_as_ok();
425 if (size == 0) {
426 return false;
427 }
428 input_->confirm_read(size);
429 return true;
430 }
431
write(Slice data)432 size_t write(Slice data) {
433 output_.append(data);
434 return data.size();
435 }
436
437 private:
438 SslStreamImpl *stream_;
439 };
440
441 SslReadByteFlow read_flow_{this};
442 SslWriteByteFlow write_flow_{this};
443
process_ssl_error(int ret)444 Result<size_t> process_ssl_error(int ret) {
445 auto os_error = OS_ERROR("SSL_ERROR_SYSCALL");
446 int error = SSL_get_error(ssl_handle_.get(), ret);
447 switch (error) {
448 case SSL_ERROR_NONE:
449 LOG(ERROR) << "SSL_get_error returned no error";
450 return 0;
451 case SSL_ERROR_ZERO_RETURN:
452 LOG(DEBUG) << "SSL_ZERO_RETURN";
453 return 0;
454 case SSL_ERROR_WANT_READ:
455 LOG(DEBUG) << "SSL_WANT_READ";
456 return 0;
457 case SSL_ERROR_WANT_WRITE:
458 LOG(DEBUG) << "SSL_WANT_WRITE";
459 return 0;
460 case SSL_ERROR_WANT_CONNECT:
461 case SSL_ERROR_WANT_ACCEPT:
462 case SSL_ERROR_WANT_X509_LOOKUP:
463 LOG(DEBUG) << "SSL: CONNECT ACCEPT LOOKUP";
464 return 0;
465 case SSL_ERROR_SYSCALL:
466 if (ERR_peek_error() == 0) {
467 if (os_error.code() != 0) {
468 LOG(DEBUG) << "SSL_ERROR_SYSCALL";
469 return std::move(os_error);
470 } else {
471 LOG(DEBUG) << "SSL_SYSCALL";
472 return 0;
473 }
474 }
475 /* fallthrough */
476 default:
477 LOG(DEBUG) << "SSL_ERROR Default";
478 return create_openssl_error(1, "SSL error ");
479 }
480 }
481 };
482
483 namespace {
strm_read(BIO * b,char * buf,int len)484 int strm_read(BIO *b, char *buf, int len) {
485 auto *stream = static_cast<SslStreamImpl *>(BIO_get_data(b));
486 CHECK(stream != nullptr);
487 BIO_clear_retry_flags(b);
488 CHECK(buf != nullptr);
489 auto res = narrow_cast<int>(stream->flow_read(MutableSlice(buf, len)));
490 if (res == 0) {
491 BIO_set_retry_read(b);
492 return -1;
493 }
494 return res;
495 }
strm_write(BIO * b,const char * buf,int len)496 int strm_write(BIO *b, const char *buf, int len) {
497 auto *stream = static_cast<SslStreamImpl *>(BIO_get_data(b));
498 CHECK(stream != nullptr);
499 BIO_clear_retry_flags(b);
500 CHECK(buf != nullptr);
501 return narrow_cast<int>(stream->flow_write(Slice(buf, len)));
502 }
503 } // namespace
504
505 } // namespace detail
506
507 SslStream::SslStream() = default;
508 SslStream::SslStream(SslStream &&) noexcept = default;
509 SslStream &SslStream::operator=(SslStream &&) noexcept = default;
510 SslStream::~SslStream() = default;
511
create(CSlice host,CSlice cert_file,VerifyPeer verify_peer,bool use_ip_address_as_host)512 Result<SslStream> SslStream::create(CSlice host, CSlice cert_file, VerifyPeer verify_peer,
513 bool use_ip_address_as_host) {
514 auto impl = make_unique<detail::SslStreamImpl>();
515 TRY_STATUS(impl->init(host, cert_file, verify_peer, use_ip_address_as_host));
516 return SslStream(std::move(impl));
517 }
SslStream(unique_ptr<detail::SslStreamImpl> impl)518 SslStream::SslStream(unique_ptr<detail::SslStreamImpl> impl) : impl_(std::move(impl)) {
519 }
read_byte_flow()520 ByteFlowInterface &SslStream::read_byte_flow() {
521 return impl_->read_byte_flow();
522 }
write_byte_flow()523 ByteFlowInterface &SslStream::write_byte_flow() {
524 return impl_->write_byte_flow();
525 }
flow_read(MutableSlice slice)526 size_t SslStream::flow_read(MutableSlice slice) {
527 return impl_->flow_read(slice);
528 }
flow_write(Slice slice)529 size_t SslStream::flow_write(Slice slice) {
530 return impl_->flow_write(slice);
531 }
532
533 } // namespace td
534
535 #else
536
537 namespace td {
538
539 namespace detail {
540 class SslStreamImpl {};
541 } // namespace detail
542
543 SslStream::SslStream() = default;
544 SslStream::SslStream(SslStream &&) = default;
545 SslStream &SslStream::operator=(SslStream &&) = default;
546 SslStream::~SslStream() = default;
547
create(CSlice host,CSlice cert_file,VerifyPeer verify_peer,bool check_ip_address_as_host)548 Result<SslStream> SslStream::create(CSlice host, CSlice cert_file, VerifyPeer verify_peer,
549 bool check_ip_address_as_host) {
550 return Status::Error("Not supported in emscripten");
551 }
552
SslStream(unique_ptr<detail::SslStreamImpl> impl)553 SslStream::SslStream(unique_ptr<detail::SslStreamImpl> impl) : impl_(std::move(impl)) {
554 }
555
read_byte_flow()556 ByteFlowInterface &SslStream::read_byte_flow() {
557 UNREACHABLE();
558 }
559
write_byte_flow()560 ByteFlowInterface &SslStream::write_byte_flow() {
561 UNREACHABLE();
562 }
563
flow_read(MutableSlice slice)564 size_t SslStream::flow_read(MutableSlice slice) {
565 UNREACHABLE();
566 }
567
flow_write(Slice slice)568 size_t SslStream::flow_write(Slice slice) {
569 UNREACHABLE();
570 }
571
572 } // namespace td
573
574 #endif
575