mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
stream-ssl: Make changing keys and certificate at runtime reliable.
OpenSSL is picky about the order in which keys and certificates are changed: you have to change the certificate first, then the key. It doesn't document this, but deep in the source code, in a function that sets a new certificate, it has this comment: /* don't fail for a cert/key mismatch, just free * current private key (when switching to a different * cert & key, first this function should be used, * then ssl_set_pkey */ Brilliant, guys, thanks a lot. Bug #2921.
This commit is contained in:
@@ -975,32 +975,75 @@ update_ssl_config(struct ssl_config_file *config, const char *file_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
stream_ssl_set_private_key_file__(const char *file_name)
|
||||
{
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, file_name, SSL_FILETYPE_PEM) == 1) {
|
||||
private_key.read = true;
|
||||
} else {
|
||||
VLOG_ERR("SSL_use_PrivateKey_file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stream_ssl_set_private_key_file(const char *file_name)
|
||||
{
|
||||
if (!update_ssl_config(&private_key, file_name)) {
|
||||
return;
|
||||
if (update_ssl_config(&private_key, file_name)) {
|
||||
stream_ssl_set_private_key_file__(file_name);
|
||||
}
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, file_name, SSL_FILETYPE_PEM) != 1) {
|
||||
VLOG_ERR("SSL_use_PrivateKey_file: %s",
|
||||
}
|
||||
|
||||
static void
|
||||
stream_ssl_set_certificate_file__(const char *file_name)
|
||||
{
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, file_name) == 1) {
|
||||
certificate.read = true;
|
||||
} else {
|
||||
VLOG_ERR("SSL_use_certificate_file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return;
|
||||
}
|
||||
private_key.read = true;
|
||||
}
|
||||
|
||||
void
|
||||
stream_ssl_set_certificate_file(const char *file_name)
|
||||
{
|
||||
if (!update_ssl_config(&certificate, file_name)) {
|
||||
return;
|
||||
if (update_ssl_config(&certificate, file_name)) {
|
||||
stream_ssl_set_certificate_file__(file_name);
|
||||
}
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, file_name) != 1) {
|
||||
VLOG_ERR("SSL_use_certificate_file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sets the private key and certificate files in one operation. Use this
|
||||
* interface, instead of calling stream_ssl_set_private_key_file() and
|
||||
* stream_ssl_set_certificate_file() individually, in the main loop of a
|
||||
* long-running program whose key and certificate might change at runtime.
|
||||
*
|
||||
* This is important because of OpenSSL's behavior. If an OpenSSL context
|
||||
* already has a certificate, and stream_ssl_set_private_key_file() is called
|
||||
* to install a new private key, OpenSSL will report an error because the new
|
||||
* private key does not match the old certificate. The other order, of setting
|
||||
* a new certificate, then setting a new private key, does work.
|
||||
*
|
||||
* If this were the only problem, calling stream_ssl_set_certificate_file()
|
||||
* before stream_ssl_set_private_key_file() would fix it. But, if the private
|
||||
* key is changed before the certificate (e.g. someone "scp"s or "mv"s the new
|
||||
* private key in place before the certificate), then OpenSSL would reject that
|
||||
* change, and then the change of certificate would succeed, but there would be
|
||||
* no associated private key (because it had only changed once and therefore
|
||||
* there was no point in re-reading it).
|
||||
*
|
||||
* This function avoids both problems by, whenever either the certificate or
|
||||
* the private key file changes, re-reading both of them, in the correct order.
|
||||
*/
|
||||
void
|
||||
stream_ssl_set_key_and_cert(const char *private_key_file,
|
||||
const char *certificate_file)
|
||||
{
|
||||
if (update_ssl_config(&private_key, private_key_file)
|
||||
|| update_ssl_config(&certificate, certificate_file)) {
|
||||
stream_ssl_set_certificate_file__(certificate_file);
|
||||
stream_ssl_set_private_key_file__(private_key_file);
|
||||
}
|
||||
certificate.read = true;
|
||||
}
|
||||
|
||||
/* Reads the X509 certificate or certificates in file 'file_name'. On success,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 Nicira Networks.
|
||||
* Copyright (c) 2008, 2009, 2010 Nicira Networks.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,9 +20,15 @@
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
bool stream_ssl_is_configured(void);
|
||||
|
||||
void stream_ssl_set_private_key_file(const char *file_name);
|
||||
void stream_ssl_set_certificate_file(const char *file_name);
|
||||
void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap);
|
||||
|
||||
void stream_ssl_set_key_and_cert(const char *private_key_file,
|
||||
const char *certificate_file);
|
||||
|
||||
|
||||
void stream_ssl_set_peer_ca_cert_file(const char *file_name);
|
||||
|
||||
/* Define the long options for SSL support.
|
||||
|
@@ -283,8 +283,8 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
/* Configure SSL. */
|
||||
stream_ssl_set_private_key_file(query_db_string(db, private_key_file));
|
||||
stream_ssl_set_certificate_file(query_db_string(db, certificate_file));
|
||||
stream_ssl_set_key_and_cert(query_db_string(db, private_key_file),
|
||||
query_db_string(db, certificate_file));
|
||||
stream_ssl_set_ca_cert_file(query_db_string(db, ca_cert_file),
|
||||
bootstrap_ca_cert);
|
||||
#endif
|
||||
|
@@ -350,8 +350,7 @@ bridge_configure_ssl(const struct ovsrec_ssl *ssl)
|
||||
{
|
||||
/* XXX SSL should be configurable on a per-bridge basis. */
|
||||
if (ssl) {
|
||||
stream_ssl_set_private_key_file(ssl->private_key);
|
||||
stream_ssl_set_certificate_file(ssl->certificate);
|
||||
stream_ssl_set_key_and_cert(ssl->private_key, ssl->certificate);
|
||||
stream_ssl_set_ca_cert_file(ssl->ca_cert, ssl->bootstrap_ca_cert);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user