3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <grpc/grpc_security.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/log.h>
25 #include <grpc/support/string_util.h>
27 #include "src/core/lib/gpr/env.h"
28 #include "src/core/lib/gpr/string.h"
29 #include "src/core/lib/gpr/tmpfile.h"
30 #include "src/core/lib/gprpp/ref_counted_ptr.h"
31 #include "src/core/lib/security/context/security_context.h"
32 #include "src/core/lib/security/security_connector/security_connector.h"
33 #include "src/core/lib/security/security_connector/ssl_utils.h"
34 #include "src/core/lib/slice/slice_string_helpers.h"
35 #include "src/core/tsi/ssl_transport_security.h"
36 #include "src/core/tsi/transport_security.h"
37 #include "test/core/util/test_config.h"
39 #ifndef TSI_OPENSSL_ALPN_SUPPORT
40 #define TSI_OPENSSL_ALPN_SUPPORT 1
43 static int check_transport_security_type(const grpc_auth_context* ctx) {
44 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
45 ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
46 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
47 if (prop == nullptr) return 0;
48 if (strncmp(prop->value, GRPC_SSL_TRANSPORT_SECURITY_TYPE,
49 prop->value_length) != 0) {
52 /* Check that we have only one property with this name. */
53 if (grpc_auth_property_iterator_next(&it) != nullptr) return 0;
57 static int check_peer_property(const tsi_peer* peer,
58 const tsi_peer_property* expected) {
60 for (i = 0; i < peer->property_count; i++) {
61 const tsi_peer_property* prop = &peer->properties[i];
62 if ((strcmp(prop->name, expected->name) == 0) &&
63 (prop->value.length == expected->value.length) &&
64 (memcmp(prop->value.data, expected->value.data,
65 expected->value.length) == 0)) {
69 return 0; /* Not found... */
72 static int check_ssl_peer_equivalence(const tsi_peer* original,
73 const tsi_peer* reconstructed) {
74 /* The reconstructed peer only has CN, SAN and pem cert properties. */
76 for (i = 0; i < original->property_count; i++) {
77 const tsi_peer_property* prop = &original->properties[i];
78 if ((strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) ||
79 (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
81 (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0)) {
82 if (!check_peer_property(reconstructed, prop)) return 0;
88 static void test_unauthenticated_ssl_peer(void) {
91 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
92 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
93 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
94 &peer.properties[0]) == TSI_OK);
95 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
96 grpc_ssl_peer_to_auth_context(&peer);
97 GPR_ASSERT(ctx != nullptr);
98 GPR_ASSERT(!grpc_auth_context_peer_is_authenticated(ctx.get()));
99 GPR_ASSERT(check_transport_security_type(ctx.get()));
101 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get());
102 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
104 grpc_shallow_peer_destruct(&rpeer);
105 tsi_peer_destruct(&peer);
106 ctx.reset(DEBUG_LOCATION, "test");
109 static int check_identity(const grpc_auth_context* ctx,
110 const char* expected_property_name,
111 const char** expected_identities,
112 size_t num_identities) {
113 grpc_auth_property_iterator it;
114 const grpc_auth_property* prop;
116 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
117 it = grpc_auth_context_peer_identity(ctx);
118 for (i = 0; i < num_identities; i++) {
119 prop = grpc_auth_property_iterator_next(&it);
120 if (prop == nullptr) {
121 gpr_log(GPR_ERROR, "Expected identity value %s not found.",
122 expected_identities[i]);
125 if (strcmp(prop->name, expected_property_name) != 0) {
126 gpr_log(GPR_ERROR, "Expected peer identity property name %s and got %s.",
127 expected_property_name, prop->name);
130 if (strncmp(prop->value, expected_identities[i], prop->value_length) != 0) {
131 gpr_log(GPR_ERROR, "Expected peer identity %s and got %s.",
132 expected_identities[i], prop->value);
139 static int check_x509_cn(const grpc_auth_context* ctx,
140 const char* expected_cn) {
141 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
142 ctx, GRPC_X509_CN_PROPERTY_NAME);
143 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
144 if (prop == nullptr) {
145 gpr_log(GPR_ERROR, "CN property not found.");
148 if (strncmp(prop->value, expected_cn, prop->value_length) != 0) {
149 gpr_log(GPR_ERROR, "Expected CN %s and got %s", expected_cn, prop->value);
152 if (grpc_auth_property_iterator_next(&it) != nullptr) {
153 gpr_log(GPR_ERROR, "Expected only one property for CN.");
159 static int check_x509_pem_cert(const grpc_auth_context* ctx,
160 const char* expected_pem_cert) {
161 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
162 ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
163 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
164 if (prop == nullptr) {
165 gpr_log(GPR_ERROR, "Pem certificate property not found.");
168 if (strncmp(prop->value, expected_pem_cert, prop->value_length) != 0) {
169 gpr_log(GPR_ERROR, "Expected pem cert %s and got %s", expected_pem_cert,
173 if (grpc_auth_property_iterator_next(&it) != nullptr) {
174 gpr_log(GPR_ERROR, "Expected only one property for pem cert.");
180 static void test_cn_only_ssl_peer_to_auth_context(void) {
183 const char* expected_cn = "cn1";
184 const char* expected_pem_cert = "pem_cert1";
185 GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK);
186 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
187 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
188 &peer.properties[0]) == TSI_OK);
189 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
190 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
191 &peer.properties[1]) == TSI_OK);
192 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
193 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
194 &peer.properties[2]) == TSI_OK);
195 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
196 grpc_ssl_peer_to_auth_context(&peer);
197 GPR_ASSERT(ctx != nullptr);
198 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get()));
200 check_identity(ctx.get(), GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1));
201 GPR_ASSERT(check_transport_security_type(ctx.get()));
202 GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn));
203 GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert));
205 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get());
206 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
208 grpc_shallow_peer_destruct(&rpeer);
209 tsi_peer_destruct(&peer);
210 ctx.reset(DEBUG_LOCATION, "test");
213 static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
216 const char* expected_cn = "cn1";
217 const char* expected_san = "san1";
218 const char* expected_pem_cert = "pem_cert1";
219 GPR_ASSERT(tsi_construct_peer(4, &peer) == TSI_OK);
220 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
221 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
222 &peer.properties[0]) == TSI_OK);
223 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
224 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
225 &peer.properties[1]) == TSI_OK);
226 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
227 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san,
228 &peer.properties[2]) == TSI_OK);
229 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
230 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
231 &peer.properties[3]) == TSI_OK);
233 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
234 grpc_ssl_peer_to_auth_context(&peer);
235 GPR_ASSERT(ctx != nullptr);
236 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get()));
238 check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1));
239 GPR_ASSERT(check_transport_security_type(ctx.get()));
240 GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn));
241 GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert));
243 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get());
244 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
246 grpc_shallow_peer_destruct(&rpeer);
247 tsi_peer_destruct(&peer);
248 ctx.reset(DEBUG_LOCATION, "test");
251 static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
254 const char* expected_cn = "cn1";
255 const char* expected_sans[] = {"san1", "san2", "san3"};
256 const char* expected_pem_cert = "pem_cert1";
258 GPR_ASSERT(tsi_construct_peer(3 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
260 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
261 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
262 &peer.properties[0]) == TSI_OK);
263 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
264 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
265 &peer.properties[1]) == TSI_OK);
266 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
267 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
268 &peer.properties[2]) == TSI_OK);
269 for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
270 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
271 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
272 expected_sans[i], &peer.properties[3 + i]) == TSI_OK);
274 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
275 grpc_ssl_peer_to_auth_context(&peer);
276 GPR_ASSERT(ctx != nullptr);
277 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get()));
278 GPR_ASSERT(check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME,
279 expected_sans, GPR_ARRAY_SIZE(expected_sans)));
280 GPR_ASSERT(check_transport_security_type(ctx.get()));
281 GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn));
282 GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert));
284 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get());
285 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
287 grpc_shallow_peer_destruct(&rpeer);
288 tsi_peer_destruct(&peer);
289 ctx.reset(DEBUG_LOCATION, "test");
292 static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
296 const char* expected_cn = "cn1";
297 const char* expected_pem_cert = "pem_cert1";
298 const char* expected_sans[] = {"san1", "san2", "san3"};
300 GPR_ASSERT(tsi_construct_peer(5 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
302 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
303 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
304 &peer.properties[0]) == TSI_OK);
305 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
306 "foo", "bar", &peer.properties[1]) == TSI_OK);
307 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
308 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
309 &peer.properties[2]) == TSI_OK);
310 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
311 "chapi", "chapo", &peer.properties[3]) == TSI_OK);
312 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
313 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
314 &peer.properties[4]) == TSI_OK);
315 for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
316 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
317 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
318 expected_sans[i], &peer.properties[5 + i]) == TSI_OK);
320 grpc_core::RefCountedPtr<grpc_auth_context> ctx =
321 grpc_ssl_peer_to_auth_context(&peer);
322 GPR_ASSERT(ctx != nullptr);
323 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx.get()));
324 GPR_ASSERT(check_identity(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME,
325 expected_sans, GPR_ARRAY_SIZE(expected_sans)));
326 GPR_ASSERT(check_transport_security_type(ctx.get()));
327 GPR_ASSERT(check_x509_cn(ctx.get(), expected_cn));
328 GPR_ASSERT(check_x509_pem_cert(ctx.get(), expected_pem_cert));
330 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx.get());
331 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
333 grpc_shallow_peer_destruct(&rpeer);
334 tsi_peer_destruct(&peer);
335 ctx.reset(DEBUG_LOCATION, "test");
338 static const char* roots_for_override_api = "roots for override api";
340 static grpc_ssl_roots_override_result override_roots_success(
341 char** pem_root_certs) {
342 *pem_root_certs = gpr_strdup(roots_for_override_api);
343 return GRPC_SSL_ROOTS_OVERRIDE_OK;
346 static grpc_ssl_roots_override_result override_roots_permanent_failure(
347 char** pem_root_certs) {
348 return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
351 static void test_ipv6_address_san(void) {
352 const char* addresses[] = {
353 "2001:db8::1", "fe80::abcd:ef65:4321%em0", "fd11:feed:beef:0:cafe::4",
354 "128.10.0.1:8888", "[2001:db8::1]:8080", "[2001:db8::1%em1]:8080",
356 const char* san_ips[] = {
357 "2001:db8::1", "fe80::abcd:ef65:4321", "fd11:feed:beef:0:cafe::4",
358 "128.10.0.1", "2001:db8::1", "2001:db8::1",
361 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
362 for (size_t i = 0; i < GPR_ARRAY_SIZE(addresses); i++) {
363 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
364 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, san_ips[i],
365 &peer.properties[0]) == TSI_OK);
366 GPR_ASSERT(grpc_ssl_host_matches_name(&peer, addresses[i]));
367 tsi_peer_property_destruct(&peer.properties[0]);
369 tsi_peer_destruct(&peer);
371 namespace grpc_core {
374 class TestDefaultSslRootStore : public DefaultSslRootStore {
376 static grpc_slice ComputePemRootCertsForTesting() {
377 return ComputePemRootCerts();
382 } // namespace grpc_core
384 // TODO: Convert this test to C++ test when security_connector implementation
385 // is converted to C++.
386 static void test_default_ssl_roots(void) {
387 const char* roots_for_env_var = "roots for env var";
389 char* roots_env_var_file_path;
390 FILE* roots_env_var_file =
391 gpr_tmpfile("test_roots_for_env_var", &roots_env_var_file_path);
392 fwrite(roots_for_env_var, 1, strlen(roots_for_env_var), roots_env_var_file);
393 fclose(roots_env_var_file);
395 /* First let's get the root through the override: set the env to an invalid
397 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
398 grpc_set_ssl_roots_override_callback(override_roots_success);
400 grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
401 char* roots_contents = grpc_slice_to_c_string(roots);
402 grpc_slice_unref(roots);
403 GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
404 gpr_free(roots_contents);
406 /* Now let's set the env var: We should get the contents pointed value
408 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
409 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
410 roots_contents = grpc_slice_to_c_string(roots);
411 grpc_slice_unref(roots);
412 GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
413 gpr_free(roots_contents);
415 /* Now reset the env var. We should fall back to the value overridden using
417 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
418 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
419 roots_contents = grpc_slice_to_c_string(roots);
420 grpc_slice_unref(roots);
421 GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
422 gpr_free(roots_contents);
424 /* Now setup a permanent failure for the overridden roots and we should get
426 gpr_setenv("GRPC_NOT_USE_SYSTEM_SSL_ROOTS", "true");
427 grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
428 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
429 GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
430 const tsi_ssl_root_certs_store* root_store =
431 grpc_core::TestDefaultSslRootStore::GetRootStore();
432 GPR_ASSERT(root_store == nullptr);
435 remove(roots_env_var_file_path);
436 gpr_free(roots_env_var_file_path);
439 static void test_peer_alpn_check(void) {
440 #if TSI_OPENSSL_ALPN_SUPPORT
442 const char* alpn = "grpc";
443 const char* wrong_alpn = "wrong";
444 // peer does not have a TSI_SSL_ALPN_SELECTED_PROTOCOL property.
445 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
446 GPR_ASSERT(tsi_construct_string_peer_property("wrong peer property name",
448 &peer.properties[0]) == TSI_OK);
449 grpc_error* error = grpc_ssl_check_alpn(&peer);
450 GPR_ASSERT(error != GRPC_ERROR_NONE);
451 tsi_peer_destruct(&peer);
452 GRPC_ERROR_UNREF(error);
453 // peer has a TSI_SSL_ALPN_SELECTED_PROTOCOL property but with an incorrect
455 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
456 GPR_ASSERT(tsi_construct_string_peer_property(TSI_SSL_ALPN_SELECTED_PROTOCOL,
457 wrong_alpn, strlen(wrong_alpn),
458 &peer.properties[0]) == TSI_OK);
459 error = grpc_ssl_check_alpn(&peer);
460 GPR_ASSERT(error != GRPC_ERROR_NONE);
461 tsi_peer_destruct(&peer);
462 GRPC_ERROR_UNREF(error);
463 // peer has a TSI_SSL_ALPN_SELECTED_PROTOCOL property with a correct property
465 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
466 GPR_ASSERT(tsi_construct_string_peer_property(TSI_SSL_ALPN_SELECTED_PROTOCOL,
468 &peer.properties[0]) == TSI_OK);
469 GPR_ASSERT(grpc_ssl_check_alpn(&peer) == GRPC_ERROR_NONE);
470 tsi_peer_destruct(&peer);
472 GPR_ASSERT(grpc_ssl_check_alpn(nullptr) == GRPC_ERROR_NONE);
476 int main(int argc, char** argv) {
477 grpc::testing::TestEnvironment env(argc, argv);
480 test_unauthenticated_ssl_peer();
481 test_cn_only_ssl_peer_to_auth_context();
482 test_cn_and_one_san_ssl_peer_to_auth_context();
483 test_cn_and_multiple_sans_ssl_peer_to_auth_context();
484 test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
485 test_ipv6_address_san();
486 test_default_ssl_roots();
487 test_peer_alpn_check();