| 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  | } |