-
Notifications
You must be signed in to change notification settings - Fork 84
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
TLS server support SNI based certificate selection #596
Conversation
f1192f5
to
fa0565c
Compare
fa0565c
to
3ab50cc
Compare
src/tls/openssl/tls.c
Outdated
if (!pl_isset(&pl)) | ||
return EINVAL; | ||
|
||
/* skip record header, handshake header, client version and random */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to do the TLS message parsing in OpenSSL instead ?
does it work with TLS 1.2 and TLS 1.3 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to do the TLS message parsing in OpenSSL instead ?
does it work with TLS 1.2 and TLS 1.3 ?
I searched in the openssl code for a while and couldn't find an adequate function. Today, we found the API function:
SSL_CTX_set_client_hello_cb()
I try to learn from the apache source code how they do cert selection via SNI. I set this PR to draft so far.
Apache copied code from The last commit in this PR also uses I guess it works only for TLS 1.3 because in man page of Note: I have to test this before we can proceed. |
https://stackoverflow.com/questions/5113333/how-to-implement-server-name-indication-sni it would be nice to implement this without any manual parsing of packets. we support TLS v1.2 and v1.3 |
Thanks for this hint Alfred! |
src/tls/openssl/sni.c
Outdated
CONTENT_TYPE_HANDSH = 22, | ||
HANDSH_CLIENT_HELLO = 1, | ||
RECORD_LAYER_SKIP = 4, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these used ?
src/tls/openssl/sni.c
Outdated
*len = (uint8_t) (*pl->p); | ||
pl_advance(pl, 1); | ||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct pl is designed for operating on strings.
for this it is probably better to use mbuf
return NULL; | ||
|
||
sz = (int) sni->l + 1; | ||
cn = mem_zalloc(sz, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check for OOM
please add a test to retest with SNI
@@ -143,7 +154,7 @@ static int keytype2int(enum tls_keytype type) | |||
|
|||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ | |||
!defined(LIBRESSL_VERSION_NUMBER) | |||
static int verify_handler(int ok, X509_STORE_CTX *ctx) | |||
int tls_verify_handler(int ok, X509_STORE_CTX *ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer handlers to be static.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.
The perfect name for a function in tls.c
that turns on SSL_VERIFY_PEER for a TLS client and sets a verify handler would be: void tls_set_verify_client(tls)
But there is already a function with this name that does the opposite. It's sets the handler verify_trust_all
. :-(
src/tls/openssl/tls_tcp.c
Outdated
@@ -241,7 +241,7 @@ static bool recv_handler(int *err, struct mbuf *mb, bool *estab, void *arg) | |||
*err = tls_accept(tc); | |||
} | |||
|
|||
DEBUG_INFO("state=0x%04x\n", SSL_state(tc->ssl)); | |||
DEBUG_INFO("state: %s\n", SSL_state_string_long(tc->ssl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps move to separate PR ?
Thanks! First I try to rewrite this like you already mentioned: #596 (comment) |
Separated: #613 |
TODO: Test the change to the SSL_CTX_set_tlsext_servername_callback. |
d865232
to
fdc8a82
Compare
I would like to suggest the following:
The test can be a back-to-back test with a TLS connection If you want you can close this PR and make a new one. |
fdc8a82
to
1dc4bdc
Compare
New PR is not necessary. I re-based and squashed the commits. Now I'll start to work on the retest. |
some general comments:
|
src/tls/openssl/sni.c
Outdated
#include <re_dbg.h> | ||
|
||
#include <re_list.h> | ||
#include <re_hash.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move these 2 lines up, so that include re_* is grouped
src/tls/openssl/tls.c
Outdated
} | ||
|
||
BIO_free(bio); | ||
bio = BIO_new_file(certf, "r"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BIO_new_file is called twice, is it needed ?
Can you use the same BIO for cert and private key ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already read about BIO_reset()
. But can't remember the result. I will test it when I have the retest.
Yes they have.
Okay, I'll put it in the "out:" section like it is done in other function in the tls module. It doesn't hurt if it called too often.
I move some functions from tls.c to sni.c and add
My understanding is that public functions are in |
ec150d1
to
6a272d7
Compare
Multiple certificates combined with private key and host name for the host name verification can be added with a new function `tls_add_certf()`. For incoming SIP requests a certificate is selected by SNI in the TLS client hello before `SSL_accept()` is called.
- use const char * instead of struct pl in the public API - in for loops, move declaration of i into for loop - in all places where openssl return error, call ERR_clear_error() - global symbols in the tls module should have prefix: tls_ - move sni.h into tls.h - add doxygen comment to global and private API functions
a342c18
to
26868cf
Compare
src/tls/openssl/tls.c
Outdated
@@ -266,6 +290,7 @@ int tls_alloc(struct tls **tlsp, enum tls_method method, const char *keyfile, | |||
} | |||
} | |||
|
|||
tls_enable_sni(tls); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should SNI be enabled by default, also for clients ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can enable it in first call of tls_add_certf()
.
} | ||
} | ||
|
||
BIO_reset(bio); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this line needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. See #596 (comment)!
These steps are done in tls_add_certf()
:
- first read certificate
- read potentially following CAs
- reset the BIO and read the key anywhere in the file
e.g. use case: incoming OPTIONS from SIP servers for client is alive polling
TODO: maybe in follow up PRs in order to keep this PR small.
tls_set_verify_server()
andtls_set_verify_client()
are not very proper. Maybe we could add a deprecated logging/doxygen and add new functions:tls_conn_enable_verify_peer(struct tls_conn *tc, const char *host)
with optionalhost
parameter andtls_trust_all(struct tls *tls)