#include "packets.h"
#include "poll-loop.h"
#include "socket-util.h"
-#include "socket-util.h"
#include "util.h"
#include "stream-provider.h"
#include "stream.h"
struct ssl_config_file {
bool read; /* Whether the file was successfully read. */
char *file_name; /* Configured file name, if any. */
- long long int next_retry; /* If 'file_name' but not 'read', next time to
- * retry reading. */
+ struct timespec mtime; /* File mtime as of last time we read it. */
};
/* SSL configuration files. */
static struct ssl_config_file certificate;
static struct ssl_config_file ca_cert;
+/* Ordinarily, the SSL client and server verify each other's certificates using
+ * a CA certificate. Setting this to false disables this behavior. (This is a
+ * security risk.) */
+static bool verify_peer_cert = true;
+
/* Ordinarily, we require a CA certificate for the peer to be locally
* available. We can, however, bootstrap the CA certificate from the peer at
* the beginning of our first connection then use that certificate on all
VLOG_ERR("Certificate must be configured to use SSL");
retval = ENOPROTOOPT;
}
- if (!ca_cert.read && !bootstrap_ca_cert) {
+ if (!ca_cert.read && verify_peer_cert && !bootstrap_ca_cert) {
VLOG_ERR("CA certificate must be configured to use SSL");
retval = ENOPROTOOPT;
}
retval = ENOPROTOOPT;
goto error;
}
- if (bootstrap_ca_cert && type == CLIENT) {
+ if (!verify_peer_cert || (bootstrap_ca_cert && type == CLIENT)) {
SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
}
if (errno == EEXIST) {
VLOG_INFO("reading CA cert %s created by another process",
ca_cert.file_name);
- stream_ssl_set_ca_cert_file__(ca_cert.file_name, true);
+ stream_ssl_set_ca_cert_file(ca_cert.file_name, true);
return EPROTO;
} else {
VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s",
}
} else if (bootstrap_ca_cert) {
return do_ca_cert_bootstrap(stream);
- } else if ((SSL_get_verify_mode(sslv->ssl)
- & (SSL_VERIFY_NONE | SSL_VERIFY_PEER))
- != SSL_VERIFY_PEER) {
+ } else if (verify_peer_cert
+ && ((SSL_get_verify_mode(sslv->ssl)
+ & (SSL_VERIFY_NONE | SSL_VERIFY_PEER))
+ != SSL_VERIFY_PEER)) {
/* Two or more SSL connections completed at the same time while we
* were in bootstrap mode. Only one of these can finish the
* bootstrap successfully. The other one(s) must be rejected
static bool
update_ssl_config(struct ssl_config_file *config, const char *file_name)
{
- if (ssl_init()
- || !file_name
- || (config->file_name
- && !strcmp(config->file_name, file_name)
- && time_msec() < config->next_retry)) {
+ struct timespec mtime;
+
+ if (ssl_init() || !file_name) {
return false;
}
- config->next_retry = time_msec() + 60 * 1000;
- free(config->file_name);
- config->file_name = xstrdup(file_name);
+ /* If the file name hasn't changed and neither has the file contents, stop
+ * here. */
+ get_mtime(file_name, &mtime);
+ if (config->file_name
+ && !strcmp(config->file_name, file_name)
+ && mtime.tv_sec == config->mtime.tv_sec
+ && mtime.tv_nsec == config->mtime.tv_nsec) {
+ return false;
+ }
+
+ /* Update 'config'. */
+ config->mtime = mtime;
+ if (file_name != config->file_name) {
+ free(config->file_name);
+ config->file_name = xstrdup(file_name);
+ }
return true;
}
size_t n_certs;
struct stat s;
- if (bootstrap && stat(file_name, &s) && errno == ENOENT) {
+ if (!strcmp(file_name, "none")) {
+ verify_peer_cert = false;
+ VLOG_WARN("Peer certificate validation disabled "
+ "(this is a security risk)");
+ } else if (bootstrap && stat(file_name, &s) && errno == ENOENT) {
bootstrap_ca_cert = true;
} else if (!read_cert_file(file_name, &certs, &n_certs)) {
size_t i;