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