|
/*
* Copyright (c) 2020 Bob Beck <beck@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <err.h>
#include <string.h>
#include <openssl/safestack.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "x509_internal.h"
#define FAIL(msg, ...) \
do { \
fprintf(stderr, "[%s:%d] FAIL: ", __FILE__, __LINE__); \
fprintf(stderr, msg, ##__VA_ARGS__); \
} while(0)
unsigned char *valid_hostnames[] = {
"openbsd.org",
"op3nbsd.org",
"org",
"3openbsd.com",
"3-0penb-d.c-m",
"a",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"open_bsd.org", /* because this is liberal */
NULL,
};
unsigned char *valid_sandns_names[] = {
"*.ca",
"*.op3nbsd.org",
"c*.openbsd.org",
"foo.*.d*.c*.openbsd.org",
NULL,
};
unsigned char *valid_domain_constraints[] = {
"",
".ca",
".op3nbsd.org",
".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"www.openbsd.org",
NULL,
};
unsigned char *valid_mbox_names[] = {
"\"!#$%&\\\"*+-/=?\002^_`{|}~.\"@openbsd.org",
"beck@openbsd.org",
"beck@openbsd.org",
"beck@op3nbsd.org",
"beck@org",
"beck@3openbsd.com",
"beck@3-0penb-d.c-m",
"bec@a",
"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"beck@open_bsd.org", /* because this is liberal */
NULL,
};
unsigned char *invalid_hostnames[] = {
"openbsd.org.",
"openbsd..org",
"openbsd.org-",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
"-p3nbsd.org",
"openbs-.org",
"openbsd\n.org",
"open\178bsd.org",
"open\255bsd.org",
"*.openbsd.org",
NULL,
};
unsigned char *invalid_sandns_names[] = {
"",
".",
"*.a",
"*.",
"*.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
"*.-p3nbsd.org",
"*.*..openbsd.org",
"*..openbsd.org",
".openbsd.org",
"c*c.openbsd.org",
NULL,
};
unsigned char *invalid_mbox_names[] = {
"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
"beck@.-openbsd.org",
"beck@.openbsd.org.",
"beck@.a",
"beck@.",
"beck@",
"beck@.ca",
"@openbsd.org",
NULL,
};
unsigned char *invalid_domain_constraints[] = {
".",
".a",
"..",
".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
".-p3nbsd.org",
"..openbsd.org",
NULL,
};
unsigned char *invaliduri[] = {
"https://-www.openbsd.org",
"https://.www.openbsd.org/",
"https://www.ope|nbsd.org%",
"https://www.openbsd.org.#",
"///",
"//",
"/",
"",
NULL,
};
static int
test_valid_hostnames(void)
{
int i, failure = 0;
for (i = 0; valid_hostnames[i] != NULL; i++) {
if (!x509_constraints_valid_host(valid_hostnames[i],
strlen(valid_hostnames[i]))) {
FAIL("Valid hostname '%s' rejected\n",
valid_hostnames[i]);
failure = 1;
goto done;
}
if (!x509_constraints_valid_sandns(valid_hostnames[i],
strlen(valid_hostnames[i]))) {
FAIL("Valid sandns '%s' rejected\n",
valid_hostnames[i]);
failure = 1;
goto done;
}
}
done:
return failure;
}
static int
test_valid_sandns_names(void)
{
int i, failure = 0;
for (i = 0; valid_sandns_names[i] != NULL; i++) {
if (!x509_constraints_valid_sandns(valid_sandns_names[i],
strlen(valid_sandns_names[i]))) {
FAIL("Valid dnsname '%s' rejected\n",
valid_sandns_names[i]);
failure = 1;
goto done;
}
}
done:
return failure;
}
static int
test_valid_domain_constraints(void)
{
int i, failure = 0;
for (i = 0; valid_domain_constraints[i] != NULL; i++) {
if (!x509_constraints_valid_domain_constraint(valid_domain_constraints[i],
strlen(valid_domain_constraints[i]))) {
FAIL("Valid dnsname '%s' rejected\n",
valid_domain_constraints[i]);
failure = 1;
goto done;
}
}
done:
return failure;
}
static int
test_valid_mbox_names(void)
{
struct x509_constraints_name name = {0};
int i, failure = 0;
for (i = 0; valid_mbox_names[i] != NULL; i++) {
if (!x509_constraints_parse_mailbox(valid_mbox_names[i],
strlen(valid_mbox_names[i]), &name)) {
FAIL("Valid mailbox name '%s' rejected\n",
valid_mbox_names[i]);
failure = 1;
goto done;
}
free(name.name);
name.name = NULL;
free(name.local);
name.local = NULL;
}
done:
return failure;
}
static int
test_invalid_hostnames(void)
{
int i, failure = 0;
char *nulhost = "www.openbsd.org\0";
for (i = 0; invalid_hostnames[i] != NULL; i++) {
if (x509_constraints_valid_host(invalid_hostnames[i],
strlen(invalid_hostnames[i]))) {
FAIL("Invalid hostname '%s' accepted\n",
invalid_hostnames[i]);
failure = 1;
goto done;
}
}
if (x509_constraints_valid_host(nulhost,
strlen(nulhost) + 1)) {
FAIL("hostname with NUL byte accepted\n");
failure = 1;
goto done;
}
if (x509_constraints_valid_sandns(nulhost,
strlen(nulhost) + 1)) {
FAIL("sandns with NUL byte accepted\n");
failure = 1;
goto done;
}
done:
return failure;
}
static int
test_invalid_sandns_names(void)
{
int i, failure = 0;
for (i = 0; invalid_sandns_names[i] != NULL; i++) {
if (x509_constraints_valid_sandns(invalid_sandns_names[i],
strlen(invalid_sandns_names[i]))) {
FAIL("Valid dnsname '%s' rejected\n",
invalid_sandns_names[i]);
failure = 1;
goto done;
}
}
done:
return failure;
}
static int
test_invalid_mbox_names(void)
{
int i, failure = 0;
struct x509_constraints_name name = {0};
for (i = 0; invalid_mbox_names[i] != NULL; i++) {
if (x509_constraints_parse_mailbox(invalid_mbox_names[i],
strlen(invalid_mbox_names[i]), &name)) {
FAIL("invalid mailbox name '%s' accepted\n",
invalid_mbox_names[i]);
failure = 1;
goto done;
}
free(name.name);
name.name = NULL;
free(name.local);
name.local = NULL;
}
done:
return failure;
}
static int
test_invalid_domain_constraints(void)
{
int i, failure = 0;
for (i = 0; invalid_domain_constraints[i] != NULL; i++) {
if (x509_constraints_valid_domain_constraint(invalid_domain_constraints[i],
strlen(invalid_domain_constraints[i]))) {
FAIL("invalid dnsname '%s' accepted\n",
invalid_domain_constraints[i]);
failure = 1;
goto done;
}
}
done:
return failure;
}
static int
test_invalid_uri(void)
{
int j, failure=0;
char *hostpart = NULL;
for (j = 0; invaliduri[j] != NULL; j++) {
if (x509_constraints_uri_host(invaliduri[j],
strlen(invaliduri[j]), &hostpart) != 0) {
FAIL("invalid URI '%s' accepted\n",
invaliduri[j]);
failure = 1;
goto done;
}
free(hostpart);
hostpart = NULL;
}
done:
return failure;
}
static int
test_constraints1(void)
{
char *c; size_t cl;
char *d; size_t dl;
int failure = 0;
int error = 0;
int i, j;
unsigned char *constraints[] = {
".org",
".openbsd.org",
"www.openbsd.org",
NULL,
};
unsigned char *failing[] = {
".ca",
"openbsd.ca",
"org",
NULL,
};
unsigned char *matching[] = {
"www.openbsd.org",
NULL,
};
unsigned char *matchinguri[] = {
"https://www.openbsd.org",
"https://www.openbsd.org/",
"https://www.openbsd.org?",
"https://www.openbsd.org#",
"herp://beck@www.openbsd.org:",
"spiffe://beck@www.openbsd.org/this/is/so/spiffe/",
NULL,
};
unsigned char *failinguri[] = {
"https://www.openbsd.ca",
"https://www.freebsd.com/",
"https://www.openbsd.net?",
"https://org#",
"herp://beck@org:",
"///",
"//",
"/",
"",
NULL,
};
unsigned char *noauthority[] = {
"urn:open62541.server.application",
NULL,
};
for (i = 0; constraints[i] != NULL; i++) {
char *constraint = constraints[i];
size_t clen = strlen(constraints[i]);
for (j = 0; matching[j] != NULL; j++) {
if (!x509_constraints_domain(matching[j],
strlen(matching[j]), constraint, clen)) {
FAIL("constraint '%s' should have matched"
" '%s'\n",
constraint, matching[j]);
failure = 1;
goto done;
}
}
for (j = 0; matchinguri[j] != NULL; j++) {
error = 0;
if (!x509_constraints_uri(matchinguri[j],
strlen(matchinguri[j]), constraint, clen, &error)) {
FAIL("constraint '%s' should have matched URI"
" '%s' (error %d)\n",
constraint, matchinguri[j], error);
failure = 1;
goto done;
}
}
for (j = 0; failing[j] != NULL; j++) {
if (x509_constraints_domain(failing[j],
strlen(failing[j]), constraint, clen)) {
FAIL("constraint '%s' should not have matched"
" '%s'\n",
constraint, failing[j]);
failure = 1;
goto done;
}
}
for (j = 0; failinguri[j] != NULL; j++) {
error = 0;
if (x509_constraints_uri(failinguri[j],
strlen(failinguri[j]), constraint, clen, &error)) {
FAIL("constraint '%s' should not have matched URI"
" '%s' (error %d)\n",
constraint, failinguri[j], error);
failure = 1;
goto done;
}
}
for (j = 0; noauthority[j] != NULL; j++) {
char *hostpart = NULL;
error = 0;
if (!x509_constraints_uri_host(noauthority[j],
strlen(noauthority[j]), &hostpart)) {
FAIL("name '%s' should parse as a URI",
noauthority[j]);
failure = 1;
free(hostpart);
goto done;
}
free(hostpart);
if (x509_constraints_uri(noauthority[j],
strlen(noauthority[j]), constraint, clen, &error)) {
FAIL("constraint '%s' should not have matched URI"
" '%s' (error %d)\n",
constraint, failinguri[j], error);
failure = 1;
goto done;
}
}
}
c = ".openbsd.org";
cl = strlen(".openbsd.org");
d = "*.openbsd.org";
dl = strlen("*.openbsd.org");
if (!x509_constraints_domain(d, dl, c, cl)) {
FAIL("constraint '%s' should have matched '%s'\n",
c, d);
failure = 1;
goto done;
}
c = "www.openbsd.org";
cl = strlen("www.openbsd.org");
if (x509_constraints_domain(d, dl, c, cl)) {
FAIL("constraint '%s' should not have matched '%s'\n",
c, d);
failure = 1;
goto done;
}
c = "";
cl = 0;
if (!x509_constraints_domain(d, dl, c, cl)) {
FAIL("constraint '%s' should have matched '%s'\n",
c, d);
failure = 1;
goto done;
}
done:
return failure;
}
int
main(int argc, char **argv)
{
int failed = 0;
failed |= test_valid_hostnames();
failed |= test_invalid_hostnames();
failed |= test_valid_sandns_names();
failed |= test_invalid_sandns_names();
failed |= test_valid_mbox_names();
failed |= test_invalid_mbox_names();
failed |= test_valid_domain_constraints();
failed |= test_invalid_domain_constraints();
failed |= test_invalid_uri();
failed |= test_constraints1();
return (failed);
}
|