transport_security_test.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. *
  3. * Copyright 2015 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/tsi/transport_security.h"
  19. #include <string.h>
  20. #include <string>
  21. #include <openssl/crypto.h>
  22. #include "absl/strings/str_format.h"
  23. #include <grpc/support/alloc.h>
  24. #include <grpc/support/log.h>
  25. #include <grpc/support/string_util.h>
  26. #include "src/core/lib/gpr/string.h"
  27. #include "src/core/lib/gpr/useful.h"
  28. #include "src/core/tsi/fake_transport_security.h"
  29. #include "src/core/tsi/ssl_transport_security.h"
  30. #include "test/core/util/test_config.h"
  31. typedef struct {
  32. /* 1 if success, 0 if failure. */
  33. int expected;
  34. /* Host name to match. */
  35. const char* host_name;
  36. /* Common name (CN). */
  37. const char* common_name;
  38. /* Comma separated list of certificate names to match against. Any occurrence
  39. of '#' will be replaced with a null character before processing. */
  40. const char* dns_names;
  41. /* Comma separated list of IP SANs to match aggainst */
  42. const char* ip_names;
  43. } cert_name_test_entry;
  44. /* Largely inspired from:
  45. chromium/src/net/cert/x509_certificate_unittest.cc.
  46. TODO(jboeuf) uncomment test cases as we fix tsi_ssl_peer_matches_name. */
  47. const cert_name_test_entry cert_name_test_entries[] = {
  48. {1, "foo.com", "foo.com", nullptr, nullptr},
  49. {1, "f", "f", nullptr, nullptr},
  50. {0, "h", "i", nullptr, nullptr},
  51. {1, "bar.foo.com", "*.foo.com", nullptr, nullptr},
  52. {1, "www.test.fr", "common.name",
  53. "*.test.com,*.test.co.uk,*.test.de,*.test.fr", nullptr},
  54. /*
  55. {1, "wwW.tESt.fr", "common.name", ",*.*,*.test.de,*.test.FR,www"},
  56. */
  57. {0, "f.uk", ".uk", nullptr, nullptr},
  58. {0, "w.bar.foo.com", "?.bar.foo.com", nullptr, nullptr},
  59. {0, "www.foo.com", "(www|ftp).foo.com", nullptr, nullptr},
  60. {0, "www.foo.com", "www.foo.com#", nullptr, nullptr}, /* # = null char. */
  61. {0, "www.foo.com", "", "www.foo.com#*.foo.com,#,#", nullptr},
  62. {0, "www.house.example", "ww.house.example", nullptr, nullptr},
  63. {0, "test.org", "", "www.test.org,*.test.org,*.org", nullptr},
  64. {0, "w.bar.foo.com", "w*.bar.foo.com", nullptr, nullptr},
  65. {0, "www.bar.foo.com", "ww*ww.bar.foo.com", nullptr, nullptr},
  66. {0, "wwww.bar.foo.com", "ww*ww.bar.foo.com", nullptr, nullptr},
  67. {0, "wwww.bar.foo.com", "w*w.bar.foo.com", nullptr, nullptr},
  68. {0, "wwww.bar.foo.com", "w*w.bar.foo.c0m", nullptr, nullptr},
  69. {0, "WALLY.bar.foo.com", "wa*.bar.foo.com", nullptr, nullptr},
  70. {0, "wally.bar.foo.com", "*Ly.bar.foo.com", nullptr, nullptr},
  71. /*
  72. {1, "ww%57.foo.com", "", "www.foo.com"},
  73. {1, "www&.foo.com", "www%26.foo.com", NULL},
  74. */
  75. /* Common name must not be used if subject alternative name was provided. */
  76. {0, "www.test.co.jp", "www.test.co.jp",
  77. "*.test.de,*.jp,www.test.co.uk,www.*.co.jp", nullptr},
  78. {0, "www.bar.foo.com", "www.bar.foo.com",
  79. "*.foo.com,*.*.foo.com,*.*.bar.foo.com,*..bar.foo.com,", nullptr},
  80. /* IDN tests */
  81. {1, "xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br", nullptr, nullptr},
  82. {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", nullptr,
  83. nullptr},
  84. {0, "xn--poema-9qae5a.com.br", "",
  85. "*.xn--poema-9qae5a.com.br,"
  86. "xn--poema-*.com.br,"
  87. "xn--*-9qae5a.com.br,"
  88. "*--poema-9qae5a.com.br",
  89. nullptr},
  90. /* The following are adapted from the examples quoted from
  91. http://tools.ietf.org/html/rfc6125#section-6.4.3
  92. (e.g., *.example.com would match foo.example.com but
  93. not bar.foo.example.com or example.com). */
  94. {1, "foo.example.com", "*.example.com", nullptr, nullptr},
  95. {0, "bar.foo.example.com", "*.example.com", nullptr, nullptr},
  96. {0, "example.com", "*.example.com", nullptr, nullptr},
  97. /* Partial wildcards are disallowed, though RFC 2818 rules allow them.
  98. That is, forms such as baz*.example.net, *baz.example.net, and
  99. b*z.example.net should NOT match domains. Instead, the wildcard must
  100. always be the left-most label, and only a single label. */
  101. {0, "baz1.example.net", "baz*.example.net", nullptr, nullptr},
  102. {0, "foobaz.example.net", "*baz.example.net", nullptr, nullptr},
  103. {0, "buzz.example.net", "b*z.example.net", nullptr, nullptr},
  104. {0, "www.test.example.net", "www.*.example.net", nullptr, nullptr},
  105. /* Wildcards should not be valid for public registry controlled domains,
  106. and unknown/unrecognized domains, at least three domain components must
  107. be present. */
  108. {1, "www.test.example", "*.test.example", nullptr, nullptr},
  109. {1, "test.example.co.uk", "*.example.co.uk", nullptr, nullptr},
  110. {0, "test.example", "*.example", nullptr, nullptr},
  111. /*
  112. {0, "example.co.uk", "*.co.uk", NULL},
  113. */
  114. {0, "foo.com", "*.com", nullptr, nullptr},
  115. {0, "foo.us", "*.us", nullptr, nullptr},
  116. {0, "foo", "*", nullptr, nullptr},
  117. /* IDN variants of wildcards and registry controlled domains. */
  118. {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", nullptr,
  119. nullptr},
  120. {1, "test.example.xn--mgbaam7a8h", "*.example.xn--mgbaam7a8h", nullptr,
  121. nullptr},
  122. /*
  123. {0, "xn--poema-9qae5a.com.br", "*.com.br", NULL},
  124. */
  125. {0, "example.xn--mgbaam7a8h", "*.xn--mgbaam7a8h", nullptr, nullptr},
  126. /* Wildcards should be permissible for 'private' registry controlled
  127. domains. */
  128. {1, "www.appspot.com", "*.appspot.com", nullptr, nullptr},
  129. {1, "foo.s3.amazonaws.com", "*.s3.amazonaws.com", nullptr, nullptr},
  130. /* Multiple wildcards are not valid. */
  131. {0, "foo.example.com", "*.*.com", nullptr, nullptr},
  132. {0, "foo.bar.example.com", "*.bar.*.com", nullptr, nullptr},
  133. /* Absolute vs relative DNS name tests. Although not explicitly specified
  134. in RFC 6125, absolute reference names (those ending in a .) should
  135. match either absolute or relative presented names. */
  136. {1, "foo.com", "foo.com.", nullptr, nullptr},
  137. {1, "foo.com.", "foo.com", nullptr, nullptr},
  138. {1, "foo.com.", "foo.com.", nullptr, nullptr},
  139. {1, "f", "f.", nullptr, nullptr},
  140. {1, "f.", "f", nullptr, nullptr},
  141. {1, "f.", "f.", nullptr, nullptr},
  142. {1, "www-3.bar.foo.com", "*.bar.foo.com.", nullptr, nullptr},
  143. {1, "www-3.bar.foo.com.", "*.bar.foo.com", nullptr, nullptr},
  144. {1, "www-3.bar.foo.com.", "*.bar.foo.com.", nullptr, nullptr},
  145. {0, ".", ".", nullptr, nullptr},
  146. {0, "example.com", "*.com.", nullptr, nullptr},
  147. {0, "example.com.", "*.com", nullptr, nullptr},
  148. {0, "example.com.", "*.com.", nullptr, nullptr},
  149. {0, "foo.", "*.", nullptr, nullptr},
  150. {0, "foo", "*.", nullptr, nullptr},
  151. /*
  152. {0, "foo.co.uk", "*.co.uk.", NULL},
  153. {0, "foo.co.uk.", "*.co.uk.", NULL},
  154. */
  155. /* An empty CN is OK. */
  156. {1, "test.foo.com", "", "test.foo.com", nullptr},
  157. /* An IP should not be used for the CN. */
  158. {0, "173.194.195.139", "173.194.195.139", nullptr, nullptr},
  159. /* An IP can be used if the SAN IP is present */
  160. {1, "173.194.195.139", "foo.example.com", nullptr, "173.194.195.139"},
  161. {0, "173.194.195.139", "foo.example.com", nullptr, "8.8.8.8"},
  162. {0, "173.194.195.139", "foo.example.com", nullptr, "8.8.8.8,8.8.4.4"},
  163. {1, "173.194.195.139", "foo.example.com", nullptr,
  164. "8.8.8.8,173.194.195.139"},
  165. {0, "173.194.195.139", "foo.example.com", nullptr, "173.194.195.13"},
  166. {0, "2001:db8:a0b:12f0::1", "foo.example.com", nullptr, "173.194.195.13"},
  167. {1, "2001:db8:a0b:12f0::1", "foo.example.com", nullptr,
  168. "2001:db8:a0b:12f0::1"},
  169. {0, "2001:db8:a0b:12f0::1", "foo.example.com", nullptr,
  170. "2001:db8:a0b:12f0::2"},
  171. {1, "2001:db8:a0b:12f0::1", "foo.example.com", nullptr,
  172. "2001:db8:a0b:12f0::2,2001:db8:a0b:12f0::1,8.8.8.8"},
  173. };
  174. typedef struct name_list {
  175. const char* name;
  176. struct name_list* next;
  177. } name_list;
  178. typedef struct {
  179. size_t name_count;
  180. char* buffer;
  181. name_list* names;
  182. } parsed_names;
  183. name_list* name_list_add(const char* n) {
  184. name_list* result = static_cast<name_list*>(gpr_malloc(sizeof(name_list)));
  185. result->name = n;
  186. result->next = nullptr;
  187. return result;
  188. }
  189. static parsed_names parse_names(const char* names_str) {
  190. parsed_names result;
  191. name_list* current_nl;
  192. size_t i;
  193. memset(&result, 0, sizeof(parsed_names));
  194. if (names_str == nullptr) return result;
  195. result.name_count = 1;
  196. result.buffer = gpr_strdup(names_str);
  197. result.names = name_list_add(result.buffer);
  198. current_nl = result.names;
  199. for (i = 0; i < strlen(names_str); i++) {
  200. if (names_str[i] == ',') {
  201. result.buffer[i] = '\0';
  202. result.name_count++;
  203. i++;
  204. current_nl->next = name_list_add(result.buffer + i);
  205. current_nl = current_nl->next;
  206. }
  207. }
  208. return result;
  209. }
  210. static void destruct_parsed_names(parsed_names* pdn) {
  211. name_list* nl = pdn->names;
  212. if (pdn->buffer != nullptr) gpr_free(pdn->buffer);
  213. while (nl != nullptr) {
  214. name_list* to_be_free = nl;
  215. nl = nl->next;
  216. gpr_free(to_be_free);
  217. }
  218. }
  219. static char* processed_name(const char* name) {
  220. char* result = gpr_strdup(name);
  221. size_t i;
  222. for (i = 0; i < strlen(result); i++) {
  223. if (result[i] == '#') {
  224. result[i] = '\0';
  225. }
  226. }
  227. return result;
  228. }
  229. static tsi_peer peer_from_cert_name_test_entry(
  230. const cert_name_test_entry* entry) {
  231. size_t i;
  232. tsi_peer peer;
  233. name_list* nl;
  234. parsed_names dns_entries = parse_names(entry->dns_names);
  235. parsed_names ip_entries = parse_names(entry->ip_names);
  236. nl = dns_entries.names;
  237. GPR_ASSERT(tsi_construct_peer(
  238. 1 + dns_entries.name_count + ip_entries.name_count, &peer) ==
  239. TSI_OK);
  240. GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
  241. TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, entry->common_name,
  242. &peer.properties[0]) == TSI_OK);
  243. i = 1;
  244. while (nl != nullptr) {
  245. char* processed = processed_name(nl->name);
  246. GPR_ASSERT(tsi_construct_string_peer_property(
  247. TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, processed,
  248. strlen(nl->name), &peer.properties[i++]) == TSI_OK);
  249. nl = nl->next;
  250. gpr_free(processed);
  251. }
  252. nl = ip_entries.names;
  253. while (nl != nullptr) {
  254. char* processed = processed_name(nl->name);
  255. GPR_ASSERT(tsi_construct_string_peer_property(
  256. TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, processed,
  257. strlen(nl->name), &peer.properties[i++]) == TSI_OK);
  258. nl = nl->next;
  259. gpr_free(processed);
  260. }
  261. destruct_parsed_names(&dns_entries);
  262. destruct_parsed_names(&ip_entries);
  263. return peer;
  264. }
  265. std::string cert_name_test_entry_to_string(const cert_name_test_entry* entry) {
  266. return absl::StrFormat(
  267. "{ success = %s, host_name = %s, common_name = %s, dns_names = "
  268. "%s, ip_names = %s}",
  269. entry->expected ? "true" : "false", entry->host_name, entry->common_name,
  270. entry->dns_names != nullptr ? entry->dns_names : "",
  271. entry->ip_names != nullptr ? entry->ip_names : "");
  272. }
  273. static void test_peer_matches_name(void) {
  274. size_t i = 0;
  275. for (i = 0; i < GPR_ARRAY_SIZE(cert_name_test_entries); i++) {
  276. const cert_name_test_entry* entry = &cert_name_test_entries[i];
  277. tsi_peer peer = peer_from_cert_name_test_entry(entry);
  278. int result = tsi_ssl_peer_matches_name(&peer, entry->host_name);
  279. if (result != entry->expected) {
  280. gpr_log(GPR_ERROR, "%s", cert_name_test_entry_to_string(entry).c_str());
  281. GPR_ASSERT(0); /* Unexpected result. */
  282. }
  283. tsi_peer_destruct(&peer);
  284. }
  285. }
  286. typedef struct {
  287. tsi_result res;
  288. const char* str;
  289. } tsi_result_string_pair;
  290. static void test_result_strings(void) {
  291. const tsi_result_string_pair results[] = {
  292. {TSI_OK, "TSI_OK"},
  293. {TSI_UNKNOWN_ERROR, "TSI_UNKNOWN_ERROR"},
  294. {TSI_INVALID_ARGUMENT, "TSI_INVALID_ARGUMENT"},
  295. {TSI_PERMISSION_DENIED, "TSI_PERMISSION_DENIED"},
  296. {TSI_INCOMPLETE_DATA, "TSI_INCOMPLETE_DATA"},
  297. {TSI_FAILED_PRECONDITION, "TSI_FAILED_PRECONDITION"},
  298. {TSI_UNIMPLEMENTED, "TSI_UNIMPLEMENTED"},
  299. {TSI_INTERNAL_ERROR, "TSI_INTERNAL_ERROR"},
  300. {TSI_DATA_CORRUPTED, "TSI_DATA_CORRUPTED"},
  301. {TSI_NOT_FOUND, "TSI_NOT_FOUND"},
  302. {TSI_PROTOCOL_FAILURE, "TSI_PROTOCOL_FAILURE"},
  303. {TSI_HANDSHAKE_IN_PROGRESS, "TSI_HANDSHAKE_IN_PROGRESS"},
  304. {TSI_OUT_OF_RESOURCES, "TSI_OUT_OF_RESOURCES"}};
  305. size_t i;
  306. for (i = 0; i < GPR_ARRAY_SIZE(results); i++) {
  307. GPR_ASSERT(strcmp(results[i].str, tsi_result_to_string(results[i].res)) ==
  308. 0);
  309. }
  310. GPR_ASSERT(strcmp("UNKNOWN", tsi_result_to_string((tsi_result)42)) == 0);
  311. }
  312. static void test_protector_invalid_args(void) {
  313. GPR_ASSERT(tsi_frame_protector_protect(nullptr, nullptr, nullptr, nullptr,
  314. nullptr) == TSI_INVALID_ARGUMENT);
  315. GPR_ASSERT(tsi_frame_protector_protect_flush(
  316. nullptr, nullptr, nullptr, nullptr) == TSI_INVALID_ARGUMENT);
  317. GPR_ASSERT(tsi_frame_protector_unprotect(nullptr, nullptr, nullptr, nullptr,
  318. nullptr) == TSI_INVALID_ARGUMENT);
  319. }
  320. static void test_handshaker_invalid_args(void) {
  321. GPR_ASSERT(tsi_handshaker_get_result(nullptr) == TSI_INVALID_ARGUMENT);
  322. GPR_ASSERT(tsi_handshaker_extract_peer(nullptr, nullptr) ==
  323. TSI_INVALID_ARGUMENT);
  324. GPR_ASSERT(tsi_handshaker_create_frame_protector(nullptr, nullptr, nullptr) ==
  325. TSI_INVALID_ARGUMENT);
  326. GPR_ASSERT(tsi_handshaker_process_bytes_from_peer(
  327. nullptr, nullptr, nullptr) == TSI_INVALID_ARGUMENT);
  328. GPR_ASSERT(tsi_handshaker_get_bytes_to_send_to_peer(
  329. nullptr, nullptr, nullptr) == TSI_INVALID_ARGUMENT);
  330. GPR_ASSERT(tsi_handshaker_next(nullptr, nullptr, 0, nullptr, nullptr, nullptr,
  331. nullptr, nullptr) == TSI_INVALID_ARGUMENT);
  332. }
  333. static void test_handshaker_invalid_state(void) {
  334. tsi_handshaker* h = tsi_create_fake_handshaker(0);
  335. tsi_peer peer;
  336. tsi_frame_protector* p;
  337. GPR_ASSERT(tsi_handshaker_extract_peer(h, &peer) == TSI_FAILED_PRECONDITION);
  338. GPR_ASSERT(tsi_handshaker_create_frame_protector(h, nullptr, &p) ==
  339. TSI_FAILED_PRECONDITION);
  340. tsi_handshaker_destroy(h);
  341. }
  342. int main(int argc, char** argv) {
  343. grpc::testing::TestEnvironment env(argc, argv);
  344. test_peer_matches_name();
  345. test_result_strings();
  346. test_protector_invalid_args();
  347. test_handshaker_invalid_args();
  348. test_handshaker_invalid_state();
  349. return 0;
  350. }