xref: /aosp_15_r20/external/ot-br-posix/third_party/Simple-web-server/repo/server_https.hpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 #ifndef SIMPLE_WEB_SERVER_HTTPS_HPP
2 #define SIMPLE_WEB_SERVER_HTTPS_HPP
3 
4 #include "server_http.hpp"
5 
6 #ifdef ASIO_STANDALONE
7 #include <asio/ssl.hpp>
8 #else
9 #include <boost/asio/ssl.hpp>
10 #endif
11 
12 #include <algorithm>
13 #include <openssl/ssl.h>
14 
15 namespace SimpleWeb {
16   using HTTPS = asio::ssl::stream<asio::ip::tcp::socket>;
17 
18   template <>
19   class Server<HTTPS> : public ServerBase<HTTPS> {
20     bool set_session_id_context = false;
21 
22   public:
23     /**
24      * Constructs a server object.
25      *
26      * @param certification_file Sends the given certification file to client.
27      * @param private_key_file   Specifies the file containing the private key for certification_file.
28      * @param verify_file        If non-empty, use this certificate authority file to perform verification of client's certificate and hostname according to RFC 2818.
29      */
Server(const std::string & certification_file,const std::string & private_key_file,const std::string & verify_file=std::string ())30     Server(const std::string &certification_file, const std::string &private_key_file, const std::string &verify_file = std::string())
31         : ServerBase<HTTPS>::ServerBase(443),
32 #if(ASIO_STANDALONE && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300
33           context(asio::ssl::context::tls_server) {
34       // Disabling TLS 1.0 and 1.1 (see RFC 8996)
35       context.set_options(asio::ssl::context::no_tlsv1);
36       context.set_options(asio::ssl::context::no_tlsv1_1);
37 #else
38           context(asio::ssl::context::tlsv12) {
39 #endif
40 
41       context.use_certificate_chain_file(certification_file);
42       context.use_private_key_file(private_key_file, asio::ssl::context::pem);
43 
44       if(verify_file.size() > 0) {
45         context.load_verify_file(verify_file);
46         context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert | asio::ssl::verify_client_once);
47         set_session_id_context = true;
48       }
49     }
50 
51   protected:
52     asio::ssl::context context;
53 
54     void after_bind() override {
55       if(set_session_id_context) {
56         // Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
57         auto session_id_context = std::to_string(acceptor->local_endpoint().port()) + ':';
58         session_id_context.append(config.address.rbegin(), config.address.rend());
59         SSL_CTX_set_session_id_context(context.native_handle(),
60                                        reinterpret_cast<const unsigned char *>(session_id_context.data()),
61                                        static_cast<unsigned int>(std::min<std::size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH)));
62       }
63     }
64 
65     void accept() override {
66       auto connection = create_connection(*io_service, context);
67 
68       acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code &ec) {
69         auto lock = connection->handler_runner->continue_lock();
70         if(!lock)
71           return;
72 
73         if(ec != error::operation_aborted)
74           this->accept();
75 
76         auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection);
77 
78         if(!ec) {
79           asio::ip::tcp::no_delay option(true);
80           error_code ec;
81           session->connection->socket->lowest_layer().set_option(option, ec);
82 
83           session->connection->set_timeout(config.timeout_request);
84           session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) {
85             session->connection->cancel_timeout();
86             auto lock = session->connection->handler_runner->continue_lock();
87             if(!lock)
88               return;
89             if(!ec)
90               this->read(session);
91             else if(this->on_error)
92               this->on_error(session->request, ec);
93           });
94         }
95         else if(this->on_error)
96           this->on_error(session->request, ec);
97       });
98     }
99   };
100 } // namespace SimpleWeb
101 
102 #endif /* SIMPLE_WEB_SERVER_HTTPS_HPP */
103