2
0
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:
Ben Pfaff
2010-08-05 09:24:00 -07:00
parent 55574bb0d2
commit 6f1e91b1d7
4 changed files with 66 additions and 18 deletions

View File

@@ -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,

View File

@@ -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.

View File

@@ -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

View File

@@ -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);
}
}