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-​2022·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2022·​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 ·​·​{
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(cons​t·​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 ·​·​·​·​else69 ·​·​·​·​·​·​·​·​·​·​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 ·​·​·​·​else84 ·​·​·​·​·​·​·​·​·​·​}
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(leng​th)​;​
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 ·​·​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 }