LCOV - code coverage report
Current view: top level - test/core/tsi - transport_security_test.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 60 69 87.0 %
Date: 2015-10-10 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  * Copyright 2015, Google Inc.
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions are
       8             :  * met:
       9             :  *
      10             :  *     * Redistributions of source code must retain the above copyright
      11             :  * notice, this list of conditions and the following disclaimer.
      12             :  *     * Redistributions in binary form must reproduce the above
      13             :  * copyright notice, this list of conditions and the following disclaimer
      14             :  * in the documentation and/or other materials provided with the
      15             :  * distribution.
      16             :  *     * Neither the name of Google Inc. nor the names of its
      17             :  * contributors may be used to endorse or promote products derived from
      18             :  * this software without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      23             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      24             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      25             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      26             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      27             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      28             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      29             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      30             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      31             :  *
      32             :  */
      33             : 
      34             : #include "src/core/tsi/transport_security.h"
      35             : 
      36             : #include <string.h>
      37             : 
      38             : #include <grpc/support/alloc.h>
      39             : #include <grpc/support/log.h>
      40             : #include <grpc/support/string_util.h>
      41             : #include <grpc/support/useful.h>
      42             : 
      43             : #include <openssl/crypto.h>
      44             : 
      45             : #include "src/core/support/string.h"
      46             : #include "src/core/tsi/ssl_transport_security.h"
      47             : #include "test/core/util/test_config.h"
      48             : 
      49             : typedef struct {
      50             :   /* 1 if success, 0 if failure. */
      51             :   int expected;
      52             : 
      53             :   /* Host name to match. */
      54             :   const char *host_name;
      55             : 
      56             :   /* Common name (CN). */
      57             :   const char *common_name;
      58             : 
      59             :   /* Comma separated list of certificate names to match against. Any occurrence
      60             :      of '#' will be replaced with a null character before processing. */
      61             :   const char *dns_names;
      62             : 
      63             : } cert_name_test_entry;
      64             : 
      65             : /* Largely inspired from:
      66             :    chromium/src/net/cert/x509_certificate_unittest.cc.
      67             :    TODO(jboeuf) uncomment test cases as we fix tsi_ssl_peer_matches_name. */
      68             : const cert_name_test_entry cert_name_test_entries[] = {
      69             :     {1, "foo.com", "foo.com", NULL},
      70             :     {1, "f", "f", NULL},
      71             :     {0, "h", "i", NULL},
      72             :     {1, "bar.foo.com", "*.foo.com", NULL},
      73             :     {1, "www.test.fr", "common.name",
      74             :      "*.test.com,*.test.co.uk,*.test.de,*.test.fr"},
      75             :     /*
      76             :        {1, "wwW.tESt.fr", "common.name", ",*.*,*.test.de,*.test.FR,www"},
      77             :      */
      78             :     {0, "f.uk", ".uk", NULL},
      79             :     {0, "w.bar.foo.com", "?.bar.foo.com", NULL},
      80             :     {0, "www.foo.com", "(www|ftp).foo.com", NULL},
      81             :     {0, "www.foo.com", "www.foo.com#", NULL}, /* # = null char. */
      82             :     {0, "www.foo.com", "", "www.foo.com#*.foo.com,#,#"},
      83             :     {0, "www.house.example", "ww.house.example", NULL},
      84             :     {0, "test.org", "", "www.test.org,*.test.org,*.org"},
      85             :     {0, "w.bar.foo.com", "w*.bar.foo.com", NULL},
      86             :     {0, "www.bar.foo.com", "ww*ww.bar.foo.com", NULL},
      87             :     {0, "wwww.bar.foo.com", "ww*ww.bar.foo.com", NULL},
      88             :     {0, "wwww.bar.foo.com", "w*w.bar.foo.com", NULL},
      89             :     {0, "wwww.bar.foo.com", "w*w.bar.foo.c0m", NULL},
      90             :     {0, "WALLY.bar.foo.com", "wa*.bar.foo.com", NULL},
      91             :     {0, "wally.bar.foo.com", "*Ly.bar.foo.com", NULL},
      92             :     /*
      93             :        {1, "ww%57.foo.com", "", "www.foo.com"},
      94             :        {1, "www&.foo.com", "www%26.foo.com", NULL},
      95             :      */
      96             : 
      97             :     /* Common name must not be used if subject alternative name was provided. */
      98             :     {0, "www.test.co.jp", "www.test.co.jp",
      99             :      "*.test.de,*.jp,www.test.co.uk,www.*.co.jp"},
     100             :     {0, "www.bar.foo.com", "www.bar.foo.com",
     101             :      "*.foo.com,*.*.foo.com,*.*.bar.foo.com,*..bar.foo.com,"},
     102             : 
     103             :     /* IDN tests */
     104             :     {1, "xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br", NULL},
     105             :     {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL},
     106             :     {0, "xn--poema-9qae5a.com.br", "",
     107             :      "*.xn--poema-9qae5a.com.br,"
     108             :      "xn--poema-*.com.br,"
     109             :      "xn--*-9qae5a.com.br,"
     110             :      "*--poema-9qae5a.com.br"},
     111             : 
     112             :     /* The following are adapted from the  examples quoted from
     113             :        http://tools.ietf.org/html/rfc6125#section-6.4.3
     114             :        (e.g., *.example.com would match foo.example.com but
     115             :        not bar.foo.example.com or example.com). */
     116             :     {1, "foo.example.com", "*.example.com", NULL},
     117             :     {0, "bar.foo.example.com", "*.example.com", NULL},
     118             :     {0, "example.com", "*.example.com", NULL},
     119             : 
     120             :     /* Partial wildcards are disallowed, though RFC 2818 rules allow them.
     121             :        That is, forms such as baz*.example.net, *baz.example.net, and
     122             :        b*z.example.net should NOT match domains. Instead, the wildcard must
     123             :        always be the left-most label, and only a single label. */
     124             :     {0, "baz1.example.net", "baz*.example.net", NULL},
     125             :     {0, "foobaz.example.net", "*baz.example.net", NULL},
     126             :     {0, "buzz.example.net", "b*z.example.net", NULL},
     127             :     {0, "www.test.example.net", "www.*.example.net", NULL},
     128             : 
     129             :     /* Wildcards should not be valid for public registry controlled domains,
     130             :        and unknown/unrecognized domains, at least three domain components must
     131             :        be present. */
     132             :     {1, "www.test.example", "*.test.example", NULL},
     133             :     {1, "test.example.co.uk", "*.example.co.uk", NULL},
     134             :     {0, "test.example", "*.example", NULL},
     135             :     /*
     136             :        {0, "example.co.uk", "*.co.uk", NULL},
     137             :      */
     138             :     {0, "foo.com", "*.com", NULL},
     139             :     {0, "foo.us", "*.us", NULL},
     140             :     {0, "foo", "*", NULL},
     141             : 
     142             :     /* IDN variants of wildcards and registry controlled domains. */
     143             :     {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL},
     144             :     {1, "test.example.xn--mgbaam7a8h", "*.example.xn--mgbaam7a8h", NULL},
     145             :     /*
     146             :        {0, "xn--poema-9qae5a.com.br", "*.com.br", NULL},
     147             :      */
     148             :     {0, "example.xn--mgbaam7a8h", "*.xn--mgbaam7a8h", NULL},
     149             : 
     150             :     /* Wildcards should be permissible for 'private' registry controlled
     151             :        domains. */
     152             :     {1, "www.appspot.com", "*.appspot.com", NULL},
     153             :     {1, "foo.s3.amazonaws.com", "*.s3.amazonaws.com", NULL},
     154             : 
     155             :     /* Multiple wildcards are not valid. */
     156             :     {0, "foo.example.com", "*.*.com", NULL},
     157             :     {0, "foo.bar.example.com", "*.bar.*.com", NULL},
     158             : 
     159             :     /* Absolute vs relative DNS name tests. Although not explicitly specified
     160             :        in RFC 6125, absolute reference names (those ending in a .) should
     161             :        match either absolute or relative presented names. */
     162             :     {1, "foo.com", "foo.com.", NULL},
     163             :     {1, "foo.com.", "foo.com", NULL},
     164             :     {1, "foo.com.", "foo.com.", NULL},
     165             :     {1, "f", "f.", NULL},
     166             :     {1, "f.", "f", NULL},
     167             :     {1, "f.", "f.", NULL},
     168             :     {1, "www-3.bar.foo.com", "*.bar.foo.com.", NULL},
     169             :     {1, "www-3.bar.foo.com.", "*.bar.foo.com", NULL},
     170             :     {1, "www-3.bar.foo.com.", "*.bar.foo.com.", NULL},
     171             :     {0, ".", ".", NULL},
     172             :     {0, "example.com", "*.com.", NULL},
     173             :     {0, "example.com.", "*.com", NULL},
     174             :     {0, "example.com.", "*.com.", NULL},
     175             :     {0, "foo.", "*.", NULL},
     176             :     {0, "foo", "*.", NULL},
     177             :     /*
     178             :        {0, "foo.co.uk", "*.co.uk.", NULL},
     179             :        {0, "foo.co.uk.", "*.co.uk.", NULL},
     180             :      */
     181             : 
     182             :     /* An empty CN is OK. */
     183             :     {1, "test.foo.com", "", "test.foo.com"},
     184             : 
     185             :     /* An IP should not be used for the CN. */
     186             :     {0, "173.194.195.139", "173.194.195.139", NULL},
     187             : };
     188             : 
     189             : typedef struct name_list {
     190             :   const char *name;
     191             :   struct name_list *next;
     192             : } name_list;
     193             : 
     194             : typedef struct {
     195             :   size_t name_count;
     196             :   char *buffer;
     197             :   name_list *names;
     198             : } parsed_dns_names;
     199             : 
     200          24 : name_list *name_list_add(const char *n) {
     201          24 :   name_list *result = gpr_malloc(sizeof(name_list));
     202          24 :   result->name = n;
     203          24 :   result->next = NULL;
     204          24 :   return result;
     205             : }
     206             : 
     207          61 : static parsed_dns_names parse_dns_names(const char *dns_names_str) {
     208             :   parsed_dns_names result;
     209             :   name_list *current_nl;
     210             :   size_t i;
     211          61 :   memset(&result, 0, sizeof(parsed_dns_names));
     212          61 :   if (dns_names_str == 0) return result;
     213           7 :   result.name_count = 1;
     214           7 :   result.buffer = gpr_strdup(dns_names_str);
     215           7 :   result.names = name_list_add(result.buffer);
     216           7 :   current_nl = result.names;
     217         281 :   for (i = 0; i < strlen(dns_names_str); i++) {
     218         274 :     if (dns_names_str[i] == ',') {
     219          17 :       result.buffer[i] = '\0';
     220          17 :       result.name_count++;
     221          17 :       i++;
     222          17 :       current_nl->next = name_list_add(result.buffer + i);
     223          17 :       current_nl = current_nl->next;
     224             :     }
     225             :   }
     226           7 :   return result;
     227             : }
     228             : 
     229          61 : static void destruct_parsed_dns_names(parsed_dns_names *pdn) {
     230          61 :   name_list *nl = pdn->names;
     231          61 :   if (pdn->buffer != NULL) gpr_free(pdn->buffer);
     232         146 :   while (nl != NULL) {
     233          24 :     name_list *to_be_free = nl;
     234          24 :     nl = nl->next;
     235          24 :     gpr_free(to_be_free);
     236             :   }
     237          61 : }
     238             : 
     239          24 : static char *processed_dns_name(const char *dns_name) {
     240          24 :   char *result = gpr_strdup(dns_name);
     241             :   size_t i;
     242         288 :   for (i = 0; i < strlen(result); i++) {
     243         264 :     if (result[i] == '#') {
     244           3 :       result[i] = '\0';
     245             :     }
     246             :   }
     247          24 :   return result;
     248             : }
     249             : 
     250          61 : static tsi_peer peer_from_cert_name_test_entry(
     251             :     const cert_name_test_entry *entry) {
     252             :   size_t i;
     253             :   tsi_peer peer;
     254             :   name_list *nl;
     255          61 :   parsed_dns_names dns_entries = parse_dns_names(entry->dns_names);
     256          61 :   nl = dns_entries.names;
     257          61 :   GPR_ASSERT(tsi_construct_peer(1 + dns_entries.name_count, &peer) == TSI_OK);
     258          61 :   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
     259             :                  TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, entry->common_name,
     260             :                  &peer.properties[0]) == TSI_OK);
     261          61 :   i = 1;
     262         146 :   while (nl != NULL) {
     263          24 :     char *processed = processed_dns_name(nl->name);
     264          24 :     GPR_ASSERT(tsi_construct_string_peer_property(
     265             :                    TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, processed,
     266             :                    strlen(nl->name), &peer.properties[i++]) == TSI_OK);
     267          24 :     nl = nl->next;
     268          24 :     gpr_free(processed);
     269             :   }
     270          61 :   destruct_parsed_dns_names(&dns_entries);
     271          61 :   return peer;
     272             : }
     273             : 
     274           0 : char *cert_name_test_entry_to_string(const cert_name_test_entry *entry) {
     275             :   char *s;
     276           0 :   gpr_asprintf(
     277             :       &s, "{ success = %s, host_name = %s, common_name = %s, dns_names = %s}",
     278           0 :       entry->expected ? "true" : "false", entry->host_name, entry->common_name,
     279           0 :       entry->dns_names != NULL ? entry->dns_names : "");
     280           0 :   return s;
     281             : }
     282             : 
     283           1 : static void test_peer_matches_name(void) {
     284           1 :   size_t i = 0;
     285          62 :   for (i = 0; i < GPR_ARRAY_SIZE(cert_name_test_entries); i++) {
     286          61 :     const cert_name_test_entry *entry = &cert_name_test_entries[i];
     287          61 :     tsi_peer peer = peer_from_cert_name_test_entry(entry);
     288          61 :     int result = tsi_ssl_peer_matches_name(&peer, entry->host_name);
     289          61 :     if (result != entry->expected) {
     290           0 :       char *entry_str = cert_name_test_entry_to_string(entry);
     291           0 :       gpr_log(GPR_ERROR, "%s", entry_str);
     292           0 :       gpr_free(entry_str);
     293           0 :       GPR_ASSERT(0); /* Unexpected result. */
     294             :     }
     295          61 :     tsi_peer_destruct(&peer);
     296             :   }
     297           1 : }
     298             : 
     299           1 : int main(int argc, char **argv) {
     300           1 :   grpc_test_init(argc, argv);
     301           1 :   test_peer_matches_name();
     302           1 :   return 0;
     303             : }

Generated by: LCOV version 1.10