Improve ctx->param handling

- wolfSSL_X509_verify_cert: add host check from `ctx->param`
- wolfSSL_X509_verify_cert: Set `ctx->error_depth` on error
- Use WOLFSSL_-prefixed error constants (always available) instead of
  OPENSSL_COEXIST-guarded macros, fixing error code mismatch in
  coexist builds
- Set ctx->current_cert = orig on hostname/IP mismatch so error
  reporting aligns with error_depth = 0 (leaf cert)
- Add IP address verification test cases (match + mismatch)
This commit is contained in:
Juliusz Sosinowicz
2026-03-11 18:19:29 +01:00
parent 15fa0b7abe
commit 99ae809e08
7 changed files with 144 additions and 2 deletions
+6
View File
@@ -27084,6 +27084,12 @@ static const char* wolfSSL_ERR_reason_error_string_OpenSSL(unsigned long e)
case WOLFSSL_X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
return "subject issuer mismatch";
case WOLFSSL_X509_V_ERR_HOSTNAME_MISMATCH:
return "hostname mismatch";
case WOLFSSL_X509_V_ERR_IP_ADDRESS_MISMATCH:
return "IP address mismatch";
default:
return NULL;
}
+27
View File
@@ -740,6 +740,33 @@ exit:
wolfSSL_sk_X509_free(certsToUse);
}
/* Enforce hostname / IP verification from X509_VERIFY_PARAM if set.
* Always check against the leaf (end-entity) certificate, captured in
* orig before the chain-building loop modified ctx->current_cert. */
if (ctx->param != NULL) {
if (ret == WOLFSSL_SUCCESS && ctx->param->hostName[0] != '\0') {
if (wolfSSL_X509_check_host(orig,
ctx->param->hostName,
XSTRLEN(ctx->param->hostName),
ctx->param->hostFlags, NULL) != WOLFSSL_SUCCESS) {
ctx->error = WOLFSSL_X509_V_ERR_HOSTNAME_MISMATCH;
ctx->error_depth = 0;
ctx->current_cert = orig;
ret = WOLFSSL_FAILURE;
}
}
if (ret == WOLFSSL_SUCCESS && ctx->param->ipasc[0] != '\0') {
if (wolfSSL_X509_check_ip_asc(orig,
ctx->param->ipasc,
ctx->param->hostFlags) != WOLFSSL_SUCCESS) {
ctx->error = WOLFSSL_X509_V_ERR_IP_ADDRESS_MISMATCH;
ctx->error_depth = 0;
ctx->current_cert = orig;
ret = WOLFSSL_FAILURE;
}
}
}
return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
}
+2
View File
@@ -27168,6 +27168,8 @@ static int error_test(void)
{17, 15},
{19, 19},
{27, 26 },
{61, 30},
{63, 63},
#endif
{ -9, WC_SPAN1_FIRST_E + 1 },
{ -124, -124 },
+98
View File
@@ -244,6 +244,104 @@ int test_x509_GetCAByAKID(void)
return EXPECT_RESULT();
}
/* Regression test: wolfSSL_X509_verify_cert() must honour the hostname set via
* X509_VERIFY_PARAM_set1_host(). Before the fix the hostname was stored in
* ctx->param->hostName but never consulted, so any chain-valid certificate
* would pass regardless of hostname mismatch (RFC 6125 sec. 6.4.1 violation).
*
* Uses existing PEM fixtures:
* svrCertFile - CN=www.wolfssl.com, SAN DNS=example.com, SAN IP=127.0.0.1
* caCertFile - CA that signed svrCertFile
*/
int test_x509_verify_cert_hostname_check(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_RSA)
WOLFSSL_X509_STORE* store = NULL;
WOLFSSL_X509_STORE_CTX* ctx = NULL;
WOLFSSL_X509* ca = NULL;
WOLFSSL_X509* leaf = NULL;
WOLFSSL_X509_VERIFY_PARAM* param = NULL;
ExpectNotNull(store = wolfSSL_X509_STORE_new());
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
ExpectNotNull(leaf = wolfSSL_X509_load_certificate_file(svrCertFile,
SSL_FILETYPE_PEM));
/* Case 1: no hostname constraint - must succeed. */
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, leaf, NULL),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_verify_cert(ctx), WOLFSSL_SUCCESS);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Case 2: hostname matches a SAN DNS entry - must succeed. */
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, leaf, NULL),
WOLFSSL_SUCCESS);
param = wolfSSL_X509_STORE_CTX_get0_param(ctx);
ExpectNotNull(param);
ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_host(param, "example.com",
XSTRLEN("example.com")), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_verify_cert(ctx), WOLFSSL_SUCCESS);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Case 3: hostname does not match - must FAIL with the right error code. */
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, leaf, NULL),
WOLFSSL_SUCCESS);
param = wolfSSL_X509_STORE_CTX_get0_param(ctx);
ExpectNotNull(param);
ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_host(param, "wrong.com",
XSTRLEN("wrong.com")), WOLFSSL_SUCCESS);
ExpectIntNE(wolfSSL_X509_verify_cert(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
X509_V_ERR_HOSTNAME_MISMATCH);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error_depth(ctx), 0);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
#ifdef WOLFSSL_IP_ALT_NAME
/* Case 4: IP matches a SAN IP entry - must succeed. */
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, leaf, NULL),
WOLFSSL_SUCCESS);
param = wolfSSL_X509_STORE_CTX_get0_param(ctx);
ExpectNotNull(param);
ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(param, "127.0.0.1"),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_verify_cert(ctx), WOLFSSL_SUCCESS);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Case 5: IP does not match - must FAIL with the right error code. */
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, leaf, NULL),
WOLFSSL_SUCCESS);
param = wolfSSL_X509_STORE_CTX_get0_param(ctx);
ExpectNotNull(param);
ExpectIntEQ(wolfSSL_X509_VERIFY_PARAM_set1_ip_asc(param, "192.168.1.1"),
WOLFSSL_SUCCESS);
ExpectIntNE(wolfSSL_X509_verify_cert(ctx), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
X509_V_ERR_IP_ADDRESS_MISMATCH);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error_depth(ctx), 0);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
#endif /* WOLFSSL_IP_ALT_NAME */
wolfSSL_X509_free(leaf);
wolfSSL_X509_free(ca);
wolfSSL_X509_STORE_free(store);
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_RSA */
return EXPECT_RESULT();
}
int test_x509_set_serialNumber(void)
{
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
+3 -1
View File
@@ -25,10 +25,12 @@
int test_x509_rfc2818_verification_callback(void);
int test_x509_GetCAByAKID(void);
int test_x509_set_serialNumber(void);
int test_x509_verify_cert_hostname_check(void);
#define TEST_X509_DECLS \
TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback), \
TEST_DECL_GROUP("x509", test_x509_GetCAByAKID), \
TEST_DECL_GROUP("x509", test_x509_set_serialNumber)
TEST_DECL_GROUP("x509", test_x509_set_serialNumber), \
TEST_DECL_GROUP("x509", test_x509_verify_cert_hostname_check)
#endif /* WOLFCRYPT_TEST_X509_H */
+3 -1
View File
@@ -2685,7 +2685,9 @@ enum {
WOLFSSL_X509_V_ERR_PATH_LENGTH_EXCEEDED = 25,
WOLFSSL_X509_V_ERR_CERT_REJECTED = 28,
WOLFSSL_X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29,
WC_OSSL_V509_V_ERR_MAX = 30,
WOLFSSL_X509_V_ERR_HOSTNAME_MISMATCH = 62,
WOLFSSL_X509_V_ERR_IP_ADDRESS_MISMATCH = 64,
WC_OSSL_V509_V_ERR_MAX = 65,
#ifdef HAVE_OCSP
/* OCSP Flags */
+5
View File
@@ -4819,6 +4819,11 @@ extern void uITRON4_free(void *p) ;
#error "OPENSSL_ALL can not be defined with OPENSSL_COEXIST"
#endif
/* OPENSSL_ALL requires WOLFSSL_IP_ALT_NAME for IP SAN verification. */
#if defined(OPENSSL_ALL) && !defined(WOLFSSL_IP_ALT_NAME)
#error "OPENSSL_ALL requires WOLFSSL_IP_ALT_NAME"
#endif
#if !defined(NO_DSA) && defined(NO_SHA)
#error "Please disable DSA if disabling SHA-1"
#endif