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)
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)
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;
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
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;
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));
}
} 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;
}
} 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 */