Skip to content

Comments

radsecproxy, TLS : Make SIGHUP reload client certs and keys#76

Closed
imtiyaz-arista wants to merge 2 commits intoradsecproxy:masterfrom
imtiyaz-arista:master
Closed

radsecproxy, TLS : Make SIGHUP reload client certs and keys#76
imtiyaz-arista wants to merge 2 commits intoradsecproxy:masterfrom
imtiyaz-arista:master

Conversation

@imtiyaz-arista
Copy link

Today, SIGHUP causes the CA and CRLs to be reloaded.
This change makes client certificates and keys to be reloaded as well.
This is needed for the case when the client certificates have expired.

PS : client implies, radsecproxy and server being the radius server itself.

Today, SIGHUP causes the CA and CRLs to be reloaded.
This change makes client certificates and keys to be reloaded as well.
This is needed for the case when the certificates have expired.
Copy link
Contributor

@fmauchle fmauchle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is lots of duplicate code already present in tlscreatectx. This should be avoided.

Did you check if calling these SSL_CTX functions is threadsave?

tlscommon.c Outdated
Comment on lines 538 to 542
if (conf->certkeypwd) {
debug(DBG_INFO, "tls: set default passwd for certkeypwd");
SSL_CTX_set_default_passwd_cb_userdata(conf->tlsctx, conf->certkeypwd);
SSL_CTX_set_default_passwd_cb(conf->tlsctx, pem_passwd_cb);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not much sense in redoing the password callback. It can't have changed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your comments Fabian. Agree with you, this block is not needed.

while ((error = ERR_get_error()))
debug(DBG_ERR, "tls SSL: %s", ERR_error_string(error, NULL));
debug(DBG_ERR, "tls: Error initialising SSL/TLS in TLS context %s", conf->name);
SSL_CTX_free(conf->tlsctx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is extremely dangerous. tlsctx is still refered to, and the next time a connection is opened, this will get accessed; likely resulting in a segfault.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. You are right. But this is a tricky situation there. I don't know the internal details of the three APIs, SSL_CTX_use_certificate_chain_file, SSL_CTX_use_certificate_chain_file and SSL_CTX_check_private_key. Now, in the above expression, if SSL_CTX_use_certificate_chain_file() succeeds, it might change something about conf->tlsctx now assuming SSL_CTX_use_PrivateKey_file() fails for some reason, it will be too late to just bail out with a partially modified conf->tlsctx. We need some way to ensure we update all the three APIs or None.

@imtiyaz-arista
Copy link
Author

There is lots of duplicate code already present in tlscreatectx. This should be avoided.

Did you check if calling these SSL_CTX functions is threadsave?

I tried to find about the SSL_CTX being threadsafe or not and could not find anything concrete to suggest either way. Some literature did suggest that there might be race issues between the SSL_CTX_* APIs and SSL_new() and looking at the code closely, We are using server->conf->tlsconf->lock to protect SSL_new(). Perhaps, we can protect the SSL_CTXs with this lock and that will take care of the race. Since we already are updating CA and CRLs, it seemed like a straightforward thing to reload other certs and keys.

There is another way of doing this but that is more effort (from some discussion on internet):-

One way to
do this safely in that situation is to create a new SSL_CTX with the
new certificate chain, and arrange for new connections to use the new
context, while existing connections continue to use the old context.

It is possible to call SSL_CTX_free() on the old context even while
it is in use, since the object is reference counted and will be finally
freed by the last thread to release the object.  However, care is required
to avoid a race against new threads starting to still use the old context.
So some sort of memory barrier is needed to ensure that the only the new
context is used to start new connections before calling SSL_CTX_free() on
the old.  In practice you need some sort of lock that supports shared and
exclusive access around whatever structure encapsulates the updatable
SSL_CTX:

   worker thread:
        acquire read lock
        use current SSL_CTX to call SSL_new()
        release read lock

   update thread:
        acquire write lock:
        SSL_CTX_free current context
        set new context as current context
        release write lock

@fmauchle
Copy link
Contributor

If SSL_CTX is not explicitly declared threadsafe, I would consider it not to be and external locking is required. This is already done in the tls and dtls code using the tlsconf->lock mutex, so it should be used here too. However I don't think a shared read/write lock is requied.

As for the idea of creating a new SSL_CTX, I think this would be quite a good solution. It would also allow error handling and aborting the certificate reload if anything goes wrong (and continue to use the old one instead of breaking the proxy or even crashing it).

@fmauchle fmauchle added this to the radsecproxy 1.11 milestone Mar 31, 2023
@fmauchle
Copy link
Contributor

fmauchle commented Oct 2, 2023

radsecproxy now completely reloads the TLS context on SIGHUP, which also re-reads clielnt/server certificates and keys.

@fmauchle fmauchle closed this Oct 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants