/** * gnutls_x509_name_constraints_check_crt: * @nc: the extracted name constraints * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t) * @cert: the certificate to be checked * * This function will check the provided certificate names against the constraints in * @nc using the RFC5280 rules. It will traverse all the certificate's names and * alternative names. * * 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_crt(gnutls_x509_name_constraints_t nc, gnutls_x509_subject_alt_name_t type, gnutls_x509_crt_t cert) { char name[MAX_CN]; size_t name_size; int ret; unsigned idx, t, san_type; gnutls_datum_t n; unsigned found_one; if (is_nc_empty(nc, type) != 0) return 1; /* shortcut; no constraints to check */ if (type == GNUTLS_SAN_RFC822NAME) { idx = found_one = 0; do { name_size = sizeof(name); ret = gnutls_x509_crt_get_subject_alt_name2(cert, idx++, name, &name_size, &san_type, NULL); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; else if (ret < 0) return gnutls_assert_val(0); if (san_type != GNUTLS_SAN_RFC822NAME) continue; found_one = 1; n.data = (void*)name; n.size = name_size; t = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &n); if (t == 0) return gnutls_assert_val(t); } while(ret >= 0); /* there is at least a single e-mail. That means that the EMAIL field will * not be used for verifying the identity of the holder. */ if (found_one != 0) return 1; do { /* ensure there is only a single EMAIL, similarly to CN handling (rfc6125) */ name_size = sizeof(name); ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 1, 0, name, &name_size); if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) return gnutls_assert_val(0); name_size = sizeof(name); ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, name, &name_size); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; else if (ret < 0) return gnutls_assert_val(0); found_one = 1; n.data = (void*)name; n.size = name_size; t = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME, &n); if (t == 0) return gnutls_assert_val(t); } while(0); /* passed */ if (found_one != 0) return 1; else { /* no name was found. According to RFC5280: * If no name of the type is in the certificate, the certificate is acceptable. */ return gnutls_assert_val(1); } } else if (type == GNUTLS_SAN_DNSNAME) { idx = found_one = 0; do { name_size = sizeof(name); ret = gnutls_x509_crt_get_subject_alt_name2(cert, idx++, name, &name_size, &san_type, NULL); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; else if (ret < 0) return gnutls_assert_val(0); if (san_type != GNUTLS_SAN_DNSNAME) continue; found_one = 1; n.data = (void*)name; n.size = name_size; t = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &n); if (t == 0) return gnutls_assert_val(t); } while(ret >= 0); /* there is at least a single DNS name. That means that the CN will * not be used for verifying the identity of the holder. */ if (found_one != 0) return 1; /* verify the name constraints against the CN, if the certificate is * not a CA. We do this check only on certificates marked as WWW server, * because that's where the CN check is only performed. */ if (_gnutls_check_key_purpose(cert, GNUTLS_KP_TLS_WWW_SERVER, 0) != 0) do { /* ensure there is only a single CN, according to rfc6125 */ name_size = sizeof(name); ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 1, 0, name, &name_size); if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) return gnutls_assert_val(0); name_size = sizeof(name); ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &name_size); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; else if (ret < 0) return gnutls_assert_val(0); found_one = 1; n.data = (void*)name; n.size = name_size; t = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &n); if (t == 0) return gnutls_assert_val(t); } while(0); /* passed */ if (found_one != 0) return 1; else { /* no name was found. According to RFC5280: * If no name of the type is in the certificate, the certificate is acceptable. */ return gnutls_assert_val(1); } } else if (type == GNUTLS_SAN_IPADDRESS || type == GNUTLS_SAN_URI) { return check_unsupported_constraint2(cert, nc, type); } else return check_unsupported_constraint(nc, type); }
void doit(void) { int ret, suite; gnutls_x509_name_constraints_t nc1, nc2; gnutls_datum_t name; gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(1000); /* 0: test the merge permitted name constraints * NC1: permitted DNS org * permitted DNS ccc.com * permitted email ccc.com * NC2: permitted DNS org * permitted DNS aaa.bbb.ccc.com */ suite = 0; ret = gnutls_x509_name_constraints_init(&nc1); check_for_error(ret); ret = gnutls_x509_name_constraints_init(&nc2); check_for_error(ret); set_name("org", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("ccc.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("ccc.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_RFC822NAME, &name); check_for_error(ret); set_name("org", &name); ret = gnutls_x509_name_constraints_add_permitted(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("aaa.bbb.ccc.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); ret = _gnutls_x509_name_constraints_merge(nc1, nc2); check_for_error(ret); /* unrelated */ set_name("xxx.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.org", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); set_name("com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("xxx.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); /* check intersection of permitted */ set_name("xxx.aaa.bbb.ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); set_name("aaa.bbb.ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); set_name("xxx.bbb.ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("xxx.ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_RFC822NAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); set_name("xxx.ccc.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_RFC822NAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); gnutls_x509_name_constraints_deinit(nc1); gnutls_x509_name_constraints_deinit(nc2); /* 1: test the merge of excluded name constraints * NC1: denied DNS example.com * NC2: denied DNS example.net */ suite = 1; ret = gnutls_x509_name_constraints_init(&nc1); check_for_error(ret); ret = gnutls_x509_name_constraints_init(&nc2); check_for_error(ret); set_name("example.com", &name); ret = gnutls_x509_name_constraints_add_excluded(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("example.net", &name); ret = gnutls_x509_name_constraints_add_excluded(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); ret = _gnutls_x509_name_constraints_merge(nc1, nc2); check_for_error(ret); set_name("xxx.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("xxx.example.net", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.net", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.org", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); gnutls_x509_name_constraints_deinit(nc1); gnutls_x509_name_constraints_deinit(nc2); /* 2: test permitted constraints with empty intersection * (no permitted nodes remain) * NC1: permitted DNS one.example.com * NC2: permitted DNS two.example.com */ suite = 2; ret = gnutls_x509_name_constraints_init(&nc1); check_for_error(ret); ret = gnutls_x509_name_constraints_init(&nc2); check_for_error(ret); set_name("one.example.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("two.example.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); ret = _gnutls_x509_name_constraints_merge(nc1, nc2); check_for_error(ret); set_name("one.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("two.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("three.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("org", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); gnutls_x509_name_constraints_deinit(nc1); gnutls_x509_name_constraints_deinit(nc2); /* 3: test more permitted constraints, some with empty intersection * NC1: permitted DNS foo.com * permitted DNS bar.com * permitted email redhat.com * NC2: permitted DNS sub.foo.com */ suite = 3; ret = gnutls_x509_name_constraints_init(&nc1); check_for_error(ret); ret = gnutls_x509_name_constraints_init(&nc2); check_for_error(ret); set_name("foo.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("bar.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("sub.foo.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); ret = _gnutls_x509_name_constraints_merge(nc1, nc2); check_for_error(ret); set_name("foo.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("bar.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("sub.foo.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_ACCEPTED, &name); set_name("anothersub.foo.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); gnutls_x509_name_constraints_deinit(nc1); gnutls_x509_name_constraints_deinit(nc2); /* 4: test permitted constraints with empty intersection * almost identical to 2, but extra name constraint of different type * that remains after intersection * NC1: permitted DNS three.example.com * permitted email redhat.com * NC2: permitted DNS four.example.com */ suite = 4; ret = gnutls_x509_name_constraints_init(&nc1); check_for_error(ret); ret = gnutls_x509_name_constraints_init(&nc2); check_for_error(ret); set_name("three.example.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); set_name("redhat.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc1, GNUTLS_SAN_RFC822NAME, &name); check_for_error(ret); set_name("four.example.com", &name); ret = gnutls_x509_name_constraints_add_permitted(nc2, GNUTLS_SAN_DNSNAME, &name); check_for_error(ret); ret = _gnutls_x509_name_constraints_merge(nc1, nc2); check_for_error(ret); set_name("three.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("four.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("five.example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("example.com", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); set_name("org", &name); ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME, &name); check_test_result(suite, ret, NAME_REJECTED, &name); gnutls_x509_name_constraints_deinit(nc1); gnutls_x509_name_constraints_deinit(nc2); /* Test footer */ if (debug) success("Test success.\n"); }