mirror of
https://github.com/osmarks/ngircd.git
synced 2024-12-13 02:10:27 +00:00
Add support for GnuTLS certificate reload
This requires keeping track of currently active certificates, so those are stored separately, along with a reference counter, and discarded when they are no longer in use.
This commit is contained in:
parent
9c5e42458e
commit
eead4a631f
@ -40,6 +40,7 @@ struct ConnSSL_State {
|
|||||||
gnutls_session_t gnutls_session;
|
gnutls_session_t gnutls_session;
|
||||||
void *cookie; /* pointer to server configuration structure
|
void *cookie; /* pointer to server configuration structure
|
||||||
(for outgoing connections), or NULL. */
|
(for outgoing connections), or NULL. */
|
||||||
|
size_t x509_cred_idx; /* index of active x509 credential record */
|
||||||
#endif
|
#endif
|
||||||
char *fingerprint;
|
char *fingerprint;
|
||||||
};
|
};
|
||||||
|
@ -62,7 +62,14 @@ static bool ConnSSL_LoadServerKey_openssl PARAMS(( SSL_CTX *c ));
|
|||||||
|
|
||||||
#define MAX_HASH_SIZE 64 /* from gnutls-int.h */
|
#define MAX_HASH_SIZE 64 /* from gnutls-int.h */
|
||||||
|
|
||||||
static gnutls_certificate_credentials_t x509_cred;
|
typedef struct {
|
||||||
|
int refcnt;
|
||||||
|
gnutls_certificate_credentials_t x509_cred;
|
||||||
|
} x509_cred_slot;
|
||||||
|
|
||||||
|
static array x509_creds = INIT_ARRAY;
|
||||||
|
static size_t x509_cred_idx;
|
||||||
|
|
||||||
static gnutls_dh_params_t dh_params;
|
static gnutls_dh_params_t dh_params;
|
||||||
static gnutls_priority_t priorities_cache;
|
static gnutls_priority_t priorities_cache;
|
||||||
static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
|
static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
|
||||||
@ -266,6 +273,20 @@ void ConnSSL_Free(CONNECTION *c)
|
|||||||
gnutls_bye(sess, GNUTLS_SHUT_RDWR);
|
gnutls_bye(sess, GNUTLS_SHUT_RDWR);
|
||||||
gnutls_deinit(sess);
|
gnutls_deinit(sess);
|
||||||
}
|
}
|
||||||
|
x509_cred_slot *slot = array_get(&x509_creds, sizeof(x509_cred_slot), c->ssl_state.x509_cred_idx);
|
||||||
|
assert(slot != NULL);
|
||||||
|
assert(slot->refcnt > 0);
|
||||||
|
assert(slot->x509_cred != NULL);
|
||||||
|
slot->refcnt--;
|
||||||
|
if ((c->ssl_state.x509_cred_idx != x509_cred_idx) && (slot->refcnt <= 0)) {
|
||||||
|
Log(LOG_INFO, "Discarding X509 certificate credentials from slot %zd.",
|
||||||
|
c->ssl_state.x509_cred_idx);
|
||||||
|
/* TODO/FIXME: DH parameters will still leak memory. */
|
||||||
|
gnutls_certificate_free_keys(slot->x509_cred);
|
||||||
|
gnutls_certificate_free_credentials(slot->x509_cred);
|
||||||
|
slot->x509_cred = NULL;
|
||||||
|
slot->refcnt = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
assert(Conn_OPTION_ISSET(c, CONN_SSL));
|
assert(Conn_OPTION_ISSET(c, CONN_SSL));
|
||||||
/* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */
|
/* can't just set bitmask to 0 -- there are other, non-ssl related flags, e.g. CONN_ZIP. */
|
||||||
@ -348,17 +369,13 @@ out:
|
|||||||
int err;
|
int err;
|
||||||
static bool initialized;
|
static bool initialized;
|
||||||
|
|
||||||
if (initialized) {
|
if (!initialized) {
|
||||||
/* TODO: cannot reload gnutls keys: can't simply free x509
|
err = gnutls_global_init();
|
||||||
* context -- it may still be in use */
|
if (err) {
|
||||||
return false;
|
Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
|
||||||
}
|
gnutls_strerror(err));
|
||||||
|
goto out;
|
||||||
err = gnutls_global_init();
|
}
|
||||||
if (err) {
|
|
||||||
Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
|
|
||||||
gnutls_strerror(err));
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ConnSSL_LoadServerKey_gnutls())
|
if (!ConnSSL_LoadServerKey_gnutls())
|
||||||
@ -389,6 +406,9 @@ ConnSSL_LoadServerKey_gnutls(void)
|
|||||||
int err;
|
int err;
|
||||||
const char *cert_file;
|
const char *cert_file;
|
||||||
|
|
||||||
|
x509_cred_slot *slot = NULL;
|
||||||
|
gnutls_certificate_credentials_t x509_cred;
|
||||||
|
|
||||||
err = gnutls_certificate_allocate_credentials(&x509_cred);
|
err = gnutls_certificate_allocate_credentials(&x509_cred);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
Log(LOG_ERR, "Failed to allocate certificate credentials: %s",
|
Log(LOG_ERR, "Failed to allocate certificate credentials: %s",
|
||||||
@ -419,6 +439,42 @@ ConnSSL_LoadServerKey_gnutls(void)
|
|||||||
gnutls_strerror(err));
|
gnutls_strerror(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free currently active x509 context (if any) unless it is still in use */
|
||||||
|
slot = array_get(&x509_creds, sizeof(x509_cred_slot), x509_cred_idx);
|
||||||
|
if ((slot != NULL) && (slot->refcnt <= 0) && (slot->x509_cred != NULL)) {
|
||||||
|
Log(LOG_INFO, "Discarding X509 certificate credentials from slot %zd.", x509_cred_idx);
|
||||||
|
/* TODO/FIXME: DH parameters will still leak memory. */
|
||||||
|
gnutls_certificate_free_keys(slot->x509_cred);
|
||||||
|
gnutls_certificate_free_credentials(slot->x509_cred);
|
||||||
|
slot->x509_cred = NULL;
|
||||||
|
slot->refcnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find free slot */
|
||||||
|
x509_cred_idx = (size_t) -1;
|
||||||
|
size_t i;
|
||||||
|
for (slot = array_start(&x509_creds), i = 0;
|
||||||
|
i < array_length(&x509_creds, sizeof(x509_cred_slot));
|
||||||
|
slot++, i++) {
|
||||||
|
if (slot->refcnt <= 0) {
|
||||||
|
x509_cred_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ... allocate new slot otherwise. */
|
||||||
|
if (x509_cred_idx == (size_t) -1) {
|
||||||
|
x509_cred_idx = array_length(&x509_creds, sizeof(x509_cred_slot));
|
||||||
|
slot = array_alloc(&x509_creds, sizeof(x509_cred_slot), x509_cred_idx);
|
||||||
|
if (slot == NULL) {
|
||||||
|
Log(LOG_ERR, "Failed to allocate new slot for certificate credentials");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log(LOG_INFO, "Storing new X509 certificate credentials in slot %zd.", x509_cred_idx);
|
||||||
|
slot->x509_cred = x509_cred;
|
||||||
|
slot->refcnt = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -520,8 +576,13 @@ ConnSSL_Init_SSL(CONNECTION *c)
|
|||||||
(gnutls_transport_ptr_t) (long) c->sock);
|
(gnutls_transport_ptr_t) (long) c->sock);
|
||||||
gnutls_certificate_server_set_request(c->ssl_state.gnutls_session,
|
gnutls_certificate_server_set_request(c->ssl_state.gnutls_session,
|
||||||
GNUTLS_CERT_REQUEST);
|
GNUTLS_CERT_REQUEST);
|
||||||
|
|
||||||
|
Log(LOG_INFO, "Using X509 credentials from slot %zd", x509_cred_idx);
|
||||||
|
c->ssl_state.x509_cred_idx = x509_cred_idx;
|
||||||
|
x509_cred_slot *slot = array_get(&x509_creds, sizeof(x509_cred_slot), x509_cred_idx);
|
||||||
|
slot->refcnt++;
|
||||||
ret = gnutls_credentials_set(c->ssl_state.gnutls_session,
|
ret = gnutls_credentials_set(c->ssl_state.gnutls_session,
|
||||||
GNUTLS_CRD_CERTIFICATE, x509_cred);
|
GNUTLS_CRD_CERTIFICATE, slot->x509_cred);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
Log(LOG_ERR, "Failed to set SSL credentials: %s",
|
Log(LOG_ERR, "Failed to set SSL credentials: %s",
|
||||||
gnutls_strerror(ret));
|
gnutls_strerror(ret));
|
||||||
|
Loading…
Reference in New Issue
Block a user