From: Bob Beck Date: Thu, 29 Jan 2026 18:31:40 +0000 (-0700) Subject: Deprecate the X509_check_{email,host,ip,ip_asc} family of functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c7c8dea22984bab394bc227fabfe1b9416df952f;p=thirdparty%2Fopenssl.git Deprecate the X509_check_{email,host,ip,ip_asc} family of functions Our own documentation for quite some time has indicated that you should call X509_verify_cert() instead of using these. Actually deprecate them and make apps not use the now deprecated functions. Resolves: https://github.com/openssl/project/issues/1899 References: https://github.com/openssl/project/issues/1897 Reviewed-by: Neil Horman Reviewed-by: Eugene Syromiatnikov Reviewed-by: Norbert Pocs MergeDate: Mon May 11 00:08:33 2026 (Merged from https://github.com/openssl/openssl/pull/30403) --- diff --git a/CHANGES.md b/CHANGES.md index 94953f18bd6..1dd27df4ba1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -80,6 +80,13 @@ OpenSSL Releases *John Claus* +* 'X509_check_host()', 'X509_check_email()', 'X509_check_ip()', and 'X509_check_ip_asc()' + have been deprecated. Applications should migrate to setting a reference identifier + to check using 'X509_VERIFY_PARAM_set1_host()', 'X509_VERIFY_PARAM_set1_email()', or + X509_VERIFY_PARAM_set1_ip_asc()', and using 'X509_verify_cert()'. + + *Bob Beck* + * Added AVX2 optimized ML-DSA NTT operations on `x86_64`. *Marcel Cornu and Tomasz Kantecki* diff --git a/apps/include/apps.h b/apps/include/apps.h index 43097c013e9..97c6669e3af 100644 --- a/apps/include/apps.h +++ b/apps/include/apps.h @@ -317,9 +317,9 @@ extern char *psk_key; unsigned char *next_protos_parse(size_t *outlen, const char *in); -int check_cert_attributes(BIO *bio, X509 *x, +int check_cert_might_be_valid(BIO *bio, BIO *bio_err, X509 *x, const char *checkhost, const char *checkemail, - const char *checkip, int print); + const char *checkip); void store_setup_crl_download(X509_STORE *st); diff --git a/apps/lib/apps.c b/apps/lib/apps.c index fe1bc7e8120..467f36ae1f9 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -86,6 +86,22 @@ int app_init(long mesgwin) } #endif +static int maybe_printf(BIO *bio, const char *format, ...) +{ + va_list args; + int ret = 0; + + if (bio != NULL) { + va_start(args, format); + + ret = BIO_vprintf(bio, format, args); + + va_end(args); + } + + return ret; +} + int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, int noCAfile, const char *CApath, int noCApath, @@ -2447,42 +2463,132 @@ unsigned char *next_protos_parse(size_t *outlen, const char *in) return out; } -int check_cert_attributes(BIO *bio, X509 *x, const char *checkhost, - const char *checkemail, const char *checkip, - int print) +int check_cert_might_be_valid(BIO *bio, BIO *b_err, X509 *x, const char *checkhost, + const char *checkemail, const char *checkip) { - int valid_host = 0; - int valid_mail = 0; - int valid_ip = 0; - int ret = 1; + int ret = 0; + int error; + X509_STORE_CTX *ctx = NULL; + X509_STORE *store = NULL; + X509_VERIFY_PARAM *vpm = NULL; - if (x == NULL) - return 0; + if (x == NULL) { + maybe_printf(b_err, "Internal error, NULL certificate\n"); + goto err; + } - if (checkhost != NULL) { - valid_host = X509_check_host(x, checkhost, 0, 0, NULL); - if (print) - BIO_printf(bio, "Hostname %s does%s match certificate\n", - checkhost, valid_host == 1 ? "" : " NOT"); - ret = ret && valid_host > 0; + if ((store = X509_STORE_new()) == NULL) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; } - if (checkemail != NULL) { - valid_mail = X509_check_email(x, checkemail, 0, 0); - if (print) - BIO_printf(bio, "Email %s does%s match certificate\n", - checkemail, valid_mail ? "" : " NOT"); - ret = ret && valid_mail > 0; + if (!X509_STORE_add_cert(store, x)) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; } - if (checkip != NULL) { - valid_ip = X509_check_ip_asc(x, checkip, 0); - if (print) - BIO_printf(bio, "IP %s does%s match certificate\n", - checkip, valid_ip ? "" : " NOT"); - ret = ret && valid_ip > 0; + if ((vpm = X509_STORE_get0_param(store)) == NULL) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; + } + + if ((ctx = X509_STORE_CTX_new()) == NULL) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; } + /* + * As this is "might verify": + * + * We don't care about the verification time. + * We are trusting ourselves. + * We are very liberal in what we allow. + * + * Needless to say these flags should normally not be used in a + * for real verification. + */ + X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME); + X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN); + X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); + X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS); + X509_VERIFY_PARAM_set_trust(vpm, X509_TRUST_OK_ANY_EKU); + + if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, checkip)) { + maybe_printf(b_err, "Invalid IP address: %s\n", checkip); + goto err; + } + + if (!X509_VERIFY_PARAM_set1_host(vpm, checkhost, 0)) { + maybe_printf(b_err, "Invalid host name: %s\n", checkhost); + goto err; + } + + if (!X509_VERIFY_PARAM_set1_email(vpm, checkemail, 0)) { + maybe_printf(b_err, "Invalid email address: %s\n", checkemail); + goto err; + } + + if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, checkip)) { + maybe_printf(b_err, "Invalid IP address: %s\n", checkip); + goto err; + } + + if (!X509_STORE_CTX_init(ctx, store, x, NULL)) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; + } + + /* We might be verifying for ANY purpose ... */ + if (!X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_ANY)) { + maybe_printf(b_err, "Malloc failed or internal error\n"); + goto err; + } + + ret = X509_verify_cert(ctx); + error = X509_STORE_CTX_get_error(ctx); + if (!ret) { + + maybe_printf(bio, "Certificate may not verify: error %s\n", + X509_verify_cert_error_string(error)); + + if (checkhost != NULL && error == X509_V_ERR_HOSTNAME_MISMATCH) + maybe_printf(bio, "Hostname %s does NOT match certificate\n", + checkhost); + else if (checkemail != NULL && error == X509_V_ERR_EMAIL_MISMATCH) + maybe_printf(bio, "Email %s does NOT match certificate\n", + checkemail); + else if (checkip != NULL && error == X509_V_ERR_IP_ADDRESS_MISMATCH) + maybe_printf(bio, "IP %s does NOT match certificate\n", + checkip); + else { + /* Originally, we only cared about the above failures */ + /* + * Suppress trust rejection errors, we don't care, because + * we don't really know what this might be used for if + * this was for real. + */ + if (error == X509_V_ERR_CERT_REJECTED) { + maybe_printf(bio, "Ignoring certificate rejection error\n"); + ret = 1; + } + } + } else { + if (checkhost != NULL) + maybe_printf(bio, "Hostname %s does match certificate\n", + checkhost); + if (checkemail != NULL) + maybe_printf(bio, "Email %s does match certificate\n", + checkemail); + if (checkip != NULL) + maybe_printf(bio, "IP %s does match certificate\n", + checkip); + } + X509_STORE_CTX_cleanup(ctx); + +err: + ERR_print_errors(b_err); + X509_STORE_free(store); + X509_STORE_CTX_free(ctx); return ret; } diff --git a/apps/s_server.c b/apps/s_server.c index bcb26cb2851..e8f431cd0a7 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -617,7 +617,8 @@ static int ssl_ech_servername_cb(SSL *s, int *ad, void *arg) return SSL_TLSEXT_ERR_NOACK; if (echrv == SSL_ECH_STATUS_SUCCESS && servername != NULL) { if (ctx2 != NULL) { - int check_host = X509_check_host(p->scert, servername, 0, 0, NULL); + int check_host = check_cert_might_be_valid(p->biodebug, + p->biodebug, p->scert, servername, NULL, NULL); if (check_host == 1) { if (p->biodebug != NULL) diff --git a/apps/x509.c b/apps/x509.c index 824daa1ef59..867961e61d1 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -1233,7 +1233,8 @@ cert_loop: goto end; } - if (!check_cert_attributes(out, x, checkhost, checkemail, checkip, 1)) + if (!check_cert_might_be_valid(out, bio_err, x, checkhost, checkemail, + checkip)) goto err; if (noout || nocert) { diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 774d3790e21..4ccfcacadb4 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1001,7 +1001,7 @@ static int do_x509_check(const X509 *x, const char *chk, size_t chklen, return 0; } -int X509_check_host(const X509 *x, const char *chk, size_t chklen, +int ossl_x509_check_host(const X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername) { if (chk == NULL) @@ -1020,6 +1020,14 @@ int X509_check_host(const X509 *x, const char *chk, size_t chklen, return do_x509_check(x, chk, chklen, flags, GEN_DNS, 0, peername); } +#if !defined(OPENSSL_NO_DEPRECATED_4_1) +int X509_check_host(const X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername) +{ + return ossl_x509_check_host(x, chk, chklen, flags, peername); +} +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ + int ossl_x509_check_rfc822(X509 *x, const char *chk, size_t chklen, unsigned int flags) { @@ -1034,6 +1042,15 @@ int ossl_x509_check_smtputf8(X509 *x, const char *chk, size_t chklen, == 1; } +int ossl_x509_check_ip(const X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags) +{ + if (chk == NULL) + return -2; + return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, 0, NULL); +} + +#if !defined(OPENSSL_NO_DEPRECATED_4_1) int X509_check_email(const X509 *x, const char *chk, size_t chklen, unsigned int flags) { @@ -1063,9 +1080,7 @@ int X509_check_email(const X509 *x, const char *chk, size_t chklen, int X509_check_ip(const X509 *x, const unsigned char *chk, size_t chklen, unsigned int flags) { - if (chk == NULL) - return -2; - return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, 0, NULL); + return ossl_x509_check_ip(x, chk, chklen, flags); } int X509_check_ip_asc(const X509 *x, const char *ipasc, unsigned int flags) @@ -1080,6 +1095,7 @@ int X509_check_ip_asc(const X509 *x, const char *ipasc, unsigned int flags) return -2; return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, 0, NULL); } +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ char *ossl_ipaddr_to_asc(const unsigned char *p, int len) { diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 3ec7f691047..27ea9921cd5 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -939,7 +939,9 @@ static int check_hosts(X509 *x, X509_VERIFY_PARAM *vpm) for (int i = 0; i < n; ++i) { size_t len = sk_X509_BUFFER_value(vpm->hosts, i)->len; name = sk_X509_BUFFER_value(vpm->hosts, i)->data; - if (X509_check_host(x, (const char *)name, len, vpm->hostflags, &vpm->peername) > 0) + if (ossl_x509_check_host(x, (const char *)name, len, vpm->hostflags, + &vpm->peername) + > 0) return 1; } return n <= 0; @@ -974,7 +976,7 @@ static int check_ips(X509 *x, X509_VERIFY_PARAM *vpm) for (int i = 0; i < n; ++i) { size_t len = sk_X509_BUFFER_value(vpm->ips, i)->len; name = sk_X509_BUFFER_value(vpm->ips, i)->data; - if (X509_check_ip(x, name, len, vpm->hostflags) > 0) + if (ossl_x509_check_ip(x, name, len, vpm->hostflags) > 0) return 1; } return n <= 0; diff --git a/doc/man1/openssl-x509.pod.in b/doc/man1/openssl-x509.pod.in index 4309c763faf..cbb2ab29e2c 100644 --- a/doc/man1/openssl-x509.pod.in +++ b/doc/man1/openssl-x509.pod.in @@ -379,6 +379,15 @@ Check that the certificate matches the specified email address. Check that the certificate matches the specified IP address. +Certificate checking is done with X.509 certificate verification, +which will fail when encountering an error. As such, when combining +the B<-checkhost>, B<-checkemail>, and B<-checkip> flags, verify will +indicate success if all checks pass, and will indicate failure if they +do not. A diagnostic message of only the first encountered failed +check that stops certificate verification will be printed in the +failing case. If a specific diagnostic message is needed for +individual checks they should be tried individually. + =back =head2 Certificate Output Options diff --git a/doc/man3/X509_check_host.pod b/doc/man3/X509_check_host.pod index 42d0baa7779..6b095f95827 100644 --- a/doc/man3/X509_check_host.pod +++ b/doc/man3/X509_check_host.pod @@ -134,11 +134,11 @@ NULs. =head1 NOTES -Applications are encouraged to use X509_VERIFY_PARAM_set1_host() -rather than explicitly calling L. Hostname -checks may be out of scope with the DANE-EE(3) certificate usage, -and the internal checks will be suppressed as appropriate when -DANE support is enabled. +Applications should use X509_VERIFY_PARAM_set1_host() and +X509_verify_cert() rather than explicitly calling +L. Hostname checks may be out of scope with the +DANE-EE(3) certificate usage, and the internal checks will be +suppressed as appropriate when DANE support is enabled. =head1 SEE ALSO @@ -146,12 +146,15 @@ L, L, L, L, -L +L, +L =head1 HISTORY These functions were added in OpenSSL 1.0.2. +These functions were deprecated in OpenSSL 4.1.0. + =head1 COPYRIGHT Copyright 2012-2026 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 06ec5ecf455..49251311800 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -408,5 +408,9 @@ int ossl_x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth); int ossl_x509_check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify); int ossl_posix_to_asn1_time(int64_t posix_time, ASN1_TIME **out_time); void ossl_x509_verify_param_set_time_posix(X509_VERIFY_PARAM *param, int64_t t); +int ossl_x509_check_host(const X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +int ossl_x509_check_ip(const X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); #endif /* OSSL_CRYPTO_X509_H */ diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 16e40f53797..8e50d31144e 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -814,13 +814,15 @@ STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(const X509 *x); */ #define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000 -int X509_check_host(const X509 *x, const char *chk, size_t chklen, +#if !defined(OPENSSL_NO_DEPRECATED_4_1) +OSSL_DEPRECATEDIN_4_1 int X509_check_host(const X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername); -int X509_check_email(const X509 *x, const char *chk, size_t chklen, +OSSL_DEPRECATEDIN_4_1 int X509_check_email(const X509 *x, const char *chk, size_t chklen, unsigned int flags); -int X509_check_ip(const X509 *x, const unsigned char *chk, size_t chklen, +OSSL_DEPRECATEDIN_4_1 int X509_check_ip(const X509 *x, const unsigned char *chk, size_t chklen, unsigned int flags); -int X509_check_ip_asc(const X509 *x, const char *ipasc, unsigned int flags); +OSSL_DEPRECATEDIN_4_1 int X509_check_ip_asc(const X509 *x, const char *ipasc, unsigned int flags); +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); diff --git a/test/v3nametest.c b/test/v3nametest.c index c73067d9471..8ae7a9e54f3 100644 --- a/test/v3nametest.c +++ b/test/v3nametest.c @@ -10,11 +10,14 @@ #include #include +#include #include #include #include "internal/nelem.h" #include "testutil.h" +#if !defined(OPENSSL_NO_DEPRECATED_4_1) +OSSL_BEGIN_ALLOW_DEPRECATED static const char *const names[] = { "a", "b", ".", "*", "@", ".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..", @@ -227,6 +230,8 @@ static int set_altname_email(X509 *crt, const char *name) { return set_altname(crt, GEN_EMAIL, name, 0); } +OSSL_END_ALLOW_DEPRECATED +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ struct set_name_fn { int (*fn)(X509 *, const char *); @@ -235,6 +240,8 @@ struct set_name_fn { int email; }; +#if !defined(OPENSSL_NO_DEPRECATED_4_1) +OSSL_BEGIN_ALLOW_DEPRECATED static const struct set_name_fn name_fns[] = { { set_cn1, "set CN", 1, 0 }, { set_cn2, "set CN", 1, 0 }, @@ -358,6 +365,8 @@ static int call_run_cert(int i) } return failed == 0; } +OSSL_END_ALLOW_DEPRECATED +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ static struct gennamedata { const unsigned char der[22]; @@ -657,7 +666,9 @@ end: int setup_tests(void) { +#if !defined(OPENSSL_NO_DEPRECATED_4_1) ADD_ALL_TESTS(call_run_cert, OSSL_NELEM(name_fns)); +#endif /* !defined(OPENSSL_NO_DEPRECATED_4_1) */ ADD_TEST(test_GENERAL_NAME_cmp); return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 4e6ac0563c1..b0d0e7266c8 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5439,10 +5439,10 @@ X509_get1_email 5436 4_0_0 EXIST::FUNCTION: X509_REQ_get1_email 5437 4_0_0 EXIST::FUNCTION: X509_email_free 5438 4_0_0 EXIST::FUNCTION: X509_get1_ocsp 5439 4_0_0 EXIST::FUNCTION: -X509_check_host 5440 4_0_0 EXIST::FUNCTION: -X509_check_email 5441 4_0_0 EXIST::FUNCTION: -X509_check_ip 5442 4_0_0 EXIST::FUNCTION: -X509_check_ip_asc 5443 4_0_0 EXIST::FUNCTION: +X509_check_host 5440 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_1 +X509_check_email 5441 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_1 +X509_check_ip 5442 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_1 +X509_check_ip_asc 5443 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_1 a2i_IPADDRESS 5444 4_0_0 EXIST::FUNCTION: a2i_IPADDRESS_NC 5445 4_0_0 EXIST::FUNCTION: X509V3_NAME_from_section 5446 4_0_0 EXIST::FUNCTION: