src/​examples/​cpp03/​ssl/​client.​cppsrc/​examples/​cpp11/​ssl/​client.​cpp
⋮⋮
1 /​/​1 /​/​
2 /​/​·​client.​cpp2 /​/​·​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·​accompanying7 /​/​·​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·​client24 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(bo​ol·​preverified,​40 ·​·​bool·​verify_certificate(bo​ol·​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·​is43 ·​·​·​·​/​/​·​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·​describes44 ·​·​·​·​/​/​·​being·​presented·​is·​valid·​for·​the·​peer.​·​For·​example,​·​RFC·​2818·​describes
42 ·​·​·​·​/​/​·​the·​steps·​involved·​in·​doing·​this·​for·​HTTPS.​·​Consult·​the·​OpenSSL45 ·​·​·​·​/​/​·​the·​steps·​involved·​in·​doing·​this·​for·​HTTPS.​·​Consult·​the·​OpenSSL
43 ·​·​·​·​/​/​·​documentation·​for·​more·​details.​·​Note·​that·​the·​callback·​is·​called·​once46 ·​·​·​·​/​/​·​documentation·​for·​more·​details.​·​Note·​that·​the·​callback·​is·​called·​once
44 ·​·​·​·​/​/​·​for·​each·​certificate·​in·​the·​certificate·​chain,​·​starting·​from·​the·​root47 ·​·​·​·​/​/​·​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_cu​rrent_cert(ctx.​native_handle()​)​;​52 ·​·​·​·​X509*·​cert·​=·​X509_STORE_CTX_get_cu​rrent_cert(ctx.​native_handle()​)​;​
50 ·​·​·​·​X509_NAME_oneline(X50​9_get_subject_name(ce​rt)​,​·​subject_name,​·​256)​;​53 ·​·​·​·​X509_NAME_oneline(X50​9_get_subject_name(ce​rt)​,​·​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 ·​·​·​·​else67 ·​·​·​·​·​·​·​·​·​·​·​·​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(cons​t·​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 ·​·​·​·​else102 ·​·​·​·​·​·​·​·​·​·​if·​(!error)​
102 ·​·​·​·​{103 ·​·​·​·​·​·​·​·​·​·​{
103 ·​·​·​·​·​·​std:​:​cout·​<<·​"Write·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​104 ·​·​·​·​·​·​·​·​·​·​·​·​receive_response(leng​th)​;​
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 ·​·​·​·​else121 ·​·​·​·​·​·​·​·​·​·​·​·​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 ·​·​try139 ·​·​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 }