add WOLFSSL_LEFT_MOST_WILDCARD_ONLY support to X509_check_host()
This commit is contained in:
parent
bf29b68600
commit
f878220b81
@ -12508,16 +12508,20 @@ int CipherRequires(byte first, byte second, int requirement)
|
||||
|
||||
#ifndef NO_CERTS
|
||||
|
||||
|
||||
/* Match names with wildcards, each wildcard can represent a single name
|
||||
component or fragment but not multiple names, i.e.,
|
||||
*.z.com matches y.z.com but not x.y.z.com
|
||||
|
||||
If flags contains WOLFSSL_LEFT_MOST_WILDCARD_ONLY, wildcard only applies
|
||||
to left-most name component, compatible with RFC 2830 identity checking.
|
||||
|
||||
return 1 on success */
|
||||
int MatchDomainName(const char* pattern, int patternLen, const char* str,
|
||||
word32 strLen)
|
||||
word32 strLen, unsigned int flags)
|
||||
{
|
||||
int ret = 0;
|
||||
byte wildcardEligible = 1;
|
||||
byte leftWildcardOnly = flags & WOLFSSL_LEFT_MOST_WILDCARD_ONLY;
|
||||
|
||||
if (pattern == NULL || str == NULL || patternLen <= 0 || strLen == 0)
|
||||
return 0;
|
||||
@ -12530,11 +12534,16 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
|
||||
|
||||
pattern++;
|
||||
|
||||
if (p == '*') {
|
||||
if ((p == '*') && wildcardEligible) {
|
||||
char s;
|
||||
/* We will always match '*' */
|
||||
patternLen--;
|
||||
|
||||
/* Only single wildcard allowed with strict left only */
|
||||
if (leftWildcardOnly) {
|
||||
wildcardEligible = 0;
|
||||
}
|
||||
|
||||
/* Consume any extra '*' chars until the next non '*' char. */
|
||||
while (patternLen > 0) {
|
||||
p = (char)XTOLOWER((unsigned char)*pattern);
|
||||
@ -12543,6 +12552,10 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
|
||||
return 0;
|
||||
if (p != '*')
|
||||
break;
|
||||
if (leftWildcardOnly && (p == '*')) {
|
||||
/* RFC2830 only allows single left-most wildcard */
|
||||
return 0;
|
||||
}
|
||||
|
||||
patternLen--;
|
||||
}
|
||||
@ -12574,6 +12587,11 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Past left-most wildcard location, not eligible if flag set*/
|
||||
if (leftWildcardOnly && wildcardEligible) {
|
||||
wildcardEligible = 0;
|
||||
}
|
||||
|
||||
/* Simple case, pattern match exactly */
|
||||
if (p != (char)XTOLOWER((unsigned char) *str))
|
||||
return 0;
|
||||
@ -12605,7 +12623,7 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
|
||||
* -1 : No matches and wild pattern match failed.
|
||||
*/
|
||||
int CheckForAltNames(DecodedCert* dCert, const char* domain, word32 domainLen,
|
||||
int* checkCN)
|
||||
int* checkCN, unsigned int flags)
|
||||
{
|
||||
int match = 0;
|
||||
DNS_entry* altName = NULL;
|
||||
@ -12636,7 +12654,7 @@ int CheckForAltNames(DecodedCert* dCert, const char* domain, word32 domainLen,
|
||||
len = (word32)altName->len;
|
||||
}
|
||||
|
||||
if (MatchDomainName(buf, (int)len, domain, domainLen)) {
|
||||
if (MatchDomainName(buf, (int)len, domain, domainLen, flags)) {
|
||||
match = 1;
|
||||
if (checkCN != NULL) {
|
||||
*checkCN = 0;
|
||||
@ -12665,13 +12683,14 @@ int CheckForAltNames(DecodedCert* dCert, const char* domain, word32 domainLen,
|
||||
* domainNameLen The length of the domain name.
|
||||
* returns DOMAIN_NAME_MISMATCH when no match found and 0 on success.
|
||||
*/
|
||||
int CheckHostName(DecodedCert* dCert, const char *domainName, size_t domainNameLen)
|
||||
int CheckHostName(DecodedCert* dCert, const char *domainName,
|
||||
size_t domainNameLen, unsigned int flags)
|
||||
{
|
||||
int checkCN;
|
||||
int ret = WC_NO_ERR_TRACE(DOMAIN_NAME_MISMATCH);
|
||||
|
||||
if (CheckForAltNames(dCert, domainName, (word32)domainNameLen,
|
||||
&checkCN) != 1) {
|
||||
&checkCN, flags) != 1) {
|
||||
ret = DOMAIN_NAME_MISMATCH;
|
||||
WOLFSSL_MSG("DomainName match on alt names failed");
|
||||
}
|
||||
@ -12682,7 +12701,7 @@ int CheckHostName(DecodedCert* dCert, const char *domainName, size_t domainNameL
|
||||
#ifndef WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY
|
||||
if (checkCN == 1) {
|
||||
if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
|
||||
domainName, (word32)domainNameLen) == 1) {
|
||||
domainName, (word32)domainNameLen, flags) == 1) {
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
@ -12699,7 +12718,7 @@ int CheckIPAddr(DecodedCert* dCert, const char* ipasc)
|
||||
{
|
||||
WOLFSSL_MSG("Checking IPAddr");
|
||||
|
||||
return CheckHostName(dCert, ipasc, (size_t)XSTRLEN(ipasc));
|
||||
return CheckHostName(dCert, ipasc, (size_t)XSTRLEN(ipasc), 0);
|
||||
}
|
||||
|
||||
|
||||
@ -13843,7 +13862,7 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int cert_err,
|
||||
/* If altNames names is present, then subject common name is ignored */
|
||||
if (args->dCert->altNames != NULL) {
|
||||
if (CheckForAltNames(args->dCert, ssl->param->hostName,
|
||||
(word32)XSTRLEN(ssl->param->hostName), NULL) != 1) {
|
||||
(word32)XSTRLEN(ssl->param->hostName), NULL, 0) != 1) {
|
||||
if (cert_err == 0) {
|
||||
ret = DOMAIN_NAME_MISMATCH;
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
@ -13857,7 +13876,7 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int cert_err,
|
||||
args->dCert->subjectCN,
|
||||
args->dCert->subjectCNLen,
|
||||
ssl->param->hostName,
|
||||
(word32)XSTRLEN(ssl->param->hostName)) == 0) {
|
||||
(word32)XSTRLEN(ssl->param->hostName), 0) == 0) {
|
||||
if (cert_err == 0) {
|
||||
ret = DOMAIN_NAME_MISMATCH;
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
@ -15747,7 +15766,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
(ssl->buffers.domainName.buffer == NULL ? 0 :
|
||||
(word32)XSTRLEN(
|
||||
(const char *)ssl->buffers.domainName.buffer)),
|
||||
NULL) != 1) {
|
||||
NULL, 0) != 1) {
|
||||
WOLFSSL_MSG("DomainName match on alt names failed");
|
||||
/* try to get peer key still */
|
||||
ret = DOMAIN_NAME_MISMATCH;
|
||||
@ -15762,7 +15781,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
(ssl->buffers.domainName.buffer == NULL ? 0 :
|
||||
(word32)XSTRLEN(
|
||||
(const char *)ssl->buffers.domainName.buffer)
|
||||
)) == 0)
|
||||
), 0) == 0)
|
||||
{
|
||||
WOLFSSL_MSG("DomainName match on common name failed");
|
||||
ret = DOMAIN_NAME_MISMATCH;
|
||||
@ -15775,14 +15794,14 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
args->dCert->subjectCNLen,
|
||||
(char*)ssl->buffers.domainName.buffer,
|
||||
(ssl->buffers.domainName.buffer == NULL ? 0 :
|
||||
(word32)XSTRLEN(ssl->buffers.domainName.buffer))) == 0)
|
||||
(word32)XSTRLEN(ssl->buffers.domainName.buffer)), 0) == 0)
|
||||
{
|
||||
WOLFSSL_MSG("DomainName match on common name failed");
|
||||
if (CheckForAltNames(args->dCert,
|
||||
(char*)ssl->buffers.domainName.buffer,
|
||||
(ssl->buffers.domainName.buffer == NULL ? 0 :
|
||||
(word32)XSTRLEN(ssl->buffers.domainName.buffer)),
|
||||
NULL) != 1) {
|
||||
NULL, 0) != 1) {
|
||||
WOLFSSL_MSG(
|
||||
"DomainName match on alt names failed too");
|
||||
/* try to get peer key still */
|
||||
|
@ -14338,7 +14338,6 @@ int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen,
|
||||
WOLFSSL_ENTER("wolfSSL_X509_check_host");
|
||||
|
||||
/* flags and peername not needed for Nginx. */
|
||||
(void)flags;
|
||||
(void)peername;
|
||||
|
||||
if ((x == NULL) || (chk == NULL)) {
|
||||
@ -14390,7 +14389,7 @@ int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen,
|
||||
chklen--;
|
||||
}
|
||||
|
||||
ret = CheckHostName(dCert, (char *)chk, chklen);
|
||||
ret = CheckHostName(dCert, (char *)chk, chklen, flags);
|
||||
|
||||
out:
|
||||
|
||||
|
81
tests/api.c
81
tests/api.c
@ -55652,20 +55652,42 @@ static int test_wolfSSL_X509_check_host(void)
|
||||
&& !defined(NO_SHA) && !defined(NO_RSA)
|
||||
X509* x509 = NULL;
|
||||
const char altName[] = "example.com";
|
||||
const char badAltName[] = "a.example.com";
|
||||
|
||||
/* cliCertFile has subjectAltName set to 'example.com', '127.0.0.1' */
|
||||
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(cliCertFile,
|
||||
SSL_FILETYPE_PEM));
|
||||
|
||||
ExpectIntEQ(X509_check_host(x509, altName, XSTRLEN(altName), 0, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(X509_check_host(x509, badAltName, XSTRLEN(badAltName), 0, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
|
||||
ExpectIntEQ(X509_check_host(x509, NULL, 0, 0, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
|
||||
/* Check WOLFSSL_LEFT_MOST_WILDCARD_ONLY flag set */
|
||||
ExpectIntEQ(X509_check_host(x509, altName, XSTRLEN(altName),
|
||||
WOLFSSL_LEFT_MOST_WILDCARD_ONLY, NULL), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(X509_check_host(x509, NULL, 0,
|
||||
WOLFSSL_LEFT_MOST_WILDCARD_ONLY, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
|
||||
ExpectIntEQ(X509_check_host(x509, badAltName, XSTRLEN(badAltName),
|
||||
WOLFSSL_LEFT_MOST_WILDCARD_ONLY, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
|
||||
X509_free(x509);
|
||||
|
||||
ExpectIntEQ(X509_check_host(NULL, altName, XSTRLEN(altName), 0, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
|
||||
/* Check again with WOLFSSL_LEFT_MOST_WILDCARD_ONLY flag set */
|
||||
ExpectIntEQ(X509_check_host(NULL, altName, XSTRLEN(altName),
|
||||
WOLFSSL_LEFT_MOST_WILDCARD_ONLY, NULL),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
@ -63359,6 +63381,12 @@ static int test_wolfSSL_X509_bad_altname(void)
|
||||
* name of "a*\0*". Ensure that it does not match "aaaaa" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name, nameLen,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT, NULL), 1);
|
||||
|
||||
/* Also make sure WOLFSSL_LEFT_MOST_WILDCARD_ONLY fails too */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name, nameLen,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), 1);
|
||||
|
||||
X509_free(x509);
|
||||
|
||||
#endif
|
||||
@ -63479,6 +63507,26 @@ static int test_wolfSSL_X509_name_match(void)
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name4, nameLen4,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT, NULL), 1);
|
||||
|
||||
/* WOLFSSL_LEFT_MOST_WILDCARD_ONLY flag should fail on all cases, since
|
||||
* 'a*' alt name does not have wildcard left-most */
|
||||
|
||||
/* Ensure that "a*" does not match "aaaaa" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name1, nameLen1,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
/* Ensure that "a*" does not match "a" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name2, nameLen2,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
/* Ensure that "a*" does not match "abbbb" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name3, nameLen3,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
/* Ensure that "a*" does not match "bbb" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name4, nameLen4,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
|
||||
wolfSSL_X509_free(x509);
|
||||
|
||||
#endif
|
||||
@ -63601,6 +63649,21 @@ static int test_wolfSSL_X509_name_match2(void)
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name4, nameLen4,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT, NULL), WOLFSSL_SUCCESS);
|
||||
|
||||
/* WOLFSSL_LEFT_MOST_WILDCARD_ONLY flag should fail on all cases, since
|
||||
* 'a*b*' alt name does not have wildcard left-most */
|
||||
ExpectIntEQ(wolfSSL_X509_check_host(x509, name1, nameLen1,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_FAILURE);
|
||||
ExpectIntEQ(wolfSSL_X509_check_host(x509, name2, nameLen2,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_FAILURE);
|
||||
ExpectIntEQ(wolfSSL_X509_check_host(x509, name3, nameLen3,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_FAILURE);
|
||||
ExpectIntEQ(wolfSSL_X509_check_host(x509, name4, nameLen4,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_FAILURE);
|
||||
|
||||
/* Ensure that "a*b*" matches "ab", testing openssl behavior replication
|
||||
* on check len input handling, 0 for len is OK as it should then use
|
||||
* strlen(name1) */
|
||||
@ -63714,6 +63777,8 @@ static int test_wolfSSL_X509_name_match3(void)
|
||||
int nameLen1 = (int)(XSTRLEN(name1));
|
||||
const char *name2 = "x.y.example.com";
|
||||
int nameLen2 = (int)(XSTRLEN(name2));
|
||||
const char *name3 = "example.com";
|
||||
int nameLen3 = (int)(XSTRLEN(name3));
|
||||
|
||||
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_buffer(
|
||||
cert_der, certSize, WOLFSSL_FILETYPE_ASN1));
|
||||
@ -63724,6 +63789,22 @@ static int test_wolfSSL_X509_name_match3(void)
|
||||
/* Ensure that "*.example.com" does NOT match "x.y.example.com" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name2, nameLen2,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT, NULL), WOLFSSL_SUCCESS);
|
||||
/* Ensure that "*.example.com" does NOT match "example.com" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name3, nameLen3,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT, NULL), WOLFSSL_SUCCESS);
|
||||
|
||||
/* WOLFSSL_LEFT_MOST_WILDCARD_ONLY, should match "foo.example.com" */
|
||||
ExpectIntEQ(wolfSSL_X509_check_host(x509, name1, nameLen1,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
/* WOLFSSL_LEFT_MOST_WILDCARD_ONLY, should NOT match "x.y.example.com" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name2, nameLen2,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
/* WOLFSSL_LEFT_MOST_WILDCARD_ONLY, should NOT match "example.com" */
|
||||
ExpectIntNE(wolfSSL_X509_check_host(x509, name3, nameLen3,
|
||||
WOLFSSL_ALWAYS_CHECK_SUBJECT | WOLFSSL_LEFT_MOST_WILDCARD_ONLY,
|
||||
NULL), WOLFSSL_SUCCESS);
|
||||
|
||||
wolfSSL_X509_free(x509);
|
||||
|
||||
|
@ -2240,9 +2240,13 @@ WOLFSSL_LOCAL void FreeAsyncCtx(WOLFSSL* ssl, byte freeAsync);
|
||||
WOLFSSL_LOCAL void FreeKeyExchange(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL void FreeSuites(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz);
|
||||
WOLFSSL_LOCAL int MatchDomainName(const char* pattern, int len, const char* str, word32 strLen);
|
||||
WOLFSSL_LOCAL int MatchDomainName(const char* pattern, int len,
|
||||
const char* str, word32 strLen,
|
||||
unsigned int flags);
|
||||
#if !defined(NO_CERTS) && !defined(NO_ASN)
|
||||
WOLFSSL_LOCAL int CheckForAltNames(DecodedCert* dCert, const char* domain, word32 domainLen, int* checkCN);
|
||||
WOLFSSL_LOCAL int CheckForAltNames(DecodedCert* dCert, const char* domain,
|
||||
word32 domainLen, int* checkCN,
|
||||
unsigned int flags);
|
||||
WOLFSSL_LOCAL int CheckIPAddr(DecodedCert* dCert, const char* ipasc);
|
||||
WOLFSSL_LOCAL void CopyDecodedName(WOLFSSL_X509_NAME* name, DecodedCert* dCert, int nameType);
|
||||
#endif
|
||||
@ -6252,7 +6256,7 @@ WOLFSSL_API void SSL_ResourceFree(WOLFSSL* ssl); /* Micrium uses */
|
||||
|
||||
#ifndef NO_ASN
|
||||
WOLFSSL_LOCAL int CheckHostName(DecodedCert* dCert, const char *domainName,
|
||||
size_t domainNameLen);
|
||||
size_t domainNameLen, unsigned int flags);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -606,6 +606,8 @@ struct WOLFSSL_X509_STORE {
|
||||
#define WOLFSSL_NO_WILDCARDS 0x2
|
||||
#define WOLFSSL_NO_PARTIAL_WILDCARDS 0x4
|
||||
#define WOLFSSL_MULTI_LABEL_WILDCARDS 0x8
|
||||
/* Custom to wolfSSL, OpenSSL compat goes up to 0x20 */
|
||||
#define WOLFSSL_LEFT_MOST_WILDCARD_ONLY 0x40
|
||||
|
||||
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
|
||||
#define WOLFSSL_USE_CHECK_TIME 0x2
|
||||
|
Loading…
Reference in New Issue
Block a user