summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEthan Rahn <erahn@arista.com>2016-10-06 16:21:33 -0700
committerBen Pfaff <blp@ovn.org>2016-11-10 10:36:42 -0800
commite18a1d0861338058f591e09b30415d758bdbac9b (patch)
treed94eaf8163bcbac6a5490c2644260dca549fbb66
parent60230e06ce89ac7bb4e2cba85a4e037a5ffbd224 (diff)
downloadopenvswitch-e18a1d0861338058f591e09b30415d758bdbac9b.tar.gz
Add support for specifying SSL connection parameters to ovsdb
Signed-off-by: Ethan Rahn <erahn@arista.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
-rw-r--r--AUTHORS1
-rw-r--r--NEWS2
-rw-r--r--lib/automake.mk2
-rw-r--r--lib/ssl-connect-syn.man5
-rw-r--r--lib/ssl-connect.man12
-rw-r--r--lib/stream-nossl.c16
-rw-r--r--lib/stream-ssl.c65
-rw-r--r--lib/stream-ssl.h20
-rw-r--r--manpages.mk8
-rw-r--r--ovn/controller-vtep/ovn-controller-vtep.c3
-rw-r--r--ovn/controller/ovn-controller.c3
-rw-r--r--ovn/northd/ovn-northd.c1
-rw-r--r--ovn/utilities/ovn-nbctl.c3
-rw-r--r--ovn/utilities/ovn-sbctl.c3
-rw-r--r--ovn/utilities/ovn-trace.c1
-rw-r--r--ovsdb/ovsdb-client.1.in3
-rw-r--r--ovsdb/ovsdb-client.c3
-rw-r--r--ovsdb/ovsdb-server.1.in3
-rw-r--r--ovsdb/ovsdb-server.c23
-rw-r--r--tests/ovsdb-server.at70
-rw-r--r--tests/test-jsonrpc.c3
-rw-r--r--utilities/ovs-ofctl.c3
-rw-r--r--utilities/ovs-testcontroller.c3
-rw-r--r--utilities/ovs-vsctl.c3
-rw-r--r--vswitchd/ovs-vswitchd.c1
-rw-r--r--vtep/vtep-ctl.c3
26 files changed, 243 insertions, 20 deletions
diff --git a/AUTHORS b/AUTHORS
index ee7da74d0..a43d88fe1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -85,6 +85,7 @@ Eohyung Lee liquidnuker@gmail.com
Eric Garver e@erig.me
Eric Sesterhenn eric.sesterhenn@lsexperts.de
Ethan J. Jackson ejj@eecs.berkeley.edu
+Ethan Rahn erahn@arista.com
Eziz Durdyyev ezizdurdy@gmail.com
Flavio Fernandes flavio@flaviof.com
Flavio Leitner fbl@redhat.com
diff --git a/NEWS b/NEWS
index 1dfe7d14d..c49d21cfa 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,7 @@
Post-v2.6.0
---------------------
+ - Utilities and daemons that support SSL now allow protocols and
+ ciphers to be configured with --ssl-protocols and --ssl-ciphers.
- OVN:
* QoS is now implemented via egress shaping rather than ingress policing.
* DSCP marking is now supported, via the new northbound QoS table.
diff --git a/lib/automake.mk b/lib/automake.mk
index 81d5097be..9345cee7d 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -461,6 +461,8 @@ MAN_FRAGMENTS += \
lib/ssl-peer-ca-cert-syn.man \
lib/ssl.man \
lib/ssl-syn.man \
+ lib/ssl-connect.man \
+ lib/ssl-connect-syn.man \
lib/table.man \
lib/unixctl.man \
lib/unixctl-syn.man \
diff --git a/lib/ssl-connect-syn.man b/lib/ssl-connect-syn.man
new file mode 100644
index 000000000..ed77f7868
--- /dev/null
+++ b/lib/ssl-connect-syn.man
@@ -0,0 +1,5 @@
+.IP "SSL connection options:"
+[\fB\-\-ssl\-protocols=\fIprotocols\fR]
+.br
+[\fB\-\-ssl\-ciphers=\fIciphers\fR]
+.br
diff --git a/lib/ssl-connect.man b/lib/ssl-connect.man
new file mode 100644
index 000000000..6e54f77ef
--- /dev/null
+++ b/lib/ssl-connect.man
@@ -0,0 +1,12 @@
+.IP "\fB\-\-ssl\-protocols=\fIprotocols\fR"
+Specifies, in a comma- or space-delimited list, the SSL protocols
+\fB\*(PN\fR will enable for SSL connections. Supported
+\fIprotocols\fR include \fBTLSv1\fR, \fBTLSv1.1\fR, and \fBTLSv1.2\fR.
+Regardless of order, the highest protocol supported by both sides will
+be chosen when making the connection. The default when this option is
+omitted is \fBTLSv1,TLSv1.1,TLSv1.2\fR.
+.
+.IP "\fB\-\-ssl\-ciphers=\fIciphers\fR"
+Specifies, in OpenSSL cipher string format, the ciphers \fB\*(PN\fR will
+support for SSL connections. The default when this option is omitted is
+\fBHIGH:!aNULL:!MD5\fR.
diff --git a/lib/stream-nossl.c b/lib/stream-nossl.c
index 26fcc978e..6ea622b7c 100644
--- a/lib/stream-nossl.c
+++ b/lib/stream-nossl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011 Nicira, Inc.
+ * Copyright (c) 2011, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,3 +74,17 @@ stream_ssl_set_key_and_cert(const char *private_key_file,
stream_ssl_set_private_key_file(private_key_file);
stream_ssl_set_certificate_file(certificate_file);
}
+
+void
+stream_ssl_set_protocols(const char *arg OVS_UNUSED)
+{
+ /* Ignore this option since it seems harmless to set SSL protocols if SSL
+ * won't be used. */
+}
+
+void
+stream_ssl_set_ciphers(const char *arg OVS_UNUSED)
+{
+ /* Ignore this option since it seems harmless to set SSL ciphers if SSL
+ * won't be used. */
+}
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index dcafc2d48..5d88b52a2 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -162,6 +162,8 @@ struct ssl_config_file {
static struct ssl_config_file private_key;
static struct ssl_config_file certificate;
static struct ssl_config_file ca_cert;
+static char *ssl_protocols = "TLSv1,TLSv1.1,TLSv1.2";
+static char *ssl_ciphers = "HIGH:!aNULL:!MD5";
/* 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
@@ -966,6 +968,7 @@ do_ssl_init(void)
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!MD5");
return 0;
}
@@ -1114,6 +1117,68 @@ stream_ssl_set_key_and_cert(const char *private_key_file,
}
}
+/* Sets SSL ciphers based on string input. Aborts with an error message
+ * if 'arg' is invalid. */
+void
+stream_ssl_set_ciphers(const char *arg)
+{
+ if (ssl_init() || !arg || !strcmp(ssl_ciphers, arg)) {
+ return;
+ }
+ if (SSL_CTX_set_cipher_list(ctx,arg) == 0) {
+ VLOG_ERR("SSL_CTX_set_cipher_list: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+ ssl_ciphers = xstrdup(arg);
+}
+
+/* Set SSL protocols based on the string input. Aborts with an error message
+ * if 'arg' is invalid. */
+void
+stream_ssl_set_protocols(const char *arg)
+{
+ if (ssl_init() || !arg || !strcmp(arg, ssl_protocols)){
+ return;
+ }
+
+ /* Start with all the flags off and turn them on as requested. */
+ long protocol_flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
+ protocol_flags |= SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
+
+ char *s = xstrdup(arg);
+ char *save_ptr = NULL;
+ char *word = strtok_r(s, " ,\t", &save_ptr);
+ if (word == NULL) {
+ VLOG_ERR("SSL protocol settings invalid");
+ goto exit;
+ }
+ while (word != NULL) {
+ long on_flag;
+ if (!strcasecmp(word, "TLSv1.2")){
+ on_flag = SSL_OP_NO_TLSv1_2;
+ } else if (!strcasecmp(word, "TLSv1.1")){
+ on_flag = SSL_OP_NO_TLSv1_1;
+ } else if (!strcasecmp(word, "TLSv1")){
+ on_flag = SSL_OP_NO_TLSv1;
+ } else {
+ VLOG_ERR("%s: SSL protocol not recognized", word);
+ goto exit;
+ }
+ /* Reverse the no flag and mask it out in the flags
+ * to turn on that protocol. */
+ protocol_flags &= ~on_flag;
+ word = strtok_r(NULL, " ,\t", &save_ptr);
+ };
+
+ /* Set the actual options. */
+ SSL_CTX_set_options(ctx, protocol_flags);
+
+ ssl_protocols = xstrdup(arg);
+
+exit:
+ free(s);
+}
+
/* Reads the X509 certificate or certificates in file 'file_name'. On success,
* stores the address of the first element in an array of pointers to
* certificates in '*certs' and the number of certificates in the array in
diff --git a/lib/stream-ssl.h b/lib/stream-ssl.h
index 030f66225..4bfe09b00 100644
--- a/lib/stream-ssl.h
+++ b/lib/stream-ssl.h
@@ -25,11 +25,19 @@ void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap);
void stream_ssl_set_peer_ca_cert_file(const char *file_name);
void stream_ssl_set_key_and_cert(const char *private_key_file,
const char *certificate_file);
+void stream_ssl_set_protocols(const char *arg);
+void stream_ssl_set_ciphers(const char *arg);
+
+#define SSL_OPTION_ENUMS \
+ OPT_SSL_PROTOCOLS, \
+ OPT_SSL_CIPHERS
#define STREAM_SSL_LONG_OPTIONS \
{"private-key", required_argument, NULL, 'p'}, \
{"certificate", required_argument, NULL, 'c'}, \
- {"ca-cert", required_argument, NULL, 'C'}
+ {"ca-cert", required_argument, NULL, 'C'}, \
+ {"ssl-protocols", required_argument, NULL, OPT_SSL_PROTOCOLS}, \
+ {"ssl-ciphers", required_argument, NULL, OPT_SSL_CIPHERS}
#define STREAM_SSL_OPTION_HANDLERS \
case 'p': \
@@ -42,6 +50,14 @@ void stream_ssl_set_key_and_cert(const char *private_key_file,
\
case 'C': \
stream_ssl_set_ca_cert_file(optarg, false); \
- break;
+ break; \
+ \
+ case OPT_SSL_PROTOCOLS: \
+ stream_ssl_set_protocols(optarg); \
+ break; \
+ \
+ case OPT_SSL_CIPHERS: \
+ stream_ssl_set_ciphers(optarg); \
+ break;
#endif /* stream-ssl.h */
diff --git a/manpages.mk b/manpages.mk
index fa9e59b07..2ff7658d1 100644
--- a/manpages.mk
+++ b/manpages.mk
@@ -20,6 +20,8 @@ ovsdb/ovsdb-client.1: \
lib/daemon.man \
lib/ssl-bootstrap-syn.man \
lib/ssl-bootstrap.man \
+ lib/ssl-connect-syn.man \
+ lib/ssl-connect.man \
lib/ssl-syn.man \
lib/ssl.man \
lib/table.man \
@@ -34,6 +36,8 @@ lib/daemon-syn.man:
lib/daemon.man:
lib/ssl-bootstrap-syn.man:
lib/ssl-bootstrap.man:
+lib/ssl-connect-syn.man:
+lib/ssl-connect.man:
lib/ssl-syn.man:
lib/ssl.man:
lib/table.man:
@@ -54,6 +58,8 @@ ovsdb/ovsdb-server.1: \
lib/service.man \
lib/ssl-bootstrap-syn.man \
lib/ssl-bootstrap.man \
+ lib/ssl-connect-syn.man \
+ lib/ssl-connect.man \
lib/ssl-peer-ca-cert-syn.man \
lib/ssl-peer-ca-cert.man \
lib/ssl-syn.man \
@@ -78,6 +84,8 @@ lib/service-syn.man:
lib/service.man:
lib/ssl-bootstrap-syn.man:
lib/ssl-bootstrap.man:
+lib/ssl-connect-syn.man:
+lib/ssl-connect.man:
lib/ssl-peer-ca-cert-syn.man:
lib/ssl-peer-ca-cert.man:
lib/ssl-syn.man:
diff --git a/ovn/controller-vtep/ovn-controller-vtep.c b/ovn/controller-vtep/ovn-controller-vtep.c
index d73f624a8..19f333d68 100644
--- a/ovn/controller-vtep/ovn-controller-vtep.c
+++ b/ovn/controller-vtep/ovn-controller-vtep.c
@@ -166,7 +166,8 @@ parse_options(int argc, char *argv[])
OPT_PEER_CA_CERT = UCHAR_MAX + 1,
OPT_BOOTSTRAP_CA_CERT,
VLOG_OPTION_ENUMS,
- DAEMON_OPTION_ENUMS
+ DAEMON_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static struct option long_options[] = {
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 944c40399..52eb491bd 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -674,7 +674,8 @@ parse_options(int argc, char *argv[])
OPT_PEER_CA_CERT = UCHAR_MAX + 1,
OPT_BOOTSTRAP_CA_CERT,
VLOG_OPTION_ENUMS,
- DAEMON_OPTION_ENUMS
+ DAEMON_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static struct option long_options[] = {
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 07c7b2de4..437da9f1b 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -4696,6 +4696,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
enum {
DAEMON_OPTION_ENUMS,
VLOG_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"ovnsb-db", required_argument, NULL, 'd'},
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index 4df6af827..477ff769b 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -166,7 +166,8 @@ parse_options(int argc, char *argv[], struct shash *local_options)
OPT_COMMANDS,
OPT_OPTIONS,
VLOG_OPTION_ENUMS,
- TABLE_OPTION_ENUMS
+ TABLE_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option global_long_options[] = {
{"db", required_argument, NULL, OPT_DB},
diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
index b72d554ea..0763b7924 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -161,7 +161,8 @@ parse_options(int argc, char *argv[], struct shash *local_options)
OPT_COMMANDS,
OPT_OPTIONS,
VLOG_OPTION_ENUMS,
- TABLE_OPTION_ENUMS
+ TABLE_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option global_long_options[] = {
{"db", required_argument, NULL, OPT_DB},
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index 3d62cf87b..302fb6978 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -153,6 +153,7 @@ parse_options(int argc, char *argv[])
OPT_MINIMAL,
OPT_ALL,
DAEMON_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
VLOG_OPTION_ENUMS
};
static const struct option long_options[] = {
diff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in
index 1bb7419d9..9658291b1 100644
--- a/ovsdb/ovsdb-client.1.in
+++ b/ovsdb/ovsdb-client.1.in
@@ -55,6 +55,7 @@ ovsdb\-client \- command-line interface to \fBovsdb-server\fR(1)
.so lib/vlog-syn.man
.so lib/ssl-syn.man
.so lib/ssl-bootstrap-syn.man
+.so lib/ssl-connect-syn.man
.so lib/common-syn.man
.
.SH DESCRIPTION
@@ -205,6 +206,8 @@ With any other command, they have no effect.
.SS "Public Key Infrastructure Options"
.so lib/ssl.man
.so lib/ssl-bootstrap.man
+.SS "SSL Connection Options"
+.so lib/ssl-connect.man
.SS "Other Options"
.so lib/common.man
.SH "SEE ALSO"
diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
index 5f569e856..bd2f152f3 100644
--- a/ovsdb/ovsdb-client.c
+++ b/ovsdb/ovsdb-client.c
@@ -175,7 +175,8 @@ parse_options(int argc, char *argv[])
OPT_TIMESTAMP,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS,
- TABLE_OPTION_ENUMS
+ TABLE_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in
index 0faf84406..a55af399a 100644
--- a/ovsdb/ovsdb-server.1.in
+++ b/ovsdb/ovsdb-server.1.in
@@ -23,6 +23,7 @@ ovsdb\-server \- Open vSwitch database server
.so lib/ssl-syn.man
.so lib/ssl-bootstrap-syn.man
.so lib/ssl-peer-ca-cert-syn.man
+.so lib/ssl-connect-syn.man
.so lib/unixctl-syn.man
.so lib/common-syn.man
.
@@ -135,6 +136,8 @@ one row in \fItable\fR.)
.so lib/ssl.man
.so lib/ssl-bootstrap.man
.so lib/ssl-peer-ca-cert.man
+.SS "SSL Connection Options"
+.so lib/ssl-connect.man
.SS "Other Options"
.so lib/unixctl.man
.so lib/common.man
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index bc71fd11a..1b0060bff 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -74,6 +74,8 @@ struct db {
static char *private_key_file;
static char *certificate_file;
static char *ca_cert_file;
+static char *ssl_protocols;
+static char *ssl_ciphers;
static bool bootstrap_ca_cert;
static unixctl_cb_func ovsdb_server_exit;
@@ -1110,13 +1112,19 @@ reconfigure_ssl(const struct shash *all_dbs)
const char *resolved_private_key;
const char *resolved_certificate;
const char *resolved_ca_cert;
+ const char *resolved_ssl_protocols;
+ const char *resolved_ssl_ciphers;
resolved_private_key = query_db_string(all_dbs, private_key_file, &errors);
resolved_certificate = query_db_string(all_dbs, certificate_file, &errors);
resolved_ca_cert = query_db_string(all_dbs, ca_cert_file, &errors);
+ resolved_ssl_protocols = query_db_string(all_dbs, ssl_protocols, &errors);
+ resolved_ssl_ciphers = query_db_string(all_dbs, ssl_ciphers, &errors);
stream_ssl_set_key_and_cert(resolved_private_key, resolved_certificate);
stream_ssl_set_ca_cert_file(resolved_ca_cert, bootstrap_ca_cert);
+ stream_ssl_set_protocols(resolved_ssl_protocols);
+ stream_ssl_set_ciphers(resolved_ssl_ciphers);
return errors.string;
}
@@ -1517,7 +1525,8 @@ parse_options(int *argcp, char **argvp[],
OPT_SYNC_EXCLUDE,
OPT_ACTIVE,
VLOG_OPTION_ENUMS,
- DAEMON_OPTION_ENUMS
+ DAEMON_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"remote", required_argument, NULL, OPT_REMOTE},
@@ -1531,9 +1540,7 @@ parse_options(int *argcp, char **argvp[],
VLOG_LONG_OPTIONS,
{"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
{"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
- {"private-key", required_argument, NULL, 'p'},
- {"certificate", required_argument, NULL, 'c'},
- {"ca-cert", required_argument, NULL, 'C'},
+ STREAM_SSL_LONG_OPTIONS,
{"sync-from", required_argument, NULL, OPT_SYNC_FROM},
{"sync-exclude-tables", required_argument, NULL, OPT_SYNC_EXCLUDE},
{"active", no_argument, NULL, OPT_ACTIVE},
@@ -1590,6 +1597,14 @@ parse_options(int *argcp, char **argvp[],
bootstrap_ca_cert = false;
break;
+ case OPT_SSL_PROTOCOLS:
+ ssl_protocols = optarg;
+ break;
+
+ case OPT_SSL_CIPHERS:
+ ssl_ciphers = optarg;
+ break;
+
case OPT_BOOTSTRAP_CA_CERT:
ca_cert_file = optarg;
bootstrap_ca_cert = true;
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index 2650508b3..3fe504e99 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -513,9 +513,13 @@ AT_DATA([schema],
"columns": {
"private_key": {"type": "string"},
"certificate": {"type": "string"},
- "ca_cert": {"type": "string"}}}}}
+ "ca_cert": {"type": "string"},
+ "ssl_protocols" : {"type": "string"},
+ "ssl_ciphers" : {"type" : "string"}}}}}
]])
AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+# The !ECDHE-ECDSA-AES256-GCM-SHA384 in the ssl_ciphers is so that
+# a cipher negotiation failure can be tested for later.
AT_CHECK(
[[ovsdb-tool transact db \
'["mydb",
@@ -523,13 +527,17 @@ AT_CHECK(
"table": "SSL",
"row": {"private_key": "'"$PKIDIR/testpki-privkey2.pem"'",
"certificate": "'"$PKIDIR/testpki-cert2.pem"'",
- "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'"}}]']],
+ "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'",
+ "ssl_protocols": "'"TLSv1.2,TLSv1.1"'",
+ "ssl_ciphers": "'"HIGH:!aNULL:!MD5:!ECDHE-ECDSA-AES256-GCM-SHA384"'"}}]']],
[0], [ignore], [ignore])
AT_CHECK(
[ovsdb-server --log-file --detach --no-chdir --pidfile \
--private-key=db:mydb,SSL,private_key \
--certificate=db:mydb,SSL,certificate \
--ca-cert=db:mydb,SSL,ca_cert \
+ --ssl-protocols=db:mydb,SSL,ssl_protocols \
+ --ssl-ciphers=db:mydb,SSL,ssl_ciphers \
--remote=pssl:0:127.0.0.1 db],
[0], [ignore], [ignore])
PARSE_LISTENING_PORT([ovsdb-server.log], [SSL_PORT])
@@ -538,18 +546,74 @@ AT_CHECK(
--private-key=$PKIDIR/testpki-privkey.pem \
--certificate=$PKIDIR/testpki-cert.pem \
--ca-cert=$PKIDIR/testpki-cacert.pem \
+ --ssl-protocols=TLSv1.2,TLSv1.1 \
+ --ssl-ciphers=HIGH:!aNULL:!MD5 \
transact ssl:127.0.0.1:$SSL_PORT \
'["mydb",
{"op": "select",
"table": "SSL",
"where": [],
- "columns": ["private_key"]}]']],
+ "columns": ["private_key"]}]']],
[0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
cat stdout >> output
AT_CHECK_UNQUOTED(
[cat output], [0],
[[@<:@{"rows":@<:@{"private_key":"$PKIDIR/testpki-privkey2.pem"}@:>@}@:>@
]], [ignore], [test ! -e pid || kill `cat pid`])
+# Check that when the server has TLSv1.1+ and the client has
+# TLSv1 that the connection fails.
+AT_CHECK(
+ [[ovsdb-client \
+ --private-key=$PKIDIR/testpki-privkey.pem \
+ --certificate=$PKIDIR/testpki-cert.pem \
+ --ca-cert=$PKIDIR/testpki-cacert.pem \
+ --ssl-protocols=TLSv1 \
+ --ssl-ciphers=HIGH:!aNULL:!MD5 \
+ transact ssl:127.0.0.1:$SSL_PORT \
+ '["mydb",
+ {"op": "select",
+ "table": "SSL",
+ "where": [],
+ "columns": ["private_key"]}]']],
+ [1], [stdout],
+ [stderr],
+ [test ! -e pid || kill `cat pid`])
+cat stderr > output
+AT_CHECK_UNQUOTED(
+ [grep "failed to connect" output], [0],
+ [ovsdb-client: failed to connect to "ssl:127.0.0.1:$SSL_PORT" (Protocol error)
+],
+ [ignore], [test ! -e pid || kill `cat pid`])
+# Check that when ciphers are not compatible, that a negotiation
+# failure occurs.
+AT_CHECK(
+ [[ovsdb-client \
+ --private-key=$PKIDIR/testpki-privkey.pem \
+ --certificate=$PKIDIR/testpki-cert.pem \
+ --ca-cert=$PKIDIR/testpki-cacert.pem \
+ --ssl-protocols=TLSv1.2,TLSv1.1 \
+ --ssl-ciphers=ECDHE-ECDSA-AES256-GCM-SHA384 \
+ transact ssl:127.0.0.1:$SSL_PORT \
+ '["mydb",
+ {"op": "select",
+ "table": "SSL",
+ "where": [],
+ "columns": ["private_key"]}]']],
+ [1], [stdout],
+ [stderr],
+ [test ! -e pid || kill `cat pid`])
+cat stderr > output
+AT_CHECK_UNQUOTED(
+ [grep "failed to connect" output], [0],
+ [ovsdb-client: failed to connect to "ssl:127.0.0.1:$SSL_PORT" (Protocol error)
+],
+ [ignore], [test ! -e pid || kill `cat pid`])
+# The error message for being unable to negotiate a shared ciphersuite
+# is 'sslv3 alert handshake failure'. This is not the clearest message.
+AT_CHECK_UNQUOTED(
+ [grep "sslv3 alert handshake failure" output], [0],
+ [stdout],
+ [ignore], [test ! -e pid || kill `cat pid`])
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP
diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c
index 684601a37..a7ca69148 100644
--- a/tests/test-jsonrpc.c
+++ b/tests/test-jsonrpc.c
@@ -55,7 +55,8 @@ parse_options(int argc, char *argv[])
{
enum {
OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
- DAEMON_OPTION_ENUMS
+ DAEMON_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"verbose", optional_argument, NULL, 'v'},
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 5a43da4cd..4b8a43c99 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -190,7 +190,8 @@ parse_options(int argc, char *argv[])
OPT_READ_ONLY,
DAEMON_OPTION_ENUMS,
OFP_VERSION_OPTION_ENUMS,
- VLOG_OPTION_ENUMS
+ VLOG_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"timeout", required_argument, NULL, 't'},
diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c
index 2998de207..004632e92 100644
--- a/utilities/ovs-testcontroller.c
+++ b/utilities/ovs-testcontroller.c
@@ -259,7 +259,8 @@ parse_options(int argc, char *argv[])
OPT_UNIXCTL,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS,
- OFP_VERSION_OPTION_ENUMS
+ OFP_VERSION_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option long_options[] = {
{"hub", no_argument, NULL, 'H'},
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index ab5188b18..a05084016 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -206,7 +206,8 @@ parse_options(int argc, char *argv[], struct shash *local_options)
OPT_COMMANDS,
OPT_OPTIONS,
VLOG_OPTION_ENUMS,
- TABLE_OPTION_ENUMS
+ TABLE_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option global_long_options[] = {
{"db", required_argument, NULL, OPT_DB},
diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
index c2a91585c..bed3fb5c3 100644
--- a/vswitchd/ovs-vswitchd.c
+++ b/vswitchd/ovs-vswitchd.c
@@ -144,6 +144,7 @@ parse_options(int argc, char *argv[], char **unixctl_pathp)
OPT_DISABLE_SYSTEM,
DAEMON_OPTION_ENUMS,
OPT_DPDK,
+ SSL_OPTION_ENUMS,
OPT_DUMMY_NUMA,
};
static const struct option long_options[] = {
diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
index 3450deb70..c57f592be 100644
--- a/vtep/vtep-ctl.c
+++ b/vtep/vtep-ctl.c
@@ -165,7 +165,8 @@ parse_options(int argc, char *argv[], struct shash *local_options)
OPT_PEER_CA_CERT,
OPT_LOCAL,
VLOG_OPTION_ENUMS,
- TABLE_OPTION_ENUMS
+ TABLE_OPTION_ENUMS,
+ SSL_OPTION_ENUMS,
};
static const struct option global_long_options[] = {
{"db", required_argument, NULL, OPT_DB},