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
19 #include <stdio.h>
20 #include <string.h>
21
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>
26
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/security/context/security_context.h"
31 #include "src/core/lib/security/security_connector/security_connector.h"
32 #include "src/core/lib/slice/slice_string_helpers.h"
33 #include "src/core/tsi/ssl_transport_security.h"
34 #include "src/core/tsi/transport_security.h"
35 #include "test/core/util/test_config.h"
36
check_transport_security_type(const grpc_auth_context * ctx)37 static int check_transport_security_type(const grpc_auth_context* ctx) {
38 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
39 ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
40 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
41 if (prop == nullptr) return 0;
42 if (strncmp(prop->value, GRPC_SSL_TRANSPORT_SECURITY_TYPE,
43 prop->value_length) != 0) {
44 return 0;
45 }
46 /* Check that we have only one property with this name. */
47 if (grpc_auth_property_iterator_next(&it) != nullptr) return 0;
48 return 1;
49 }
50
check_peer_property(const tsi_peer * peer,const tsi_peer_property * expected)51 static int check_peer_property(const tsi_peer* peer,
52 const tsi_peer_property* expected) {
53 size_t i;
54 for (i = 0; i < peer->property_count; i++) {
55 const tsi_peer_property* prop = &peer->properties[i];
56 if ((strcmp(prop->name, expected->name) == 0) &&
57 (prop->value.length == expected->value.length) &&
58 (memcmp(prop->value.data, expected->value.data,
59 expected->value.length) == 0)) {
60 return 1;
61 }
62 }
63 return 0; /* Not found... */
64 }
65
check_ssl_peer_equivalence(const tsi_peer * original,const tsi_peer * reconstructed)66 static int check_ssl_peer_equivalence(const tsi_peer* original,
67 const tsi_peer* reconstructed) {
68 /* The reconstructed peer only has CN, SAN and pem cert properties. */
69 size_t i;
70 for (i = 0; i < original->property_count; i++) {
71 const tsi_peer_property* prop = &original->properties[i];
72 if ((strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) ||
73 (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
74 0) ||
75 (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0)) {
76 if (!check_peer_property(reconstructed, prop)) return 0;
77 }
78 }
79 return 1;
80 }
81
test_unauthenticated_ssl_peer(void)82 static void test_unauthenticated_ssl_peer(void) {
83 tsi_peer peer;
84 tsi_peer rpeer;
85 grpc_auth_context* ctx;
86 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
87 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
88 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
89 &peer.properties[0]) == TSI_OK);
90 ctx = grpc_ssl_peer_to_auth_context(&peer);
91 GPR_ASSERT(ctx != nullptr);
92 GPR_ASSERT(!grpc_auth_context_peer_is_authenticated(ctx));
93 GPR_ASSERT(check_transport_security_type(ctx));
94
95 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx);
96 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
97
98 grpc_shallow_peer_destruct(&rpeer);
99 tsi_peer_destruct(&peer);
100 GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
101 }
102
check_identity(const grpc_auth_context * ctx,const char * expected_property_name,const char ** expected_identities,size_t num_identities)103 static int check_identity(const grpc_auth_context* ctx,
104 const char* expected_property_name,
105 const char** expected_identities,
106 size_t num_identities) {
107 grpc_auth_property_iterator it;
108 const grpc_auth_property* prop;
109 size_t i;
110 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
111 it = grpc_auth_context_peer_identity(ctx);
112 for (i = 0; i < num_identities; i++) {
113 prop = grpc_auth_property_iterator_next(&it);
114 if (prop == nullptr) {
115 gpr_log(GPR_ERROR, "Expected identity value %s not found.",
116 expected_identities[i]);
117 return 0;
118 }
119 if (strcmp(prop->name, expected_property_name) != 0) {
120 gpr_log(GPR_ERROR, "Expected peer identity property name %s and got %s.",
121 expected_property_name, prop->name);
122 return 0;
123 }
124 if (strncmp(prop->value, expected_identities[i], prop->value_length) != 0) {
125 gpr_log(GPR_ERROR, "Expected peer identity %s and got %s.",
126 expected_identities[i], prop->value);
127 return 0;
128 }
129 }
130 return 1;
131 }
132
check_x509_cn(const grpc_auth_context * ctx,const char * expected_cn)133 static int check_x509_cn(const grpc_auth_context* ctx,
134 const char* expected_cn) {
135 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
136 ctx, GRPC_X509_CN_PROPERTY_NAME);
137 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
138 if (prop == nullptr) {
139 gpr_log(GPR_ERROR, "CN property not found.");
140 return 0;
141 }
142 if (strncmp(prop->value, expected_cn, prop->value_length) != 0) {
143 gpr_log(GPR_ERROR, "Expected CN %s and got %s", expected_cn, prop->value);
144 return 0;
145 }
146 if (grpc_auth_property_iterator_next(&it) != nullptr) {
147 gpr_log(GPR_ERROR, "Expected only one property for CN.");
148 return 0;
149 }
150 return 1;
151 }
152
check_x509_pem_cert(const grpc_auth_context * ctx,const char * expected_pem_cert)153 static int check_x509_pem_cert(const grpc_auth_context* ctx,
154 const char* expected_pem_cert) {
155 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
156 ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
157 const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
158 if (prop == nullptr) {
159 gpr_log(GPR_ERROR, "Pem certificate property not found.");
160 return 0;
161 }
162 if (strncmp(prop->value, expected_pem_cert, prop->value_length) != 0) {
163 gpr_log(GPR_ERROR, "Expected pem cert %s and got %s", expected_pem_cert,
164 prop->value);
165 return 0;
166 }
167 if (grpc_auth_property_iterator_next(&it) != nullptr) {
168 gpr_log(GPR_ERROR, "Expected only one property for pem cert.");
169 return 0;
170 }
171 return 1;
172 }
173
test_cn_only_ssl_peer_to_auth_context(void)174 static void test_cn_only_ssl_peer_to_auth_context(void) {
175 tsi_peer peer;
176 tsi_peer rpeer;
177 grpc_auth_context* ctx;
178 const char* expected_cn = "cn1";
179 const char* expected_pem_cert = "pem_cert1";
180 GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK);
181 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
182 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
183 &peer.properties[0]) == TSI_OK);
184 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
185 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
186 &peer.properties[1]) == TSI_OK);
187 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
188 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
189 &peer.properties[2]) == TSI_OK);
190 ctx = grpc_ssl_peer_to_auth_context(&peer);
191 GPR_ASSERT(ctx != nullptr);
192 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
193 GPR_ASSERT(check_identity(ctx, GRPC_X509_CN_PROPERTY_NAME, &expected_cn, 1));
194 GPR_ASSERT(check_transport_security_type(ctx));
195 GPR_ASSERT(check_x509_cn(ctx, expected_cn));
196 GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
197
198 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx);
199 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
200
201 grpc_shallow_peer_destruct(&rpeer);
202 tsi_peer_destruct(&peer);
203 GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
204 }
205
test_cn_and_one_san_ssl_peer_to_auth_context(void)206 static void test_cn_and_one_san_ssl_peer_to_auth_context(void) {
207 tsi_peer peer;
208 tsi_peer rpeer;
209 grpc_auth_context* ctx;
210 const char* expected_cn = "cn1";
211 const char* expected_san = "san1";
212 const char* expected_pem_cert = "pem_cert1";
213 GPR_ASSERT(tsi_construct_peer(4, &peer) == TSI_OK);
214 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
215 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
216 &peer.properties[0]) == TSI_OK);
217 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
218 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
219 &peer.properties[1]) == TSI_OK);
220 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
221 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san,
222 &peer.properties[2]) == TSI_OK);
223 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
224 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
225 &peer.properties[3]) == TSI_OK);
226 ctx = grpc_ssl_peer_to_auth_context(&peer);
227 GPR_ASSERT(ctx != nullptr);
228 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
229 GPR_ASSERT(
230 check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, &expected_san, 1));
231 GPR_ASSERT(check_transport_security_type(ctx));
232 GPR_ASSERT(check_x509_cn(ctx, expected_cn));
233 GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
234
235 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx);
236 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
237
238 grpc_shallow_peer_destruct(&rpeer);
239 tsi_peer_destruct(&peer);
240 GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
241 }
242
test_cn_and_multiple_sans_ssl_peer_to_auth_context(void)243 static void test_cn_and_multiple_sans_ssl_peer_to_auth_context(void) {
244 tsi_peer peer;
245 tsi_peer rpeer;
246 grpc_auth_context* ctx;
247 const char* expected_cn = "cn1";
248 const char* expected_sans[] = {"san1", "san2", "san3"};
249 const char* expected_pem_cert = "pem_cert1";
250 size_t i;
251 GPR_ASSERT(tsi_construct_peer(3 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
252 TSI_OK);
253 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
254 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
255 &peer.properties[0]) == TSI_OK);
256 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
257 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
258 &peer.properties[1]) == TSI_OK);
259 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
260 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
261 &peer.properties[2]) == TSI_OK);
262 for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
263 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
264 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
265 expected_sans[i], &peer.properties[3 + i]) == TSI_OK);
266 }
267 ctx = grpc_ssl_peer_to_auth_context(&peer);
268 GPR_ASSERT(ctx != nullptr);
269 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
270 GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans,
271 GPR_ARRAY_SIZE(expected_sans)));
272 GPR_ASSERT(check_transport_security_type(ctx));
273 GPR_ASSERT(check_x509_cn(ctx, expected_cn));
274 GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
275
276 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx);
277 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
278
279 grpc_shallow_peer_destruct(&rpeer);
280 tsi_peer_destruct(&peer);
281 GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
282 }
283
test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(void)284 static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(
285 void) {
286 tsi_peer peer;
287 tsi_peer rpeer;
288 grpc_auth_context* ctx;
289 const char* expected_cn = "cn1";
290 const char* expected_pem_cert = "pem_cert1";
291 const char* expected_sans[] = {"san1", "san2", "san3"};
292 size_t i;
293 GPR_ASSERT(tsi_construct_peer(5 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
294 TSI_OK);
295 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
296 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
297 &peer.properties[0]) == TSI_OK);
298 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
299 "foo", "bar", &peer.properties[1]) == TSI_OK);
300 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
301 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, expected_cn,
302 &peer.properties[2]) == TSI_OK);
303 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
304 "chapi", "chapo", &peer.properties[3]) == TSI_OK);
305 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
306 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
307 &peer.properties[4]) == TSI_OK);
308 for (i = 0; i < GPR_ARRAY_SIZE(expected_sans); i++) {
309 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
310 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
311 expected_sans[i], &peer.properties[5 + i]) == TSI_OK);
312 }
313 ctx = grpc_ssl_peer_to_auth_context(&peer);
314 GPR_ASSERT(ctx != nullptr);
315 GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
316 GPR_ASSERT(check_identity(ctx, GRPC_X509_SAN_PROPERTY_NAME, expected_sans,
317 GPR_ARRAY_SIZE(expected_sans)));
318 GPR_ASSERT(check_transport_security_type(ctx));
319 GPR_ASSERT(check_x509_cn(ctx, expected_cn));
320 GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
321
322 rpeer = grpc_shallow_peer_from_ssl_auth_context(ctx);
323 GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
324
325 grpc_shallow_peer_destruct(&rpeer);
326 tsi_peer_destruct(&peer);
327 GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
328 }
329
330 static const char* roots_for_override_api = "roots for override api";
331
override_roots_success(char ** pem_root_certs)332 static grpc_ssl_roots_override_result override_roots_success(
333 char** pem_root_certs) {
334 *pem_root_certs = gpr_strdup(roots_for_override_api);
335 return GRPC_SSL_ROOTS_OVERRIDE_OK;
336 }
337
override_roots_permanent_failure(char ** pem_root_certs)338 static grpc_ssl_roots_override_result override_roots_permanent_failure(
339 char** pem_root_certs) {
340 return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
341 }
342
test_ipv6_address_san(void)343 static void test_ipv6_address_san(void) {
344 const char* addresses[] = {
345 "2001:db8::1", "fe80::abcd:ef65:4321%em0", "fd11:feed:beef:0:cafe::4",
346 "128.10.0.1:8888", "[2001:db8::1]:8080", "[2001:db8::1%em1]:8080",
347 };
348 const char* san_ips[] = {
349 "2001:db8::1", "fe80::abcd:ef65:4321", "fd11:feed:beef:0:cafe::4",
350 "128.10.0.1", "2001:db8::1", "2001:db8::1",
351 };
352 tsi_peer peer;
353 GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
354 for (size_t i = 0; i < GPR_ARRAY_SIZE(addresses); i++) {
355 GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
356 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, san_ips[i],
357 &peer.properties[0]) == TSI_OK);
358 GPR_ASSERT(grpc_ssl_host_matches_name(&peer, addresses[i]));
359 tsi_peer_property_destruct(&peer.properties[0]);
360 }
361 tsi_peer_destruct(&peer);
362 }
363 namespace grpc_core {
364 namespace {
365
366 class TestDefaultSslRootStore : public DefaultSslRootStore {
367 public:
ComputePemRootCertsForTesting()368 static grpc_slice ComputePemRootCertsForTesting() {
369 return ComputePemRootCerts();
370 }
371 };
372
373 } // namespace
374 } // namespace grpc_core
375
376 // TODO: Convert this test to C++ test when security_connector implementation
377 // is converted to C++.
test_default_ssl_roots(void)378 static void test_default_ssl_roots(void) {
379 const char* roots_for_env_var = "roots for env var";
380
381 char* roots_env_var_file_path;
382 FILE* roots_env_var_file =
383 gpr_tmpfile("test_roots_for_env_var", &roots_env_var_file_path);
384 fwrite(roots_for_env_var, 1, strlen(roots_for_env_var), roots_env_var_file);
385 fclose(roots_env_var_file);
386
387 /* First let's get the root through the override: set the env to an invalid
388 value. */
389 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
390 grpc_set_ssl_roots_override_callback(override_roots_success);
391 grpc_slice roots =
392 grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
393 char* roots_contents = grpc_slice_to_c_string(roots);
394 grpc_slice_unref(roots);
395 GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
396 gpr_free(roots_contents);
397
398 /* Now let's set the env var: We should get the contents pointed value
399 instead. */
400 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
401 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
402 roots_contents = grpc_slice_to_c_string(roots);
403 grpc_slice_unref(roots);
404 GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
405 gpr_free(roots_contents);
406
407 /* Now reset the env var. We should fall back to the value overridden using
408 the api. */
409 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
410 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
411 roots_contents = grpc_slice_to_c_string(roots);
412 grpc_slice_unref(roots);
413 GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
414 gpr_free(roots_contents);
415
416 /* Now setup a permanent failure for the overridden roots and we should get
417 an empty slice. */
418 gpr_setenv("GRPC_NOT_USE_SYSTEM_SSL_ROOTS", "true");
419 grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
420 roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting();
421 GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
422 const tsi_ssl_root_certs_store* root_store =
423 grpc_core::TestDefaultSslRootStore::GetRootStore();
424 GPR_ASSERT(root_store == nullptr);
425
426 /* Cleanup. */
427 remove(roots_env_var_file_path);
428 gpr_free(roots_env_var_file_path);
429 }
430
main(int argc,char ** argv)431 int main(int argc, char** argv) {
432 grpc_test_init(argc, argv);
433 grpc_init();
434
435 test_unauthenticated_ssl_peer();
436 test_cn_only_ssl_peer_to_auth_context();
437 test_cn_and_one_san_ssl_peer_to_auth_context();
438 test_cn_and_multiple_sans_ssl_peer_to_auth_context();
439 test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
440 test_ipv6_address_san();
441 test_default_ssl_roots();
442
443 grpc_shutdown();
444 return 0;
445 }
446