Skip to content

SSL_new(ctx) does not copy hostflags from SSL_CTX to SSL #14579

@tiran

Description

@tiran

Python's ssl module uses ssl.SSLContext objects are central configuration objects for all TLS related options. The C code behind the SSLContext object is mostly a wrapper of SSL_CTX.

A while ago I added a setter/getter for X509_CHECK_FLAG_NEVER_CHECK_SUBJECT flag.

    @property
    def hostname_checks_common_name(self):
        ncs = self._host_flags & _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
        return ncs != _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT

    @hostname_checks_common_name.setter
    def hostname_checks_common_name(self, value):
        if value:
            self._host_flags &= ~_ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
        else:
            self._host_flags |= _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT```
static int
set_host_flags(PySSLContext *self, PyObject *arg, void *c)
{
    X509_VERIFY_PARAM *param;
    unsigned int new_flags = 0;

    if (!PyArg_Parse(arg, "I", &new_flags))
        return -1;

    param = SSL_CTX_get0_param(self->ctx);
    self->hostflags = new_flags;
    X509_VERIFY_PARAM_set_hostflags(param, new_flags);
    return 0;
}

The code correctly sets ctx->params->hostflags to value 36 (X509_CHECK_FLAG_NEVER_CHECK_SUBJECT|X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS). However it doesn't have any affect on SSLSocket ssl->params->hostflags is always 0 and TLS handshake accepts certificate with just a subject CN and no SAN DNS entries. It took me a while to realize that hostflags are not copied from SSL_CTX to SSL. X509_VERIFY_PARAM_inherit() ignores the hostflags when there is no verify hosts configured. Python's ssl module uses X509_VERIFY_PARAM_set1_host() only on connection objects, never on the context itself. ctx->params->hosts is always NULL.

/* Copy the host flags if and only if we're copying the host list */
if (test_x509_verify_param_copy(hosts, NULL)) {
sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
dest->hosts = NULL;
if (src->hosts) {
dest->hosts =
sk_OPENSSL_STRING_deep_copy(src->hosts, str_copy, str_free);
if (dest->hosts == NULL)
return 0;
dest->hostflags = src->hostflags;
}
}

This behavior is surprising. I assumed that hostflags behave like any other flag. I don't see the special case documented at https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_flags.html either.

Version: OpenSSL 1.1.1j
Python upstream bug: https://bugs.python.org/issue43522
workaround PR: python/cpython#24899

Metadata

Metadata

Assignees

No one assigned

    Labels

    branch: 1.1.1Applies to OpenSSL_1_1_1-stable branch (EOL)branch: masterApplies to master branchtriaged: bugThe issue/pr is/fixes a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions