提交 a09e4d24 编写于 作者: V Viktor Dukhovni 提交者: Dr. Stephen Henson

Client-side namecheck wildcards.

A client reference identity of ".example.com" matches a server
certificate presented identity that is any sub-domain of "example.com"
(e.g. "www.sub.example.com).

With the X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS flag, it matches
only direct child sub-domains (e.g. "www.sub.example.com").
上级 abfb989f
...@@ -572,11 +572,50 @@ typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len, ...@@ -572,11 +572,50 @@ typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len,
const unsigned char *subject, size_t subject_len, const unsigned char *subject, size_t subject_len,
unsigned int flags); unsigned int flags);
/* Skip pattern prefix to match "wildcard" subject */
static void skip_prefix(const unsigned char **p, size_t *plen,
const unsigned char *subject, size_t subject_len,
unsigned int flags)
{
const unsigned char *pattern = *p;
size_t pattern_len = *plen;
/*
* If subject starts with a leading '.' followed by more octets, and
* pattern is longer, compare just an equal-length suffix with the
* full subject (starting at the '.'), provided the prefix contains
* no NULs. (We check again that subject starts with '.' and
* contains at least one subsequent character, just in case the
* internal _X509_CHECK_FLAG_DOT_SUBDOMAINS flag was erroneously
* set by the user).
*/
if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0 ||
subject_len <= 1 || subject[0] != '.')
return;
while (pattern_len > subject_len && *pattern)
{
if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) &&
*pattern == '.')
break;
++pattern;
--pattern_len;
}
/* Skip if entire prefix acceptable */
if (pattern_len == subject_len)
{
*p = pattern;
*plen = pattern_len;
}
}
/* Compare while ASCII ignoring case. */ /* Compare while ASCII ignoring case. */
static int equal_nocase(const unsigned char *pattern, size_t pattern_len, static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
const unsigned char *subject, size_t subject_len, const unsigned char *subject, size_t subject_len,
unsigned int unused_flags) unsigned int flags)
{ {
skip_prefix(&pattern, &pattern_len, subject, subject_len, flags);
if (pattern_len != subject_len) if (pattern_len != subject_len)
return 0; return 0;
while (pattern_len) while (pattern_len)
...@@ -605,11 +644,9 @@ static int equal_nocase(const unsigned char *pattern, size_t pattern_len, ...@@ -605,11 +644,9 @@ static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
/* Compare using memcmp. */ /* Compare using memcmp. */
static int equal_case(const unsigned char *pattern, size_t pattern_len, static int equal_case(const unsigned char *pattern, size_t pattern_len,
const unsigned char *subject, size_t subject_len, const unsigned char *subject, size_t subject_len,
unsigned int unused_flags) unsigned int flags)
{ {
/* The pattern must not contain NUL characters. */ skip_prefix(&pattern, &pattern_len, subject, subject_len, flags);
if (memchr(pattern, '\0', pattern_len) != NULL)
return 0;
if (pattern_len != subject_len) if (pattern_len != subject_len)
return 0; return 0;
return !memcmp(pattern, subject, pattern_len); return !memcmp(pattern, subject, pattern_len);
...@@ -797,7 +834,14 @@ static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, ...@@ -797,7 +834,14 @@ static int equal_wildcard(const unsigned char *pattern, size_t pattern_len,
const unsigned char *subject, size_t subject_len, const unsigned char *subject, size_t subject_len,
unsigned int flags) unsigned int flags)
{ {
const unsigned char *star = valid_star(pattern, pattern_len, flags); const unsigned char *star = NULL;
/*
* Subject names starting with '.' can only match a wildcard pattern
* via a subject sub-domain pattern suffix match.
*/
if (!(subject_len > 1 && subject[0] == '.'))
star = valid_star(pattern, pattern_len, flags);
if (star == NULL) if (star == NULL)
return equal_nocase(pattern, pattern_len, return equal_nocase(pattern, pattern_len,
subject, subject_len, flags); subject, subject_len, flags);
...@@ -860,6 +904,9 @@ static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen, ...@@ -860,6 +904,9 @@ static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen,
else if (check_type == GEN_DNS) else if (check_type == GEN_DNS)
{ {
cnid = NID_commonName; cnid = NID_commonName;
/* Implicit client-side DNS sub-domain pattern */
if (chklen > 1 && chk[0] == '.')
flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS;
alt_type = V_ASN1_IA5STRING; alt_type = V_ASN1_IA5STRING;
if (flags & X509_CHECK_FLAG_NO_WILDCARDS) if (flags & X509_CHECK_FLAG_NO_WILDCARDS)
equal = equal_nocase; equal = equal_nocase;
......
...@@ -11,6 +11,7 @@ static const char *const names[] = ...@@ -11,6 +11,7 @@ static const char *const names[] =
"*@example.com", "test@*.example.com", "example.com", "www.example.com", "*@example.com", "test@*.example.com", "example.com", "www.example.com",
"test.www.example.com", "*.example.com", "*.www.example.com", "test.www.example.com", "*.example.com", "*.www.example.com",
"test.*.example.com", "www.*.com", "test.*.example.com", "www.*.com",
".www.example.com", "*www.example.com",
"example.net", "xn--rger-koa.example.com", "example.net", "xn--rger-koa.example.com",
"a.example.com", "b.example.com", "a.example.com", "b.example.com",
"postmaster@example.com", "Postmaster@example.com", "postmaster@example.com", "Postmaster@example.com",
...@@ -25,6 +26,11 @@ static const char *const exceptions[] = ...@@ -25,6 +26,11 @@ static const char *const exceptions[] =
"set CN: host: [*.example.com] matches [www.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: [*.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 [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-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 emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]", "set emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]",
...@@ -34,6 +40,11 @@ static const char *const exceptions[] = ...@@ -34,6 +40,11 @@ static const char *const exceptions[] =
"set dnsName: host: [*.example.com] matches [b.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: [*.example.com] matches [xn--rger-koa.example.com]",
"set dnsName: host: [*.www.example.com] matches [test.www.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 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]",
"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]", "set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
......
...@@ -710,6 +710,14 @@ STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); ...@@ -710,6 +710,14 @@ STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4 #define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4
/* Allow (non-partial) wildcards to match multiple labels. */ /* Allow (non-partial) wildcards to match multiple labels. */
#define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 #define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8
/* Constraint verifier subdomain patterns to match a single labels. */
#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10
/*
* Match reference identifiers starting with "." to any sub-domain.
* This is a non-public flag, turned on implicitly when the subject
* reference identity is a DNS name.
*/
#define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000
int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen, int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
unsigned int flags); unsigned int flags);
......
...@@ -27,7 +27,10 @@ X509_check_host() checks if the certificate matches the specified ...@@ -27,7 +27,10 @@ X509_check_host() checks if the certificate matches the specified
host name, which must be encoded in the preferred name syntax host name, which must be encoded in the preferred name syntax
described in section 3.5 of RFC 1034. The B<namelen> argument must be described in section 3.5 of RFC 1034. The B<namelen> argument must be
the number of characters in the name string or zero in which case the the number of characters in the name string or zero in which case the
length is calculated with strlen(name). length is calculated with strlen(name). When B<name> starts with
a dot (e.g ".example.com"), it will be matched by a certificate
valid for any sub-domain of B<name>, (see also
B<X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS> below).
X509_check_email() checks if the certificate matches the specified X509_check_email() checks if the certificate matches the specified
email address. Only the mailbox syntax of RFC 822 is supported, email address. Only the mailbox syntax of RFC 822 is supported,
...@@ -59,6 +62,8 @@ flags: ...@@ -59,6 +62,8 @@ flags:
=item B<X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS>. =item B<X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS>.
=item B<X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS>.
=back =back
The B<X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT> flag causes the function The B<X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT> flag causes the function
...@@ -74,10 +79,18 @@ If set, B<X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS> suppresses support ...@@ -74,10 +79,18 @@ If set, B<X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS> suppresses support
for "*" as wildcard pattern in labels that have a prefix or suffix, for "*" as wildcard pattern in labels that have a prefix or suffix,
such as: "www*" or "*www"; this only aplies to B<X509_check_host>. such as: "www*" or "*www"; this only aplies to B<X509_check_host>.
If set, B<X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS>, allows a "*" If set, B<X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS> allows a "*" that
that constitutes the complete label of a DNS name (e.g. constitutes the complete label of a DNS name (e.g. "*.example.com")
"*.example.com") to match more than one label in B<name>; to match more than one label in B<name>; this flag only applies
this only applies to B<X509_check_host>. to B<X509_check_host>.
If set, B<X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS> restricts B<name>
values which start with ".", that would otherwise match any sub-domain
in the peer certificate, to only match direct child sub-domains.
Thus, for instance, with this flag set a B<name> of ".example.com"
would match a peer certificate with a DNS name of "www.example.com",
but would not match a peer certificate with a DNS name of
"www.sub.example.com"; this flag only applies to B<X509_check_host>.
=head1 RETURN VALUES =head1 RETURN VALUES
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册