| 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-2021·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2021·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 | ··{ |  | 
| 58 | ····if·(!error) |  | 
| 59 | ····{ |  | 
| 60 | ······socket_.async_handshake(asio::ssl::stream_base::client, |  | 
| 61 | ··········boost::bind(&client::handle_handshake,·this, |  | 
| 62 | ············asio::placeholders::error)); |  | 
| 63 | ····} |  | 
| 64 | ····else |  | 
| 65 | ····{ |  | 
| 66 | ······std::cout·<<·"Connect·failed:·"·<<·error.message()·<<·"\n"; |  | 
| 67 | ····} |  | 
| 68 | ··} |  | 
| 69 |  |  | 
| 70 | ··void·handle_handshake(const·asio::error_code&·error) |  | 
| 71 | ··{ |  | 
| 72 | ····if·(!error) |  | 
| 73 | ····{ |  | 
| 74 | ······std::cout·<<·"Enter·message:·"; |  | 
| 75 | ······std::cin.getline(request_,·max_length); |  | 
| 76 | ······size_t·request_length·=·strlen(request_); |  | 
| 77 |  |  | 
| 78 | ······asio::async_write(socket_, |  | 
| 79 | ··········asio::buffer(request_,·request_length), |  | 
| 80 | ··········boost::bind(&client::handle_write,·this, |  | 
| 81 | ············asio::placeholders::error, |  | 
| 82 | ············asio::placeholders::bytes_transferred)); |  | 
| 83 | ····} |  | 
| 84 | ····else |  | 
| 85 | ····{ |  | 
| 86 | ······std::cout·<<·"Handshake·failed:·"·<<·error.message()·<<·"\n"; |  | 
| 87 | ····} |  | 
| 88 | ··} |  | 
| 89 |  |  | 
| 90 | ··void·handle_write(const·asio::error_code&·error, |  | 
| 91 | ······size_t·bytes_transferred) |  | 
| 92 | ··{ | 60 | ··{ | 
| 93 | ····if·(!error) | 61 | ····asio::async_connect(socket_.lowest_layer(),·endpoints, | 
| 94 | ····{ | 62 | ········[this](const·std::error_code&·error, | 
| 95 | ······asio::async_read(socket_, | 63 | ··········const·tcp::endpoint&·/*endpoint*/) | 
| 96 | ··········asio::buffer(reply_,·bytes_transferred), | 64 | ········{ | 
| 97 | ··········boost::bind(&client::handle_read,·this, | 65 | ··········if·(!error) | 
| 98 | ············asio::placeholders::error, | 66 | ··········{ | 
| 99 | ············asio::placeholders::bytes_transferred)); | 67 | ············handshake(); | 
| 100 | ····} | 68 | ··········} | 
| 101 | ····else | 69 | ··········else | 
| 102 | ····{ | 70 | ··········{ | 
| 103 | ······std::cout·<<·"Write·failed:·"·<<·error.message()·<<·"\n"; | 71 | ············std::cout·<<·"Connect·failed:·"·<<·error.message()·<<·"\n"; | 
| 104 | ····} | 72 | ··········} | 
| 105 | ··} | 73 | ········}); | 
| 106 |  | 74 | ··} | 
| 107 | ··void·handle_read(const·asio::error_code&·error, | 75 |  | 
| 108 | ······size_t·bytes_transferred) | 76 | ··void·handshake() | 
| 109 | ··{ | 77 | ··{ | 
| 110 | ····if·(!error) | 78 | ····socket_.async_handshake(asio::ssl::stream_base::client, | 
| 111 | ····{ | 79 | ········[this](const·std::error_code&·error) | 
| 112 | ······std::cout·<<·"Reply:·"; | 80 | ········{ | 
| 113 | ······std::cout.write(reply_,·bytes_transferred); | 81 | ··········if·(!error) | 
| 114 | ······std::cout·<<·"\n"; | 82 | ··········{ | 
| 115 | ····} | 83 | ············send_request(); | 
| 116 | ····else | 84 | ··········} | 
| 117 | ····{ | 85 | ··········else | 
| 118 | ······std::cout·<<·"Read·failed:·"·<<·error.message()·<<·"\n"; | 86 | ··········{ | 
| 119 | ····} | 87 | ············std::cout·<<·"Handshake·failed:·"·<<·error.message()·<<·"\n"; | 
|  | 88 | ··········} | 
|  | 89 | ········}); | 
|  | 90 | ··} | 
|  | 91 |  | 
|  | 92 | ··void·send_request() | 
|  | 93 | ··{ | 
|  | 94 | ····std::cout·<<·"Enter·message:·"; | 
|  | 95 | ····std::cin.getline(request_,·max_length); | 
|  | 96 | ····size_t·request_length·=·std::strlen(request_); | 
|  | 97 |  | 
|  | 98 | ····asio::async_write(socket_, | 
|  | 99 | ········asio::buffer(request_,·request_length), | 
|  | 100 | ········[this](const·std::error_code&·error,·std::size_t·length) | 
|  | 101 | ········{ | 
|  | 102 | ··········if·(!error) | 
|  | 103 | ··········{ | 
|  | 104 | ············receive_response(length); | 
|  | 105 | ··········} | 
|  | 106 | ··········else | 
|  | 107 | ··········{ | 
|  | 108 | ············std::cout·<<·"Write·failed:·"·<<·error.message()·<<·"\n"; | 
|  | 109 | ··········} | 
|  | 110 | ········}); | 
|  | 111 | ··} | 
|  | 112 |  | 
|  | 113 | ··void·receive_response(std::size_t·length) | 
|  | 114 | ··{ | 
|  | 115 | ····asio::async_read(socket_, | 
|  | 116 | ········asio::buffer(reply_,·length), | 
|  | 117 | ········[this](const·std::error_code&·error,·std::size_t·length) | 
|  | 118 | ········{ | 
|  | 119 | ··········if·(!error) | 
|  | 120 | ··········{ | 
|  | 121 | ············std::cout·<<·"Reply:·"; | 
|  | 122 | ············std::cout.write(reply_,·length); | 
|  | 123 | ············std::cout·<<·"\n"; | 
|  | 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 | } |