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-​2018·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2018·​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.​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,​·​_1,​·​_2)​)​;​34 ·​·​·​·​·​·​·​·​std:​:​bind(&client:​:​verify_certificate,​·​this,​·​_1,​·​_2)​)​;​
30 35
31 ·​·​·​·​asio:​:​async_connect(socket_​.​lowest_layer()​,​·​endpoints,​36 ·​·​·​·​connect(endpoints)​;​
32 ·​·​·​·​·​·​·​·​boost:​:​bind(&client:​:​handle_connect,​·​this,​
33 ·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​
34 ·​·​}37 ·​·​}
35 38
39 private:​
36 ·​·​bool·​verify_certificate(bo​ol·​preverified,​40 ·​·​bool·​verify_certificate(bo​ol·​preverified,​
37 ·​·​·​·​·​·​asio:​:​ssl:​:​verify_context&·​ctx)​41 ·​·​·​·​·​·​asio:​:​ssl:​:​verify_context&·​ctx)​
38 ·​·​{42 ·​·​{
39 ·​·​·​·​/​/​·​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
40 ·​·​·​·​/​/​·​being·​presented·​is·​valid·​for·​the·​peer.​·​For·​example,​·​RFC·​2818·​describes44 ·​·​·​·​/​/​·​being·​presented·​is·​valid·​for·​the·​peer.​·​For·​example,​·​RFC·​2818·​describes
41 ·​·​·​·​/​/​·​the·​steps·​involved·​in·​doing·​this·​for·​HTTPS.​·​Consult·​the·​OpenSSL45 ·​·​·​·​/​/​·​the·​steps·​involved·​in·​doing·​this·​for·​HTTPS.​·​Consult·​the·​OpenSSL
42 ·​·​·​·​/​/​·​documentation·​for·​more·​details.​·​Note·​that·​the·​callback·​is·​called·​once46 ·​·​·​·​/​/​·​documentation·​for·​more·​details.​·​Note·​that·​the·​callback·​is·​called·​once
43 ·​·​·​·​/​/​·​for·​each·​certificate·​in·​the·​certificate·​chain,​·​starting·​from·​the·​root47 ·​·​·​·​/​/​·​for·​each·​certificate·​in·​the·​certificate·​chain,​·​starting·​from·​the·​root
44 ·​·​·​·​/​/​·​certificate·​authority.​48 ·​·​·​·​/​/​·​certificate·​authority.​
45 49
46 ·​·​·​·​/​/​·​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.​
47 ·​·​·​·​char·​subject_name[256];​51 ·​·​·​·​char·​subject_name[256];​
48 ·​·​·​·​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()​)​;​
49 ·​·​·​·​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)​;​
50 ·​·​·​·​std:​:​cout·​<<·​"Verifying·​"·​<<·​subject_name·​<<·​"\n";​54 ·​·​·​·​std:​:​cout·​<<·​"Verifying·​"·​<<·​subject_name·​<<·​"\n";​
51 55
52 ·​·​·​·​return·​preverified;​56 ·​·​·​·​return·​preverified;​
53 ·​·​}57 ·​·​}
54 58
55 ·​·​void·​handle_connect(const·​asio:​:​error_code&·​error)​59 ·​·​void·​connect(const·​tcp:​:​resolver:​:​results_type&·​endpoints)​
56 ·​·​{
57 ·​·​·​·​if·​(!error)​
58 ·​·​·​·​{
59 ·​·​·​·​·​·​socket_.​async_handshake(asio:​:​ssl:​:​stream_base:​:​client,​
60 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&client:​:​handle_handshake,​·​this,​
61 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​
62 ·​·​·​·​}
63 ·​·​·​·​else
64 ·​·​·​·​{
65 ·​·​·​·​·​·​std:​:​cout·​<<·​"Connect·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​
66 ·​·​·​·​}
67 ·​·​}
68
69 ·​·​void·​handle_handshake(cons​t·​asio:​:​error_code&·​error)​
70 ·​·​{
71 ·​·​·​·​if·​(!error)​
72 ·​·​·​·​{
73 ·​·​·​·​·​·​std:​:​cout·​<<·​"Enter·​message:​·​";​
74 ·​·​·​·​·​·​std:​:​cin.​getline(request_,​·​max_length)​;​
75 ·​·​·​·​·​·​size_t·​request_length·​=·​strlen(request_)​;​
76
77 ·​·​·​·​·​·​asio:​:​async_write(socket_,​
78 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(request_,​·​request_length)​,​
79 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&client:​:​handle_write,​·​this,​
80 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error,​
81 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​bytes_transferred)​)​;​
82 ·​·​·​·​}
83 ·​·​·​·​else
84 ·​·​·​·​{
85 ·​·​·​·​·​·​std:​:​cout·​<<·​"Handshake·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​
86 ·​·​·​·​}
87 ·​·​}
88
89 ·​·​void·​handle_write(const·​asio:​:​error_code&·​error,​
90 ·​·​·​·​·​·​size_t·​bytes_transferred)​
91 ·​·​{60 ·​·​{
92 ·​·​·​·​if·​(!error)​61 ·​·​·​·​asio:​:​async_connect(socket_​.​lowest_layer()​,​·​endpoints,​
93 ·​·​·​·​{62 ·​·​·​·​·​·​·​·​[this](const·​std:​:​error_code&·​error,​
94 ·​·​·​·​·​·​asio:​:​async_read(socket_,​63 ·​·​·​·​·​·​·​·​·​·​const·​tcp:​:​endpoint&·​/​*endpoint*/​)​
95 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(reply_,​·​bytes_transferred)​,​64 ·​·​·​·​·​·​·​·​{
96 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&client:​:​handle_read,​·​this,​65 ·​·​·​·​·​·​·​·​·​·​if·​(!error)​
97 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error,​66 ·​·​·​·​·​·​·​·​·​·​{
98 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​bytes_transferred)​)​;​67 ·​·​·​·​·​·​·​·​·​·​·​·​handshake()​;​
99 ·​·​·​·​}68 ·​·​·​·​·​·​·​·​·​·​}
100 ·​·​·​·​else69 ·​·​·​·​·​·​·​·​·​·​else
101 ·​·​·​·​{70 ·​·​·​·​·​·​·​·​·​·​{
102 ·​·​·​·​·​·​std:​:​cout·​<<·​"Write·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​71 ·​·​·​·​·​·​·​·​·​·​·​·​std:​:​cout·​<<·​"Connect·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​
103 ·​·​·​·​}72 ·​·​·​·​·​·​·​·​·​·​}
104 ·​·​}73 ·​·​·​·​·​·​·​·​})​;​
105 74 ·​·​}
106 ·​·​void·​handle_read(const·​asio:​:​error_code&·​error,​75
107 ·​·​·​·​·​·​size_t·​bytes_transferred)​76 ·​·​void·​handshake()​
108 ·​·​{77 ·​·​{
109 ·​·​·​·​if·​(!error)​78 ·​·​·​·​socket_.​async_handshake(asio:​:​ssl:​:​stream_base:​:​client,​
110 ·​·​·​·​{79 ·​·​·​·​·​·​·​·​[this](const·​std:​:​error_code&·​error)​
111 ·​·​·​·​·​·​std:​:​cout·​<<·​"Reply:​·​";​80 ·​·​·​·​·​·​·​·​{
112 ·​·​·​·​·​·​std:​:​cout.​write(reply_,​·​bytes_transferred)​;​81 ·​·​·​·​·​·​·​·​·​·​if·​(!error)​
113 ·​·​·​·​·​·​std:​:​cout·​<<·​"\n";​82 ·​·​·​·​·​·​·​·​·​·​{
114 ·​·​·​·​}83 ·​·​·​·​·​·​·​·​·​·​·​·​send_request()​;​
115 ·​·​·​·​else84 ·​·​·​·​·​·​·​·​·​·​}
116 ·​·​·​·​{85 ·​·​·​·​·​·​·​·​·​·​else
117 ·​·​·​·​·​·​std:​:​cout·​<<·​"Read·​failed:​·​"·​<<·​error.​message()​·​<<·​"\n";​86 ·​·​·​·​·​·​·​·​·​·​{
118 ·​·​·​·​}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 ·​·​·​·​·​·​·​·​})​;​
119 ·​·​}130 ·​·​}
120 131
121 private:​132 ·​·​asio:​:​ssl:​:​stream<tcp:​:​socket>·​socket_;​
122 ·​·​asio:​:​ssl:​:​stream<asio:​:​ip:​:​tcp:​:​socket>·​socket_;​
123 ·​·​char·​request_[max_length];​133 ·​·​char·​request_[max_length];​
124 ·​·​char·​reply_[max_length];​134 ·​·​char·​reply_[max_length];​
125 };​135 };​
126 136
127 int·​main(int·​argc,​·​char*·​argv[])​137 int·​main(int·​argc,​·​char*·​argv[])​
128 {138 {
129 ·​·​try139 ·​·​try
130 ·​·​{140 ·​·​{
131 ·​·​·​·​if·​(argc·​!=·​3)​141 ·​·​·​·​if·​(argc·​!=·​3)​
132 ·​·​·​·​{142 ·​·​·​·​{
133 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​client·​<host>·​<port>\n";​143 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​client·​<host>·​<port>\n";​
134 ·​·​·​·​·​·​return·​1;​144 ·​·​·​·​·​·​return·​1;​
135 ·​·​·​·​}145 ·​·​·​·​}
136 146
137 ·​·​·​·​asio:​:​io_context·​io_context;​147 ·​·​·​·​asio:​:​io_context·​io_context;​
138 148
139 ·​·​·​·​asio:​:​ip:​:​tcp:​:​resolver·​resolver(io_context)​;​149 ·​·​·​·​tcp:​:​resolver·​resolver(io_context)​;​
140 ·​·​·​·​asio:​:​ip:​:​tcp:​:​resolver:​:​results_type·​endpoints·​=150 ·​·​·​·​auto·​endpoints·​=·​resolver.​resolve(argv[1],​·​argv[2])​;​
141 ·​·​·​·​·​·​resolver.​resolve(argv[1],​·​argv[2])​;​
142 151
143 ·​·​·​·​asio:​:​ssl:​:​context·​ctx(asio:​:​ssl:​:​context:​:​sslv23)​;​152 ·​·​·​·​asio:​:​ssl:​:​context·​ctx(asio:​:​ssl:​:​context:​:​sslv23)​;​
144 ·​·​·​·​ctx.​load_verify_file("ca.​pem")​;​153 ·​·​·​·​ctx.​load_verify_file("ca.​pem")​;​
145 154
146 ·​·​·​·​client·​c(io_context,​·​ctx,​·​endpoints)​;​155 ·​·​·​·​client·​c(io_context,​·​ctx,​·​endpoints)​;​
147 156
148 ·​·​·​·​io_context.​run()​;​157 ·​·​·​·​io_context.​run()​;​
149 ·​·​}158 ·​·​}
150 ·​·​catch·​(std:​:​exception&·​e)​159 ·​·​catch·​(std:​:​exception&·​e)​
151 ·​·​{160 ·​·​{
152 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​161 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​
153 ·​·​}162 ·​·​}
154 163
155 ·​·​return·​0;​164 ·​·​return·​0;​
156 }165 }