client_ssl.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. *
  3. * Copyright 2016 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include "src/core/lib/iomgr/port.h"
  19. // This test won't work except with posix sockets enabled
  20. #ifdef GRPC_POSIX_SOCKET_TCP
  21. #include <arpa/inet.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <sys/socket.h>
  25. #include <unistd.h>
  26. #include <string>
  27. #include <openssl/err.h>
  28. #include <openssl/ssl.h>
  29. #include "absl/strings/str_cat.h"
  30. #include <grpc/grpc.h>
  31. #include <grpc/grpc_security.h>
  32. #include <grpc/support/alloc.h>
  33. #include <grpc/support/log.h>
  34. #include "src/core/lib/debug/trace.h"
  35. #include "src/core/lib/gprpp/sync.h"
  36. #include "src/core/lib/gprpp/thd.h"
  37. #include "src/core/lib/iomgr/load_file.h"
  38. #include "test/core/util/port.h"
  39. #include "test/core/util/test_config.h"
  40. #define SSL_CERT_PATH "src/core/tsi/test_creds/server1.pem"
  41. #define SSL_KEY_PATH "src/core/tsi/test_creds/server1.key"
  42. #define SSL_CA_PATH "src/core/tsi/test_creds/ca.pem"
  43. grpc_core::TraceFlag client_ssl_tsi_tracing_enabled(false, "tsi");
  44. class SslLibraryInfo {
  45. public:
  46. SslLibraryInfo() {}
  47. void Notify() {
  48. grpc_core::MutexLock lock(&mu_);
  49. ready_ = true;
  50. cv_.Signal();
  51. }
  52. void Await() {
  53. grpc_core::MutexLock lock(&mu_);
  54. while (!ready_) {
  55. cv_.Wait(&mu_);
  56. }
  57. }
  58. private:
  59. grpc_core::Mutex mu_;
  60. grpc_core::CondVar cv_;
  61. bool ready_ ABSL_GUARDED_BY(mu_) = false;
  62. };
  63. // Arguments for TLS server thread.
  64. typedef struct {
  65. int socket;
  66. char* alpn_preferred;
  67. SslLibraryInfo* ssl_library_info;
  68. } server_args;
  69. // Based on https://wiki.openssl.org/index.php/Simple_TLS_Server.
  70. // Pick an arbitrary unused port and return it in *out_port. Return
  71. // an fd>=0 on success.
  72. static int create_socket(int* out_port) {
  73. int s;
  74. struct sockaddr_in addr;
  75. socklen_t addr_len;
  76. *out_port = -1;
  77. addr.sin_family = AF_INET;
  78. addr.sin_port = 0;
  79. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  80. s = socket(AF_INET, SOCK_STREAM, 0);
  81. if (s < 0) {
  82. perror("Unable to create socket");
  83. return -1;
  84. }
  85. if (bind(s, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
  86. perror("Unable to bind");
  87. gpr_log(GPR_ERROR, "%s", "Unable to bind to any port");
  88. close(s);
  89. return -1;
  90. }
  91. if (listen(s, 1) < 0) {
  92. perror("Unable to listen");
  93. close(s);
  94. return -1;
  95. }
  96. addr_len = sizeof(addr);
  97. if (getsockname(s, reinterpret_cast<struct sockaddr*>(&addr), &addr_len) !=
  98. 0 ||
  99. addr_len > sizeof(addr)) {
  100. perror("getsockname");
  101. gpr_log(GPR_ERROR, "%s", "Unable to get socket local address");
  102. close(s);
  103. return -1;
  104. }
  105. *out_port = ntohs(addr.sin_port);
  106. return s;
  107. }
  108. // Server callback during ALPN negotiation. See man page for
  109. // SSL_CTX_set_alpn_select_cb.
  110. static int alpn_select_cb(SSL* /*ssl*/, const uint8_t** out, uint8_t* out_len,
  111. const uint8_t* in, unsigned in_len, void* arg) {
  112. const uint8_t* alpn_preferred = static_cast<const uint8_t*>(arg);
  113. *out = alpn_preferred;
  114. *out_len = static_cast<uint8_t>(
  115. strlen(reinterpret_cast<const char*>(alpn_preferred)));
  116. // Validate that the ALPN list includes "h2" and "grpc-exp", that "grpc-exp"
  117. // precedes "h2".
  118. bool grpc_exp_seen = false;
  119. bool h2_seen = false;
  120. const char* inp = reinterpret_cast<const char*>(in);
  121. const char* in_end = inp + in_len;
  122. while (inp < in_end) {
  123. const size_t length = static_cast<size_t>(*inp++);
  124. if (length == strlen("grpc-exp") && strncmp(inp, "grpc-exp", length) == 0) {
  125. grpc_exp_seen = true;
  126. GPR_ASSERT(!h2_seen);
  127. }
  128. if (length == strlen("h2") && strncmp(inp, "h2", length) == 0) {
  129. h2_seen = true;
  130. GPR_ASSERT(grpc_exp_seen);
  131. }
  132. inp += length;
  133. }
  134. GPR_ASSERT(inp == in_end);
  135. GPR_ASSERT(grpc_exp_seen);
  136. GPR_ASSERT(h2_seen);
  137. return SSL_TLSEXT_ERR_OK;
  138. }
  139. static void ssl_log_where_info(const SSL* ssl, int where, int flag,
  140. const char* msg) {
  141. if ((where & flag) &&
  142. GRPC_TRACE_FLAG_ENABLED(client_ssl_tsi_tracing_enabled)) {
  143. gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg,
  144. SSL_state_string_long(ssl), SSL_state_string(ssl));
  145. }
  146. }
  147. static void ssl_server_info_callback(const SSL* ssl, int where, int ret) {
  148. if (ret == 0) {
  149. gpr_log(GPR_ERROR, "ssl_server_info_callback: error occurred.\n");
  150. return;
  151. }
  152. ssl_log_where_info(ssl, where, SSL_CB_LOOP, "Server: LOOP");
  153. ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START,
  154. "Server: HANDSHAKE START");
  155. ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE,
  156. "Server: HANDSHAKE DONE");
  157. }
  158. // Minimal TLS server. This is largely based on the example at
  159. // https://wiki.openssl.org/index.php/Simple_TLS_Server and the gRPC core
  160. // internals in src/core/tsi/ssl_transport_security.c.
  161. static void server_thread(void* arg) {
  162. const server_args* args = static_cast<server_args*>(arg);
  163. SSL_load_error_strings();
  164. OpenSSL_add_ssl_algorithms();
  165. args->ssl_library_info->Notify();
  166. const SSL_METHOD* method = TLSv1_2_server_method();
  167. SSL_CTX* ctx = SSL_CTX_new(method);
  168. if (!ctx) {
  169. perror("Unable to create SSL context");
  170. ERR_print_errors_fp(stderr);
  171. abort();
  172. }
  173. // Load key pair.
  174. if (SSL_CTX_use_certificate_file(ctx, SSL_CERT_PATH, SSL_FILETYPE_PEM) < 0) {
  175. perror("Unable to use certificate file.");
  176. ERR_print_errors_fp(stderr);
  177. abort();
  178. }
  179. if (SSL_CTX_use_PrivateKey_file(ctx, SSL_KEY_PATH, SSL_FILETYPE_PEM) < 0) {
  180. perror("Unable to use private key file.");
  181. ERR_print_errors_fp(stderr);
  182. abort();
  183. }
  184. if (SSL_CTX_check_private_key(ctx) != 1) {
  185. perror("Check private key failed.");
  186. ERR_print_errors_fp(stderr);
  187. abort();
  188. }
  189. // Set the cipher list to match the one expressed in
  190. // src/core/tsi/ssl_transport_security.cc.
  191. const char* cipher_list =
  192. "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-"
  193. "SHA384:ECDHE-RSA-AES256-GCM-SHA384";
  194. if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
  195. ERR_print_errors_fp(stderr);
  196. gpr_log(GPR_ERROR, "Couldn't set server cipher list.");
  197. abort();
  198. }
  199. // Enable automatic curve selection. This is a NO-OP when using OpenSSL
  200. // versions > 1.0.2.
  201. if (!SSL_CTX_set_ecdh_auto(ctx, /*onoff=*/1)) {
  202. ERR_print_errors_fp(stderr);
  203. gpr_log(GPR_ERROR, "Couldn't set automatic curve selection.");
  204. abort();
  205. }
  206. // Register the ALPN selection callback.
  207. SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, args->alpn_preferred);
  208. // bind/listen/accept at TCP layer.
  209. const int sock = args->socket;
  210. gpr_log(GPR_INFO, "Server listening");
  211. struct sockaddr_in addr;
  212. socklen_t len = sizeof(addr);
  213. const int client =
  214. accept(sock, reinterpret_cast<struct sockaddr*>(&addr), &len);
  215. if (client < 0) {
  216. perror("Unable to accept");
  217. abort();
  218. }
  219. // Establish a SSL* and accept at SSL layer.
  220. SSL* ssl = SSL_new(ctx);
  221. SSL_set_info_callback(ssl, ssl_server_info_callback);
  222. GPR_ASSERT(ssl);
  223. SSL_set_fd(ssl, client);
  224. if (SSL_accept(ssl) <= 0) {
  225. ERR_print_errors_fp(stderr);
  226. gpr_log(GPR_ERROR, "Handshake failed.");
  227. } else {
  228. gpr_log(GPR_INFO, "Handshake successful.");
  229. }
  230. // Send out the settings frame.
  231. const char settings_frame[] = "\x00\x00\x00\x04\x00\x00\x00\x00\x00";
  232. SSL_write(ssl, settings_frame, sizeof(settings_frame) - 1);
  233. // Wait until the client drops its connection.
  234. char buf;
  235. while (SSL_read(ssl, &buf, sizeof(buf)) > 0) {
  236. }
  237. SSL_free(ssl);
  238. close(client);
  239. close(sock);
  240. SSL_CTX_free(ctx);
  241. }
  242. // This test launches a minimal TLS server on a separate thread and then
  243. // establishes a TLS handshake via the core library to the server. The TLS
  244. // server validates ALPN aspects of the handshake and supplies the protocol
  245. // specified in the server_alpn_preferred argument to the client.
  246. static bool client_ssl_test(char* server_alpn_preferred) {
  247. bool success = true;
  248. grpc_init();
  249. // Find a port we can bind to. Retries added to handle flakes in port server
  250. // and port picking.
  251. int port = -1;
  252. int server_socket = -1;
  253. int socket_retries = 30;
  254. while (server_socket == -1 && socket_retries-- > 0) {
  255. server_socket = create_socket(&port);
  256. if (server_socket == -1) {
  257. sleep(1);
  258. }
  259. }
  260. GPR_ASSERT(server_socket > 0 && port > 0);
  261. // Launch the TLS server thread.
  262. SslLibraryInfo ssl_library_info;
  263. server_args args = {server_socket, server_alpn_preferred, &ssl_library_info};
  264. bool ok;
  265. grpc_core::Thread thd("grpc_client_ssl_test", server_thread, &args, &ok);
  266. GPR_ASSERT(ok);
  267. thd.Start();
  268. ssl_library_info.Await();
  269. // Load key pair and establish client SSL credentials.
  270. grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
  271. grpc_slice ca_slice, cert_slice, key_slice;
  272. GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
  273. grpc_load_file(SSL_CA_PATH, 1, &ca_slice)));
  274. GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
  275. grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
  276. GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
  277. grpc_load_file(SSL_KEY_PATH, 1, &key_slice)));
  278. const char* ca_cert =
  279. reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
  280. pem_key_cert_pair.private_key =
  281. reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
  282. pem_key_cert_pair.cert_chain =
  283. reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
  284. grpc_channel_credentials* ssl_creds = grpc_ssl_credentials_create(
  285. ca_cert, &pem_key_cert_pair, nullptr, nullptr);
  286. // Establish a channel pointing at the TLS server. Since the gRPC runtime is
  287. // lazy, this won't necessarily establish a connection yet.
  288. std::string target = absl::StrCat("127.0.0.1:", port);
  289. grpc_arg ssl_name_override = {
  290. GRPC_ARG_STRING,
  291. const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
  292. {const_cast<char*>("foo.test.google.fr")}};
  293. grpc_channel_args grpc_args;
  294. grpc_args.num_args = 1;
  295. grpc_args.args = &ssl_name_override;
  296. grpc_channel* channel =
  297. grpc_channel_create(target.c_str(), ssl_creds, &grpc_args);
  298. GPR_ASSERT(channel);
  299. // Initially the channel will be idle, the
  300. // grpc_channel_check_connectivity_state triggers an attempt to connect.
  301. GPR_ASSERT(grpc_channel_check_connectivity_state(
  302. channel, 1 /* try_to_connect */) == GRPC_CHANNEL_IDLE);
  303. // Wait a bounded number of times for the channel to be ready. When the
  304. // channel is ready, the initial TLS handshake will have successfully
  305. // completed and we know that the client's ALPN list satisfied the server.
  306. int retries = 10;
  307. grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
  308. grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
  309. while (state != GRPC_CHANNEL_READY && retries-- > 0) {
  310. grpc_channel_watch_connectivity_state(
  311. channel, state, grpc_timeout_seconds_to_deadline(3), cq, nullptr);
  312. gpr_timespec cq_deadline = grpc_timeout_seconds_to_deadline(5);
  313. grpc_event ev = grpc_completion_queue_next(cq, cq_deadline, nullptr);
  314. GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
  315. state =
  316. grpc_channel_check_connectivity_state(channel, 0 /* try_to_connect */);
  317. }
  318. grpc_completion_queue_destroy(cq);
  319. if (retries < 0) {
  320. success = false;
  321. }
  322. grpc_channel_destroy(channel);
  323. grpc_channel_credentials_release(ssl_creds);
  324. grpc_slice_unref(cert_slice);
  325. grpc_slice_unref(key_slice);
  326. grpc_slice_unref(ca_slice);
  327. thd.Join();
  328. grpc_shutdown();
  329. return success;
  330. }
  331. int main(int argc, char* argv[]) {
  332. grpc::testing::TestEnvironment env(argc, argv);
  333. // Handshake succeeeds when the server has grpc-exp as the ALPN preference.
  334. GPR_ASSERT(client_ssl_test(const_cast<char*>("grpc-exp")));
  335. // Handshake succeeeds when the server has h2 as the ALPN preference. This
  336. // covers legacy gRPC servers which don't support grpc-exp.
  337. GPR_ASSERT(client_ssl_test(const_cast<char*>("h2")));
  338. // Handshake fails when the server uses a fake protocol as its ALPN
  339. // preference. This validates the client is correctly validating ALPN returns
  340. // and sanity checks the client_ssl_test.
  341. GPR_ASSERT(!client_ssl_test(const_cast<char*>("foo")));
  342. // Clean up the SSL libraries.
  343. EVP_cleanup();
  344. return 0;
  345. }
  346. #else /* GRPC_POSIX_SOCKET_TCP */
  347. int main(int argc, char** argv) { return 1; }
  348. #endif /* GRPC_POSIX_SOCKET_TCP */