| src/examples/cpp03/ssl/client.cpp | src/examples/cpp11/ssl/client.cpp |
| ⋮ | ⋮ |
| 1 | // | 1 | // |
| 2 | //·client.cpp | 2 | //·client.cpp |
| 3 | //·~~~~~~~~~~ | 3 | //·~~~~~~~~~~ |
| 4 | // | 4 | // |
| 5 | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) |
| 6 | // | 6 | // |
| 7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying |
| 8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) | 8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) |
| 9 | // | 9 | // |
| 10 | | 10 | |
| 11 | #include·<cstdlib> | 11 | #include·<cstdlib> |
| | 12 | #include·<cstring> |
| | 13 | #include·<functional> |
| 12 | #include·<iostream> | 14 | #include·<iostream> |
| 13 | #include·<boost/bind/bind.hpp> | |
| 14 | #include·"asio.hpp" | 15 | #include·"asio.hpp" |
| 15 | #include·"asio/ssl.hpp" | 16 | #include·"asio/ssl.hpp" |
| 16 | | 17 | |
| | 18 | using·asio::ip::tcp; |
| | 19 | using·std::placeholders::_1; |
| | 20 | using·std::placeholders::_2; |
| | 21 | |
| 17 | enum·{·max_length·=·1024·}; | 22 | enum·{·max_length·=·1024·}; |
| 18 | | 23 | |
| 19 | class·client | 24 | class·client |
| 20 | { | 25 | { |
| 21 | public: | 26 | public: |
| 22 | ··client(asio::io_context&·io_context, | 27 | ··client(asio::io_context&·io_context, |
| 23 | ······asio::ssl::context&·context, | 28 | ······asio::ssl::context&·context, |
| 24 | ······asio::ip::tcp::resolver::results_type·endpoints) | 29 | ······const·tcp::resolver::results_type&·endpoints) |
| 25 | ····:·socket_(io_context,·context) | 30 | ····:·socket_(io_context,·context) |
| 26 | ··{ | 31 | ··{ |
| 27 | ····socket_.set_verify_mode(asio::ssl::verify_peer); | 32 | ····socket_.set_verify_mode(asio::ssl::verify_peer); |
| 28 | ····socket_.set_verify_callback( | 33 | ····socket_.set_verify_callback( |
| 29 | ········boost::bind(&client::verify_certificate,·this, | 34 | ········std::bind(&client::verify_certificate,·this,·_1,·_2)); |
| 30 | ··········boost::placeholders::_1,·boost::placeholders::_2)); | |
| 31 | | 35 | |
| 32 | ····asio::async_connect(socket_.lowest_layer(),·endpoints, | 36 | ····connect(endpoints); |
| 33 | ········boost::bind(&client::handle_connect,·this, | |
| 34 | ··········asio::placeholders::error)); | |
| 35 | ··} | 37 | ··} |
| 36 | | 38 | |
| | 39 | private: |
| 37 | ··bool·verify_certificate(bool·preverified, | 40 | ··bool·verify_certificate(bool·preverified, |
| 38 | ······asio::ssl::verify_context&·ctx) | 41 | ······asio::ssl::verify_context&·ctx) |
| 39 | ··{ | 42 | ··{ |
| 40 | ····//·The·verify·callback·can·be·used·to·check·whether·the·certificate·that·is | 43 | ····//·The·verify·callback·can·be·used·to·check·whether·the·certificate·that·is |
| 41 | ····//·being·presented·is·valid·for·the·peer.·For·example,·RFC·2818·describes | 44 | ····//·being·presented·is·valid·for·the·peer.·For·example,·RFC·2818·describes |
| 42 | ····//·the·steps·involved·in·doing·this·for·HTTPS.·Consult·the·OpenSSL | 45 | ····//·the·steps·involved·in·doing·this·for·HTTPS.·Consult·the·OpenSSL |
| 43 | ····//·documentation·for·more·details.·Note·that·the·callback·is·called·once | 46 | ····//·documentation·for·more·details.·Note·that·the·callback·is·called·once |
| 44 | ····//·for·each·certificate·in·the·certificate·chain,·starting·from·the·root | 47 | ····//·for·each·certificate·in·the·certificate·chain,·starting·from·the·root |
| 45 | ····//·certificate·authority. | 48 | ····//·certificate·authority. |
| 46 | | 49 | |
| 47 | ····//·In·this·example·we·will·simply·print·the·certificate's·subject·name. | 50 | ····//·In·this·example·we·will·simply·print·the·certificate's·subject·name. |
| 48 | ····char·subject_name[256]; | 51 | ····char·subject_name[256]; |
| 49 | ····X509*·cert·=·X509_STORE_CTX_get_current_cert(ctx.native_handle()); | 52 | ····X509*·cert·=·X509_STORE_CTX_get_current_cert(ctx.native_handle()); |
| 50 | ····X509_NAME_oneline(X509_get_subject_name(cert),·subject_name,·256); | 53 | ····X509_NAME_oneline(X509_get_subject_name(cert),·subject_name,·256); |
| 51 | ····std::cout·<<·"Verifying·"·<<·subject_name·<<·"\n"; | 54 | ····std::cout·<<·"Verifying·"·<<·subject_name·<<·"\n"; |
| 52 | | 55 | |
| 53 | ····return·preverified; | 56 | ····return·preverified; |
| 54 | ··} | 57 | ··} |
| 55 | | 58 | |
| 56 | ··void·handle_connect(const·asio::error_code&·error) | 59 | ··void·connect(const·tcp::resolver::results_type&·endpoints) |
| 57 | ··{ | 60 | ··{ |
| 58 | ····if·(!error) | 61 | ····asio::async_connect(socket_.lowest_layer(),·endpoints, |
| 59 | ····{ | 62 | ········[this](const·std::error_code&·error, |
| 60 | ······socket_.async_handshake(asio::ssl::stream_base::client, | 63 | ··········const·tcp::endpoint&·/*endpoint*/) |
| 61 | ··········boost::bind(&client::handle_handshake,·this, | 64 | ········{ |
| 62 | ············asio::placeholders::error)); | 65 | ··········if·(!error) |
| 63 | ····} | 66 | ··········{ |
| 64 | ····else | 67 | ············handshake(); |
| 65 | ····{ | 68 | ··········} |
| 66 | ······std::cout·<<·"Connect·failed:·"·<<·error.message()·<<·"\n"; | 69 | ··········else |
| 67 | ····} | 70 | ··········{ |
| | 71 | ············std::cout·<<·"Connect·failed:·"·<<·error.message()·<<·"\n"; |
| | 72 | ··········} |
| | 73 | ········}); |
| 68 | ··} | 74 | ··} |
| 69 | | 75 | |
| 70 | ··void·handle_handshake(const·asio::error_code&·error) | 76 | ··void·handshake() |
| 71 | ··{ | 77 | ··{ |
| 72 | ····if·(!error) | 78 | ····socket_.async_handshake(asio::ssl::stream_base::client, |
| 73 | ····{ | 79 | ········[this](const·std::error_code&·error) |
| 74 | ······std::cout·<<·"Enter·message:·"; | 80 | ········{ |
| 75 | ······std::cin.getline(request_,·max_length); | 81 | ··········if·(!error) |
| 76 | ······size_t·request_length·=·strlen(request_); | 82 | ··········{ |
| 77 | | 83 | ············send_request(); |
| 78 | ······asio::async_write(socket_, | 84 | ··········} |
| 79 | ··········asio::buffer(request_,·request_length), | 85 | ··········else |
| 80 | ··········boost::bind(&client::handle_write,·this, | 86 | ··········{ |
| 81 | ············asio::placeholders::error, | 87 | ············std::cout·<<·"Handshake·failed:·"·<<·error.message()·<<·"\n"; |
| 82 | ············asio::placeholders::bytes_transferred)); | 88 | ··········} |
| 83 | ····} | 89 | ········}); |
| 84 | ····else | |
| 85 | ····{ | |
| 86 | ······std::cout·<<·"Handshake·failed:·"·<<·error.message()·<<·"\n"; | |
| 87 | ····} | |
| 88 | ··} | 90 | ··} |
| 89 | | 91 | |
| 90 | ··void·handle_write(const·asio::error_code&·error, | 92 | ··void·send_request() |
| 91 | ······size_t·bytes_transferred) | |
| 92 | ··{ | 93 | ··{ |
| 93 | ····if·(!error) | 94 | ····std::cout·<<·"Enter·message:·"; |
| 94 | ····{ | 95 | ····std::cin.getline(request_,·max_length); |
| 95 | ······asio::async_read(socket_, | 96 | ····size_t·request_length·=·std::strlen(request_); |
| 96 | ··········asio::buffer(reply_,·bytes_transferred), | 97 | |
| 97 | ··········boost::bind(&client::handle_read,·this, | 98 | ····asio::async_write(socket_, |
| 98 | ············asio::placeholders::error, | 99 | ········asio::buffer(request_,·request_length), |
| 99 | ············asio::placeholders::bytes_transferred)); | 100 | ········[this](const·std::error_code&·error,·std::size_t·length) |
| 100 | ····} | 101 | ········{ |
| 101 | ····else | 102 | ··········if·(!error) |
| 102 | ····{ | 103 | ··········{ |
| 103 | ······std::cout·<<·"Write·failed:·"·<<·error.message()·<<·"\n"; | 104 | ············receive_response(length); |
| 104 | ····} | 105 | ··········} |
| | 106 | ··········else |
| | 107 | ··········{ |
| | 108 | ············std::cout·<<·"Write·failed:·"·<<·error.message()·<<·"\n"; |
| | 109 | ··········} |
| | 110 | ········}); |
| 105 | ··} | 111 | ··} |
| 106 | | 112 | |
| 107 | ··void·handle_read(const·asio::error_code&·error, | 113 | ··void·receive_response(std::size_t·length) |
| 108 | ······size_t·bytes_transferred) | |
| 109 | ··{ | 114 | ··{ |
| 110 | ····if·(!error) | 115 | ····asio::async_read(socket_, |
| 111 | ····{ | 116 | ········asio::buffer(reply_,·length), |
| 112 | ······std::cout·<<·"Reply:·"; | 117 | ········[this](const·std::error_code&·error,·std::size_t·length) |
| 113 | ······std::cout.write(reply_,·bytes_transferred); | 118 | ········{ |
| 114 | ······std::cout·<<·"\n"; | 119 | ··········if·(!error) |
| 115 | ····} | 120 | ··········{ |
| 116 | ····else | 121 | ············std::cout·<<·"Reply:·"; |
| 117 | ····{ | 122 | ············std::cout.write(reply_,·length); |
| 118 | ······std::cout·<<·"Read·failed:·"·<<·error.message()·<<·"\n"; | 123 | ············std::cout·<<·"\n"; |
| 119 | ····} | 124 | ··········} |
| | 125 | ··········else |
| | 126 | ··········{ |
| | 127 | ············std::cout·<<·"Read·failed:·"·<<·error.message()·<<·"\n"; |
| | 128 | ··········} |
| | 129 | ········}); |
| 120 | ··} | 130 | ··} |
| 121 | | 131 | |
| 122 | private: | 132 | ··asio::ssl::stream<tcp::socket>·socket_; |
| 123 | ··asio::ssl::stream<asio::ip::tcp::socket>·socket_; | |
| 124 | ··char·request_[max_length]; | 133 | ··char·request_[max_length]; |
| 125 | ··char·reply_[max_length]; | 134 | ··char·reply_[max_length]; |
| 126 | }; | 135 | }; |
| 127 | | 136 | |
| 128 | int·main(int·argc,·char*·argv[]) | 137 | int·main(int·argc,·char*·argv[]) |
| 129 | { | 138 | { |
| 130 | ··try | 139 | ··try |
| 131 | ··{ | 140 | ··{ |
| 132 | ····if·(argc·!=·3) | 141 | ····if·(argc·!=·3) |
| 133 | ····{ | 142 | ····{ |
| 134 | ······std::cerr·<<·"Usage:·client·<host>·<port>\n"; | 143 | ······std::cerr·<<·"Usage:·client·<host>·<port>\n"; |
| 135 | ······return·1; | 144 | ······return·1; |
| 136 | ····} | 145 | ····} |
| 137 | | 146 | |
| 138 | ····asio::io_context·io_context; | 147 | ····asio::io_context·io_context; |
| 139 | | 148 | |
| 140 | ····asio::ip::tcp::resolver·resolver(io_context); | 149 | ····tcp::resolver·resolver(io_context); |
| 141 | ····asio::ip::tcp::resolver::results_type·endpoints·= | 150 | ····auto·endpoints·=·resolver.resolve(argv[1],·argv[2]); |
| 142 | ······resolver.resolve(argv[1],·argv[2]); | |
| 143 | | 151 | |
| 144 | ····asio::ssl::context·ctx(asio::ssl::context::sslv23); | 152 | ····asio::ssl::context·ctx(asio::ssl::context::sslv23); |
| 145 | ····ctx.load_verify_file("ca.pem"); | 153 | ····ctx.load_verify_file("ca.pem"); |
| 146 | | 154 | |
| 147 | ····client·c(io_context,·ctx,·endpoints); | 155 | ····client·c(io_context,·ctx,·endpoints); |
| 148 | | 156 | |
| 149 | ····io_context.run(); | 157 | ····io_context.run(); |
| 150 | ··} | 158 | ··} |
| 151 | ··catch·(std::exception&·e) | 159 | ··catch·(std::exception&·e) |
| 152 | ··{ | 160 | ··{ |
| 153 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 161 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; |
| 154 | ··} | 162 | ··} |
| 155 | | 163 | |
| 156 | ··return·0; | 164 | ··return·0; |
| 157 | } | 165 | } |