• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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