-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ECH-draft-13c: s_server ctx switch (switch to inner) bug #30
Comments
Relevant documentation [1]:
The documentation strongly recommends not directly using X509_check_host, but I think that is for the case of verifying peer certificates. In our case we are checking our own certificate, not a peer certificate, but with a peer-supplied inner SNI. [1] https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set1_host.html |
Relevant code: Here is what I think is the erroneous code. I believe the intention in to check that int mrv;
X509_VERIFY_PARAM *vpm = NULL;
BIO_printf(p->biodebug,
"ssl_ech_servername_cb: TLS servername: %s.\n",
servername);
BIO_printf(p->biodebug,
"ssl_ech_servername_cb: Cert servername: %s.\n",
p->servername);
vpm = X509_VERIFY_PARAM_new();
if (vpm == NULL)
return SSL_TLSEXT_ERR_NOACK;
mrv = X509_VERIFY_PARAM_set1_host(vpm, servername,
strlen(servername));
X509_VERIFY_PARAM_free(vpm);
if (mrv == 1) { Here are the definitions that gives our value for int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
{
return int_x509_param_set_hosts(param, SET_HOST, name, namelen);
} I think this is just creating a stack of hosts to be checked at some point, but not checking them now: (In our case this will pretty much always return 1 (unless we run out of memory). static int int_x509_param_set_hosts(X509_VERIFY_PARAM *vpm, int mode,
const char *name, size_t namelen)
{
char *copy;
/*
* Refuse names with embedded NUL bytes, except perhaps as final byte.
* XXX: Do we need to push an error onto the error stack?
*/
if (namelen == 0 || name == NULL)
namelen = name ? strlen(name) : 0;
else if (name != NULL
&& memchr(name, '\0', namelen > 1 ? namelen - 1 : namelen) != NULL)
return 0;
if (namelen > 0 && name[namelen - 1] == '\0')
--namelen;
if (mode == SET_HOST) {
sk_OPENSSL_STRING_pop_free(vpm->hosts, str_free);
vpm->hosts = NULL;
}
if (name == NULL || namelen == 0)
return 1;
copy = OPENSSL_strndup(name, namelen);
if (copy == NULL)
return 0;
if (vpm->hosts == NULL &&
(vpm->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
OPENSSL_free(copy);
return 0;
}
if (!sk_OPENSSL_STRING_push(vpm->hosts, copy)) {
OPENSSL_free(copy);
if (sk_OPENSSL_STRING_num(vpm->hosts) == 0) {
sk_OPENSSL_STRING_free(vpm->hosts);
vpm->hosts = NULL;
}
return 0;
}
return 1;
} |
While we're here, is it necessary to cryptographically verify the inner SNI against the |
Reproduction: Follow instructions for localhost ECH server/client in https://github.com/defo-project/ech-dev-utils/blob/main/howtos/localhost-tests.md, (I created ~/code/openssl/cadir and ~/code/openssl/echconfig.pem), where Server:
Clients (first with inner SNI as foo.example.com then with wrong.example.com) both return certificate for the inner server (foo.example.com), which is wrong, we should see the main server certificate (example.com) when we pass ~/code/openssl$ LD_LIBRARY_PATH=. $HOME/code/ech-dev-utils/scripts/echcli.sh -s localhost -H foo.example.com -p 8443 -P echconfig.pem -f index.html -d --wait 0 | grep DNS
DNS:*.foo.example.com, DNS:foo.example.com
~/code/openssl$ LD_LIBRARY_PATH=. $HOME/code/ech-dev-utils/scripts/echcli.sh -s localhost -H wrong.example.com -p 8443 -P echconfig.pem -f index.html -d --wait 0 | grep DNS
DNS:*.foo.example.com, DNS:foo.example.com
Other details:
|
Fix here (but I don't know how to create a PR across repos): https://github.com/Neimhin/openssl/pull/4/files
In
s_server
we should switch to ctx2 when ECH is successful and when the inner SNI matches the host of the cert in ctx2. I believe the logic currently switches context whenever ECH is successful and an inner SNI is provided (regardless of whether the inner SNI matches the cert for ctx2).This
if
condition in [1] is, I think, always true.I haven't yet run any code to test this, let me know if you want me to do a demo of this bug.
The comment preceding the servername callback function says to use
X509_check_host
[2], which actually checks whether a hostname matches the CN of the cert (but perhaps does not verify it?). It seems to me it would be okay to not verify the hostname since the server owns the cert.[1]
openssl/apps/s_server.c
Line 682 in 6145168
[2]
openssl/apps/s_server.c
Line 522 in 6145168
The text was updated successfully, but these errors were encountered: