Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / tool / client.cc
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/base.h>
16
17 // TODO(davidben): bssl client does not work on Windows.
18 #if !defined(OPENSSL_WINDOWS)
19
20 #include <string>
21 #include <vector>
22
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #if !defined(OPENSSL_WINDOWS)
29 #include <arpa/inet.h>
30 #include <fcntl.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 #include <sys/select.h>
34 #include <unistd.h>
35 #else
36 #include <WinSock2.h>
37 #include <WS2tcpip.h>
38 typedef int socklen_t;
39 #endif
40
41 #include <openssl/err.h>
42 #include <openssl/ssl.h>
43
44 #include "internal.h"
45
46
47 static const struct argument kArguments[] = {
48     {
49      "-connect", true,
50      "The hostname and port of the server to connect to, e.g. foo.com:443",
51     },
52     {
53      "-cipher", false,
54      "An OpenSSL-style cipher suite string that configures the offered ciphers",
55     },
56     {
57      "", false, "",
58     },
59 };
60
61 // Connect sets |*out_sock| to be a socket connected to the destination given
62 // in |hostname_and_port|, which should be of the form "www.example.com:123".
63 // It returns true on success and false otherwise.
64 static bool Connect(int *out_sock, const std::string &hostname_and_port) {
65   const size_t colon_offset = hostname_and_port.find_last_of(':');
66   std::string hostname, port;
67
68   if (colon_offset == std::string::npos) {
69     hostname = hostname_and_port;
70     port = "443";
71   } else {
72     hostname = hostname_and_port.substr(0, colon_offset);
73     port = hostname_and_port.substr(colon_offset + 1);
74   }
75
76   struct addrinfo hint, *result;
77   memset(&hint, 0, sizeof(hint));
78   hint.ai_family = AF_UNSPEC;
79   hint.ai_socktype = SOCK_STREAM;
80
81   int ret = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &result);
82   if (ret != 0) {
83     fprintf(stderr, "getaddrinfo returned: %s\n", gai_strerror(ret));
84     return false;
85   }
86
87   bool ok = false;
88   char buf[256];
89
90   *out_sock =
91       socket(result->ai_family, result->ai_socktype, result->ai_protocol);
92   if (*out_sock < 0) {
93     perror("socket");
94     goto out;
95   }
96
97   switch (result->ai_family) {
98     case AF_INET: {
99       struct sockaddr_in *sin =
100           reinterpret_cast<struct sockaddr_in *>(result->ai_addr);
101       fprintf(stderr, "Connecting to %s:%d\n",
102               inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)),
103               ntohs(sin->sin_port));
104       break;
105     }
106     case AF_INET6: {
107       struct sockaddr_in6 *sin6 =
108           reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
109       fprintf(stderr, "Connecting to [%s]:%d\n",
110               inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)),
111               ntohs(sin6->sin6_port));
112       break;
113     }
114   }
115
116   if (connect(*out_sock, result->ai_addr, result->ai_addrlen) != 0) {
117     perror("connect");
118     goto out;
119   }
120   ok = true;
121
122 out:
123   freeaddrinfo(result);
124   return ok;
125 }
126
127 static void PrintConnectionInfo(const SSL *ssl) {
128   const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
129
130   fprintf(stderr, "  Version: %s\n", SSL_get_version(ssl));
131   fprintf(stderr, "  Cipher: %s\n", SSL_CIPHER_get_name(cipher));
132   fprintf(stderr, "  Secure renegotiation: %s\n",
133           SSL_get_secure_renegotiation_support(ssl) ? "yes" : "no");
134 }
135
136 static bool SocketSetNonBlocking(int sock, bool is_non_blocking) {
137   bool ok;
138
139 #if defined(OPENSSL_WINDOWS)
140   u_long arg = is_non_blocking;
141   ok = 0 == ioctlsocket(sock, FIOBIO, &arg);
142 #else
143   int flags = fcntl(sock, F_GETFL, 0);
144   if (flags < 0) {
145     return false;
146   }
147   if (is_non_blocking) {
148     flags |= O_NONBLOCK;
149   } else {
150     flags &= ~O_NONBLOCK;
151   }
152   ok = 0 == fcntl(sock, F_SETFL, flags);
153 #endif
154   if (!ok) {
155     fprintf(stderr, "Failed to set socket non-blocking.\n");
156   }
157   return ok;
158 }
159
160 // PrintErrorCallback is a callback function from OpenSSL's
161 // |ERR_print_errors_cb| that writes errors to a given |FILE*|.
162 static int PrintErrorCallback(const char *str, size_t len, void *ctx) {
163   fwrite(str, len, 1, reinterpret_cast<FILE*>(ctx));
164   return 1;
165 }
166
167 bool TransferData(SSL *ssl, int sock) {
168   bool stdin_open = true;
169
170   fd_set read_fds;
171   FD_ZERO(&read_fds);
172
173   if (!SocketSetNonBlocking(sock, true)) {
174     return false;
175   }
176
177   for (;;) {
178     if (stdin_open) {
179       FD_SET(0, &read_fds);
180     }
181     FD_SET(sock, &read_fds);
182
183     int ret = select(sock + 1, &read_fds, NULL, NULL, NULL);
184     if (ret <= 0) {
185       perror("select");
186       return false;
187     }
188
189     if (FD_ISSET(0, &read_fds)) {
190       uint8_t buffer[512];
191       ssize_t n;
192
193       do {
194         n = read(0, buffer, sizeof(buffer));
195       } while (n == -1 && errno == EINTR);
196
197       if (n == 0) {
198         FD_CLR(0, &read_fds);
199         stdin_open = false;
200         shutdown(sock, SHUT_WR);
201         continue;
202       } else if (n < 0) {
203         perror("read from stdin");
204         return false;
205       }
206
207       if (!SocketSetNonBlocking(sock, false)) {
208         return false;
209       }
210       int ssl_ret = SSL_write(ssl, buffer, n);
211       if (!SocketSetNonBlocking(sock, true)) {
212         return false;
213       }
214
215       if (ssl_ret <= 0) {
216         int ssl_err = SSL_get_error(ssl, ssl_ret);
217         fprintf(stderr, "Error while writing: %d\n", ssl_err);
218         ERR_print_errors_cb(PrintErrorCallback, stderr);
219         return false;
220       } else if (ssl_ret != n) {
221         fprintf(stderr, "Short write from SSL_write.\n");
222         return false;
223       }
224     }
225
226     if (FD_ISSET(sock, &read_fds)) {
227       uint8_t buffer[512];
228       int ssl_ret = SSL_read(ssl, buffer, sizeof(buffer));
229
230       if (ssl_ret < 0) {
231         int ssl_err = SSL_get_error(ssl, ssl_ret);
232         if (ssl_err == SSL_ERROR_WANT_READ) {
233           continue;
234         }
235         fprintf(stderr, "Error while reading: %d\n", ssl_err);
236         ERR_print_errors_cb(PrintErrorCallback, stderr);
237         return false;
238       } else if (ssl_ret == 0) {
239         return true;
240       }
241
242       ssize_t n;
243       do {
244         n = write(1, buffer, ssl_ret);
245       } while (n == -1 && errno == EINTR);
246
247       if (n != ssl_ret) {
248         fprintf(stderr, "Short write to stderr.\n");
249         return false;
250       }
251     }
252   }
253 }
254
255 bool Client(const std::vector<std::string> &args) {
256   std::map<std::string, std::string> args_map;
257
258   if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
259     PrintUsage(kArguments);
260     return false;
261   }
262
263   SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
264
265   const char *keylog_file = getenv("SSLKEYLOGFILE");
266   if (keylog_file) {
267     BIO *keylog_bio = BIO_new_file(keylog_file, "a");
268     if (!keylog_bio) {
269       ERR_print_errors_cb(PrintErrorCallback, stderr);
270       return false;
271     }
272     SSL_CTX_set_keylog_bio(ctx, keylog_bio);
273   }
274
275   if (args_map.count("-cipher") != 0) {
276     SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str());
277   }
278
279   int sock = -1;
280   if (!Connect(&sock, args_map["-connect"])) {
281     return false;
282   }
283
284   BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
285   SSL *ssl = SSL_new(ctx);
286   SSL_set_bio(ssl, bio, bio);
287
288   int ret = SSL_connect(ssl);
289   if (ret != 1) {
290     int ssl_err = SSL_get_error(ssl, ret);
291     fprintf(stderr, "Error while connecting: %d\n", ssl_err);
292     ERR_print_errors_cb(PrintErrorCallback, stderr);
293     return false;
294   }
295
296   fprintf(stderr, "Connected.\n");
297   PrintConnectionInfo(ssl);
298
299   bool ok = TransferData(ssl, sock);
300
301   SSL_free(ssl);
302   SSL_CTX_free(ctx);
303   return ok;
304 }
305
306 #endif  // !OPENSSL_WINDOWS