iostream-openssl-params.c \
istream-openssl.c \
ostream-openssl.c
+
+test_programs = test-ssl-iostream
+noinst_PROGRAMS = $(test_programs)
+
+check-local:
+ for bin in $(test_programs); do \
+ if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+ done
+
+LIBDOVECOT_TEST_DEPS = \
+ libssl_iostream_openssl.la \
+ libssl_iostream.la \
+ ../lib-test/libtest.la \
+ ../lib/liblib.la
+LIBDOVECOT_TEST = \
+ $(LIBDOVECOT_TEST_DEPS) \
+ $(MODULE_LIBS)
+
+test_ssl_iostream_LDADD = $(LIBDOVECOT_TEST)
+test_ssl_iostream_DEPENDENCIES = $(LIBDOVECOT_TEST_DEPS)
+test_ssl_iostream_CFLAGS = $(AM_CPPFLAGS)
+test_ssl_iostream_SOURCES = test-ssl-iostream.c
endif
libssl_iostream_la_SOURCES = \
DOVECOT_SSL_PROTO_ALL = 0x1f
};
+#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
+static const struct {
+ const char *name;
+ int version;
+} protocol_versions[] = {
+ { SSL_TXT_SSLV3, SSL3_VERSION },
+ { SSL_TXT_TLSV1, TLS1_VERSION },
+ { SSL_TXT_TLSV1_1, TLS1_1_VERSION },
+ { SSL_TXT_TLSV1_2, TLS1_2_VERSION },
+};
+int ssl_protocols_to_min_protocol(const char *ssl_protocols,
+ int *min_protocol_r, const char **error_r)
+{
+ /* Array where -1 = disable, 0 = not found, 1 = enable */
+ int protos[N_ELEMENTS(protocol_versions)];
+ memset(protos, 0, sizeof(protos));
+ bool explicit_enable = FALSE;
+
+ const char *const *tmp = t_strsplit_spaces(ssl_protocols, ", ");
+ for (; *tmp != NULL; tmp++) {
+ const char *p = *tmp;
+ bool enable = TRUE;
+ if (p[0] == '!') {
+ enable = FALSE;
+ ++p;
+ }
+ for (unsigned i = 0; i < N_ELEMENTS(protocol_versions); i++) {
+ if (strcmp(p, protocol_versions[i].name) == 0) {
+ if (enable) {
+ protos[i] = 1;
+ explicit_enable = TRUE;
+ } else {
+ protos[i] = -1;
+ }
+ goto found;
+ }
+ }
+ *error_r = t_strdup_printf("Unrecognized protocol '%s'", p);
+ return -1;
+
+ found:;
+ }
+
+ unsigned min = N_ELEMENTS(protocol_versions);
+ for (unsigned i = 0; i < N_ELEMENTS(protocol_versions); i++) {
+ if (explicit_enable) {
+ if (protos[i] > 0)
+ min = I_MIN(min, i);
+ } else if (protos[i] == 0)
+ min = I_MIN(min, i);
+ }
+ if (min == N_ELEMENTS(protocol_versions)) {
+ *error_r = "All protocols disabled";
+ return -1;
+ }
+
+ *min_protocol_r = protocol_versions[min].version;
+ return 0;
+}
+#endif /* HAVE_SSL_CTX_SET_MIN_PROTO_VERSION */
+
int openssl_get_protocol_options(const char *protocols)
{
const char *const *tmp;
#define OPENSSL_ALL_PROTOCOL_OPTIONS \
(SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1)
+#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
+/* min_protocol_r is the version int for SSL_CTX_set_min_proto_version().
+ Return 0 on success, and -1 on failure.
+
+ If ssl_protocols only disables protocols like "!SSLv3 !TLSv1", then all the
+ remaining protocols are considered enabled. If it enables some protocols
+ like "TLSv1.1 TLSv1.2", then only the explicitly enabled protocols are
+ considered enabled. */
+int ssl_protocols_to_min_protocol(const char *ssl_protocols,
+ int *min_protocol_r, const char **error_r);
+#endif
+
/* Sync plain_input/plain_output streams with BIOs. Returns TRUE if at least
one byte was read/written. */
bool openssl_iostream_bio_sync(struct ssl_iostream *ssl_io);
--- /dev/null
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "iostream-openssl.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
+
+struct test {
+ /* ssl_protocols input */
+ const char *s;
+ /* expected output */
+ int min;
+ int ret;
+};
+
+static const struct test tests[] = {
+ { "!TLSv1 !TLSv1.2", SSL3_VERSION, 0 },
+ { "!SSLv3", TLS1_VERSION, 0 },
+ { "SSLv3", SSL3_VERSION, 0 },
+ { "!SSLv3 !TLSv1 !TLSv1.2", TLS1_1_VERSION, 0 },
+ { "!SSLv3 !TLSv1 !TLSv1.1 !TLSv1.2", 0, -1},
+ { "TLSv1.1 TLSv1.2", TLS1_1_VERSION, 0 },
+ { "TLSv1.1", TLS1_1_VERSION, 0 },
+ { "TLSv1.1 !SSLv3", TLS1_1_VERSION, 0 },
+ { "TLSv1.2 !TLSv1.1", TLS1_2_VERSION, 0 },
+};
+
+static
+void test_ssl_protocols_to_min_protocol(void)
+{
+ test_begin("test_ssl_protocols_to_min_protocol");
+ for (unsigned i = 0; i < N_ELEMENTS(tests); ++i) {
+ const struct test *t = &tests[i];
+ const char *error;
+ int min, ret;
+ ret = ssl_protocols_to_min_protocol(t->s, &min, &error);
+ if (ret >= 0 && t->min != min)
+ i_debug("%s (exp,actual): min(%d,%d) ret(%d,%d)",
+ t->s, t->min, min, t->ret, ret);
+ test_assert_idx(t->ret == ret, i);
+ if (ret < 0)
+ continue;
+ test_assert_idx(t->min == min, i);
+ }
+ test_end();
+}
+
+int main(void) {
+ static void (*test_functions[])(void) = {
+ test_ssl_protocols_to_min_protocol,
+ NULL,
+ };
+ return test_run(test_functions);
+}
+
+#else /* HAVE_SSL_CTX_SET_MIN_PROTO_VERSION */
+int main(void) {
+ return 0;
+}
+#endif /* HAVE_SSL_CTX_SET_MIN_PROTO_VERSION */