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 | ····:·local_socket(io_context,·context) | 30 | ····:·local_socket(io_context,·context) |
26 | ··{ | 31 | ··{ |
27 | ····local_socket.set_verify_mode(asio::ssl::verify_peer); | 32 | ····local_socket.set_verify_mode(asio::ssl::verify_peer); |
28 | ····local_socket.set_verify_callback( | 33 | ····local_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 | } |