Rewrite X.509 name-matching tests.

This replaces v3name_test.cc which is rather difficult to follow.
v3name_test.cc ran all pairs of names against each other, used a
default case-insensitivity rule, and then had a list of string
exceptions to that rule. This is hopefully easier for us to adjust
later. It also fixes a testing bug we wouldn't notice if an expected
"exception" didn't fire.

Sadly, we cannot use designated initializers in C++ yet. MSVC does not
support them until MSVC 2019.

Change-Id: Ia8e3bf5f57d33a9bf1fc929ba1e8cd2a270a8a24
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/50725
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
fips-20220613
David Benjamin 3 years ago committed by Boringssl LUCI CQ
parent c3c540b9a4
commit 405c7888a7
  1. 1
      crypto/CMakeLists.txt
  2. 321
      crypto/x509/x509_test.cc
  3. 413
      crypto/x509v3/v3name_test.cc

@ -552,7 +552,6 @@ add_executable(
x509/x509_test.cc
x509/x509_time_test.cc
x509v3/tab_test.cc
x509v3/v3name_test.cc
$<TARGET_OBJECTS:crypto_test_data>
$<TARGET_OBJECTS:boringssl_gtest_main>

@ -3533,3 +3533,324 @@ TEST(X509Test, BER) {
// Padding bits in BIT STRINGs must be zero in BER.
EXPECT_FALSE(CertFromPEM(kNonZeroPadding));
}
TEST(X509Test, Names) {
bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
ASSERT_TRUE(key);
bssl::UniquePtr<X509> root =
MakeTestCert("Root", "Root", key.get(), /*is_ca=*/true);
ASSERT_TRUE(root);
ASSERT_TRUE(X509_sign(root.get(), key.get(), EVP_sha256()));
struct {
std::vector<std::pair<int, std::string>> cert_subject;
std::vector<std::string> cert_dns_names;
std::vector<std::string> cert_emails;
std::vector<std::string> valid_dns_names;
std::vector<std::string> invalid_dns_names;
std::vector<std::string> valid_emails;
std::vector<std::string> invalid_emails;
unsigned flags;
} kTests[] = {
// DNS names only match DNS names and do so case-insensitively.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{"example.com", "WWW.EXAMPLE.COM"},
/*cert_emails=*/{},
/*valid_dns_names=*/
{"example.com", "EXAMPLE.COM", "www.example.com", "WWW.EXAMPLE.COM"},
/*invalid_dns_names=*/{"test.example.com", "example.org"},
/*valid_emails=*/{},
/*invalid_emails=*/{"test@example.com", "example.com"},
/*flags=*/0,
},
// DNS wildcards match exactly one component.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{"*.example.com", "*.EXAMPLE.ORG"},
/*cert_emails=*/{},
/*valid_dns_names=*/
{"www.example.com", "WWW.EXAMPLE.COM", "www.example.org",
"WWW.EXAMPLE.ORG"},
/*invalid_dns_names=*/{"example.com", "test.www.example.com"},
/*valid_emails=*/{},
/*invalid_emails=*/{"test@example.com", "www.example.com"},
/*flags=*/0,
},
// DNS wildcards can be disabled.
// TODO(davidben): Can we remove this feature? Does anyone use it?
{
/*cert_subject=*/{},
/*cert_dns_names=*/{"example.com", "*.example.com"},
/*cert_emails=*/{},
/*valid_dns_names=*/{"example.com"},
/*invalid_dns_names=*/{"www.example.com"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/X509_CHECK_FLAG_NO_WILDCARDS,
},
// Invalid DNS wildcards do not match.
{
/*cert_subject=*/{},
/*cert_dns_names=*/
{"a.*", "**.b.example", "*c.example", "d*.example", "e*e.example",
"*", ".", "..", "*."},
/*cert_emails=*/{},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/
{"a.example", "test.b.example", "cc.example", "dd.example",
"eee.example", "f", "g."},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// IDNs match like any other DNS labels.
{
/*cert_subject=*/{},
/*cert_dns_names=*/
{"xn--rger-koa.a.example", "*.xn--rger-koa.b.example",
"www.xn--rger-koa.c.example"},
/*cert_emails=*/{},
/*valid_dns_names=*/
{"xn--rger-koa.a.example", "www.xn--rger-koa.b.example",
"www.xn--rger-koa.c.example"},
/*invalid_dns_names=*/
{"www.xn--rger-koa.a.example", "xn--rger-koa.b.example",
"www.xn--rger-koa.d.example"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// For now, DNS names are also extracted out of the common name, but only
// there is no SAN list.
// TODO(https://crbug.com/boringssl/464): Remove this.
{
/*cert_subject=*/{{NID_commonName, "a.example"},
{NID_commonName, "*.b.example"}},
/*cert_dns_names=*/{},
/*cert_emails=*/{},
/*valid_dns_names=*/
{"a.example", "A.EXAMPLE", "test.b.example", "TEST.B.EXAMPLE"},
/*invalid_dns_names=*/{},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
{
/*cert_subject=*/{{NID_commonName, "a.example"},
{NID_commonName, "*.b.example"}},
/*cert_dns_names=*/{"example.com"},
/*cert_emails=*/{},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/
{"a.example", "A.EXAMPLE", "test.b.example", "TEST.B.EXAMPLE"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// Other subject RDNs do not provide DNS names.
{
/*cert_subject=*/{{NID_organizationName, "example.com"}},
/*cert_dns_names=*/{},
/*cert_emails=*/{},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/{"example.com"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// Input DNS names cannot have wildcards.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{"www.example.com"},
/*cert_emails=*/{},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/{"*.example.com"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// However, OpenSSL has some non-standard behavior that implements this
// with a different syntax.
// TODO(https://crbug.com/boringssl/463): Remove this.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{"www.a.example", "*.b.test"},
/*cert_emails=*/{},
/*valid_dns_names=*/{".a.example", ".b.test", ".example", ".test"},
/*invalid_dns_names=*/{".www.a.example", ".www.b.test"},
/*valid_emails=*/{},
/*invalid_emails=*/{},
/*flags=*/0,
},
// Emails match case-sensitively before the '@' and case-insensitively
// after. They do not match DNS names.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{},
/*cert_emails=*/{"test@a.example", "TEST@B.EXAMPLE"},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/{"a.example", "b.example"},
/*valid_emails=*/
{"test@a.example", "test@A.EXAMPLE", "TEST@b.example",
"TEST@B.EXAMPLE"},
/*invalid_emails=*/
{"TEST@a.example", "test@B.EXAMPLE", "another-test@a.example",
"est@a.example"},
/*flags=*/0,
},
// Emails may also be found in the subject.
{
/*cert_subject=*/{{NID_pkcs9_emailAddress, "test@a.example"},
{NID_pkcs9_emailAddress, "TEST@B.EXAMPLE"}},
/*cert_dns_names=*/{},
/*cert_emails=*/{},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/{"a.example", "b.example"},
/*valid_emails=*/
{"test@a.example", "test@A.EXAMPLE", "TEST@b.example",
"TEST@B.EXAMPLE"},
/*invalid_emails=*/
{"TEST@a.example", "test@B.EXAMPLE", "another-test@a.example",
"est@a.example"},
/*flags=*/0,
},
// There are no email wildcard names.
{
/*cert_subject=*/{},
/*cert_dns_names=*/{},
/*cert_emails=*/{"test@*.a.example", "@b.example", "*@c.example"},
/*valid_dns_names=*/{},
/*invalid_dns_names=*/{},
/*valid_emails=*/{},
/*invalid_emails=*/
{"test@test.a.example", "test@b.example", "test@c.example"},
/*flags=*/0,
},
// Unrelated RDNs can be skipped when looking in the subject.
{
/*cert_subject=*/{{NID_organizationName, "Acme Corporation"},
{NID_commonName, "a.example"},
{NID_pkcs9_emailAddress, "test@b.example"},
{NID_countryName, "US"}},
/*cert_dns_names=*/{},
/*cert_emails=*/{},
/*valid_dns_names=*/{"a.example"},
/*invalid_dns_names=*/{},
/*valid_emails=*/{"test@b.example"},
/*invalid_emails=*/{},
/*flags=*/0,
},
};
size_t i = 0;
for (const auto &t : kTests) {
SCOPED_TRACE(i++);
// Issue a test certificate.
bssl::UniquePtr<X509> cert =
MakeTestCert("Root", "Leaf", key.get(), /*is_ca=*/false);
ASSERT_TRUE(cert);
if (!t.cert_subject.empty()) {
bssl::UniquePtr<X509_NAME> subject(X509_NAME_new());
ASSERT_TRUE(subject);
for (const auto &entry : t.cert_subject) {
ASSERT_TRUE(X509_NAME_add_entry_by_NID(
subject.get(), entry.first, MBSTRING_ASC,
reinterpret_cast<const unsigned char *>(entry.second.data()),
entry.second.size(), /*loc=*/-1, /*set=*/0));
}
ASSERT_TRUE(X509_set_subject_name(cert.get(), subject.get()));
}
bssl::UniquePtr<GENERAL_NAMES> sans(sk_GENERAL_NAME_new_null());
ASSERT_TRUE(sans);
for (const auto &dns : t.cert_dns_names) {
bssl::UniquePtr<GENERAL_NAME> name(GENERAL_NAME_new());
ASSERT_TRUE(name);
name->type = GEN_DNS;
name->d.dNSName = ASN1_IA5STRING_new();
ASSERT_TRUE(name->d.dNSName);
ASSERT_TRUE(ASN1_STRING_set(name->d.dNSName, dns.data(), dns.size()));
ASSERT_TRUE(bssl::PushToStack(sans.get(), std::move(name)));
}
for (const auto &email : t.cert_emails) {
bssl::UniquePtr<GENERAL_NAME> name(GENERAL_NAME_new());
ASSERT_TRUE(name);
name->type = GEN_EMAIL;
name->d.rfc822Name = ASN1_IA5STRING_new();
ASSERT_TRUE(name->d.rfc822Name);
ASSERT_TRUE(
ASN1_STRING_set(name->d.rfc822Name, email.data(), email.size()));
ASSERT_TRUE(bssl::PushToStack(sans.get(), std::move(name)));
}
if (sk_GENERAL_NAME_num(sans.get()) != 0) {
ASSERT_TRUE(X509_add1_ext_i2d(cert.get(), NID_subject_alt_name,
sans.get(), /*crit=*/0, /*flags=*/0));
}
ASSERT_TRUE(X509_sign(cert.get(), key.get(), EVP_sha256()));
for (const auto &dns : t.valid_dns_names) {
SCOPED_TRACE(dns);
EXPECT_EQ(1, X509_check_host(cert.get(), dns.data(), dns.size(), t.flags,
/*peername=*/nullptr));
EXPECT_EQ(X509_V_OK,
Verify(cert.get(), {root.get()}, /*intermediates=*/{},
/*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
ASSERT_TRUE(X509_VERIFY_PARAM_set1_host(
param, dns.data(), dns.size()));
X509_VERIFY_PARAM_set_hostflags(param, t.flags);
}));
}
for (const auto &dns : t.invalid_dns_names) {
SCOPED_TRACE(dns);
EXPECT_EQ(0, X509_check_host(cert.get(), dns.data(), dns.size(), t.flags,
/*peername=*/nullptr));
EXPECT_EQ(X509_V_ERR_HOSTNAME_MISMATCH,
Verify(cert.get(), {root.get()}, /*intermediates=*/{},
/*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
ASSERT_TRUE(X509_VERIFY_PARAM_set1_host(
param, dns.data(), dns.size()));
X509_VERIFY_PARAM_set_hostflags(param, t.flags);
}));
}
for (const auto &email : t.valid_emails) {
SCOPED_TRACE(email);
EXPECT_EQ(
1, X509_check_email(cert.get(), email.data(), email.size(), t.flags));
EXPECT_EQ(X509_V_OK,
Verify(cert.get(), {root.get()}, /*intermediates=*/{},
/*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
ASSERT_TRUE(X509_VERIFY_PARAM_set1_email(
param, email.data(), email.size()));
X509_VERIFY_PARAM_set_hostflags(param, t.flags);
}));
}
for (const auto &email : t.invalid_emails) {
SCOPED_TRACE(email);
EXPECT_EQ(
0, X509_check_email(cert.get(), email.data(), email.size(), t.flags));
EXPECT_EQ(X509_V_ERR_EMAIL_MISMATCH,
Verify(cert.get(), {root.get()}, /*intermediates=*/{},
/*crls=*/{}, /*flags=*/0, [&](X509_VERIFY_PARAM *param) {
ASSERT_TRUE(X509_VERIFY_PARAM_set1_email(
param, email.data(), email.size()));
X509_VERIFY_PARAM_set_hostflags(param, t.flags);
}));
}
}
}

@ -1,413 +0,0 @@
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
* 1999.
*/
/* ====================================================================
* Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <stdarg.h>
#include <string.h>
#include <gtest/gtest.h>
#include <openssl/crypto.h>
#include <openssl/mem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "../internal.h"
#include "internal.h"
static const char *const names[] = {
"a", "b", ".", "*", "@",
".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
"-example.com", "example-.com",
"@@", "**", "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
"*@example.com", "test@*.example.com", "example.com", "www.example.com",
"test.www.example.com", "*.example.com", "*.www.example.com",
"test.*.example.com", "www.*.com",
".www.example.com", "*www.example.com",
"example.net", "xn--rger-koa.example.com",
"*.xn--rger-koa.example.com", "www.xn--rger-koa.example.com",
"*.good--example.com", "www.good--example.com",
"*.xn--bar.com", "xn--foo.xn--bar.com",
"a.example.com", "b.example.com",
"postmaster@example.com", "Postmaster@example.com",
"postmaster@EXAMPLE.COM",
NULL
};
static const char *const exceptions[] = {
"set CN: host: [*.example.com] matches [a.example.com]",
"set CN: host: [*.example.com] matches [b.example.com]",
"set CN: host: [*.example.com] matches [www.example.com]",
"set CN: host: [*.example.com] matches [xn--rger-koa.example.com]",
"set CN: host: [*.www.example.com] matches [test.www.example.com]",
"set CN: host: [*.www.example.com] matches [.www.example.com]",
"set CN: host: [*www.example.com] matches [www.example.com]",
"set CN: host: [test.www.example.com] matches [.www.example.com]",
"set CN: host: [*.xn--rger-koa.example.com] matches [www.xn--rger-koa.example.com]",
"set CN: host: [*.xn--bar.com] matches [xn--foo.xn--bar.com]",
"set CN: host: [*.good--example.com] matches [www.good--example.com]",
"set CN: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
"set CN: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
"set emailAddress: email: [postmaster@example.com] does not match [Postmaster@example.com]",
"set emailAddress: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
"set emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]",
"set emailAddress: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
"set dnsName: host: [*.example.com] matches [www.example.com]",
"set dnsName: host: [*.example.com] matches [a.example.com]",
"set dnsName: host: [*.example.com] matches [b.example.com]",
"set dnsName: host: [*.example.com] matches [xn--rger-koa.example.com]",
"set dnsName: host: [*.www.example.com] matches [test.www.example.com]",
"set dnsName: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
"set dnsName: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
"set dnsName: host: [*.www.example.com] matches [.www.example.com]",
"set dnsName: host: [*www.example.com] matches [www.example.com]",
"set dnsName: host: [test.www.example.com] matches [.www.example.com]",
"set dnsName: host: [*.xn--rger-koa.example.com] matches [www.xn--rger-koa.example.com]",
"set dnsName: host: [*.xn--bar.com] matches [xn--foo.xn--bar.com]",
"set dnsName: host: [*.good--example.com] matches [www.good--example.com]",
"set rfc822Name: email: [postmaster@example.com] does not match [Postmaster@example.com]",
"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@example.com]",
"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
"set rfc822Name: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
NULL
};
static int is_exception(const char *msg)
{
const char *const *p;
for (p = exceptions; *p; ++p)
if (strcmp(msg, *p) == 0)
return 1;
return 0;
}
static int set_cn(X509 *crt, ...)
{
int ret = 0;
X509_NAME *n = NULL;
va_list ap;
va_start(ap, crt);
n = X509_NAME_new();
if (n == NULL)
goto out;
while (1) {
int nid;
const char *name;
nid = va_arg(ap, int);
if (nid == 0)
break;
name = va_arg(ap, const char *);
if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC,
(unsigned char *)name, -1, -1, 1))
goto out;
}
if (!X509_set_subject_name(crt, n))
goto out;
ret = 1;
out:
X509_NAME_free(n);
va_end(ap);
return ret;
}
/*
* int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); X509_EXTENSION
* *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid, int crit,
* ASN1_OCTET_STRING *data); int X509_add_ext(X509 *x, X509_EXTENSION *ex,
* int loc);
*/
static int set_altname(X509 *crt, ...)
{
int ret = 0;
GENERAL_NAMES *gens = NULL;
GENERAL_NAME *gen = NULL;
ASN1_IA5STRING *ia5 = NULL;
va_list ap;
va_start(ap, crt);
gens = sk_GENERAL_NAME_new_null();
if (gens == NULL)
goto out;
while (1) {
int type;
const char *name;
type = va_arg(ap, int);
if (type == 0)
break;
name = va_arg(ap, const char *);
gen = GENERAL_NAME_new();
if (gen == NULL)
goto out;
ia5 = ASN1_IA5STRING_new();
if (ia5 == NULL)
goto out;
if (!ASN1_STRING_set(ia5, name, -1))
goto out;
switch (type) {
case GEN_EMAIL:
case GEN_DNS:
GENERAL_NAME_set0_value(gen, type, ia5);
ia5 = NULL;
break;
default:
abort();
}
sk_GENERAL_NAME_push(gens, gen);
gen = NULL;
}
if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
goto out;
ret = 1;
out:
ASN1_IA5STRING_free(ia5);
GENERAL_NAME_free(gen);
GENERAL_NAMES_free(gens);
va_end(ap);
return ret;
}
static int set_cn1(X509 *crt, const char *name)
{
return set_cn(crt, NID_commonName, name, 0);
}
static int set_cn_and_email(X509 *crt, const char *name)
{
return set_cn(crt, NID_commonName, name,
NID_pkcs9_emailAddress, "dummy@example.com", 0);
}
static int set_cn2(X509 *crt, const char *name)
{
return set_cn(crt, NID_commonName, "dummy value",
NID_commonName, name, 0);
}
static int set_cn3(X509 *crt, const char *name)
{
return set_cn(crt, NID_commonName, name,
NID_commonName, "dummy value", 0);
}
static int set_email1(X509 *crt, const char *name)
{
return set_cn(crt, NID_pkcs9_emailAddress, name, 0);
}
static int set_email2(X509 *crt, const char *name)
{
return set_cn(crt, NID_pkcs9_emailAddress, "dummy@example.com",
NID_pkcs9_emailAddress, name, 0);
}
static int set_email3(X509 *crt, const char *name)
{
return set_cn(crt, NID_pkcs9_emailAddress, name,
NID_pkcs9_emailAddress, "dummy@example.com", 0);
}
static int set_email_and_cn(X509 *crt, const char *name)
{
return set_cn(crt, NID_pkcs9_emailAddress, name,
NID_commonName, "www.example.org", 0);
}
static int set_altname_dns(X509 *crt, const char *name)
{
return set_altname(crt, GEN_DNS, name, 0);
}
static int set_altname_email(X509 *crt, const char *name)
{
return set_altname(crt, GEN_EMAIL, name, 0);
}
struct set_name_fn {
int (*fn) (X509 *, const char *);
const char *name;
int host;
int email;
};
static const struct set_name_fn name_fns[] = {
{set_cn1, "set CN", 1, 0},
{set_cn2, "set CN", 1, 0},
{set_cn3, "set CN", 1, 0},
{set_cn_and_email, "set CN", 1, 0},
{set_email1, "set emailAddress", 0, 1},
{set_email2, "set emailAddress", 0, 1},
{set_email3, "set emailAddress", 0, 1},
{set_email_and_cn, "set emailAddress", 0, 1},
{set_altname_dns, "set dnsName", 1, 0},
{set_altname_email, "set rfc822Name", 0, 1},
{NULL, NULL, 0, 0},
};
static X509 *make_cert(void)
{
X509 *ret = NULL;
X509 *crt = NULL;
X509_NAME *issuer = NULL;
crt = X509_new();
if (crt == NULL)
goto out;
if (!X509_set_version(crt, X509_VERSION_3))
goto out;
ret = crt;
crt = NULL;
out:
X509_NAME_free(issuer);
return ret;
}
static int errors;
static void check_message(const struct set_name_fn *fn, const char *op,
const char *nameincert, int match, const char *name)
{
char msg[1024];
if (match < 0)
return;
BIO_snprintf(msg, sizeof(msg), "%s: %s: [%s] %s [%s]",
fn->name, op, nameincert,
match ? "matches" : "does not match", name);
if (is_exception(msg))
return;
puts(msg);
++errors;
}
static void run_cert(X509 *crt, const char *nameincert,
const struct set_name_fn *fn)
{
const char *const *pname = names;
while (*pname) {
int samename = OPENSSL_strcasecmp(nameincert, *pname) == 0;
size_t namelen = strlen(*pname);
char *name = (char *)malloc(namelen);
int match, ret;
OPENSSL_memcpy(name, *pname, namelen);
ret = X509_check_host(crt, name, namelen, 0, NULL);
match = -1;
if (ret < 0) {
fprintf(stderr, "internal error in X509_check_host\n");
++errors;
} else if (fn->host) {
if (ret == 1 && !samename)
match = 1;
if (ret == 0 && samename)
match = 0;
} else if (ret == 1)
match = 1;
check_message(fn, "host", nameincert, match, *pname);
ret = X509_check_host(crt, name, namelen,
X509_CHECK_FLAG_NO_WILDCARDS, NULL);
match = -1;
if (ret < 0) {
fprintf(stderr, "internal error in X509_check_host\n");
++errors;
} else if (fn->host) {
if (ret == 1 && !samename)
match = 1;
if (ret == 0 && samename)
match = 0;
} else if (ret == 1)
match = 1;
check_message(fn, "host-no-wildcards", nameincert, match, *pname);
ret = X509_check_email(crt, name, namelen, 0);
match = -1;
if (fn->email) {
if (ret && !samename)
match = 1;
if (!ret && samename && strchr(nameincert, '@') != NULL)
match = 0;
} else if (ret)
match = 1;
check_message(fn, "email", nameincert, match, *pname);
++pname;
free(name);
}
}
// TODO(davidben): Convert this test to GTest more thoroughly.
TEST(X509V3Test, NameTest) {
const struct set_name_fn *pfn = name_fns;
while (pfn->name) {
const char *const *pname = names;
while (*pname) {
// The common name fallback requires the name look sufficiently
// DNS-like.
if (strcmp(pfn->name, "set CN") == 0 &&
!x509v3_looks_like_dns_name(
reinterpret_cast<const unsigned char*>(*pname),
strlen(*pname))) {
++pname;
continue;
}
bssl::UniquePtr<X509> crt(make_cert());
ASSERT_TRUE(crt);
ASSERT_TRUE(pfn->fn(crt.get(), *pname));
run_cert(crt.get(), *pname, pfn);
++pname;
}
++pfn;
}
EXPECT_EQ(0, errors);
}
Loading…
Cancel
Save