#ifdef HAVE_LIBSSL
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/dh.h>
static SSL_CTX * ssl_ctx;
static DH *dh_params;
#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;
+ gnutls_dh_params_t dh_params;
+} x509_cred_slot;
+
+static array x509_creds = INIT_ARRAY;
+static size_t x509_cred_idx;
+
static gnutls_dh_params_t dh_params;
-static gnutls_priority_t priorities_cache;
+static gnutls_priority_t priorities_cache = NULL;
static bool ConnSSL_LoadServerKey_gnutls PARAMS(( void ));
#endif
gnutls_bye(sess, GNUTLS_SHUT_RDWR);
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);
+ gnutls_certificate_free_keys(slot->x509_cred);
+ gnutls_certificate_free_credentials(slot->x509_cred);
+ slot->x509_cred = NULL;
+ gnutls_dh_params_deinit(slot->dh_params);
+ slot->dh_params = NULL;
+ slot->refcnt = 0;
+ }
#endif
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. */
#ifdef HAVE_LIBSSL
SSL_CTX *newctx;
+#if OPENSSL_API_COMPAT < 0x10100000L
if (!ssl_ctx) {
SSL_library_init();
SSL_load_error_strings();
}
+#endif
if (!RAND_status()) {
Log(LOG_ERR, "OpenSSL PRNG not seeded: /dev/urandom missing?");
return false;
}
- if (!ConnSSL_LoadServerKey_openssl(newctx))
+ if (!ConnSSL_LoadServerKey_openssl(newctx)) {
+ /* Failed to read new key but an old ssl context
+ * already exists -> reuse old context */
+ if (ssl_ctx) {
+ SSL_CTX_free(newctx);
+ Log(LOG_WARNING,
+ "Re-Initializing of SSL failed, using old keys!");
+ return true;
+ }
+ /* No preexisting old context -> error. */
goto out;
+ }
if (SSL_CTX_set_cipher_list(newctx, Conf_SSLOptions.CipherList) == 0) {
Log(LOG_ERR, "Failed to apply OpenSSL cipher list \"%s\"!",
Verify_openssl);
SSL_CTX_free(ssl_ctx);
ssl_ctx = newctx;
- Log(LOG_INFO, "%s initialized.", SSLeay_version(SSLEAY_VERSION));
+ Log(LOG_INFO, "%s initialized.", OpenSSL_version(OPENSSL_VERSION));
return true;
out:
SSL_CTX_free(newctx);
int err;
static bool initialized;
- if (initialized) {
- /* TODO: cannot reload gnutls keys: can't simply free x509
- * context -- it may still be in use */
- return false;
- }
-
- err = gnutls_global_init();
- if (err) {
- Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
- gnutls_strerror(err));
- goto out;
+ if (!initialized) {
+ err = gnutls_global_init();
+ if (err) {
+ Log(LOG_ERR, "Failed to initialize GnuTLS: %s",
+ gnutls_strerror(err));
+ goto out;
+ }
}
if (!ConnSSL_LoadServerKey_gnutls())
goto out;
+ if (priorities_cache != NULL) {
+ gnutls_priority_deinit(priorities_cache);
+ }
if (gnutls_priority_init(&priorities_cache, Conf_SSLOptions.CipherList,
NULL) != GNUTLS_E_SUCCESS) {
Log(LOG_ERR,
int err;
const char *cert_file;
+ x509_cred_slot *slot = NULL;
+ gnutls_certificate_credentials_t x509_cred;
+
err = gnutls_certificate_allocate_credentials(&x509_cred);
if (err < 0) {
Log(LOG_ERR, "Failed to allocate certificate credentials: %s",
gnutls_strerror(err));
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);
+ gnutls_certificate_free_keys(slot->x509_cred);
+ gnutls_certificate_free_credentials(slot->x509_cred);
+ slot->x509_cred = NULL;
+ gnutls_dh_params_deinit(slot->dh_params);
+ slot->dh_params = 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;
}
#endif
(gnutls_transport_ptr_t) (long) c->sock);
gnutls_certificate_server_set_request(c->ssl_state.gnutls_session,
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,
- GNUTLS_CRD_CERTIFICATE, x509_cred);
+ GNUTLS_CRD_CERTIFICATE, slot->x509_cred);
if (ret != 0) {
Log(LOG_ERR, "Failed to set SSL credentials: %s",
gnutls_strerror(ret));
gnutls_x509_crt_deinit(cert);
return 0;
}
-
+
if (gnutls_x509_crt_import(cert, &cert_list[0],
GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) {
gnutls_x509_crt_deinit(cert);
#endif /* SSL_SUPPORT */
/* -eof- */
-
-