Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

328 wiersze
9.7 KiB

  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. #include <openssl/base.h>
  15. #include <stdio.h>
  16. #include <openssl/err.h>
  17. #include <openssl/pem.h>
  18. #include <openssl/ssl.h>
  19. #include "internal.h"
  20. #include "transport_common.h"
  21. static const struct argument kArguments[] = {
  22. {
  23. "-connect", kRequiredArgument,
  24. "The hostname and port of the server to connect to, e.g. foo.com:443",
  25. },
  26. {
  27. "-cipher", kOptionalArgument,
  28. "An OpenSSL-style cipher suite string that configures the offered ciphers",
  29. },
  30. {
  31. "-max-version", kOptionalArgument,
  32. "The maximum acceptable protocol version",
  33. },
  34. {
  35. "-min-version", kOptionalArgument,
  36. "The minimum acceptable protocol version",
  37. },
  38. {
  39. "-server-name", kOptionalArgument,
  40. "The server name to advertise",
  41. },
  42. {
  43. "-select-next-proto", kOptionalArgument,
  44. "An NPN protocol to select if the server supports NPN",
  45. },
  46. {
  47. "-alpn-protos", kOptionalArgument,
  48. "A comma-separated list of ALPN protocols to advertise",
  49. },
  50. {
  51. "-fallback-scsv", kBooleanArgument,
  52. "Enable FALLBACK_SCSV",
  53. },
  54. {
  55. "-ocsp-stapling", kBooleanArgument,
  56. "Advertise support for OCSP stabling",
  57. },
  58. {
  59. "-signed-certificate-timestamps", kBooleanArgument,
  60. "Advertise support for signed certificate timestamps",
  61. },
  62. {
  63. "-channel-id-key", kOptionalArgument,
  64. "The key to use for signing a channel ID",
  65. },
  66. {
  67. "-false-start", kBooleanArgument,
  68. "Enable False Start",
  69. },
  70. { "-session-in", kOptionalArgument,
  71. "A file containing a session to resume.",
  72. },
  73. { "-session-out", kOptionalArgument,
  74. "A file to write the negotiated session to.",
  75. },
  76. {
  77. "-key", kOptionalArgument,
  78. "Private-key file to use (default is no client certificate)",
  79. },
  80. {
  81. "-starttls", kOptionalArgument,
  82. "A STARTTLS mini-protocol to run before the TLS handshake. Supported"
  83. " values: 'smtp'",
  84. },
  85. {
  86. "", kOptionalArgument, "",
  87. },
  88. };
  89. static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
  90. bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
  91. if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
  92. return nullptr;
  93. }
  94. bssl::UniquePtr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr,
  95. nullptr, nullptr));
  96. return pkey;
  97. }
  98. static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
  99. const uint8_t* in, unsigned inlen, void* arg) {
  100. *out = reinterpret_cast<uint8_t *>(arg);
  101. *outlen = strlen(reinterpret_cast<const char *>(arg));
  102. return SSL_TLSEXT_ERR_OK;
  103. }
  104. static FILE *g_keylog_file = nullptr;
  105. static void KeyLogCallback(const SSL *ssl, const char *line) {
  106. fprintf(g_keylog_file, "%s\n", line);
  107. fflush(g_keylog_file);
  108. }
  109. static bssl::UniquePtr<BIO> session_out;
  110. static int NewSessionCallback(SSL *ssl, SSL_SESSION *session) {
  111. if (session_out) {
  112. if (!PEM_write_bio_SSL_SESSION(session_out.get(), session) ||
  113. BIO_flush(session_out.get()) <= 0) {
  114. fprintf(stderr, "Error while saving session:\n");
  115. ERR_print_errors_cb(PrintErrorCallback, stderr);
  116. return 0;
  117. }
  118. }
  119. return 0;
  120. }
  121. bool Client(const std::vector<std::string> &args) {
  122. if (!InitSocketLibrary()) {
  123. return false;
  124. }
  125. std::map<std::string, std::string> args_map;
  126. if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
  127. PrintUsage(kArguments);
  128. return false;
  129. }
  130. bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(SSLv23_client_method()));
  131. const char *keylog_file = getenv("SSLKEYLOGFILE");
  132. if (keylog_file) {
  133. g_keylog_file = fopen(keylog_file, "a");
  134. if (g_keylog_file == nullptr) {
  135. perror("fopen");
  136. return false;
  137. }
  138. SSL_CTX_set_keylog_callback(ctx.get(), KeyLogCallback);
  139. }
  140. if (args_map.count("-cipher") != 0 &&
  141. !SSL_CTX_set_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
  142. fprintf(stderr, "Failed setting cipher list\n");
  143. return false;
  144. }
  145. if (args_map.count("-max-version") != 0) {
  146. uint16_t version;
  147. if (!VersionFromString(&version, args_map["-max-version"])) {
  148. fprintf(stderr, "Unknown protocol version: '%s'\n",
  149. args_map["-max-version"].c_str());
  150. return false;
  151. }
  152. SSL_CTX_set_max_version(ctx.get(), version);
  153. }
  154. if (args_map.count("-min-version") != 0) {
  155. uint16_t version;
  156. if (!VersionFromString(&version, args_map["-min-version"])) {
  157. fprintf(stderr, "Unknown protocol version: '%s'\n",
  158. args_map["-min-version"].c_str());
  159. return false;
  160. }
  161. SSL_CTX_set_min_version(ctx.get(), version);
  162. }
  163. if (args_map.count("-select-next-proto") != 0) {
  164. const std::string &proto = args_map["-select-next-proto"];
  165. if (proto.size() > 255) {
  166. fprintf(stderr, "Bad NPN protocol: '%s'\n", proto.c_str());
  167. return false;
  168. }
  169. // |SSL_CTX_set_next_proto_select_cb| is not const-correct.
  170. SSL_CTX_set_next_proto_select_cb(ctx.get(), NextProtoSelectCallback,
  171. const_cast<char *>(proto.c_str()));
  172. }
  173. if (args_map.count("-alpn-protos") != 0) {
  174. const std::string &alpn_protos = args_map["-alpn-protos"];
  175. std::vector<uint8_t> wire;
  176. size_t i = 0;
  177. while (i <= alpn_protos.size()) {
  178. size_t j = alpn_protos.find(',', i);
  179. if (j == std::string::npos) {
  180. j = alpn_protos.size();
  181. }
  182. size_t len = j - i;
  183. if (len > 255) {
  184. fprintf(stderr, "Invalid ALPN protocols: '%s'\n", alpn_protos.c_str());
  185. return false;
  186. }
  187. wire.push_back(static_cast<uint8_t>(len));
  188. wire.resize(wire.size() + len);
  189. memcpy(wire.data() + wire.size() - len, alpn_protos.data() + i, len);
  190. i = j + 1;
  191. }
  192. if (SSL_CTX_set_alpn_protos(ctx.get(), wire.data(), wire.size()) != 0) {
  193. return false;
  194. }
  195. }
  196. if (args_map.count("-fallback-scsv") != 0) {
  197. SSL_CTX_set_mode(ctx.get(), SSL_MODE_SEND_FALLBACK_SCSV);
  198. }
  199. if (args_map.count("-ocsp-stapling") != 0) {
  200. SSL_CTX_enable_ocsp_stapling(ctx.get());
  201. }
  202. if (args_map.count("-signed-certificate-timestamps") != 0) {
  203. SSL_CTX_enable_signed_cert_timestamps(ctx.get());
  204. }
  205. if (args_map.count("-channel-id-key") != 0) {
  206. bssl::UniquePtr<EVP_PKEY> pkey =
  207. LoadPrivateKey(args_map["-channel-id-key"]);
  208. if (!pkey || !SSL_CTX_set1_tls_channel_id(ctx.get(), pkey.get())) {
  209. return false;
  210. }
  211. }
  212. if (args_map.count("-false-start") != 0) {
  213. SSL_CTX_set_mode(ctx.get(), SSL_MODE_ENABLE_FALSE_START);
  214. }
  215. if (args_map.count("-key") != 0) {
  216. const std::string &key = args_map["-key"];
  217. if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key.c_str(), SSL_FILETYPE_PEM)) {
  218. fprintf(stderr, "Failed to load private key: %s\n", key.c_str());
  219. return false;
  220. }
  221. if (!SSL_CTX_use_certificate_chain_file(ctx.get(), key.c_str())) {
  222. fprintf(stderr, "Failed to load cert chain: %s\n", key.c_str());
  223. return false;
  224. }
  225. }
  226. if (args_map.count("-session-out") != 0) {
  227. session_out.reset(BIO_new_file(args_map["-session-out"].c_str(), "wb"));
  228. if (!session_out) {
  229. fprintf(stderr, "Error while opening %s:\n",
  230. args_map["-session-out"].c_str());
  231. ERR_print_errors_cb(PrintErrorCallback, stderr);
  232. return false;
  233. }
  234. SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_CLIENT);
  235. SSL_CTX_sess_set_new_cb(ctx.get(), NewSessionCallback);
  236. }
  237. int sock = -1;
  238. if (!Connect(&sock, args_map["-connect"])) {
  239. return false;
  240. }
  241. if (args_map.count("-starttls") != 0) {
  242. const std::string& starttls = args_map["-starttls"];
  243. if (starttls == "smtp") {
  244. if (!DoSMTPStartTLS(sock)) {
  245. return false;
  246. }
  247. } else {
  248. fprintf(stderr, "Unknown value for -starttls: %s\n", starttls.c_str());
  249. return false;
  250. }
  251. }
  252. bssl::UniquePtr<BIO> bio(BIO_new_socket(sock, BIO_CLOSE));
  253. bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
  254. if (args_map.count("-server-name") != 0) {
  255. SSL_set_tlsext_host_name(ssl.get(), args_map["-server-name"].c_str());
  256. }
  257. if (args_map.count("-session-in") != 0) {
  258. bssl::UniquePtr<BIO> in(BIO_new_file(args_map["-session-in"].c_str(),
  259. "rb"));
  260. if (!in) {
  261. fprintf(stderr, "Error reading session\n");
  262. ERR_print_errors_cb(PrintErrorCallback, stderr);
  263. return false;
  264. }
  265. bssl::UniquePtr<SSL_SESSION> session(PEM_read_bio_SSL_SESSION(in.get(),
  266. nullptr, nullptr, nullptr));
  267. if (!session) {
  268. fprintf(stderr, "Error reading session\n");
  269. ERR_print_errors_cb(PrintErrorCallback, stderr);
  270. return false;
  271. }
  272. SSL_set_session(ssl.get(), session.get());
  273. }
  274. SSL_set_bio(ssl.get(), bio.get(), bio.get());
  275. bio.release();
  276. int ret = SSL_connect(ssl.get());
  277. if (ret != 1) {
  278. int ssl_err = SSL_get_error(ssl.get(), ret);
  279. fprintf(stderr, "Error while connecting: %d\n", ssl_err);
  280. ERR_print_errors_cb(PrintErrorCallback, stderr);
  281. return false;
  282. }
  283. fprintf(stderr, "Connected.\n");
  284. PrintConnectionInfo(ssl.get());
  285. bool ok = TransferData(ssl.get(), sock);
  286. return ok;
  287. }