]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support for e-mail constraints.
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 19 Feb 2014 09:01:49 +0000 (10:01 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 19 Feb 2014 09:01:49 +0000 (10:01 +0100)
lib/x509/name_constraints.c
tests/name-constraints.c
tests/suppressions.valgrind

index dd07e6fe9d41a206369bdfa7fd3203f4e4ba340a..2c0da148e6b8ab538f18a20b70aa8b72ce98f176 100644 (file)
@@ -481,9 +481,28 @@ unsigned ends_with(const gnutls_datum_t * str, const gnutls_datum_t * suffix)
        return 0;
 }
 
+static
+unsigned email_ends_with(const gnutls_datum_t * str, const gnutls_datum_t * suffix)
+{
+       if (suffix->size >= str->size)
+               return 0;
+
+       if (suffix->size > 1 && suffix->data[0] == '.') {
+               /* .domain.com */
+               if (memcmp(str->data + str->size - suffix->size, suffix->data, suffix->size) == 0)
+                       return 1;
+       } else {
+               if (memcmp(str->data + str->size - suffix->size, suffix->data, suffix->size) == 0 &&
+                       str->data[str->size - suffix->size -1] == '@')
+                       return 1;
+       }
+
+       return 0;
+}
+
 static unsigned dnsname_matches(const gnutls_datum_t *name, const gnutls_datum_t *suffix)
 {
-       _gnutls_hard_log("matching %.*s with constraint %.*s\n", name->size, name->data,
+       _gnutls_hard_log("matching %.*s with DNS constraint %.*s\n", name->size, name->data,
                suffix->size, suffix->data);
 
        if (suffix->size == name->size && memcmp(suffix->data, name->data, suffix->size) == 0)
@@ -492,6 +511,17 @@ static unsigned dnsname_matches(const gnutls_datum_t *name, const gnutls_datum_t
        return ends_with(name, suffix);
 }
 
+static unsigned email_matches(const gnutls_datum_t *name, const gnutls_datum_t *suffix)
+{
+       _gnutls_hard_log("matching %.*s with e-mail constraint %.*s\n", name->size, name->data,
+               suffix->size, suffix->data);
+
+       if (suffix->size == name->size && memcmp(suffix->data, name->data, suffix->size) == 0)
+               return 1; /* match */
+
+       return email_ends_with(name, suffix);
+}
+
 static
 unsigned check_unsupported_constraint(gnutls_x509_name_constraints_t nc,
                                       gnutls_x509_subject_alt_name_t type)
@@ -519,22 +549,8 @@ gnutls_datum_t rname;
        return 1;
 }
 
-/**
- * gnutls_x509_name_constraints_check:
- * @nc: the extracted name constraints structure
- * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
- * @name: the name to be checked
- *
- * This function will check the provided name against the constraints in
- * @nc using the RFC5280 rules. Currently this function is limited to DNS
- * names (of type %GNUTLS_SAN_DNSNAME).
- *
- * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
- *
- * Since: 3.3.0
- **/
-unsigned gnutls_x509_name_constraints_check(gnutls_x509_name_constraints_t nc,
-                                      gnutls_x509_subject_alt_name_t type,
+static
+unsigned check_dns_constraints(gnutls_x509_name_constraints_t nc,
                                       const gnutls_datum_t * name)
 {
 unsigned i;
@@ -543,47 +559,127 @@ unsigned rtype;
 unsigned allowed_found = 0;
 gnutls_datum_t rname;
 
-       if (type != GNUTLS_SAN_DNSNAME)
-               return check_unsupported_constraint(nc, type);
+       /* check restrictions */
+       i = 0;
+       do {
+               ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype, &rname);
+               if (ret >= 0) {
+                       if (rtype != GNUTLS_SAN_DNSNAME)
+                               continue;
+
+                       /* a name of value 0 means that the CA shouldn't have issued
+                        * a certificate with a DNSNAME. */
+                       if (rname.size == 0)
+                               return gnutls_assert_val(0);
+
+                       if (dnsname_matches(name, &rname) != 0)
+                               return gnutls_assert_val(0); /* rejected */
+               }
+       } while(ret == 0);
+
+       /* check allowed */
+       i = 0;
+       do {
+               ret = gnutls_x509_name_constraints_get_permitted(nc, i++, &rtype, &rname);
+               if (ret >= 0) {
+                       if (rtype != GNUTLS_SAN_DNSNAME)
+                               continue;
+
+                       if (rname.size == 0)
+                               continue;
+
+                       allowed_found = 1;
+
+                       if (dnsname_matches(name, &rname) != 0)
+                               return 1; /* accepted */
+               }
+       } while(ret == 0);
+
+       if (allowed_found != 0) /* there are allowed directives but this host wasn't found */
+               return gnutls_assert_val(0);
+
+       return 1;
+}
+
+static
+unsigned check_email_constraints(gnutls_x509_name_constraints_t nc,
+                                      const gnutls_datum_t * name)
+{
+unsigned i;
+int ret;
+unsigned rtype;
+unsigned allowed_found = 0;
+gnutls_datum_t rname;
 
        /* check restrictions */
        i = 0;
        do {
                ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype, &rname);
-               if (ret >= 0 && rtype != type)
-                       continue;
+               if (ret >= 0) {
+                       if (rtype != GNUTLS_SAN_RFC822NAME)
+                               continue;
 
-               /* a name of value 0 means that the CA shouldn't have issued
-                * a certificate with a DNSNAME. */
-               if (rname.size == 0)
-                       return gnutls_assert_val(0);
+                       /* a name of value 0 means that the CA shouldn't have issued
+                        * a certificate with an e-mail. */
+                       if (rname.size == 0)
+                               return gnutls_assert_val(0);
 
-               if (dnsname_matches(name, &rname) != 0)
-                       return gnutls_assert_val(0); /* rejected */
+                       if (email_matches(name, &rname) != 0)
+                               return gnutls_assert_val(0); /* rejected */
+               }
        } while(ret == 0);
 
        /* check allowed */
        i = 0;
        do {
                ret = gnutls_x509_name_constraints_get_permitted(nc, i++, &rtype, &rname);
-               if (ret >= 0 && rtype != type)
-                       continue;
+               if (ret >= 0) {
+                       if (rtype != GNUTLS_SAN_RFC822NAME)
+                               continue;
 
-               if (rname.size == 0)
-                       continue;
+                       if (rname.size == 0)
+                               continue;
 
-               allowed_found = 1;
+                       allowed_found = 1;
 
-               if (dnsname_matches(name, &rname) != 0)
-                       return 1; /* accepted */
+                       if (email_matches(name, &rname) != 0)
+                               return 1; /* accepted */
+               }
        } while(ret == 0);
 
        if (allowed_found != 0) /* there are allowed directives but this host wasn't found */
                return gnutls_assert_val(0);
-       
+
        return 1;
 }
 
+/**
+ * gnutls_x509_name_constraints_check:
+ * @nc: the extracted name constraints structure
+ * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
+ * @name: the name to be checked
+ *
+ * This function will check the provided name against the constraints in
+ * @nc using the RFC5280 rules. Currently this function is limited to DNS
+ * names and emails (of type %GNUTLS_SAN_DNSNAME and %GNUTLS_SAN_RFC822NAME).
+ *
+ * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
+ *
+ * Since: 3.3.0
+ **/
+unsigned gnutls_x509_name_constraints_check(gnutls_x509_name_constraints_t nc,
+                                      gnutls_x509_subject_alt_name_t type,
+                                      const gnutls_datum_t * name)
+{
+       if (type == GNUTLS_SAN_DNSNAME)
+               return check_dns_constraints(nc, name);
+
+       if (type == GNUTLS_SAN_RFC822NAME)
+               return check_email_constraints(nc, name);
+
+       return check_unsupported_constraint(nc, type);
+}
+
 /**
  * gnutls_x509_name_constraints_get_permitted:
  * @nc: the extracted name constraints structure
index b5b29882c698d2c531cc885a0af84f4ddab98820..c99d3c28311872d12b152c4ec35d702b08fcfe57 100644 (file)
@@ -77,6 +77,11 @@ const gnutls_datum_t name1 = { (void*)"com", 3 };
 const gnutls_datum_t name2 = { (void*)"example.com", sizeof("example.com")-1 };
 const gnutls_datum_t name3 = { (void*)"another.example.com", sizeof("another.example.com")-1 };
 
+const gnutls_datum_t mail1 = { (void*)"example.com", sizeof("example.com")-1 };
+const gnutls_datum_t mail2 = { (void*)".example.net", sizeof(".example.net")-1 };
+const gnutls_datum_t mail3 = { (void*)"nmav@redhat.com", sizeof("nmav@redhat.com")-1 };
+const gnutls_datum_t mail4 = { (void*)"koko.example.net", sizeof("koko.example.net")-1 };
+
 void doit(void)
 {
        int ret;
@@ -168,6 +173,26 @@ void doit(void)
        if (ret < 0)
                fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
 
+       ret = gnutls_x509_name_constraints_add_permitted(nc, GNUTLS_SAN_RFC822NAME,
+               &mail1);
+       if (ret < 0)
+               fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
+
+       ret = gnutls_x509_name_constraints_add_permitted(nc, GNUTLS_SAN_RFC822NAME,
+               &mail2);
+       if (ret < 0)
+               fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
+
+       ret = gnutls_x509_name_constraints_add_permitted(nc, GNUTLS_SAN_RFC822NAME,
+               &mail3);
+       if (ret < 0)
+               fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
+
+       ret = gnutls_x509_name_constraints_add_excluded(nc, GNUTLS_SAN_RFC822NAME,
+               &mail4);
+       if (ret < 0)
+               fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
+
        ret = gnutls_x509_crt_set_name_constraints(crt, nc, 1);
        if (ret < 0)
                fail("error in %d: %s\n", __LINE__, gnutls_strerror(ret));
@@ -185,8 +210,8 @@ void doit(void)
                }
        } while(ret == 0);
 
-       if (i-1 != 1) {
-               fail("Could not read all contraints; read %d, expected %d\n", i-1, 1);
+       if (i-1 != 4) {
+               fail("Could not read all contraints; read %d, expected %d\n", i-1, 4);
        }
 
        i = 0;
@@ -205,19 +230,56 @@ void doit(void)
                }
        } while(ret == 0);
 
-       if (i-1 != 3) {
-               fail("Could not read all excluded contraints; read %d, expected %d\n", i-1, 3);
+       if (i-1 != 4) {
+               fail("Could not read all excluded contraints; read %d, expected %d\n", i-1, 4);
        }
 
        /* 3: test the name constraints check function */
 
-       /* This name constraints structure doesn't have any excluded RFC822NAME so
+       /* This name constraints structure doesn't have any excluded GNUTLS_SAN_DN so
         * this test should succeed */
+       name.data = (unsigned char*)"ASFHAJHjhafjs";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DN, &name);
+       if (ret == 0)
+               fail("Checking DN should have succeeded\n");
+
+       /* Test e-mails */
+       name.data = (unsigned char*)"nmav@redhat.com";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
+       if (ret == 0)
+               fail("Checking email should have succeeded\n");
+
+       name.data = (unsigned char*)"nmav@radhat.com";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
+       if (ret != 0)
+               fail("Checking email should have failed\n");
+
        name.data = (unsigned char*)"nmav@example.com";
        name.size = strlen((char*)name.data);
        ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
        if (ret == 0)
-               fail("Checking e-mail should have succeeded\n");
+               fail("Checking email should have succeeded\n");
+
+       name.data = (unsigned char*)"nmav@test.example.net";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
+       if (ret == 0)
+               fail("Checking email should have succeeded\n");
+
+       name.data = (unsigned char*)"nmav@example.net";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
+       if (ret != 0)
+               fail("Checking email should have failed\n");
+
+       name.data = (unsigned char*)"nmav@koko.example.net";
+       name.size = strlen((char*)name.data);
+       ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &name);
+       if (ret != 0)
+               fail("Checking email should have failed\n");
 
        /* This name constraints structure does have an excluded URI so
         * this test should fail */
index 67c4a4c30941b2f4b73247d43195fdd37f5f8ead..20c98897ea95a7b52f77000967f30eb2dc4ca623 100644 (file)
    obj:*
 }
 
+{
+   nettle memxor
+   Memcheck:Addr8
+   fun:memxor
+   obj:*
+}
+