1 /*************************************************************************
6 * [2011] - [2015] Realm Inc
9 * NOTICE: All information contained herein is, and remains
10 * the property of Realm Incorporated and its suppliers,
11 * if any. The intellectual and technical concepts contained
12 * herein are proprietary to Realm Incorporated
13 * and its suppliers and may be covered by U.S. and Foreign Patents,
14 * patents in process, and are protected by trade secret or copyright law.
15 * Dissemination of this information or reproduction of this material
16 * is strictly forbidden unless prior written permission is obtained
17 * from Realm Incorporated.
19 **************************************************************************/
20 #ifndef REALM_UTIL_NETWORK_SSL_HPP
21 #define REALM_UTIL_NETWORK_SSL_HPP
28 #include <system_error>
30 #include <realm/util/features.h>
31 #include <realm/util/assert.hpp>
32 #include <realm/util/misc_errors.hpp>
33 #include <realm/util/network.hpp>
34 #include <realm/util/optional.hpp>
36 #if REALM_HAVE_OPENSSL
37 # include <openssl/ssl.h>
38 # include <openssl/err.h>
39 #elif REALM_HAVE_SECURE_TRANSPORT
40 # include <realm/util/cf_ptr.hpp>
41 # include <Security/Security.h>
42 # include <Security/SecureTransport.h>
44 #define REALM_HAVE_KEYCHAIN_APIS (TARGET_OS_MAC && !TARGET_OS_IPHONE)
48 // FIXME: Add necessary support for customizing the SSL server and client
51 // FIXME: Currently, the synchronous SSL operations (handshake, read, write,
52 // shutdown) do not automatically retry if the underlying SSL function returns
53 // with SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. This normally never
54 // happens, but it can happen according to the man pages, but in the case of
55 // SSL_write(), only when a renegotiation has to take place. It is likely that
56 // the solution is to to wrap the SSL calls inside a loop, such that they keep
57 // retrying until they succeed, however, such a simple scheme will fail if the
58 // synchronous operations were to be used with an underlying TCP socket in
59 // nonblocking mode. Currently, the underlying TCP socket is always in blocking
60 // mode when performing synchronous operations, but that may continue to be the
61 // case in teh future.
70 certificate_rejected = 1,
73 const std::error_category& ssl_error_category();
75 std::error_condition make_error_condition(Error value);
78 } // namespace network
85 struct is_error_condition_enum<realm::util::network::ssl::Error>: public true_type {};
94 #if REALM_HAVE_OPENSSL
96 const std::error_category& openssl_error_category();
98 #elif REALM_HAVE_SECURE_TRANSPORT
100 const std::error_category& secure_transport_error_category();
105 class ProtocolNotSupported;
108 /// `VerifyMode::none` corresponds to OpenSSL's `SSL_VERIFY_NONE`, and
109 /// `VerifyMode::peer` to `SSL_VERIFY_PEER`.
110 enum class VerifyMode { none, peer };
118 /// File must be in PEM format. Corresponds to OpenSSL's
119 /// `SSL_CTX_use_certificate_chain_file()`.
120 void use_certificate_chain_file(const std::string& path);
122 /// File must be in PEM format. Corresponds to OpenSSL's
123 /// `SSL_CTX_use_PrivateKey_file()`.
124 void use_private_key_file(const std::string& path);
126 /// Calling use_default_verify() will make a client use the
127 /// device default certificates for server verification.
128 /// For OpenSSL, use_default_verify() corresponds to
129 /// SSL_CTX_set_default_verify_paths(SSL_CTX*);
130 void use_default_verify();
132 /// The verify file is a PEM file containing trust
133 /// certificates that the client will use to
134 /// verify the server crtificate. If use_verify_file()
135 /// is not called, the default device trust store will
137 /// Corresponds roughly to OpenSSL's
138 /// SSL_CTX_load_verify_locations().
139 void use_verify_file(const std::string& path);
143 void ssl_destroy() noexcept;
144 void ssl_use_certificate_chain_file(const std::string& path, std::error_code&);
145 void ssl_use_private_key_file(const std::string& path, std::error_code&);
146 void ssl_use_default_verify(std::error_code&);
147 void ssl_use_verify_file(const std::string& path, std::error_code&);
149 #if REALM_HAVE_OPENSSL
150 SSL_CTX* m_ssl_ctx = nullptr;
152 #elif REALM_HAVE_SECURE_TRANSPORT
154 #if REALM_HAVE_KEYCHAIN_APIS
155 static util::CFPtr<CFArrayRef> load_pem_file(const std::string& path, SecKeychainRef, std::error_code&);
157 std::error_code open_temporary_keychain_if_needed();
158 std::error_code update_identity_if_needed();
160 util::CFPtr<SecKeychainRef> m_keychain;
161 std::string m_keychain_path;
163 util::CFPtr<SecCertificateRef> m_certificate;
164 util::CFPtr<SecKeyRef> m_private_key;
165 util::CFPtr<SecIdentityRef> m_identity;
167 util::CFPtr<CFArrayRef> m_certificate_chain;
169 util::CFPtr<CFArrayRef> m_trust_anchors;
170 #endif // REALM_HAVE_KEYCHAIN_APIS
178 /// Switching between synchronous and asynchronous operations is allowed, but
179 /// only in a nonoverlapping fashion. That is, a synchronous operation is not
180 /// allowed to run concurrently with an asynchronous one on the same
181 /// stream. Note that an asynchronous operation is considered to be running
182 /// until its completion handler starts executing.
185 using port_type = util::network::Endpoint::port_type;
186 using SSLVerifyCallback = bool(const std::string& server_address,
187 port_type server_port,
188 const char* pem_data,
193 enum HandshakeType { client, server };
195 Stream(Socket&, Context&, HandshakeType);
198 /// \brief Set the certificate verification mode for this SSL stream.
200 /// Corresponds to OpenSSL's `SSL_set_verify()` with null passed as
201 /// `verify_callback`.
203 /// Clients should always set it to `VerifyMode::peer`, such that the client
204 /// verifies the servers certificate. Servers should only set it to
205 /// `VerifyMode::peer` if they want to request a certificate from the
206 /// client. When testing with self-signed certificates, it is necessary to
207 /// set it to `VerifyMode::none` for clients too.
209 /// It is an error if this function is called after the handshake operation
212 /// The default verify mode is `VerifyMode::none`.
213 void set_verify_mode(VerifyMode);
215 /// \brief Check the certificate against a host_name.
217 /// set_check_host() includes a host name check in the
218 /// certificate verification. It is typically used by clients
219 /// to secure that the received certificate has a common name
220 /// or subject alternative name that matches \param host_name.
222 /// set_check_host() is only useful if verify_mode is
223 /// set to VerifyMode::peer.
224 void set_check_host(std::string host_name);
225 const std::string& get_host_name();
227 /// get_server_port() and set_server_port() are getter and setter for
228 /// the server port. They are only used by the verify callback function
230 port_type get_server_port();
231 void set_server_port(port_type server_port);
233 /// If use_verify_callback() is called, the SSL certificate chain of
234 /// the server is presented to callback, one certificate at a time.
235 /// The SSL connection is accepted if and only if callback returns true
236 /// for all certificates.
237 /// The signature of \param callback is
239 /// bool(const std::string& server_address,
240 /// port_type server_port,
241 /// const char* pem_data,
243 /// int preverify_ok,
246 /// server address and server_port is the address and port of the server
247 /// that a SSL connection is being established to.
248 /// pem_data is the certificate of length pem_size in
249 /// the PEM format. preverify_ok is OpenSSL's preverification of the
250 /// certificate. preverify_ok is either 0, or 1. If preverify_ok is 1,
251 /// OpenSSL has accepted the certificate and it will generally be safe
252 /// to trust that certificate. depth represents the position of the
253 /// certificate in the certificate chain sent by the server. depth = 0
254 /// represents the actual server certificate that should contain the
255 /// host name(server address) of the server. The highest depth is the
256 /// root certificate.
257 /// The callback function will receive the certificates starting from
258 /// the root certificate and moving down the chain until it reaches the
259 /// server's own certificate with a host name. The depth of the last
260 /// certificate is 0. The depth of the first certificate is chain
263 /// The return value of the callback function decides whether the
264 /// client accepts the certificate. If the return value is false, the
265 /// processing of the certificate chain is interrupted and the SSL
266 /// connection is rejected. If the return value is true, the verification
267 /// process continues. If the callback function returns true for all
268 /// presented certificates including the depth == 0 certificate, the
269 /// SSL connection is accepted.
271 /// A recommended way of using the callback function is to return true
272 /// if preverify_ok = 1 and depth > 0,
273 /// always check the host name if depth = 0,
274 /// and use an independent verification step if preverify_ok = 0.
276 /// Another possible way of using the callback is to collect all the
277 /// certificates until depth = 0, and present the entire chain for
278 /// independent verification.
279 void use_verify_callback(const std::function<SSLVerifyCallback>& callback);
283 /// Read and write operations behave the same way as they do on \ref
284 /// network::Socket, except that after cancellation of asynchronous
285 /// operations (`lowest_layer().cancel()`), the stream may be left in a bad
286 /// state (see below).
288 /// The handshake operation must complete successfully before any read,
289 /// write, or shutdown operations are performed.
291 /// The shutdown operation sends the shutdown alert to the peer, and
292 /// returns/completes as soon as the alert message has been written to the
293 /// underlying socket. It is an error if the shutdown operation is initiated
294 /// while there are read or write operations in progress. No read or write
295 /// operations are allowed to be initiated after the shutdown operation has
296 /// been initiated. When the shutdown operation has completed, it is safe to
297 /// close the underlying socket (`lowest_layer().close()`).
299 /// If a write operation is executing while, or is initiated after a close
300 /// notify alert is received from the remote peer, the write operation will
301 /// fail with error::broken_pipe.
303 /// Callback functions for async read and write operations must take two
304 /// arguments, an std::error_code(), and an integer of a type std::size_t
305 /// indicating the number of transferred bytes (other types are allowed as
306 /// long as implicit conversion can take place).
308 /// Callback functions for async handshake and shutdown operations must take
309 /// a single argument of type std::error_code() (other types are allowed as
310 /// long as implicit conversion can take place).
312 /// Resumption of stream operation after cancellation of asynchronous
313 /// operations is not supported (does not work). Since the shutdown
314 /// operation involves network communication, that operation is also not
315 /// allowed after cancellation. The only thing that is allowed, is to
316 /// destroy the stream object. Other stream objects are not affected.
319 std::error_code handshake(std::error_code&);
321 std::size_t read(char* buffer, std::size_t size);
322 std::size_t read(char* buffer, std::size_t size, std::error_code& ec);
323 std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&);
324 std::size_t read(char* buffer, std::size_t size, ReadAheadBuffer&, std::error_code& ec);
325 std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&);
326 std::size_t read_until(char* buffer, std::size_t size, char delim, ReadAheadBuffer&,
327 std::error_code& ec);
329 std::size_t write(const char* data, std::size_t size);
330 std::size_t write(const char* data, std::size_t size, std::error_code& ec);
332 std::size_t read_some(char* buffer, std::size_t size);
333 std::size_t read_some(char* buffer, std::size_t size, std::error_code&);
335 std::size_t write_some(const char* data, std::size_t size);
336 std::size_t write_some(const char* data, std::size_t size, std::error_code&);
339 std::error_code shutdown(std::error_code&);
341 template<class H> void async_handshake(H handler);
343 template<class H> void async_read(char* buffer, std::size_t size, H handler);
344 template<class H> void async_read(char* buffer, std::size_t size, ReadAheadBuffer&, H handler);
345 template<class H> void async_read_until(char* buffer, std::size_t size, char delim,
346 ReadAheadBuffer&, H handler);
348 template<class H> void async_write(const char* data, std::size_t size, H handler);
350 template<class H> void async_read_some(char* buffer, std::size_t size, H handler);
352 template<class H> void async_write_some(const char* data, std::size_t size, H handler);
354 template<class H> void async_shutdown(H handler);
358 /// Returns a reference to the underlying socket.
359 Socket& lowest_layer() noexcept;
362 using Want = Service::Want;
363 using StreamOps = Service::BasicStreamOps<Stream>;
365 class HandshakeOperBase;
366 template<class H> class HandshakeOper;
367 class ShutdownOperBase;
368 template<class H> class ShutdownOper;
370 using LendersHandshakeOperPtr = std::unique_ptr<HandshakeOperBase, Service::LendersOperDeleter>;
371 using LendersShutdownOperPtr = std::unique_ptr<ShutdownOperBase, Service::LendersOperDeleter>;
373 Socket& m_tcp_socket;
374 Context& m_ssl_context;
375 const HandshakeType m_handshake_type;
377 // The host name that the certificate should be checked against.
378 // The host name is called server address in the certificate verify
379 // callback function.
380 std::string m_host_name;
382 // The port of the server which is used in the certificate verify
383 // callback function.
384 port_type m_server_port;
386 // The callback for certificate verification and an
387 // opaque argument that will be supplied to the callback.
388 const std::function<SSLVerifyCallback>* m_ssl_verify_callback = nullptr;
390 // See Service::BasicStreamOps for details on these these 6 functions.
391 void do_init_read_async(std::error_code&, Want&) noexcept;
392 void do_init_write_async(std::error_code&, Want&) noexcept;
393 std::size_t do_read_some_sync(char* buffer, std::size_t size,
394 std::error_code&) noexcept;
395 std::size_t do_write_some_sync(const char* data, std::size_t size,
396 std::error_code&) noexcept;
397 std::size_t do_read_some_async(char* buffer, std::size_t size,
398 std::error_code&, Want&) noexcept;
399 std::size_t do_write_some_async(const char* data, std::size_t size,
400 std::error_code&, Want&) noexcept;
402 // The meaning of the arguments and return values of ssl_read() and
403 // ssl_write() are identical to do_read_some_async() and
404 // do_write_some_async() respectively, except that when the return value is
405 // nonzero, `want` is always `Want::nothing`, meaning that after bytes have
406 // been transferred, ssl_read() and ssl_write() must be called again to
407 // figure out whether it is necessary to wait for read or write readiness.
409 // The first invocation of ssl_shutdown() must send the shutdown alert to
410 // the peer. In blocking mode it must wait until the alert has been sent. In
411 // nonblocking mode, it must keep setting `want` to something other than
412 // `Want::nothing` until the alert has been sent. When the shutdown alert
413 // has been sent, it is safe to shut down the sending side of the underlying
414 // socket. On failure, ssl_shutdown() must set `ec` to something different
415 // than `std::error_code()` and return false. On success, it must set `ec`
416 // to `std::error_code()`, and return true if a shutdown alert from the peer
417 // has already been received, otherwise it must return false. When it sets
418 // `want` to something other than `Want::nothing`, it must set `ec` to
419 // `std::error_code()` and return false.
421 // The second invocation of ssl_shutdown() (after the first invocation
422 // completed) must wait for reception on the peers shutdown alert.
424 // Note: The semantics around the second invocation of shutdown is currently
425 // unused by the higher level API, because of a requirement of compatibility
426 // with Apple's Secure Transport API.
428 void ssl_destroy() noexcept;
429 void ssl_set_verify_mode(VerifyMode, std::error_code&);
430 void ssl_set_check_host(std::string, std::error_code&);
431 void ssl_use_verify_callback(const std::function<SSLVerifyCallback>&, std::error_code&);
433 void ssl_handshake(std::error_code&, Want& want) noexcept;
434 bool ssl_shutdown(std::error_code& ec, Want& want) noexcept;
435 std::size_t ssl_read(char* buffer, std::size_t size,
436 std::error_code&, Want& want) noexcept;
437 std::size_t ssl_write(const char* data, std::size_t size,
438 std::error_code&, Want& want) noexcept;
440 #if REALM_HAVE_OPENSSL
442 static BioMethod s_bio_method;
443 SSL* m_ssl = nullptr;
444 std::error_code m_bio_error_code;
446 int m_ssl_index = -1;
449 std::size_t ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept;
451 int do_ssl_accept() noexcept;
452 int do_ssl_connect() noexcept;
453 int do_ssl_shutdown() noexcept;
454 int do_ssl_read(char* buffer, std::size_t size) noexcept;
455 int do_ssl_write(const char* data, std::size_t size) noexcept;
457 static int bio_write(BIO*, const char*, int) noexcept;
458 static int bio_read(BIO*, char*, int) noexcept;
459 static int bio_puts(BIO*, const char*) noexcept;
460 static long bio_ctrl(BIO*, int, long, void*) noexcept;
461 static int bio_create(BIO*) noexcept;
462 static int bio_destroy(BIO*) noexcept;
464 // verify_callback_using_hostname is used as an argument to OpenSSL's SSL_set_verify function.
465 // verify_callback_using_hostname verifies that the certificate is valid and contains
466 // m_host_name as a Common Name or Subject Alternative Name.
467 static int verify_callback_using_hostname(int preverify_ok, X509_STORE_CTX *ctx) noexcept;
469 // verify_callback_using_delegate() is also used as an argument to OpenSSL's set_verify_function.
470 // verify_callback_using_delegate() calls out to the user supplied verify callback.
471 static int verify_callback_using_delegate(int preverify_ok, X509_STORE_CTX *ctx) noexcept;
472 #elif REALM_HAVE_SECURE_TRANSPORT
473 util::CFPtr<SSLContextRef> m_ssl;
474 VerifyMode m_verify_mode = VerifyMode::none;
476 enum class BlockingOperation {
480 util::Optional<BlockingOperation> m_last_operation;
482 // Details of the underlying I/O error that lead to errSecIO being returned
483 // from a SecureTransport function.
484 std::error_code m_last_error;
486 // The number of bytes accepted by SSWrite() but not yet confirmed to be
487 // written to the underlying socket.
488 std::size_t m_num_partially_written_bytes = 0;
491 std::size_t ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept;
493 std::pair<OSStatus, std::size_t> do_ssl_handshake() noexcept;
494 std::pair<OSStatus, std::size_t> do_ssl_shutdown() noexcept;
495 std::pair<OSStatus, std::size_t> do_ssl_read(char* buffer, std::size_t size) noexcept;
496 std::pair<OSStatus, std::size_t> do_ssl_write(const char* data, std::size_t size) noexcept;
498 static OSStatus tcp_read(SSLConnectionRef, void*, std::size_t* length) noexcept;
499 static OSStatus tcp_write(SSLConnectionRef, const void*, std::size_t* length) noexcept;
501 OSStatus tcp_read(void*, std::size_t* length) noexcept;
502 OSStatus tcp_write(const void*, std::size_t* length) noexcept;
504 OSStatus verify_peer() noexcept;
507 friend class Service::BasicStreamOps<Stream>;
508 friend class network::ReadAheadBuffer;
514 class ProtocolNotSupported: public std::exception {
516 const char* what() const noexcept override final;
519 inline Context::Context()
521 ssl_init(); // Throws
524 inline Context::~Context() noexcept
529 inline void Context::use_certificate_chain_file(const std::string& path)
532 ssl_use_certificate_chain_file(path, ec); // Throws
534 throw std::system_error(ec);
537 inline void Context::use_private_key_file(const std::string& path)
540 ssl_use_private_key_file(path, ec); // Throws
542 throw std::system_error(ec);
545 inline void Context::use_default_verify()
548 ssl_use_default_verify(ec);
550 throw std::system_error(ec);
553 inline void Context::use_verify_file(const std::string& path)
556 ssl_use_verify_file(path, ec);
558 throw std::system_error(ec);
561 class Stream::HandshakeOperBase: public Service::IoOper {
563 HandshakeOperBase(std::size_t size, Stream& stream):
570 REALM_ASSERT(this == m_stream->m_tcp_socket.m_read_oper.get());
571 REALM_ASSERT(!is_complete());
572 m_stream->m_tcp_socket.m_desc.ensure_nonblocking_mode(); // Throws
575 Want advance() noexcept override final
577 REALM_ASSERT(!is_complete());
578 REALM_ASSERT(!is_canceled());
579 REALM_ASSERT(!m_error_code);
580 Want want = Want::nothing;
581 m_stream->ssl_handshake(m_error_code, want);
582 set_is_complete(want == Want::nothing);
585 void recycle() noexcept override final
587 bool orphaned = !m_stream;
588 REALM_ASSERT(orphaned);
589 // Note: do_recycle() commits suicide.
590 do_recycle(orphaned);
592 void orphan() noexcept override final
596 Service::Descriptor& descriptor() noexcept override final
598 return m_stream->lowest_layer().m_desc;
602 std::error_code m_error_code;
605 template<class H> class Stream::HandshakeOper: public HandshakeOperBase {
607 HandshakeOper(std::size_t size, Stream& stream, H handler):
608 HandshakeOperBase{size, stream},
609 m_handler{std::move(handler)}
612 void recycle_and_execute() override final
614 REALM_ASSERT(is_complete() || is_canceled());
615 bool orphaned = !m_stream;
616 std::error_code ec = m_error_code;
618 ec = error::operation_aborted;
619 // Note: do_recycle_and_execute() commits suicide.
620 do_recycle_and_execute<H>(orphaned, m_handler, ec); // Throws
626 class Stream::ShutdownOperBase: public Service::IoOper {
628 ShutdownOperBase(std::size_t size, Stream& stream):
635 REALM_ASSERT(this == m_stream->m_tcp_socket.m_write_oper.get());
636 REALM_ASSERT(!is_complete());
637 m_stream->m_tcp_socket.m_desc.ensure_nonblocking_mode(); // Throws
640 Want advance() noexcept override final
642 REALM_ASSERT(!is_complete());
643 REALM_ASSERT(!is_canceled());
644 REALM_ASSERT(!m_error_code);
645 Want want = Want::nothing;
646 m_stream->ssl_shutdown(m_error_code, want);
647 if (want == Want::nothing)
648 set_is_complete(true);
651 void recycle() noexcept override final
653 bool orphaned = !m_stream;
654 REALM_ASSERT(orphaned);
655 // Note: do_recycle() commits suicide.
656 do_recycle(orphaned);
658 void orphan() noexcept override final
662 Service::Descriptor& descriptor() noexcept override final
664 return m_stream->lowest_layer().m_desc;
668 std::error_code m_error_code;
671 template<class H> class Stream::ShutdownOper: public ShutdownOperBase {
673 ShutdownOper(std::size_t size, Stream& stream, H handler):
674 ShutdownOperBase{size, stream},
675 m_handler{std::move(handler)}
678 void recycle_and_execute() override final
680 REALM_ASSERT(is_complete() || is_canceled());
681 bool orphaned = !m_stream;
682 std::error_code ec = m_error_code;
684 ec = error::operation_aborted;
685 // Note: do_recycle_and_execute() commits suicide.
686 do_recycle_and_execute<H>(orphaned, m_handler, ec); // Throws
692 inline Stream::Stream(Socket& socket, Context& context, HandshakeType type):
693 m_tcp_socket{socket},
694 m_ssl_context{context},
695 m_handshake_type{type}
697 ssl_init(); // Throws
700 inline Stream::~Stream() noexcept
702 m_tcp_socket.cancel();
706 inline void Stream::set_verify_mode(VerifyMode mode)
709 ssl_set_verify_mode(mode, ec); // Throws
711 throw std::system_error(ec);
714 inline void Stream::set_check_host(std::string host_name)
716 m_host_name = host_name;
718 ssl_set_check_host(host_name, ec);
720 throw std::system_error(ec);
723 inline const std::string& Stream::get_host_name()
728 inline Stream::port_type Stream::get_server_port()
730 return m_server_port;
733 inline void Stream::set_server_port(port_type server_port)
735 m_server_port = server_port;
738 inline void Stream::use_verify_callback(const std::function<SSLVerifyCallback>& callback)
741 ssl_use_verify_callback(callback, ec); // Throws
743 throw std::system_error(ec);
745 inline void Stream::handshake()
748 if (handshake(ec)) // Throws
749 throw std::system_error(ec);
752 inline std::size_t Stream::read(char* buffer, std::size_t size)
755 read(buffer, size, ec); // Throws
757 throw std::system_error(ec);
761 inline std::size_t Stream::read(char* buffer, std::size_t size, std::error_code& ec)
763 return StreamOps::read(*this, buffer, size, ec); // Throws
766 inline std::size_t Stream::read(char* buffer, std::size_t size, ReadAheadBuffer& rab)
769 read(buffer, size, rab, ec); // Throws
771 throw std::system_error(ec);
775 inline std::size_t Stream::read(char* buffer, std::size_t size, ReadAheadBuffer& rab,
778 int delim = std::char_traits<char>::eof();
779 return StreamOps::buffered_read(*this, buffer, size, delim, rab, ec); // Throws
782 inline std::size_t Stream::read_until(char* buffer, std::size_t size, char delim,
783 ReadAheadBuffer& rab)
786 std::size_t n = read_until(buffer, size, delim, rab, ec); // Throws
788 throw std::system_error(ec);
792 inline std::size_t Stream::read_until(char* buffer, std::size_t size, char delim,
793 ReadAheadBuffer& rab, std::error_code& ec)
795 int delim_2 = std::char_traits<char>::to_int_type(delim);
796 return StreamOps::buffered_read(*this, buffer, size, delim_2, rab, ec); // Throws
799 inline std::size_t Stream::write(const char* data, std::size_t size)
802 write(data, size, ec); // Throws
804 throw std::system_error(ec);
808 inline std::size_t Stream::write(const char* data, std::size_t size, std::error_code& ec)
810 return StreamOps::write(*this, data, size, ec); // Throws
813 inline std::size_t Stream::read_some(char* buffer, std::size_t size)
816 std::size_t n = read_some(buffer, size, ec); // Throws
818 throw std::system_error(ec);
822 inline std::size_t Stream::read_some(char* buffer, std::size_t size, std::error_code& ec)
824 return StreamOps::read_some(*this, buffer, size, ec); // Throws
827 inline std::size_t Stream::write_some(const char* data, std::size_t size)
830 std::size_t n = write_some(data, size, ec); // Throws
832 throw std::system_error(ec);
836 inline std::size_t Stream::write_some(const char* data, std::size_t size, std::error_code& ec)
838 return StreamOps::write_some(*this, data, size, ec); // Throws
841 inline void Stream::shutdown()
844 if (shutdown(ec)) // Throws
845 throw std::system_error(ec);
848 template<class H> inline void Stream::async_handshake(H handler)
850 LendersHandshakeOperPtr op =
851 Service::alloc<HandshakeOper<H>>(m_tcp_socket.m_read_oper, *this,
852 std::move(handler)); // Throws
853 m_tcp_socket.m_desc.initiate_oper(std::move(op)); // Throws
856 template<class H> inline void Stream::async_read(char* buffer, std::size_t size, H handler)
858 bool is_read_some = false;
859 StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws
863 inline void Stream::async_read(char* buffer, std::size_t size, ReadAheadBuffer& rab, H handler)
865 int delim = std::char_traits<char>::eof();
866 StreamOps::async_buffered_read(*this, buffer, size, delim, rab, std::move(handler)); // Throws
870 inline void Stream::async_read_until(char* buffer, std::size_t size, char delim,
871 ReadAheadBuffer& rab, H handler)
873 int delim_2 = std::char_traits<char>::to_int_type(delim);
874 StreamOps::async_buffered_read(*this, buffer, size, delim_2, rab, std::move(handler)); // Throws
877 template<class H> inline void Stream::async_write(const char* data, std::size_t size, H handler)
879 bool is_write_some = false;
880 StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws
883 template<class H> inline void Stream::async_read_some(char* buffer, std::size_t size, H handler)
885 bool is_read_some = true;
886 StreamOps::async_read(*this, buffer, size, is_read_some, std::move(handler)); // Throws
889 template<class H> inline void Stream::async_write_some(const char* data, std::size_t size, H handler)
891 bool is_write_some = true;
892 StreamOps::async_write(*this, data, size, is_write_some, std::move(handler)); // Throws
895 template<class H> inline void Stream::async_shutdown(H handler)
897 LendersShutdownOperPtr op =
898 Service::alloc<ShutdownOper<H>>(m_tcp_socket.m_write_oper, *this,
899 std::move(handler)); // Throws
900 m_tcp_socket.m_desc.initiate_oper(std::move(op)); // Throws
903 inline void Stream::do_init_read_async(std::error_code&, Want& want) noexcept
905 want = Want::nothing; // Proceed immediately unless there is an error
908 inline void Stream::do_init_write_async(std::error_code&, Want& want) noexcept
910 want = Want::nothing; // Proceed immediately unless there is an error
913 inline std::size_t Stream::do_read_some_sync(char* buffer, std::size_t size,
914 std::error_code& ec) noexcept
916 Want want = Want::nothing;
917 std::size_t n = do_read_some_async(buffer, size, ec, want);
918 if (n == 0 && want != Want::nothing)
919 ec = error::resource_unavailable_try_again;
923 inline std::size_t Stream::do_write_some_sync(const char* data, std::size_t size,
924 std::error_code& ec) noexcept
926 Want want = Want::nothing;
927 std::size_t n = do_write_some_async(data, size, ec, want);
928 if (n == 0 && want != Want::nothing)
929 ec = error::resource_unavailable_try_again;
933 inline std::size_t Stream::do_read_some_async(char* buffer, std::size_t size,
934 std::error_code& ec, Want& want) noexcept
936 return ssl_read(buffer, size, ec, want);
939 inline std::size_t Stream::do_write_some_async(const char* data, std::size_t size,
940 std::error_code& ec, Want& want) noexcept
942 return ssl_write(data, size, ec, want);
945 inline Socket& Stream::lowest_layer() noexcept
951 #if REALM_HAVE_OPENSSL
953 inline void Stream::ssl_handshake(std::error_code& ec, Want& want) noexcept
955 auto perform = [this]() noexcept {
956 switch (m_handshake_type) {
958 return do_ssl_connect();
960 return do_ssl_accept();
965 std::size_t n = ssl_perform(std::move(perform), ec, want);
966 REALM_ASSERT(n == 0 || n == 1);
967 if (want == Want::nothing && n == 0 && !ec) {
968 // End of input on TCP socket
969 ec = network::premature_end_of_input;
973 inline std::size_t Stream::ssl_read(char* buffer, std::size_t size,
974 std::error_code& ec, Want& want) noexcept
976 auto perform = [this, buffer, size]() noexcept {
977 return do_ssl_read(buffer, size);
979 std::size_t n = ssl_perform(std::move(perform), ec, want);
980 if (want == Want::nothing && n == 0 && !ec) {
981 // End of input on TCP socket
982 if (SSL_get_shutdown(m_ssl) & SSL_RECEIVED_SHUTDOWN) {
983 ec = network::end_of_input;
986 ec = network::premature_end_of_input;
992 inline std::size_t Stream::ssl_write(const char* data, std::size_t size,
993 std::error_code& ec, Want& want) noexcept
995 // While OpenSSL is able to continue writing after we have received the
996 // close notify alert fro the remote peer, Apple's Secure Transport API is
997 // not, so to achieve common behaviour, we make sure that any such attempt
998 // will result in an `error::broken_pipe` error.
999 if ((SSL_get_shutdown(m_ssl) & SSL_RECEIVED_SHUTDOWN) != 0) {
1000 ec = error::broken_pipe;
1001 want = Want::nothing;
1004 auto perform = [this, data, size]() noexcept {
1005 return do_ssl_write(data, size);
1007 std::size_t n = ssl_perform(std::move(perform), ec, want);
1008 if (want == Want::nothing && n == 0 && !ec) {
1009 // End of input on TCP socket
1010 ec = network::premature_end_of_input;
1015 inline bool Stream::ssl_shutdown(std::error_code& ec, Want& want) noexcept
1017 auto perform = [this]() noexcept {
1018 return do_ssl_shutdown();
1020 std::size_t n = ssl_perform(std::move(perform), ec, want);
1021 REALM_ASSERT(n == 0 || n == 1);
1022 if (want == Want::nothing && n == 0 && !ec) {
1023 // The first invocation of SSL_shutdown() does not signal completion
1024 // until the shutdown alert has been sent to the peer, or an error
1025 // occurred (does not wait for acknowledgment).
1027 // The second invocation (after a completed first invocation) does not
1028 // signal completion until the peers shutdown alert has been received,
1029 // or an error occurred.
1031 // It is believed that:
1033 // If this is the first time SSL_shutdown() is called, and
1034 // `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` evaluates to nonzero, then a
1035 // zero return value means "partial success" (shutdown alert was sent,
1036 // but the peers shutdown alert was not yet received), and 1 means "full
1037 // success" (peers shutdown alert has already been received).
1039 // If this is the first time SSL_shutdown() is called, and
1040 // `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` valuates to zero, then a
1041 // zero return value means "premature end of input", and 1 is supposedly
1042 // not a possibility.
1044 // If this is the second time SSL_shutdown() is called (after the first
1045 // call has returned zero), then a zero return value means "premature
1046 // end of input", and 1 means "full success" (peers shutdown alert has
1047 // now been received).
1048 if ((SSL_get_shutdown(m_ssl) & SSL_SENT_SHUTDOWN) == 0)
1049 ec = network::premature_end_of_input;
1054 // Provides a homogeneous, and mostly quirks-free interface across the OpenSSL
1055 // operations (handshake, read, write, shutdown).
1057 // First of all, if the operation remains incomplete (neither successfully
1058 // completed, nor failed), ssl_perform() will set `ec` to `std::system_error()`,
1059 // `want` to something other than `Want::nothing`, and return zero. Note that
1060 // read and write operations are partial in the sense that they do not need to
1061 // read or write everything before completing successfully. They only need to
1062 // read or write at least one byte to complete successfully.
1064 // Such a situation will normally only happen when the underlying TCP socket is
1065 // in nonblocking mode, and the read/write requirements of the operation could
1066 // not be immediately accommodated. However, as is noted in the SSL_write() man
1067 // page, it can also happen in blocking mode (at least while writing).
1069 // If an error occurred, ssl_perform() will set `ec` to something other than
1070 // `std::system_error()`, `want` to `Want::nothing`, and return 0.
1072 // If no error occurred, and the operation completed (`!ec && want ==
1073 // Want::nothing`), then the return value indicates the outcome of the
1076 // In general, a nonzero value means "full" success, and a zero value means
1077 // "partial" success, however, a zero result can also generally mean "premature
1078 // end of input" / "unclean protocol termination".
1080 // Assuming there is no premature end of input, then for reads and writes, the
1081 // returned value is the number of transferred bytes. Zero for read on end of
1082 // input. Never zero for write. For handshake it is always 1. For shutdown it is
1083 // 1 if the peer shutdown alert was already received, otherwise it is zero.
1085 // ssl_read() should use `SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN` to
1086 // distinguish between the two possible meanings of zero.
1088 // ssl_shutdown() should use `SSL_get_shutdown() & SSL_SENT_SHUTDOWN` to
1089 // distinguish between the two possible meanings of zero.
1090 template<class Oper>
1091 std::size_t Stream::ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept
1094 m_bio_error_code = std::error_code(); // Success
1096 int ssl_error = SSL_get_error(m_ssl, ret);
1097 int sys_error = int(ERR_get_error());
1099 // Guaranteed by the documentation of SSL_get_error()
1100 REALM_ASSERT((ret > 0) == (ssl_error == SSL_ERROR_NONE));
1102 REALM_ASSERT(!m_bio_error_code || ssl_error == SSL_ERROR_SYSCALL);
1104 // Judging from various comments in the man pages, and from experience with
1105 // the API, it seems that,
1107 // ret=0, ssl_error=SSL_ERROR_SYSCALL, sys_error=0
1109 // is supposed to be an indicator of "premature end of input" / "unclean
1110 // protocol termination", while
1112 // ret=0, ssl_error=SSL_ERROR_ZERO_RETURN
1114 // is supposed to be an indicator of the following success conditions:
1116 // - Mature end of input / clean protocol termination.
1118 // - Successful transmission of the shutdown alert, but no prior reception
1119 // of shutdown alert from peer.
1121 // Unfortunately, as is also remarked in various places in the man pages,
1122 // those two success conditions may actually result in `ret=0,
1123 // ssl_error=SSL_ERROR_SYSCALL, sys_error=0` too, and it seems that they
1124 // almost always do.
1126 // This means that we cannot properly discriminate between these conditions
1127 // in ssl_perform(), and will have to defer to the caller to interpret the
1128 // situation. Since thay cannot be properly told apart, we report all
1129 // `ret=0, ssl_error=SSL_ERROR_SYSCALL, sys_error=0` and `ret=0,
1130 // ssl_error=SSL_ERROR_ZERO_RETURN` cases as the latter.
1131 switch (ssl_error) {
1132 case SSL_ERROR_NONE:
1133 ec = std::error_code(); // Success
1134 want = Want::nothing;
1135 return std::size_t(ret); // ret > 0
1136 case SSL_ERROR_ZERO_RETURN:
1137 ec = std::error_code(); // Success
1138 want = Want::nothing;
1140 case SSL_ERROR_WANT_READ:
1141 ec = std::error_code(); // Success
1144 case SSL_ERROR_WANT_WRITE:
1145 ec = std::error_code(); // Success
1148 case SSL_ERROR_SYSCALL:
1149 if (REALM_UNLIKELY(sys_error != 0)) {
1150 ec = make_basic_system_error_code(sys_error);
1152 else if (REALM_UNLIKELY(m_bio_error_code)) {
1153 ec = m_bio_error_code;
1155 else if (ret == 0) {
1156 // ret = 0, ssl_eror = SSL_ERROR_SYSCALL, sys_error = 0
1158 // See remarks above!
1159 ec = std::error_code(); // Success
1162 // ret = -1, ssl_eror = SSL_ERROR_SYSCALL, sys_error = 0
1164 // This situation arises in OpenSSL version >= 1.1.
1165 // It has been observed in the SSL_connect call if the
1166 // other endpoint terminates the connection during
1167 // SSL_connect. The OpenSSL documentation states
1168 // that ret = -1 implies an underlying BIO error and
1169 // that errno should be consulted. However,
1170 // errno = 0(Undefined error) in the observed case.
1171 // At the moment. we will report
1172 // premature_end_of_input.
1173 // If we see this error case occurring in other situations in
1174 // the future, we will have to update this case.
1175 ec = network::premature_end_of_input;
1177 want = Want::nothing;
1180 ec = std::error_code(sys_error, openssl_error_category());
1181 want = Want::nothing;
1186 // We are not supposed to ever get here
1187 REALM_ASSERT(false);
1191 inline int Stream::do_ssl_accept() noexcept
1193 int ret = SSL_accept(m_ssl);
1197 inline int Stream::do_ssl_connect() noexcept
1199 int ret = SSL_connect(m_ssl);
1203 inline int Stream::do_ssl_read(char* buffer, std::size_t size) noexcept
1205 int size_2 = int(size);
1206 if (size > unsigned(std::numeric_limits<int>::max()))
1207 size_2 = std::size_t(std::numeric_limits<int>::max());
1208 int ret = SSL_read(m_ssl, buffer, size_2);
1212 inline int Stream::do_ssl_write(const char* data, std::size_t size) noexcept
1214 int size_2 = int(size);
1215 if (size > unsigned(std::numeric_limits<int>::max()))
1216 size_2 = std::size_t(std::numeric_limits<int>::max());
1217 int ret = SSL_write(m_ssl, data, size_2);
1221 inline int Stream::do_ssl_shutdown() noexcept
1223 int ret = SSL_shutdown(m_ssl);
1227 #elif REALM_HAVE_SECURE_TRANSPORT
1229 // Provides a homogeneous, and mostly quirks-free interface across the SecureTransport
1230 // operations (handshake, read, write, shutdown).
1232 // First of all, if the operation remains incomplete (neither successfully
1233 // completed, nor failed), ssl_perform() will set `ec` to `std::system_error()`,
1234 // `want` to something other than `Want::nothing`, and return zero.
1236 // If an error occurred, ssl_perform() will set `ec` to something other than
1237 // `std::system_error()`, `want` to `Want::nothing`, and return 0.
1239 // If no error occurred, and the operation completed (`!ec && want ==
1240 // Want::nothing`), then the return value indicates the outcome of the
1243 // In general, a nonzero value means "full" success, and a zero value means
1244 // "partial" success, however, a zero result can also generally mean "premature
1245 // end of input" / "unclean protocol termination".
1247 // Assuming there is no premature end of input, then for reads and writes, the
1248 // returned value is the number of transferred bytes. Zero for read on end of
1249 // input. Never zero for write. For handshake it is always 1. For shutdown it is
1250 // 1 if the peer shutdown alert was already received, otherwise it is zero.
1251 template<class Oper>
1252 std::size_t Stream::ssl_perform(Oper oper, std::error_code& ec, Want& want) noexcept
1256 std::tie(result, n) = oper();
1258 if (result == noErr) {
1259 ec = std::error_code();
1260 want = Want::nothing;
1264 if (result == errSSLWouldBlock) {
1265 REALM_ASSERT(m_last_operation);
1266 ec = std::error_code();
1267 want = m_last_operation == BlockingOperation::read ? Want::read : Want::write;
1268 m_last_operation = {};
1272 if (result == errSSLClosedGraceful) {
1273 ec = network::end_of_input;
1274 want = Want::nothing;
1278 if (result == errSSLClosedAbort || result == errSSLClosedNoNotify) {
1279 ec = network::premature_end_of_input;
1280 want = Want::nothing;
1284 if (result == errSecIO) {
1285 // A generic I/O error means something went wrong at a lower level. Use the error
1286 // code we smuggled out of our lower-level functions to provide a more specific error.
1287 REALM_ASSERT(m_last_error);
1289 want = Want::nothing;
1293 ec = std::error_code(result, secure_transport_error_category());
1294 want = Want::nothing;
1297 #endif // REALM_HAVE_OPENSSL / REALM_HAVE_SECURE_TRANSPORT
1300 } // namespace network
1302 } // namespace realm
1304 #endif // REALM_UTIL_NETWORK_SSL_HPP