[openssl-commits] [openssl] master update

Viktor Dukhovni viktor at openssl.org
Sat Jan 2 15:49:30 UTC 2016


The branch master has been updated
       via  4fa52141b08fca89250805afcf2f112a2e0d3500 (commit)
       via  57ce7b617c602ae8513c22daa2bda31f179edb0f (commit)
       via  7946ab33cecce60afcc00afc8fc18f31f9e66bff (commit)
      from  1e0784ff95cd69090e26e2205bfec6305038db56 (commit)


- Log -----------------------------------------------------------------
commit 4fa52141b08fca89250805afcf2f112a2e0d3500
Author: Viktor Dukhovni <openssl-users at dukhovni.org>
Date:   Tue Dec 29 03:24:17 2015 -0500

    Protocol version selection and negotiation rewrite
    
    The protocol selection code is now consolidated in a few consecutive
    short functions in a single file and is table driven.  Protocol-specific
    constraints that influence negotiation are moved into the flags
    field of the method structure.  The same protocol version constraints
    are now applied in all code paths.  It is now much easier to add
    new protocol versions without reworking the protocol selection
    logic.
    
    In the presence of "holes" in the list of enabled client protocols
    we no longer select client protocols below the hole based on a
    subset of the constraints and then fail shortly after when it is
    found that these don't meet the remaining constraints (suiteb, FIPS,
    security level, ...).  Ideally, with the new min/max controls users
    will be less likely to create "holes" in the first place.
    
    Reviewed-by: Kurt Roeckx <kurt at openssl.org>

commit 57ce7b617c602ae8513c22daa2bda31f179edb0f
Author: Viktor Dukhovni <openssl-users at dukhovni.org>
Date:   Tue Dec 29 03:19:24 2015 -0500

    Refine and re-wrap Min/Max protocol docs
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

commit 7946ab33cecce60afcc00afc8fc18f31f9e66bff
Author: Kurt Roeckx <kurt at roeckx.be>
Date:   Sun Dec 6 17:56:41 2015 +0100

    Add support for minimum and maximum protocol version
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                                   |  10 +
 doc/ssl/SSL_CONF_cmd.pod                  | 101 ++++--
 doc/ssl/SSL_CTX_new.pod                   | 163 +++++++---
 doc/ssl/SSL_CTX_set_min_proto_version.pod |  50 +++
 doc/ssl/SSL_CTX_set_options.pod           |  19 +-
 include/openssl/dtls1.h                   |   1 +
 include/openssl/ssl.h                     |  21 +-
 ssl/d1_lib.c                              |  28 +-
 ssl/methods.c                             |  54 ++--
 ssl/s3_lib.c                              |  27 --
 ssl/ssl_cert.c                            |  24 +-
 ssl/ssl_ciph.c                            |   8 +-
 ssl/ssl_conf.c                            |  85 ++++-
 ssl/ssl_err.c                             |  14 +-
 ssl/ssl_lib.c                             |  18 +-
 ssl/ssl_locl.h                            |  41 ++-
 ssl/statem/statem.c                       |  15 +-
 ssl/statem/statem_clnt.c                  | 204 +-----------
 ssl/statem/statem_lib.c                   | 385 +++++++++++++++++++++-
 ssl/statem/statem_srvr.c                  |  87 +----
 ssl/t1_lib.c                              |   5 +-
 test/recipes/80-test_ssl.t                | 518 +++++++++++++++++++++++++++++-
 test/ssltest.c                            | 142 +++++++-
 23 files changed, 1560 insertions(+), 460 deletions(-)
 create mode 100644 doc/ssl/SSL_CTX_set_min_proto_version.pod

diff --git a/CHANGES b/CHANGES
index 0c25e0b..b4cc2d4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 1.0.2e and 1.1.0  [xx XXX xxxx]
 
+  *) Add support for setting the minimum and maximum supported protocol.
+     It can bet set via the SSL_set_min_proto_version() and
+     SSL_set_max_proto_version(), or via the SSL_CONF's MinProtocol and
+     MaxProtcol.  It's recommended to use the new APIs to disable
+     protocols instead of disabling individual protocols using
+     SSL_set_options() or SSL_CONF's Protocol.  This change also
+     removes support for disabling TLS 1.2 in the OpenSSL TLS
+     client at compile time by defining OPENSSL_NO_TLS1_2_CLIENT.
+     [Kurt Roeckx]
+
   *) Support for ChaCha20 and Poly1305 added to libcrypto and libssl.
      [Andy Polyakov]
 
diff --git a/doc/ssl/SSL_CONF_cmd.pod b/doc/ssl/SSL_CONF_cmd.pod
index bebd204..2f70845 100644
--- a/doc/ssl/SSL_CONF_cmd.pod
+++ b/doc/ssl/SSL_CONF_cmd.pod
@@ -74,7 +74,7 @@ B<prime256v1>). Curve names are case sensitive.
 
 =item B<-named_curve>
 
-This sets the temporary curve used for ephemeral ECDH modes. Only used by 
+This sets the temporary curve used for ephemeral ECDH modes. Only used by
 servers
 
 The B<value> argument is a curve name or the special value B<auto> which
@@ -85,7 +85,7 @@ can be either the B<NIST> name (e.g. B<P-256>) or an OpenSSL OID name
 =item B<-cipher>
 
 Sets the cipher suite list to B<value>. Note: syntax checking of B<value> is
-currently not performed unless a B<SSL> or B<SSL_CTX> structure is 
+currently not performed unless a B<SSL> or B<SSL_CTX> structure is
 associated with B<cctx>.
 
 =item B<-cert>
@@ -109,11 +109,22 @@ Attempts to use the file B<value> as the set of temporary DH parameters for
 the appropriate context. This option is only supported if certificate
 operations are permitted.
 
+=item B<-min_protocol>, B<-max_protocol>
+
+Sets the minimum and maximum supported protocol.
+Currently supported protocol values are B<SSLv3>, B<TLSv1>,
+B<TLSv1.1>, B<TLSv1.2> for TLS and B<DTLSv1>, B<DTLSv1.2> for DTLS.
+If the either bound is not specified then only the other bound applies,
+if specified.
+To restrict the supported protocol versions use these commands rather
+than the deprecated alternative commands below.
+
 =item B<-no_ssl3>, B<-no_tls1>, B<-no_tls1_1>, B<-no_tls1_2>
 
-Disables protocol support for SSLv3, TLS 1.0, TLS 1.1 or TLS 1.2 
-by setting the corresponding options B<SSL_OP_NO_SSL3>,
-B<SSL_OP_NO_TLS1>, B<SSL_OP_NO_TLS1_1> and B<SSL_OP_NO_TLS1_2> respectively.
+Disables protocol support for SSLv3, TLS 1.0, TLS 1.1 or TLS 1.2
+by setting the corresponding options B<SSL_OP_NO_SSL3>, B<SSL_OP_NO_TLS1>,
+B<SSL_OP_NO_TLS1_1> and B<SSL_OP_NO_TLS1_2> respectively.
+These options are deprecated, instead use B<-min_protocol> and B<-max_protocol>.
 
 =item B<-bugs>
 
@@ -177,7 +188,7 @@ Note: the command prefix (if set) alters the recognised B<cmd> values.
 =item B<CipherString>
 
 Sets the cipher suite list to B<value>. Note: syntax checking of B<value> is
-currently not performed unless an B<SSL> or B<SSL_CTX> structure is 
+currently not performed unless an B<SSL> or B<SSL_CTX> structure is
 associated with B<cctx>.
 
 =item B<Certificate>
@@ -250,7 +261,7 @@ B<prime256v1>). Curve names are case sensitive.
 
 =item B<ECDHParameters>
 
-This sets the temporary curve used for ephemeral ECDH modes. Only used by 
+This sets the temporary curve used for ephemeral ECDH modes. Only used by
 servers
 
 The B<value> argument is a curve name or the special value B<Automatic> which
@@ -258,16 +269,48 @@ picks an appropriate curve based on client and server preferences. The curve
 can be either the B<NIST> name (e.g. B<P-256>) or an OpenSSL OID name
 (e.g B<prime256v1>). Curve names are case sensitive.
 
+=item B<MinProtocol>
+
+This sets the minimum supported SSL, TLS or DTLS version.
+
+Currently supported protocol values are B<SSLv3>, B<TLSv1>, B<TLSv1.1>,
+B<TLSv1.2>, B<DTLSv1> and B<DTLSv1.2>.
+
+=item B<MaxProtocol>
+
+This sets the maximum supported SSL, TLS or DTLS version.
+
+Currently supported protocol values are B<SSLv3>, B<TLSv1>, B<TLSv1.1>,
+B<TLSv1.2>, B<DTLSv1> and B<DTLSv1.2>.
+
 =item B<Protocol>
 
-The supported versions of the SSL or TLS protocol.
+This can be used to enable or disable certain versions of the SSL,
+TLS or DTLS protocol.
+
+The B<value> argument is a comma separated list of supported protocols
+to enable or disable.
+If a protocol is preceded by B<-> that version is disabled.
+
+All protocol versions are enabled by default.
+You need to disable at least one protocol version for this setting have any
+effect.
+Only enabling some protocol versions does not disable the other protocol
+versions.
+
+Currently supported protocol values are B<SSLv3>, B<TLSv1>, B<TLSv1.1>,
+B<TLSv1.2>, B<DTLSv1> and B<DTLSv1.2>.
+The special value B<ALL> refers to all supported versions.
 
-The B<value> argument is a comma separated list of supported protocols to
-enable or disable. If an protocol is preceded by B<-> that version is disabled.
-All versions are enabled by default, though applications may choose to
-explicitly disable some. Currently supported protocol values are 
-B<SSLv3>, B<TLSv1>, B<TLSv1.1> and B<TLSv1.2>. The special value B<ALL> refers
-to all supported versions.
+This can't enable protocols that are disabled using B<MinProtocol>
+or B<MaxProtocol>, but can disable protocols that are still allowed
+by them.
+
+The B<Protocol> command is fragile and deprecated; do not use it.
+Use B<MinProtocol> and B<MaxProtocol> instead.
+If you do use B<Protocol>, make sure that the resulting range of enabled
+protocols has no "holes", e.g. if TLS 1.0 and TLS 1.2 are both enabled, make
+sure to also leave TLS 1.1 enabled.
 
 =item B<Options>
 
@@ -404,7 +447,7 @@ can be checked instead. If -3 is returned a required argument is missing
 and an error is indicated. If 0 is returned some other error occurred and
 this can be reported back to the user.
 
-The function SSL_CONF_cmd_value_type() can be used by applications to 
+The function SSL_CONF_cmd_value_type() can be used by applications to
 check for the existence of a command or to perform additional syntax
 checking or translation of the command value. For example if the return
 value is B<SSL_CONF_TYPE_FILE> an application could translate a relative
@@ -416,12 +459,32 @@ Set supported signature algorithms:
 
  SSL_CONF_cmd(ctx, "SignatureAlgorithms", "ECDSA+SHA256:RSA+SHA256:DSA+SHA256");
 
-Enable all protocols except SSLv3:
+There are various ways to select the supported procotols.
+
+This set the minimum protocol version to TLSv1, and so disables SSLv3.
+This is the recommended way to disable protocols.
+
+ SSL_CONF_cmd(ctx, "MinProtocol", "TLSv1");
+
+The following also disables SSLv3:
+
+ SSL_CONF_cmd(ctx, "Protocol", "-SSLv3");
+
+The following will first enable all protocols, and then disable
+SSLv3.
+If no protocol versions were disabled before this has the same effect as
+"-SSLv3", but if some versions were disables this will re-enable them before
+disabling SSLv3.
 
  SSL_CONF_cmd(ctx, "Protocol", "ALL,-SSLv3");
 
 Only enable TLSv1.2:
 
+ SSL_CONF_cmd(ctx, "MinProtocol", "TLSv1.2");
+ SSL_CONF_cmd(ctx, "MaxProtocol", "TLSv1.2");
+
+This also only enables TLSv1.2:
+
  SSL_CONF_cmd(ctx, "Protocol", "-ALL,TLSv1.2");
 
 Disable TLS session tickets:
@@ -467,11 +530,13 @@ L<SSL_CONF_cmd_argv(3)>
 
 SSL_CONF_cmd() was first added to OpenSSL 1.0.2
 
-B<SSL_OP_NO_SSL2> doesn't have effect anymore since 1.1.0 but the define is kept
-for backward compatibility.
+B<SSL_OP_NO_SSL2> doesn't have effect since 1.1.0, but the macro is retained
+for backwards compatibility.
 
 B<SSL_CONF_TYPE_NONE> was first added to OpenSSL 1.1.0. In earlier versions of
 OpenSSL passing a command which didn't take an argument would return
 B<SSL_CONF_TYPE_UNKNOWN>.
 
+B<MinProtocol> and B<MaxProtocol> where added in OpenSSL 1.1.0.
+
 =cut
diff --git a/doc/ssl/SSL_CTX_new.pod b/doc/ssl/SSL_CTX_new.pod
index 15011f8..136f97b 100644
--- a/doc/ssl/SSL_CTX_new.pod
+++ b/doc/ssl/SSL_CTX_new.pod
@@ -2,7 +2,15 @@
 
 =head1 NAME
 
-SSL_CTX_new, SSLv3_method, SSLv3_server_method, SSLv3_client_method, TLSv1_method, TLSv1_server_method, TLSv1_client_method, TLSv1_1_method, TLSv1_1_server_method, TLSv1_1_client_method, TLS_method, TLS_server_method, TLS_client_method, SSLv23_method, SSLv23_server_method, SSLv23_client_method - create a new SSL_CTX object as framework for TLS/SSL enabled functions
+SSL_CTX_new, SSLv3_method, SSLv3_server_method, SSLv3_client_method,
+TLSv1_method, TLSv1_server_method, TLSv1_client_method, TLSv1_1_method,
+TLSv1_1_server_method, TLSv1_1_client_method, TLS_method,
+TLS_server_method, TLS_client_method, SSLv23_method, SSLv23_server_method,
+SSLv23_client_method, DTLS_method, DTLS_server_method, DTLS_client_method,
+DTLSv1_method, DTLSv1_server_method, DTLSv1_client_method,
+DTLSv1_2_method, DTLSv1_2_server_method, DTLSv1_2_client_method -
+create a new SSL_CTX object as framework for TLS/SSL or DTLS enabled
+functions
 
 =head1 SYNOPSIS
 
@@ -10,51 +18,86 @@ SSL_CTX_new, SSLv3_method, SSLv3_server_method, SSLv3_client_method, TLSv1_metho
 
  SSL_CTX *SSL_CTX_new(const SSL_METHOD *method);
 
+ const SSL_METHOD *TLS_method(void);
+ const SSL_METHOD *TLS_server_method(void);
+ const SSL_METHOD *TLS_client_method(void);
+
+ #define SSLv23_method           TLS_method
+ #define SSLv23_server_method    TLS_server_method
+ #define SSLv23_client_method    TLS_client_method
+
+ #ifndef OPENSSL_NO_SSL3_METHOD
+ const SSL_METHOD *SSLv3_method(void);
+ const SSL_METHOD *SSLv3_server_method(void);
+ const SSL_METHOD *SSLv3_client_method(void);
+ #endif
+
+ const SSL_METHOD *TLSv1_method(void);
+ const SSL_METHOD *TLSv1_server_method(void);
+ const SSL_METHOD *TLSv1_client_method(void);
+
+ const SSL_METHOD *TLSv1_1_method(void);
+ const SSL_METHOD *TLSv1_1_server_method(void);
+ const SSL_METHOD *TLSv1_1_client_method(void);
+
+ const SSL_METHOD *TLSv1_2_method(void);
+ const SSL_METHOD *TLSv1_2_server_method(void);
+ const SSL_METHOD *TLSv1_2_client_method(void);
+
+ const SSL_METHOD *DTLS_method(void);
+ const SSL_METHOD *DTLS_server_method(void);
+ const SSL_METHOD *DTLS_client_method(void);
+
+ const SSL_METHOD *DTLSv1_method(void);
+ const SSL_METHOD *DTLSv1_server_method(void);
+ const SSL_METHOD *DTLSv1_client_method(void);
+
+ const SSL_METHOD *DTLSv1_2_method(void);
+ const SSL_METHOD *DTLSv1_2_server_method(void);
+ const SSL_METHOD *DTLSv1_2_client_method(void);
+
 =head1 DESCRIPTION
 
-SSL_CTX_new() creates a new B<SSL_CTX> object as framework to establish
-TLS/SSL enabled connections.
+SSL_CTX_new() creates a new B<SSL_CTX> object as framework to
+establish TLS/SSL or DTLS enabled connections.
 
 =head1 NOTES
 
-The SSL_CTX object uses B<method> as connection method. The methods exist
-in a generic type (for client and server use), a server only type, and a
-client only type. B<method> can be of the following types:
+The SSL_CTX object uses B<method> as connection method.
+The methods exist in a generic type (for client and server use), a server only
+type, and a client only type.
+B<method> can be of the following types:
 
 =over 4
 
-=item SSLv3_method(void), SSLv3_server_method(void), SSLv3_client_method(void)
+=item SSLv3_method(), SSLv3_server_method(), SSLv3_client_method()
 
-A TLS/SSL connection established with these methods will only understand the
-SSLv3 protocol. A client will send out SSLv3 client hello messages
-and will indicate that it only understands SSLv3. A server will only understand
-SSLv3 client hello messages.
+An SSL connection established with these methods will only understand
+the SSLv3 protocol.
+A client will send out a SSLv3 client hello messages and will
+indicate that it supports SSLv3.
+A server will only understand SSLv3 client hello message and only
+support the SSLv3 protocol.
 
-=item TLSv1_method(void), TLSv1_server_method(void), TLSv1_client_method(void)
+=item TLSv1_method(), TLSv1_server_method(), TLSv1_client_method()
 
-A TLS/SSL connection established with these methods will only understand the
-TLSv1 protocol. A client will send out TLSv1 client hello messages
-and will indicate that it only understands TLSv1. A server will only understand
-TLSv1 client hello messages.
+A TLS connection established with these methods will only understand
+the TLS 1.0 protocol.
 
-=item TLSv1_1_method(void), TLSv1_1_server_method(void), TLSv1_1_client_method(void)
+=item TLSv1_1_method(), TLSv1_1_server_method(), TLSv1_1_client_method()
 
-A TLS/SSL connection established with these methods will only understand the
-TLSv1.1 protocol. A client will send out TLSv1.1 client hello messages
-and will indicate that it only understands TLSv1.1. A server will only
-understand TLSv1.1 client hello messages.
+A TLS connection established with these methods will only understand
+the TLS 1.1 protocol.
 
-=item TLSv1_2_method(void), TLSv1_2_server_method(void), TLSv1_2_client_method(void)
+=item TLSv1_2_method(), TLSv1_2_server_method(), TLSv1_2_client_method()
 
-A TLS/SSL connection established with these methods will only understand the
-TLSv1.2 protocol. A client will send out TLSv1.2 client hello messages
-and will indicate that it only understands TLSv1.2. A server will only
-understand TLSv1.2 client hello messages.
+A TLS connection established with these methods will only understand
+the TLS 1.2 protocol.
 
-=item TLS_method(void), TLS_server_method(void), TLS_client_method(void)
+=item TLS_method(), TLS_server_method(), TLS_client_method()
 
-A TLS/SSL connection established with these methods may understand the
-SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.
+A TLS/SSL connection established with these methods may understand
+the SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.
 
 If extensions are required (for example server name)
 a client will send out TLSv1 client hello messages including extensions and
@@ -62,26 +105,50 @@ will indicate that it also understands TLSv1.1, TLSv1.2 and permits a
 fallback to SSLv3. A server will support SSLv3, TLSv1, TLSv1.1 and TLSv1.2
 protocols. This is the best choice when compatibility is a concern.
 
-=item SSLv23_method(void), SSLv23_server_method(void), SSLv23_client_method(void)
+=item SSLv23_method(), SSLv23_server_method(), SSLv23_client_method()
 
-Use of these functions is deprecated. They have been replaced with TLS_Method(),
+Use of these functions is deprecated. They have been replaced with TLS_method(),
 TLS_server_method() and TLS_client_method() respectively. New code should use
 those functions instead.
 
-=back
+=item DTLS_method(), DTLS_server_method(), DTLS_client_method()
+
+A DTLS connection established with those methods understands all
+supported DTLS protocols.
+Currently supported protocols are DTLS 1.0 and DTLS 1.2.
+
+=item DTLSv1_method(), DTLSv1_server_method(), DTLSv1_client_method()
 
-The list of protocols available can later be limited using the
-SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1 and SSL_OP_NO_TLSv1_2
-options of the SSL_CTX_set_options() or SSL_set_options() functions.
-Using these options it is possible to choose e.g. TLS_server_method() and
-be able to negotiate with all possible clients, but to only allow newer
-protocols like TLSv1, TLSv1.1 or TLS v1.2.
+A DTLS connection established with these methods will only understand
+the DTLS 1.0 protocol.
 
-Applications which never want to support SSLv3 can set SSL_OP_NO_SSLv3.
+=item DTLSv1_2_method(), DTLSv1_2_server_method(), DTLSv1_2_client_method()
 
-SSL_CTX_new() initializes the list of ciphers, the session cache setting,
-the callbacks, the keys and certificates and the options to its default
-values.
+A DTLS connection established with these methods will only understand
+the DTLS 1.2 protocol.
+
+=back
+
+TLS_method(), TLS_server_method(), TLS_client_method(), DTLS_method(),
+DTLS_server_method() and DTLS_client_method() are the version
+flexible methods.
+All other methods only support one specific protocol version.
+Use these methods instead of the other version specific methods.
+
+If you want to limit the supported protocols for the version flexible
+methods you can use SSL_CTX_set_min_proto_version(),
+SSL_set_min_proto_version(), SSL_CTX_set_max_proto_version() and
+SSL_set_max_proto_version() functions.
+They can also be limited using by using an option like SSL_OP_NO_SSLv3
+of the SSL_CTX_set_options() or SSL_set_options() functions, but
+that's not recommended.
+Using these functions it is possible to choose e.g. TLS_server_method()
+and be able to negotiate with all possible clients, but to only
+allow newer protocols like TLS 1.0, TLS 1.1 or TLS 1.2.
+
+SSL_CTX_new() initializes the list of ciphers, the session cache
+setting, the callbacks, the keys and certificates and the options
+to its default values.
 
 =head1 RETURN VALUES
 
@@ -102,14 +169,18 @@ The return value points to an allocated SSL_CTX object.
 
 =head1 HISTORY
 
-SSLv2_method, SSLv2_server_method and SSLv2_client_method where removed in
-OpenSSL 1.1.0. SSLv23_method, SSLv23_server_method and SSLv23_client_method were
-deprecated and TLS_method, TLS_server_method and TLS_client_method
-were introduced in OpenSSL 1.1.0.
+Support for SSLv2 and the corresponding SSLv2_method(),
+SSLv2_server_method() and SSLv2_client_method() functions where
+removed in OpenSSL 1.1.0.
+
+SSLv23_method(), SSLv23_server_method() and SSLv23_client_method()
+were deprecated and the preferred TLS_method(), TLS_server_method()
+and TLS_client_method() functions were introduced in OpenSSL 1.1.0.
 
 =head1 SEE ALSO
 
 L<SSL_CTX_free(3)>, L<SSL_accept(3)>,
+L<SSL_CTX_set_min_proto_version(3)>,
 L<ssl(3)>,  L<SSL_set_connect_state(3)>
 
 =cut
diff --git a/doc/ssl/SSL_CTX_set_min_proto_version.pod b/doc/ssl/SSL_CTX_set_min_proto_version.pod
new file mode 100644
index 0000000..25f9cca
--- /dev/null
+++ b/doc/ssl/SSL_CTX_set_min_proto_version.pod
@@ -0,0 +1,50 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_min_proto_version, SSL_CTX_set_max_proto_version,
+SSL_set_min_proto_version, SSL_set_max_proto_version - Set minimum
+and maximum supported protocol version
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
+ int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
+ int SSL_set_min_proto_version(SSL *ssl, int version);
+ int SSL_set_max_proto_version(SSL *ssl, int version);
+
+=head1 DESCRIPTION
+
+The functions set the minimum and maximum supported portocol versions
+for the B<ctx> or B<ssl>.
+This works in combination with the options set via SSL_CTX_set_options()
+that also make it possible to disable specific protocol versions.
+Use these functions instead of disabling specific protocol versions.
+
+Setting the minimum or maximum version to 0, will enable protocol
+versions down to the lowest version, or up to the highest version
+supported by the library, respectively.
+
+Currently supported versions are B<SSL3_VERSION>, B<TLS1_VERSION>,
+B<TLS1_1_VERSION>, B<TLS1_2_VERSION> for TLS and B<DTLS1_VERSION>,
+B<DTLS1_2_VERSION> for DTLS.
+
+=head1 RETURN VALUES
+
+Both functions return 1 on success and 0 on failure.
+
+=head1 NOTES
+
+All these functions are implemented using macros.
+
+=head1 HISTORY
+
+The functions were added in OpenSSL 1.1.0
+
+=head1 SEE ALSO
+
+L<SSL_CTX_set_options(3)>, L<SSL_CONF_cmd(3)>
+
+=cut
diff --git a/doc/ssl/SSL_CTX_set_options.pod b/doc/ssl/SSL_CTX_set_options.pod
index cf137a5..56f62cc 100644
--- a/doc/ssl/SSL_CTX_set_options.pod
+++ b/doc/ssl/SSL_CTX_set_options.pod
@@ -2,7 +2,9 @@
 
 =head1 NAME
 
-SSL_CTX_set_options, SSL_set_options, SSL_CTX_clear_options, SSL_clear_options, SSL_CTX_get_options, SSL_get_options, SSL_get_secure_renegotiation_support - manipulate SSL options
+SSL_CTX_set_options, SSL_set_options, SSL_CTX_clear_options,
+SSL_clear_options, SSL_CTX_get_options, SSL_get_options,
+SSL_get_secure_renegotiation_support - manipulate SSL options
 
 =head1 SYNOPSIS
 
@@ -153,13 +155,15 @@ own preferences.
 ...
 
 
-=item SSL_OP_NO_SSLv3
+=item SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1,
+SSL_OP_NO_TLSv1_2, SSL_OP_NO_DTLSv1, SSL_OP_NO_DTLSv1_2
 
-Do not use the SSLv3 protocol.
-
-=item SSL_OP_NO_TLSv1
-
-Do not use the TLSv1 protocol.
+These options turn off the SSLv3, TLSv1, TLSv1.1 or TLSv1.2 protocol
+versions with TLS or the DTLSv1, DTLSv1.2 versions with DTLS,
+respectively.
+As of OpenSSL 1.1.0, these options are deprecated, use
+L<SSL_CTX_set_min_proto_version(3)> and
+L<SSL_CTX_set_max_proto_version(3)> instead.
 
 =item SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
 
@@ -269,6 +273,7 @@ secure renegotiation and 0 if it does not.
 
 L<ssl(3)>, L<SSL_new(3)>, L<SSL_clear(3)>,
 L<SSL_CTX_set_tmp_dh_callback(3)>,
+L<SSL_CTX_set_min_proto_version(3)>,
 L<dhparam(1)>
 
 =head1 HISTORY
diff --git a/include/openssl/dtls1.h b/include/openssl/dtls1.h
index f214296..1de5f68 100644
--- a/include/openssl/dtls1.h
+++ b/include/openssl/dtls1.h
@@ -66,6 +66,7 @@ extern "C" {
 
 # define DTLS1_VERSION                   0xFEFF
 # define DTLS1_2_VERSION                 0xFEFD
+# define DTLS_MIN_VERSION                DTLS1_VERSION
 # define DTLS_MAX_VERSION                DTLS1_2_VERSION
 # define DTLS1_VERSION_MAJOR             0xFE
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 8d82a6e..0d22ab7 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -438,6 +438,8 @@ typedef int (*custom_ext_parse_cb) (SSL *s, unsigned int ext_type,
 
 # define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv3|\
         SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2)
+# define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2)
+
 
 /* Removed from previous versions */
 # define SSL_OP_PKCS1_CHECK_1                            0x0
@@ -1215,10 +1217,11 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 # define SSL_CTRL_SELECT_CURRENT_CERT            116
 # define SSL_CTRL_SET_CURRENT_CERT               117
 # define SSL_CTRL_SET_DH_AUTO                    118
-# define SSL_CTRL_CHECK_PROTO_VERSION            119
 # define DTLS_CTRL_SET_LINK_MTU                  120
 # define DTLS_CTRL_GET_LINK_MIN_MTU              121
 # define SSL_CTRL_GET_EXTMS_SUPPORT              122
+# define SSL_CTRL_SET_MIN_PROTO_VERSION          123
+# define SSL_CTRL_SET_MAX_PROTO_VERSION          124
 # define SSL_CERT_SET_FIRST                      1
 # define SSL_CERT_SET_NEXT                       2
 # define SSL_CERT_SET_SERVER                     3
@@ -1350,6 +1353,15 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
         SSL_ctrl(s,SSL_CTRL_GET_RAW_CIPHERLIST,0,plst)
 # define SSL_get0_ec_point_formats(s, plst) \
         SSL_ctrl(s,SSL_CTRL_GET_EC_POINT_FORMATS,0,plst)
+#define SSL_CTX_set_min_proto_version(ctx, version) \
+        SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
+#define SSL_CTX_set_max_proto_version(ctx, version) \
+        SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
+#define SSL_set_min_proto_version(s, version) \
+        SSL_ctrl(s, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
+#define SSL_set_max_proto_version(s, version) \
+        SSL_ctrl(s, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
+
 
 __owur BIO_METHOD *BIO_f_ssl(void);
 __owur BIO *BIO_new_ssl(SSL_CTX *ctx, int client);
@@ -2086,7 +2098,6 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_SSL_SET_SESSION_ID_CONTEXT                 218
 # define SSL_F_SSL_SET_SESSION_TICKET_EXT                 294
 # define SSL_F_SSL_SET_TRUST                              228
-# define SSL_F_SSL_SET_VERSION                            347
 # define SSL_F_SSL_SET_WFD                                196
 # define SSL_F_SSL_SHUTDOWN                               224
 # define SSL_F_SSL_SRP_CTX_INIT                           313
@@ -2157,6 +2168,8 @@ void ERR_load_SSL_strings(void);
 /* Reason codes. */
 # define SSL_R_APP_DATA_IN_HANDSHAKE                      100
 # define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
+# define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE       143
+# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE     158
 # define SSL_R_BAD_ALERT_RECORD                           101
 # define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
 # define SSL_R_BAD_DATA                                   390
@@ -2310,9 +2323,6 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_NULL_SSL_METHOD_PASSED                     196
 # define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED            197
 # define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
-# define SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE       387
-# define SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE        379
-# define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE              297
 # define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG                  327
 # define SSL_R_PACKET_LENGTH_TOO_LONG                     198
 # define SSL_R_PARSE_TLSEXT                               227
@@ -2430,6 +2440,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_UNSUPPORTED_SSL_VERSION                    259
 # define SSL_R_UNSUPPORTED_STATUS_TYPE                    329
 # define SSL_R_USE_SRTP_NOT_NEGOTIATED                    369
+# define SSL_R_VERSION_TOO_HIGH                           166
 # define SSL_R_VERSION_TOO_LOW                            396
 # define SSL_R_WRONG_CERTIFICATE_TYPE                     383
 # define SSL_R_WRONG_CIPHER_RETURNED                      261
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 0fdfd51..3cd4b78 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -235,7 +235,7 @@ void dtls1_clear(SSL *s)
     if (s->options & SSL_OP_CISCO_ANYCONNECT)
         s->client_version = s->version = DTLS1_BAD_VER;
     else if (s->method->version == DTLS_ANY_VERSION)
-        s->version = DTLS1_2_VERSION;
+        s->version = DTLS_MAX_VERSION;
     else
         s->version = s->method->version;
 }
@@ -256,28 +256,6 @@ long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
     case DTLS_CTRL_LISTEN:
         ret = dtls1_listen(s, parg);
         break;
-    case SSL_CTRL_CHECK_PROTO_VERSION:
-        /*
-         * For library-internal use; checks that the current protocol is the
-         * highest enabled version (according to s->ctx->method, as version
-         * negotiation may have changed s->method).
-         */
-        if (s->version == s->ctx->method->version)
-            return 1;
-        /*
-         * Apparently we're using a version-flexible SSL_METHOD (not at its
-         * highest protocol version).
-         */
-        if (s->ctx->method->version == DTLS_method()->version) {
-#if DTLS_MAX_VERSION != DTLS1_2_VERSION
-# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
-#endif
-            if (!(s->options & SSL_OP_NO_DTLSv1_2))
-                return s->version == DTLS1_2_VERSION;
-            if (!(s->options & SSL_OP_NO_DTLSv1))
-                return s->version == DTLS1_VERSION;
-        }
-        return 0;               /* Unexpected state; fail closed. */
     case DTLS_CTRL_SET_LINK_MTU:
         if (larg < (long)dtls1_link_min_mtu())
             return 0;
@@ -698,8 +676,8 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
         /*
          * Verify client version is supported
          */
-        if ((clientvers > (unsigned int)s->method->version &&
-                              s->method->version != DTLS_ANY_VERSION)) {
+        if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) &&
+            s->method->version != DTLS_ANY_VERSION) {
             SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
             goto end;
         }
diff --git a/ssl/methods.c b/ssl/methods.c
index ef20c9c..7a8bb11 100644
--- a/ssl/methods.c
+++ b/ssl/methods.c
@@ -135,19 +135,23 @@ static const SSL_METHOD *tls1_get_method(int ver)
     return NULL;
 }
 
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method,
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_method,
                         ossl_statem_accept,
                         ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method,
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        TLSv1_2_method,
                         ossl_statem_accept,
                         ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method,
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        TLSv1_1_method,
                         ossl_statem_accept,
                         ossl_statem_connect, tls1_get_method, TLSv1_1_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method,
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        TLSv1_method,
                         ossl_statem_accept,
                         ossl_statem_connect, tls1_get_method, TLSv1_enc_data)
 
@@ -178,22 +182,26 @@ static const SSL_METHOD *tls1_get_server_method(int ver)
     return NULL;
 }
 
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method,
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
                         tls1_get_server_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method,
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        TLSv1_2_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
                         tls1_get_server_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method,
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        TLSv1_1_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
                         tls1_get_server_method, TLSv1_1_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method,
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        TLSv1_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
                         tls1_get_server_method, TLSv1_enc_data)
@@ -226,22 +234,26 @@ static const SSL_METHOD *tls1_get_client_method(int ver)
     return NULL;
 }
 
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
+                        TLS_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
                         tls1_get_client_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
+                        TLSv1_2_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
                         tls1_get_client_method, TLSv1_2_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
+                        TLSv1_1_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
                         tls1_get_client_method, TLSv1_1_enc_data)
 
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
+                        TLSv1_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
                         tls1_get_client_method, TLSv1_enc_data)
@@ -268,19 +280,19 @@ static const SSL_METHOD *dtls1_get_method(int ver)
         return NULL;
 }
 
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           DTLSv1_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
                           dtls1_get_method, DTLSv1_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           DTLSv1_2_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
                           dtls1_get_method, DTLSv1_2_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
@@ -303,19 +315,19 @@ static const SSL_METHOD *dtls1_get_server_method(int ver)
         return NULL;
 }
 
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           DTLSv1_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
                           dtls1_get_server_method, DTLSv1_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           DTLSv1_2_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
                           dtls1_get_server_method, DTLSv1_2_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
@@ -338,19 +350,19 @@ static const SSL_METHOD *dtls1_get_client_method(int ver)
         return NULL;
 }
 
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           DTLSv1_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
                           dtls1_get_client_method, DTLSv1_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           DTLSv1_2_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
                           dtls1_get_client_method, DTLSv1_2_enc_data)
 
-IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index e3e4fd3..d307ec0 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3777,33 +3777,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
         }
 #endif
 
-    case SSL_CTRL_CHECK_PROTO_VERSION:
-        /*
-         * For library-internal use; checks that the current protocol is the
-         * highest enabled version (according to s->ctx->method, as version
-         * negotiation may have changed s->method).
-         */
-        if (s->version == s->ctx->method->version)
-            return 1;
-        /*
-         * Apparently we're using a version-flexible SSL_METHOD (not at its
-         * highest protocol version).
-         */
-        if (s->ctx->method->version == TLS_method()->version) {
-#if TLS_MAX_VERSION != TLS1_2_VERSION
-# error Code needs update for TLS_method() support beyond TLS1_2_VERSION.
-#endif
-            if (!(s->options & SSL_OP_NO_TLSv1_2))
-                return s->version == TLS1_2_VERSION;
-            if (!(s->options & SSL_OP_NO_TLSv1_1))
-                return s->version == TLS1_1_VERSION;
-            if (!(s->options & SSL_OP_NO_TLSv1))
-                return s->version == TLS1_VERSION;
-            if (!(s->options & SSL_OP_NO_SSLv3))
-                return s->version == SSL3_VERSION;
-        }
-        return 0;               /* Unexpected state; fail closed. */
-
     default:
         break;
     }
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index f01d3a7..597de0a 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -1084,15 +1084,21 @@ static int ssl_security_default_callback(SSL *s, SSL_CTX *ctx, int op,
             break;
         }
     case SSL_SECOP_VERSION:
-        /* SSLv3 not allowed on level 2 */
-        if (nid <= SSL3_VERSION && level >= 2)
-            return 0;
-        /* TLS v1.1 and above only for level 3 */
-        if (nid <= TLS1_VERSION && level >= 3)
-            return 0;
-        /* TLS v1.2 only for level 4 and above */
-        if (nid <= TLS1_1_VERSION && level >= 4)
-            return 0;
+        if (!SSL_IS_DTLS(s)) {
+            /* SSLv3 not allowed at level 2 */
+            if (nid <= SSL3_VERSION && level >= 2)
+                return 0;
+            /* TLS v1.1 and above only for level 3 */
+            if (nid <= TLS1_VERSION && level >= 3)
+                return 0;
+            /* TLS v1.2 only for level 4 and above */
+            if (nid <= TLS1_1_VERSION && level >= 4)
+                return 0;
+        } else {
+            /* DTLS v1.2 only for level 4 and above */
+            if (DTLS_VERSION_LT(nid, DTLS1_2_VERSION) && level >= 4)
+                return 0;
+        }
         break;
 
     case SSL_SECOP_COMPRESSION:
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 65a5bb6..a15248d 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1349,12 +1349,8 @@ static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
     /* Check version: if TLS 1.2 ciphers allowed we can use Suite B */
 
     if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)) {
-        if (meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
-            SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST,
-                   SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-        else
-            SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST,
-                   SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+        SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST,
+               SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE);
         return 0;
     }
 # ifndef OPENSSL_NO_EC
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 21aa265..9529d30 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -142,6 +142,10 @@ struct ssl_conf_ctx_st {
     uint32_t *pcert_flags;
     /* Pointer to SSL or SSL_CTX verify_mode or NULL if none */
     uint32_t *pvfy_flags;
+    /* Pointer to SSL or SSL_CTX min_version field or NULL if none */
+    int *min_version;
+    /* Pointer to SSL or SSL_CTX max_version field or NULL if none */
+    int *max_version;
     /* Current flag table being worked on */
     const ssl_flag_tbl *tbl;
     /* Size of table */
@@ -307,13 +311,82 @@ static int cmd_Protocol(SSL_CONF_CTX *cctx, const char *value)
         SSL_FLAG_TBL_INV("SSLv3", SSL_OP_NO_SSLv3),
         SSL_FLAG_TBL_INV("TLSv1", SSL_OP_NO_TLSv1),
         SSL_FLAG_TBL_INV("TLSv1.1", SSL_OP_NO_TLSv1_1),
-        SSL_FLAG_TBL_INV("TLSv1.2", SSL_OP_NO_TLSv1_2)
+        SSL_FLAG_TBL_INV("TLSv1.2", SSL_OP_NO_TLSv1_2),
+        SSL_FLAG_TBL_INV("DTLSv1", SSL_OP_NO_DTLSv1),
+        SSL_FLAG_TBL_INV("DTLSv1.2", SSL_OP_NO_DTLSv1_2)
     };
     cctx->tbl = ssl_protocol_list;
     cctx->ntbl = OSSL_NELEM(ssl_protocol_list);
     return CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx);
 }
 
+/*
+ * protocol_from_string - converts a protocol version string to a number
+ *
+ * Returns -1 on failure or the version on success
+ */
+static int protocol_from_string(const char *value)
+{
+    struct protocol_versions {
+        const char *name;
+        int version;
+    };
+    static const struct protocol_versions versions[] = {
+        {"SSLv3", SSL3_VERSION},
+        {"TLSv1", TLS1_VERSION},
+        {"TLSv1.1", TLS1_1_VERSION},
+        {"TLSv1.2", TLS1_2_VERSION},
+        {"DTLSv1", DTLS1_VERSION},
+        {"DTLSv1.2", DTLS1_2_VERSION}};
+    size_t i;
+    size_t n = OSSL_NELEM(versions);
+
+    for (i = 0; i < n; i++)
+        if (strcmp(versions[i].name, value) == 0)
+            return versions[i].version;
+    return -1;
+}
+
+static int min_max_proto(SSL_CONF_CTX *cctx, const char *value, int *bound)
+{
+    int method_version;
+    int new_version;
+
+    if (cctx->ctx != NULL)
+        method_version = cctx->ctx->method->version;
+    else if (cctx->ssl != NULL)
+        method_version = cctx->ssl->ctx->method->version;
+    else
+        return 0;
+    if ((new_version = protocol_from_string(value)) < 0)
+        return 0;
+    return ssl_set_version_bound(method_version, new_version, bound);
+}
+
+/*
+ * cmd_MinProtocol - Set min protocol version
+ * @cctx: config structure to save settings in
+ * @value: The min protocol version in string form
+ *
+ * Returns 1 on success and 0 on failure.
+ */
+static int cmd_MinProtocol(SSL_CONF_CTX *cctx, const char *value)
+{
+    return min_max_proto(cctx, value, cctx->min_version);
+}
+
+/*
+ * cmd_MaxProtocol - Set max protocol version
+ * @cctx: config structure to save settings in
+ * @value: The max protocol version in string form
+ *
+ * Returns 1 on success and 0 on failure.
+ */
+static int cmd_MaxProtocol(SSL_CONF_CTX *cctx, const char *value)
+{
+    return min_max_proto(cctx, value, cctx->max_version);
+}
+
 static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
 {
     static const ssl_flag_tbl ssl_option_list[] = {
@@ -527,6 +600,8 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
 #endif
     SSL_CONF_CMD_STRING(CipherString, "cipher", 0),
     SSL_CONF_CMD_STRING(Protocol, NULL, 0),
+    SSL_CONF_CMD_STRING(MinProtocol, "min_protocol", SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CLIENT),
+    SSL_CONF_CMD_STRING(MaxProtocol, "max_protocol", SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CLIENT),
     SSL_CONF_CMD_STRING(Options, NULL, 0),
     SSL_CONF_CMD_STRING(VerifyMode, NULL, 0),
     SSL_CONF_CMD(Certificate, "cert", SSL_CONF_FLAG_CERTIFICATE,
@@ -831,10 +906,14 @@ void SSL_CONF_CTX_set_ssl(SSL_CONF_CTX *cctx, SSL *ssl)
     cctx->ctx = NULL;
     if (ssl) {
         cctx->poptions = &ssl->options;
+        cctx->min_version = &ssl->min_proto_version;
+        cctx->max_version = &ssl->max_proto_version;
         cctx->pcert_flags = &ssl->cert->cert_flags;
         cctx->pvfy_flags = &ssl->verify_mode;
     } else {
         cctx->poptions = NULL;
+        cctx->min_version = NULL;
+        cctx->max_version = NULL;
         cctx->pcert_flags = NULL;
         cctx->pvfy_flags = NULL;
     }
@@ -846,10 +925,14 @@ void SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *cctx, SSL_CTX *ctx)
     cctx->ssl = NULL;
     if (ctx) {
         cctx->poptions = &ctx->options;
+        cctx->min_version = &ctx->min_proto_version;
+        cctx->max_version = &ctx->max_proto_version;
         cctx->pcert_flags = &ctx->cert->cert_flags;
         cctx->pvfy_flags = &ctx->verify_mode;
     } else {
         cctx->poptions = NULL;
+        cctx->min_version = NULL;
+        cctx->max_version = NULL;
         cctx->pcert_flags = NULL;
         cctx->pvfy_flags = NULL;
     }
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 0c40b7b..d9dbf99 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -314,7 +314,6 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT),
      "SSL_set_session_ticket_ext"},
     {ERR_FUNC(SSL_F_SSL_SET_TRUST), "SSL_set_trust"},
-    {ERR_FUNC(SSL_F_SSL_SET_VERSION), "SSL_SET_VERSION"},
     {ERR_FUNC(SSL_F_SSL_SET_WFD), "SSL_set_wfd"},
     {ERR_FUNC(SSL_F_SSL_SHUTDOWN), "SSL_shutdown"},
     {ERR_FUNC(SSL_F_SSL_SRP_CTX_INIT), "SSL_SRP_CTX_init"},
@@ -416,6 +415,10 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE), "app data in handshake"},
     {ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),
      "attempt to reuse session in different context"},
+    {ERR_REASON(SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE),
+     "at least TLS 1.0 needed in FIPS mode"},
+    {ERR_REASON(SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
+     "at least (D)TLS 1.2 needed in Suite B mode"},
     {ERR_REASON(SSL_R_BAD_ALERT_RECORD), "bad alert record"},
     {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"},
     {ERR_REASON(SSL_R_BAD_DATA), "bad data"},
@@ -603,14 +606,6 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
      "old session cipher not returned"},
     {ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),
      "old session compression algorithm not returned"},
-    {ERR_REASON(SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE),
-     "only DTLS 1.2 allowed in Suite B mode"},
-    {ERR_REASON(SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE),
-     "only TLS 1.2 allowed in Suite B mode"},
-    {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),
-     "only tls allowed in fips mode"},
-    {ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),
-     "opaque PRF input too long"},
     {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG), "packet length too long"},
     {ERR_REASON(SSL_R_PARSE_TLSEXT), "parse tlsext"},
     {ERR_REASON(SSL_R_PATH_TOO_LONG), "path too long"},
@@ -794,6 +789,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION), "unsupported ssl version"},
     {ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE), "unsupported status type"},
     {ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED), "use srtp not negotiated"},
+    {ERR_REASON(SSL_R_VERSION_TOO_HIGH), "version too high"},
     {ERR_REASON(SSL_R_VERSION_TOO_LOW), "version too low"},
     {ERR_REASON(SSL_R_WRONG_CERTIFICATE_TYPE), "wrong certificate type"},
     {ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED), "wrong cipher returned"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7f4bca0..760014d 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -293,6 +293,8 @@ SSL *SSL_new(SSL_CTX *ctx)
     RECORD_LAYER_init(&s->rlayer, s);
 
     s->options = ctx->options;
+    s->min_proto_version = ctx->min_proto_version;
+    s->max_proto_version = ctx->max_proto_version;
     s->mode = ctx->mode;
     s->max_cert_list = ctx->max_cert_list;
     s->references = 1;
@@ -1198,6 +1200,12 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
             return 1;
         else
             return 0;
+    case SSL_CTRL_SET_MIN_PROTO_VERSION:
+        return ssl_set_version_bound(s->ctx->method->version, (int)larg,
+                                     &s->min_proto_version);
+    case SSL_CTRL_SET_MAX_PROTO_VERSION:
+        return ssl_set_version_bound(s->ctx->method->version, (int)larg,
+                                     &s->max_proto_version);
     default:
         return (s->method->ssl_ctrl(s, cmd, larg, parg));
     }
@@ -1314,6 +1322,12 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
         return (ctx->cert->cert_flags |= larg);
     case SSL_CTRL_CLEAR_CERT_FLAGS:
         return (ctx->cert->cert_flags &= ~larg);
+    case SSL_CTRL_SET_MIN_PROTO_VERSION:
+        return ssl_set_version_bound(ctx->method->version, (int)larg,
+                                     &ctx->min_proto_version);
+    case SSL_CTRL_SET_MAX_PROTO_VERSION:
+        return ssl_set_version_bound(ctx->method->version, (int)larg,
+                                     &ctx->max_proto_version);
     default:
         return (ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg));
     }
@@ -1781,7 +1795,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
     }
 
     if (FIPS_mode() && (meth->version < TLS1_VERSION)) {
-        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE);
         return NULL;
     }
 
@@ -1794,6 +1808,8 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
         goto err;
 
     ret->method = meth;
+    ret->min_proto_version = 0;
+    ret->max_proto_version = 0;
     ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
     ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
     /* We take the system default. */
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 4db32a9..7e07297f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -264,6 +264,11 @@
                           c[1]=(unsigned char)(((l)>> 8)&0xff), \
                           c[2]=(unsigned char)(((l)    )&0xff)),c+=3)
 
+#define DTLS_VERSION_GT(v1, v2) ((v1) < (v2))
+#define DTLS_VERSION_GE(v1, v2) ((v1) <= (v2))
+#define DTLS_VERSION_LT(v1, v2) ((v1) > (v2))
+#define DTLS_VERSION_LE(v1, v2) ((v1) >= (v2))
+
 /* LOCAL STUFF */
 
 # define SSL_DECRYPT     0
@@ -466,8 +471,8 @@
  * flags because it may not be set to correct version yet.
  */
 # define SSL_CLIENT_USE_TLS1_2_CIPHERS(s)        \
-                ((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \
-                (!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION))
+    ((!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION) || \
+     (SSL_IS_DTLS(s) && DTLS_VERSION_GE(s->client_version, DTLS1_2_VERSION)))
 
 # ifdef TLSEXT_TYPE_encrypt_then_mac
 #  define SSL_USE_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC)
@@ -530,6 +535,8 @@ struct ssl_cipher_st {
 /* Used to hold SSL/TLS functions */
 struct ssl_method_st {
     int version;
+    unsigned flags;
+    unsigned long mask;
     int (*ssl_new) (SSL *s);
     void (*ssl_clear) (SSL *s);
     void (*ssl_free) (SSL *s);
@@ -796,6 +803,8 @@ struct ssl_ctx_st {
 
     uint32_t options;
     uint32_t mode;
+    int min_proto_version;
+    int max_proto_version;
     long max_cert_list;
 
     struct cert_st /* CERT */ *cert;
@@ -1066,6 +1075,8 @@ struct ssl_st {
     uint32_t options;
     /* API behaviour */
     uint32_t mode;
+    int min_proto_version;
+    int max_proto_version;
     long max_cert_list;
     int first_packet;
     /* what was passed, used for SSLv3/TLS rollback check */
@@ -1676,12 +1687,20 @@ extern const SSL3_ENC_METHOD SSLv3_enc_data;
 extern const SSL3_ENC_METHOD DTLSv1_enc_data;
 extern const SSL3_ENC_METHOD DTLSv1_2_enc_data;
 
-# define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \
-                                s_get_meth, enc_data) \
+/*
+ * Flags for SSL methods
+ */
+#define SSL_METHOD_NO_FIPS      (1U<<0)
+#define SSL_METHOD_NO_SUITEB    (1U<<1)
+
+# define IMPLEMENT_tls_meth_func(version, flags, mask, func_name, s_accept, \
+                                 s_connect, s_get_meth, enc_data) \
 const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
                 version, \
+                flags, \
+                mask, \
                 tls1_new, \
                 tls1_clear, \
                 tls1_free, \
@@ -1718,6 +1737,8 @@ const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
                 SSL3_VERSION, \
+                SSL_METHOD_NO_FIPS | SSL_METHOD_NO_SUITEB, \
+                SSL_OP_NO_SSLv3, \
                 ssl3_new, \
                 ssl3_clear, \
                 ssl3_free, \
@@ -1749,12 +1770,14 @@ const SSL_METHOD *func_name(void)  \
         return &func_name##_data; \
         }
 
-# define IMPLEMENT_dtls1_meth_func(version, func_name, s_accept, s_connect, \
-                                        s_get_meth, enc_data) \
+# define IMPLEMENT_dtls1_meth_func(version, flags, mask, func_name, s_accept, \
+                                        s_connect, s_get_meth, enc_data) \
 const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
                 version, \
+                flags, \
+                mask, \
                 dtls1_new, \
                 dtls1_clear, \
                 dtls1_free, \
@@ -1902,6 +1925,12 @@ __owur int ssl3_handshake_write(SSL *s);
 
 __owur int ssl_allow_compression(SSL *s);
 
+__owur int ssl_set_client_hello_version(SSL *s);
+__owur int ssl_check_version_downgrade(SSL *s);
+__owur int ssl_set_version_bound(int method_version, int version, int *bound);
+__owur int ssl_choose_server_version(SSL *s);
+__owur int ssl_choose_client_version(SSL *s, int version);
+
 __owur long tls1_default_timeout(void);
 __owur int dtls1_do_write(SSL *s, int type);
 void dtls1_set_message_header(SSL *s,
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index bc3fc54..a03fe32 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -261,7 +261,8 @@ static void (*get_callback(SSL *s))(const SSL *, int, int)
  *   1: Success
  * <=0: NBIO or error
  */
-static int state_machine(SSL *s, int server) {
+static int state_machine(SSL *s, int server)
+{
     BUF_MEM *buf = NULL;
     unsigned long Time = (unsigned long)time(NULL);
     void (*cb) (const SSL *ssl, int type, int val) = NULL;
@@ -336,19 +337,15 @@ static int state_machine(SSL *s, int server) {
                 goto end;
             }
         } else {
-            if ((s->version >> 8) != SSL3_VERSION_MAJOR
-                    && s->version != TLS_ANY_VERSION) {
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR) {
                 SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
                 goto end;
             }
         }
 
-        if (!SSL_IS_DTLS(s)) {
-            if (s->version != TLS_ANY_VERSION &&
-                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-                SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
-                goto end;
-            }
+        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
+            goto end;
         }
 
         if (s->init_buf == NULL) {
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index d168b19..cfbfa5f 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -166,7 +166,6 @@
 
 static ossl_inline int cert_req_allowed(SSL *s);
 static int key_exchange_expected(SSL *s);
-static int ssl_set_version(SSL *s);
 static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
 static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
                                     unsigned char *p);
@@ -800,110 +799,12 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
     return WORK_ERROR;
 }
 
-/*
- * Work out what version we should be using for the initial ClientHello if
- * the version is currently set to (D)TLS_ANY_VERSION.
- * Returns 1 on success
- * Returns 0 on error
- */
-static int ssl_set_version(SSL *s)
-{
-    unsigned long mask, options = s->options;
-
-    if (s->method->version == TLS_ANY_VERSION) {
-        /*
-         * SSL_OP_NO_X disables all protocols above X *if* there are
-         * some protocols below X enabled. This is required in order
-         * to maintain "version capability" vector contiguous. So
-         * that if application wants to disable TLS1.0 in favour of
-         * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
-         * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
-         */
-        mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
-#if !defined(OPENSSL_NO_SSL3)
-            | SSL_OP_NO_SSLv3
-#endif
-            ;
-#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
-        if (options & SSL_OP_NO_TLSv1_2) {
-            if ((options & mask) != mask) {
-                s->version = TLS1_1_VERSION;
-            } else {
-                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
-                return 0;
-            }
-        } else {
-            s->version = TLS1_2_VERSION;
-        }
-#else
-        if ((options & mask) == mask) {
-            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
-            return 0;
-        }
-        s->version = TLS1_1_VERSION;
-#endif
-
-        mask &= ~SSL_OP_NO_TLSv1_1;
-        if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
-            s->version = TLS1_VERSION;
-        mask &= ~SSL_OP_NO_TLSv1;
-#if !defined(OPENSSL_NO_SSL3)
-        if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
-            s->version = SSL3_VERSION;
-#endif
-
-        if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) {
-            SSLerr(SSL_F_SSL_SET_VERSION,
-                   SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
-            return 0;
-        }
-
-        if (s->version == SSL3_VERSION && FIPS_mode()) {
-            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-            return 0;
-        }
-
-    } else if (s->method->version == DTLS_ANY_VERSION) {
-        /* Determine which DTLS version to use */
-        /* If DTLS 1.2 disabled correct the version number */
-        if (options & SSL_OP_NO_DTLSv1_2) {
-            if (tls1_suiteb(s)) {
-                SSLerr(SSL_F_SSL_SET_VERSION,
-                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                return 0;
-            }
-            /*
-             * Disabling all versions is silly: return an error.
-             */
-            if (options & SSL_OP_NO_DTLSv1) {
-                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION);
-                return 0;
-            }
-            /*
-             * Update method so we don't use any DTLS 1.2 features.
-             */
-            s->method = DTLSv1_client_method();
-            s->version = DTLS1_VERSION;
-        } else {
-            /*
-             * We only support one version: update method
-             */
-            if (options & SSL_OP_NO_DTLSv1)
-                s->method = DTLSv1_2_client_method();
-            s->version = DTLS1_2_VERSION;
-        }
-    }
-
-    s->client_version = s->version;
-
-    return 1;
-}
-
 int tls_construct_client_hello(SSL *s)
 {
     unsigned char *buf;
     unsigned char *p, *d;
     int i;
+    int protverr;
     unsigned long l;
     int al = 0;
 #ifndef OPENSSL_NO_COMP
@@ -915,8 +816,11 @@ int tls_construct_client_hello(SSL *s)
     buf = (unsigned char *)s->init_buf->data;
 
     /* Work out what SSL/TLS/DTLS version to use */
-    if (ssl_set_version(s) == 0)
+    protverr = ssl_set_client_hello_version(s);
+    if (protverr != 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, protverr);
         goto err;
+    }
 
     if ((sess == NULL) || (sess->ssl_version != s->version) ||
         /*
@@ -1123,97 +1027,23 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     unsigned char *cipherchars;
     int i, al = SSL_AD_INTERNAL_ERROR;
     unsigned int compression;
+    unsigned int sversion;
+    int protverr;
 #ifndef OPENSSL_NO_COMP
     SSL_COMP *comp;
 #endif
 
-    if (s->method->version == TLS_ANY_VERSION) {
-        unsigned int sversion;
-
-        if (!PACKET_get_net_2(pkt, &sversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-#if TLS_MAX_VERSION != TLS1_2_VERSION
-#error Code needs updating for new TLS version
-#endif
-#ifndef OPENSSL_NO_SSL3
-        if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
-            if (FIPS_mode()) {
-                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                       SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->method = SSLv3_client_method();
-        } else
-#endif
-        if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
-            s->method = TLSv1_client_method();
-        } else if ((sversion == TLS1_1_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_1)) {
-            s->method = TLSv1_1_client_method();
-        } else if ((sversion == TLS1_2_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_2)) {
-            s->method = TLSv1_2_client_method();
-        } else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-        s->session->ssl_version = s->version = s->method->version;
-
-        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-    } else if (s->method->version == DTLS_ANY_VERSION) {
-        /* Work out correct protocol version to use */
-        unsigned int hversion;
-        int options;
-
-        if (!PACKET_get_net_2(pkt, &hversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        options = s->options;
-        if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
-            s->method = DTLSv1_2_client_method();
-        else if (tls1_suiteb(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                   SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
-            s->method = DTLSv1_client_method();
-        else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-        s->session->ssl_version = s->version = s->method->version;
-    } else {
-        unsigned char *vers;
+    if (!PACKET_get_net_2(pkt, &sversion)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
 
-        if (!PACKET_get_bytes(pkt, &vers, 2)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if ((vers[0] != (s->version >> 8))
-                || (vers[1] != (s->version & 0xff))) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = (s->version & 0xff00) | vers[1];
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
+    protverr = ssl_choose_client_version(s, sversion);
+    if (protverr != 0) {
+        al = SSL_AD_PROTOCOL_VERSION;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr);
+        goto f_err;
     }
 
     /* load the server hello data */
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 86d200f..bf59eb3 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -229,7 +229,7 @@ MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
 {
     int al;
     long remain;
-    
+
     remain = PACKET_remaining(pkt);
     /*
      * 'Change Cipher Spec' is just a single byte, which should already have
@@ -704,3 +704,386 @@ int ssl_allow_compression(SSL *s)
         return 0;
     return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL);
 }
+
+static int version_cmp(SSL *s, int a, int b)
+{
+    int dtls = SSL_IS_DTLS(s);
+
+    if (a == b)
+        return 0;
+    if (!dtls)
+        return a < b ? -1 : 1;
+    return DTLS_VERSION_LT(a, b) ? -1 : 1;
+}
+
+typedef struct {
+    int version;
+    const SSL_METHOD *(*cmeth)(void);
+    const SSL_METHOD *(*smeth)(void);
+} version_info;
+
+#if TLS_MAX_VERSION != TLS1_2_VERSION
+# error Code needs update for TLS_method() support beyond TLS1_2_VERSION.
+#endif
+
+static const version_info tls_version_table[] = {
+    { TLS1_2_VERSION, TLSv1_2_client_method, TLSv1_2_server_method },
+    { TLS1_1_VERSION, TLSv1_1_client_method, TLSv1_1_server_method },
+    { TLS1_VERSION, TLSv1_client_method, TLSv1_server_method },
+#ifndef OPENSSL_NO_SSL3
+    { SSL3_VERSION, SSLv3_client_method, SSLv3_server_method },
+#endif
+    { 0, NULL, NULL },
+};
+
+#if DTLS_MAX_VERSION != DTLS1_2_VERSION
+# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
+#endif
+
+static const version_info dtls_version_table[] = {
+    { DTLS1_2_VERSION, DTLSv1_2_client_method, DTLSv1_2_server_method },
+    { DTLS1_VERSION, DTLSv1_client_method, DTLSv1_server_method },
+    { 0, NULL, NULL },
+};
+
+/*
+ * ssl_method_error - Check whether an SSL_METHOD is enabled.
+ *
+ * @s: The SSL handle for the candidate method
+ * @method: the intended method.
+ *
+ * Returns 0 on success, or an SSL error reason on failure.
+ */
+static int ssl_method_error(SSL *s, const SSL_METHOD *method)
+{
+    int version = method->version;
+
+    if ((s->min_proto_version != 0 &&
+         version_cmp(s, version, s->min_proto_version) < 0) ||
+        ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0)
+        return SSL_R_VERSION_TOO_LOW;
+
+    if (s->max_proto_version != 0 &&
+             version_cmp(s, version, s->max_proto_version) > 0)
+        return SSL_R_VERSION_TOO_HIGH;
+
+    if ((s->options & method->mask) != 0)
+        return SSL_R_UNSUPPORTED_PROTOCOL;
+    if ((method->flags & SSL_METHOD_NO_SUITEB) != 0 && tls1_suiteb(s))
+        return SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE;
+    else if ((method->flags & SSL_METHOD_NO_FIPS) != 0 && FIPS_mode())
+        return SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE;
+
+    return 0;
+}
+
+/*
+ * ssl_check_version_downgrade - In response to RFC7507 SCSV version
+ * fallback indication from a client check whether we're using the highest
+ * supported protocol version.
+ *
+ * @s server SSL handle.
+ *
+ * Returns 1 when using the highest enabled version, 0 otherwise.
+ */
+int ssl_check_version_downgrade(SSL *s)
+{
+    const version_info *vent;
+    const version_info *table;
+
+    /*
+     * Check that the current protocol is the highest enabled version
+     * (according to s->ctx->method, as version negotiation may have changed
+     * s->method).
+     */
+    if (s->version == s->ctx->method->version)
+        return 1;
+
+    /*
+     * Apparently we're using a version-flexible SSL_METHOD (not at its
+     * highest protocol version).
+     */
+    if (s->ctx->method->version == TLS_method()->version)
+        table = tls_version_table;
+    else if (s->ctx->method->version == DTLS_method()->version)
+        table = dtls_version_table;
+    else {
+        /* Unexpected state; fail closed. */
+        return 0;
+    }
+
+    for (vent = table; vent->version != 0; ++vent) {
+        if (vent->smeth != NULL &&
+            ssl_method_error(s, vent->smeth()) == 0)
+            return s->version == vent->version;
+    }
+    return 0;
+}
+
+/*
+ * ssl_set_version_bound - set an upper or lower bound on the supported (D)TLS
+ * protocols, provided the initial (D)TLS method is version-flexible.  This
+ * function sanity-checks the proposed value and makes sure the method is
+ * version-flexible, then sets the limit if all is well.
+ *
+ * @method_version: The version of the current SSL_METHOD.
+ * @version: the intended limit.
+ * @bound: pointer to limit to be updated.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+int ssl_set_version_bound(int method_version, int version, int *bound)
+{
+    /*-
+     * Restrict TLS methods to TLS protocol versions.
+     * Restrict DTLS methods to DTLS protocol versions.
+     * Note, DTLS version numbers are decreasing, use comparison macros.
+     *
+     * Note that for both lower-bounds we use explicit versions, not
+     * (D)TLS_MIN_VERSION.  This is because we don't want to break user
+     * configurations.  If the MIN (supported) version ever rises, the user's
+     * "floor" remains valid even if no longer available.  We don't expect the
+     * MAX ceiling to ever get lower, so making that variable makes sense.
+     */
+    switch (method_version) {
+    default:
+        /*
+         * XXX For fixed version methods, should we always fail and not set any
+         * bounds, always succeed and not set any bounds, or set the bounds and
+         * arrange to fail later if they are not met?  At present fixed-version
+         * methods are not subject to controls that disable individual protocol
+         * versions.
+         */
+        return 0;
+
+    case TLS_ANY_VERSION:
+        if (version < SSL3_VERSION || version > TLS_MAX_VERSION)
+            return 0;
+        break;
+
+    case DTLS_ANY_VERSION:
+        if (DTLS_VERSION_GT(version, DTLS_MAX_VERSION) ||
+            DTLS_VERSION_LT(version, DTLS1_VERSION))
+            return 0;
+        break;
+    }
+
+    *bound = version;
+    return 1;
+}
+
+/*
+ * ssl_choose_server_version - Choose server (D)TLS version.  Called when the
+ * client HELLO is received to select the final server protocol version and
+ * the version specific method.
+ *
+ * @s: server SSL handle.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.
+ */
+int ssl_choose_server_version(SSL *s)
+{
+    /*-
+     * With version-flexible methods we have an initial state with:
+     *
+     *   s->method->version == (D)TLS_ANY_VERSION,
+     *   s->version == (D)TLS_MAX_VERSION.
+     *
+     * So we detect version-flexible methods via the method version, not the
+     * handle version.
+     */
+    int server_version = s->method->version;
+    int client_version = s->client_version;
+    const version_info *vent;
+    const version_info *table;
+    int disabled = 0;
+
+    switch (server_version) {
+    default:
+        if (version_cmp(s, client_version, s->version) < 0)
+            return SSL_R_WRONG_SSL_VERSION;
+        /*
+         * If this SSL handle is not from a version flexible method we don't
+         * (and never did) check min/max FIPS or Suite B constraints.  Hope
+         * that's OK.  It is up to the caller to not choose fixed protocol
+         * versions they don't want.  If not, then easy to fix, just return
+         * ssl_method_error(s, s->method)
+         */
+        return 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    for (vent = table; vent->version != 0; ++vent) {
+        const SSL_METHOD *method;
+
+        if (vent->smeth == NULL ||
+            version_cmp(s, client_version, vent->version) < 0)
+            continue;
+        method = vent->smeth();
+        if (ssl_method_error(s, method) == 0) {
+            s->version = vent->version;
+            s->method = method;
+            return 0;
+        }
+        disabled = 1;
+    }
+    return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW;
+}
+
+/*
+ * ssl_choose_client_version - Choose client (D)TLS version.  Called when the
+ * server HELLO is received to select the final client protocol version and
+ * the version specific method.
+ *
+ * @s: client SSL handle.
+ * @version: The proposed version from the server's HELLO.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.
+ */
+int ssl_choose_client_version(SSL *s, int version)
+{
+    const version_info *vent;
+    const version_info *table;
+
+    switch (s->method->version) {
+    default:
+        if (version != s->version)
+            return SSL_R_WRONG_SSL_VERSION;
+        /*
+         * If this SSL handle is not from a version flexible method we don't
+         * (and never did) check min/max, FIPS or Suite B constraints.  Hope
+         * that's OK.  It is up to the caller to not choose fixed protocol
+         * versions they don't want.  If not, then easy to fix, just return
+         * ssl_method_error(s, s->method)
+         */
+        s->session->ssl_version = s->version;
+        return 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    for (vent = table; vent->version != 0; ++vent) {
+        const SSL_METHOD *method;
+        int err;
+
+        if (version != vent->version)
+            continue;
+        if (vent->cmeth == NULL)
+            break;
+        method = vent->cmeth();
+        err = ssl_method_error(s, method);
+        if (err != 0)
+            return err;
+        s->method = method;
+        s->session->ssl_version = s->version = version;
+        return 0;
+    }
+
+    return SSL_R_UNSUPPORTED_PROTOCOL;
+}
+
+/*-
+ * ssl_set_client_hello_version - Work out what version we should be using for
+ * the initial ClientHello if the version is initially (D)TLS_ANY_VERSION.  We
+ * apply any explicit SSL_OP_NO_xxx options, the MinProtocol and MaxProtocol
+ * configuration commands, any Suite B or FIPS_mode() constraints and any floor
+ * imposed by the security level here, so we don't advertise the wrong protocol
+ * version to only reject the outcome later.
+ *
+ * Computing the right floor matters.  If, e.g.,  TLS 1.0 and 1.2 are enabled,
+ * TLS 1.1 is disabled, but the security level, Suite-B  and/or MinProtocol
+ * only allow TLS 1.2, we want to advertise TLS1.2, *not* TLS1.
+ *
+ * @s: client SSL handle.
+ *
+ * Returns 0 on success or an SSL error reason number on failure.
+ */
+int ssl_set_client_hello_version(SSL *s)
+{
+    int version;
+    int hole;
+    const SSL_METHOD *single = NULL;
+    const SSL_METHOD *method;
+    const version_info *table;
+    const version_info *vent;
+
+    switch (s->method->version) {
+    default:
+        /*
+         * If this SSL handle is not from a version flexible method we don't
+         * (and never did) check min/max FIPS or Suite B constraints.  Hope
+         * that's OK.  It is up to the caller to not choose fixed protocol
+         * versions they don't want.  If not, then easy to fix, just return
+         * ssl_method_error(s, s->method)
+         */
+        s->client_version = s->version;
+        return 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    /*
+     * SSL_OP_NO_X disables all protocols above X *if* there are some protocols
+     * below X enabled. This is required in order to maintain the "version
+     * capability" vector contiguous. Any versions with a NULL client method
+     * (protocol version client is disabled at compile-time) is also a "hole".
+     *
+     * Our initial state is hole == 1, version == 0.  That is, versions above
+     * the first version in the method table are disabled (a "hole" above
+     * the valid protocol entries) and we don't have a selected version yet.
+     *
+     * Whenever "hole == 1", and we hit an enabled method, its version becomes
+     * the selected version, and the method becomes a candidate "single"
+     * method.  We're no longer in a hole, so "hole" becomes 0.
+     *
+     * If "hole == 0" and we hit an enabled method, then "single" is cleared,
+     * as we support a contiguous range of at least two methods.  If we hit
+     * a disabled method, then hole becomes true again, but nothing else
+     * changes yet, because all the remaining methods may be disabled too.
+     * If we again hit an enabled method after the new hole, it becomes
+     * selected, as we start from scratch.
+     */
+    version = 0;
+    hole = 1;
+    for (vent = table; vent->version != 0; ++vent) {
+        /*
+         * A table entry with a NULL client method is still a hole in the
+         * "version capability" vector.
+         */
+        if (vent->cmeth == NULL) {
+            hole = 1;
+            continue;
+        }
+        method = vent->cmeth();
+        if (ssl_method_error(s, method) != 0) {
+            hole = 1;
+        } else if (!hole) {
+            single = NULL;
+        } else {
+            version = (single = method)->version;
+            hole = 0;
+        }
+    }
+
+    /* Fail if everything is disabled */
+    if (version == 0)
+        return SSL_R_NO_PROTOCOLS_AVAILABLE;
+
+    if (single != NULL)
+        s->method = single;
+    s->client_version = s->version = version;
+    return 0;
+}
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 66ff3e6..604b365 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -970,7 +970,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     SSL_COMP *comp = NULL;
 #endif
     STACK_OF(SSL_CIPHER) *ciphers = NULL;
-    int protverr = 1;
+    int protverr;
     /* |cookie| will only be initialized for DTLS. */
     PACKET session_id, cipher_suites, compression, extensions, cookie;
     int is_v2_record;
@@ -1037,63 +1037,21 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         }
     }
 
-    /* Do SSL/TLS version negotiation if applicable */
+    /*
+     * Do SSL/TLS version negotiation if applicable. For DTLS we just check
+     * versions are potentially compatible. Version negotiation comes later.
+     */
     if (!SSL_IS_DTLS(s)) {
-        if (s->version != TLS_ANY_VERSION) {
-            if (s->client_version >= s->version) {
-                protverr = 0;
-            }
-        } else if (s->client_version >= SSL3_VERSION) {
-            switch(s->client_version) {
-            default:
-            case TLS1_2_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_2)) {
-                    s->version = TLS1_2_VERSION;
-                    s->method = TLSv1_2_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_1)) {
-                    s->version = TLS1_1_VERSION;
-                    s->method = TLSv1_1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1)) {
-                    s->version = TLS1_VERSION;
-                    s->method = TLSv1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case SSL3_VERSION:
-#ifndef OPENSSL_NO_SSL3
-                if(!(s->options & SSL_OP_NO_SSLv3)) {
-                    s->version = SSL3_VERSION;
-                    s->method = SSLv3_server_method();
-                    protverr = 0;
-                    break;
-                }
-#else
-                break;
-#endif
-            }
-        }
-    } else if (s->client_version <= s->version
-                || s->method->version == DTLS_ANY_VERSION) {
-        /*
-         * For DTLS we just check versions are potentially compatible. Version
-         * negotiation comes later.
-         */
+        protverr = ssl_choose_server_version(s);
+    } else if (s->method->version != DTLS_ANY_VERSION &&
+               DTLS_VERSION_LT(s->client_version, s->version)) {
+        protverr = SSL_R_VERSION_TOO_LOW;
+    } else {
         protverr = 0;
     }
 
     if (protverr) {
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr);
         if ((!s->enc_write_ctx && !s->write_hash)) {
             /*
              * similar to ssl3_get_record, send alert using remote version
@@ -1253,24 +1211,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
             s->d1->cookie_verified = 1;
         }
         if (s->method->version == DTLS_ANY_VERSION) {
-            /* Select version to use */
-            if (s->client_version <= DTLS1_2_VERSION &&
-                !(s->options & SSL_OP_NO_DTLSv1_2)) {
-                s->version = DTLS1_2_VERSION;
-                s->method = DTLSv1_2_server_method();
-            } else if (tls1_suiteb(s)) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            } else if (s->client_version <= DTLS1_VERSION &&
-                       !(s->options & SSL_OP_NO_DTLSv1)) {
-                s->version = DTLS1_VERSION;
-                s->method = DTLSv1_server_method();
-            } else {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                       SSL_R_WRONG_VERSION_NUMBER);
+            protverr = ssl_choose_server_version(s);
+            if (protverr != 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr);
                 s->version = s->client_version;
                 al = SSL_AD_PROTOCOL_VERSION;
                 goto f_err;
@@ -3278,7 +3221,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
              * version. Fail if the current version is an unexpected
              * downgrade.
              */
-            if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) {
+            if (!ssl_check_version_downgrade(s)) {
                 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
                        SSL_R_INAPPROPRIATE_FALLBACK);
                 *al = SSL_AD_INAPPROPRIATE_FALLBACK;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index a2a68af..980f2f5 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -208,7 +208,10 @@ void tls1_free(SSL *s)
 void tls1_clear(SSL *s)
 {
     ssl3_clear(s);
-    s->version = s->method->version;
+    if (s->method->version == TLS_ANY_VERSION)
+        s->version = TLS_MAX_VERSION;
+    else
+        s->version = s->method->version;
 }
 
 #ifndef OPENSSL_NO_EC
diff --git a/test/recipes/80-test_ssl.t b/test/recipes/80-test_ssl.t
index 5f520de..0f96b5b 100644
--- a/test/recipes/80-test_ssl.t
+++ b/test/recipes/80-test_ssl.t
@@ -11,8 +11,8 @@ use OpenSSL::Test::Utils;
 
 setup("test_ssl");
 
-my ($no_rsa, $no_dsa, $no_dh, $no_ec, $no_srp, $no_psk) =
-    disabled qw/rsa dsa dh ec srp psk/;
+my ($no_rsa, $no_dsa, $no_dh, $no_ec, $no_srp, $no_psk, $no_ssl3, $no_dtls) =
+    disabled qw/rsa dsa dh ec srp psk ssl3 dtls/;
 
 my $digest = "-sha1";
 my @reqcmd = ("openssl", "req");
@@ -55,7 +55,7 @@ my $P2intermediate="tmp_intP2.ss";
 plan tests =>
     1				# For testss
     + 1				# For ssltest -test_cipherlist
-    + 8				# For the first testssl
+    + 9				# For the first testssl
     + 16			# For the first testsslproxy
     + 16			# For the second testsslproxy
     ;
@@ -316,7 +316,7 @@ sub testssl {
     }
 
 
-    # plan tests => 7;
+    # plan tests => 9;
 
     subtest 'standard SSL tests' => sub {
 	######################################################################
@@ -567,6 +567,516 @@ sub testssl {
 	    }
 	}
     };
+
+    subtest 'Version min/max tests' => sub {
+
+	plan tests => 425;
+
+	SKIP : {
+            skip "ssl3 disabled", 76 if $no_ssl3;
+
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1", "-should_negotiate", "tls1"])));
+
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-server_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        }
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1", "-should_negotiate", "tls1"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-server_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-server_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "fail-server"])));
+        }
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-server"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 19 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1.1", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1", "-should_negotiate", "tls1"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_min_proto", "tls1.2", "-should_negotiate", "fail-client"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "ssl3 disabled", 6 if $no_ssl3;
+            ok(run(test([@ssltest, "-client_min_proto", "ssl3", "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+            ok(run(test([@ssltest, "-client_min_proto", "ssl3", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+            ok(run(test([@ssltest, "-client_min_proto", "ssl3", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+            ok(run(test([@ssltest, "-client_min_proto", "ssl3", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-client_min_proto", "ssl3", "-should_negotiate", "tls1.2"])));
+            ok(run(test([@ssltest, "-client_max_proto", "ssl3", "-should_negotiate", "ssl3"])));
+        }
+        ok(run(test([@ssltest, "-client_min_proto", "tls1", "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1.1", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1.2", "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1.1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_min_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-client_max_proto", "tls1", "-should_negotiate", "tls1"])));
+        ok(run(test([@ssltest, "-client_max_proto", "tls1.1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-client_max_proto", "tls1.2", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-should_negotiate", "tls1.2"])));
+
+        SKIP : {
+            skip "dtls disabled", 64 if $no_dtls;
+
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-server_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-server_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_min_proto", "dtls1.2", "-should_negotiate", "fail-client"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_max_proto", "dtls1", "-should_negotiate", "fail-server"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-server_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+
+            ok(run(test([@ssltest, "-dtls", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-client_min_proto", "dtls1", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-client_min_proto", "dtls1.2", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-client_min_proto", "dtls1", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-client_min_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-client_max_proto", "dtls1", "-should_negotiate", "dtls1"])));
+            ok(run(test([@ssltest, "-dtls", "-client_max_proto", "dtls1.2", "-should_negotiate", "dtls1.2"])));
+            ok(run(test([@ssltest, "-dtls", "-should_negotiate", "dtls1.2"])));
+        }
+    };
 }
 
 sub testsslproxy {
diff --git a/test/ssltest.c b/test/ssltest.c
index 01b6058..58e0f82 100644
--- a/test/ssltest.c
+++ b/test/ssltest.c
@@ -367,6 +367,11 @@ static const char *alpn_client;
 static const char *alpn_server;
 static const char *alpn_expected;
 static unsigned char *alpn_selected;
+static const char *server_min_proto;
+static const char *server_max_proto;
+static const char *client_min_proto;
+static const char *client_max_proto;
+static const char *should_negotiate;
 
 /*-
  * next_protos_parse parses a comma separated list of strings into a string
@@ -776,6 +781,7 @@ static void sv_usage(void)
 #endif
     fprintf(stderr, " -tls1         - use TLSv1\n");
 #ifndef OPENSSL_NO_DTLS
+    fprintf(stderr, " -dtls        - use DTLS\n");
     fprintf(stderr, " -dtls1        - use DTLSv1\n");
     fprintf(stderr, " -dtls12       - use DTLSv1.2\n");
 #endif
@@ -818,6 +824,11 @@ static void sv_usage(void)
     fprintf(stderr, " -alpn_server <string> - have server side offer ALPN\n");
     fprintf(stderr,
             " -alpn_expected <string> - the ALPN protocol that should be negotiated\n");
+    fprintf(stderr, " -server_min_proto <string> - Minimum version the server should support\n");
+    fprintf(stderr, " -server_max_proto <string> - Maximum version the server should support\n");
+    fprintf(stderr, " -client_min_proto <string> - Minimum version the client should support\n");
+    fprintf(stderr, " -client_max_proto <string> - Maximum version the client should support\n");
+    fprintf(stderr, " -should_negotiate <string> - The version that should be negotiated, fail-client or fail-server\n");
 }
 
 static void print_key_details(BIO *out, EVP_PKEY *key)
@@ -942,13 +953,58 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line)
     }
 }
 
+/*
+ * protocol_from_string - converts a protocol version string to a number
+ *
+ * Returns -1 on failure or the version on success
+ */
+static int protocol_from_string(const char *value)
+{
+    struct protocol_versions {
+        const char *name;
+        int version;
+    };
+    static const struct protocol_versions versions[] = {
+        {"ssl3", SSL3_VERSION},
+        {"tls1", TLS1_VERSION},
+        {"tls1.1", TLS1_1_VERSION},
+        {"tls1.2", TLS1_2_VERSION},
+        {"dtls1", DTLS1_VERSION},
+        {"dtls1.2", DTLS1_2_VERSION}};
+    size_t i;
+    size_t n = OSSL_NELEM(versions);
+
+    for (i = 0; i < n; i++)
+        if (strcmp(versions[i].name, value) == 0)
+            return versions[i].version;
+    return -1;
+}
+
+/*
+ * set_protocol_version - Sets protocol version minimum or maximum
+ *
+ * Returns 0 on failure and 1 on success
+ */
+static int set_protocol_version(const char *version, SSL *ssl, int setting)
+{
+    if (version != NULL) {
+        int ver = protocol_from_string(version);
+        if (ver < 0) {
+            BIO_printf(bio_err, "Error parsing: %s\n", version);
+            return 0;
+        }
+        return SSL_ctrl(ssl, setting, ver, NULL);
+    }
+    return 1;
+}
+
 int main(int argc, char *argv[])
 {
     char *CApath = NULL, *CAfile = NULL;
     int badop = 0;
     int bio_pair = 0;
     int force = 0;
-    int dtls1 = 0, dtls12 = 0, tls1 = 0, ssl3 = 0, ret = 1;
+    int dtls1 = 0, dtls12 = 0, dtls = 0, tls1 = 0, ssl3 = 0, ret = 1;
     int client_auth = 0;
     int server_auth = 0, i;
     struct app_verify_arg app_verify_arg =
@@ -1136,6 +1192,11 @@ int main(int argc, char *argv[])
             no_protocol = 1;
 #endif
             dtls12 = 1;
+        } else if (strcmp(*argv, "-dtls") == 0) {
+#ifdef OPENSSL_NO_DTLS
+            no_protocol = 1;
+#endif
+            dtls = 1;
         } else if (strncmp(*argv, "-num", 4) == 0) {
             if (--argc < 1)
                 goto bad;
@@ -1225,6 +1286,26 @@ int main(int argc, char *argv[])
             if (--argc < 1)
                 goto bad;
             alpn_expected = *(++argv);
+        } else if (strcmp(*argv, "-server_min_proto") == 0) {
+            if (--argc < 1)
+                goto bad;
+            server_min_proto = *(++argv);
+        } else if (strcmp(*argv, "-server_max_proto") == 0) {
+            if (--argc < 1)
+                goto bad;
+            server_max_proto = *(++argv);
+        } else if (strcmp(*argv, "-client_min_proto") == 0) {
+            if (--argc < 1)
+                goto bad;
+            client_min_proto = *(++argv);
+        } else if (strcmp(*argv, "-client_max_proto") == 0) {
+            if (--argc < 1)
+                goto bad;
+            client_max_proto = *(++argv);
+        } else if (strcmp(*argv, "-should_negotiate") == 0) {
+            if (--argc < 1)
+                goto bad;
+            should_negotiate = *(++argv);
         } else {
             int rv;
             arg = argv[0];
@@ -1283,8 +1364,8 @@ int main(int argc, char *argv[])
         goto end;
     }
 
-    if (ssl3 + tls1 + dtls1 + dtls12 > 1) {
-        fprintf(stderr, "At most one of -ssl3, -tls1, -dtls1 or -dtls12 should "
+    if (ssl3 + tls1 + dtls + dtls1 + dtls12 > 1) {
+        fprintf(stderr, "At most one of -ssl3, -tls1, -dtls, -dtls1 or -dtls12 should "
                 "be requested.\n");
         EXIT(1);
     }
@@ -1301,10 +1382,10 @@ int main(int argc, char *argv[])
         goto end;
     }
 
-    if (!ssl3 && !tls1 && !dtls1 && !dtls12 && number > 1 && !reuse && !force) {
+    if (!ssl3 && !tls1 && !dtls && !dtls1 && !dtls12 && number > 1 && !reuse && !force) {
         fprintf(stderr, "This case cannot work.  Use -f to perform "
                 "the test anyway (and\n-d to see what happens), "
-                "or add one of -ssl3, -tls1, -dtls1, -dtls12, -reuse\n"
+                "or add one of -ssl3, -tls1, -dtls, -dtls1, -dtls12, -reuse\n"
                 "to avoid protocol mismatch.\n");
         EXIT(1);
     }
@@ -1378,6 +1459,8 @@ int main(int argc, char *argv[])
         meth = DTLSv1_method();
     else if (dtls12)
         meth = DTLSv1_2_method();
+    else if (dtls)
+        meth = DTLS_method();
     else
 #endif
     if (tls1)
@@ -1659,6 +1742,15 @@ int main(int argc, char *argv[])
     c_ssl = SSL_new(c_ctx);
     s_ssl = SSL_new(s_ctx);
 
+    if (!set_protocol_version(server_min_proto, s_ssl, SSL_CTRL_SET_MIN_PROTO_VERSION))
+        goto end;
+    if (!set_protocol_version(server_max_proto, s_ssl, SSL_CTRL_SET_MAX_PROTO_VERSION))
+        goto end;
+    if (!set_protocol_version(client_min_proto, c_ssl, SSL_CTRL_SET_MIN_PROTO_VERSION))
+        goto end;
+    if (!set_protocol_version(client_max_proto, c_ssl, SSL_CTRL_SET_MAX_PROTO_VERSION))
+        goto end;
+
     BIO_printf(bio_stdout, "Doing handshakes=%d bytes=%ld\n", number, bytes);
     for (i = 0; i < number; i++) {
         if (!reuse) {
@@ -1674,6 +1766,23 @@ int main(int argc, char *argv[])
 	if (ret)  break;
     }
 
+    if (should_negotiate && ret == 0 &&
+        strcmp(should_negotiate, "fail-server") != 0 &&
+        strcmp(should_negotiate, "fail-client") != 0) {
+        int version = protocol_from_string(should_negotiate);
+        if (version < 0) {
+            BIO_printf(bio_err, "Error parsing: %s\n", should_negotiate);
+            ret = 1;
+            goto err;
+        }
+        if (SSL_version(c_ssl) != version) {
+            BIO_printf(bio_err, "Unxpected version negotiated. "
+                "Expected: %s, got %s\n", should_negotiate, SSL_get_version(c_ssl));
+            ret = 1;
+            goto err;
+        }
+    }
+
     if (!verbose) {
         print_details(c_ssl, "");
     }
@@ -1696,6 +1805,7 @@ int main(int argc, char *argv[])
 #endif
     }
 
+ err:
     SSL_free(s_ssl);
     SSL_free(c_ssl);
 
@@ -1728,6 +1838,8 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
     BIO *s_ssl_bio = NULL, *c_ssl_bio = NULL;
     BIO *server = NULL, *server_io = NULL, *client = NULL, *client_io = NULL;
     int ret = 1;
+    int err_in_client = 0;
+    int err_in_server = 0;
 
     size_t bufsiz = 256;        /* small buffer for testing */
 
@@ -1820,6 +1932,7 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
                 if (r < 0) {
                     if (!BIO_should_retry(c_ssl_bio)) {
                         fprintf(stderr, "ERROR in CLIENT\n");
+                        err_in_client = 1;
                         goto err;
                     }
                     /*
@@ -1845,6 +1958,7 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
                 if (r < 0) {
                     if (!BIO_should_retry(c_ssl_bio)) {
                         fprintf(stderr, "ERROR in CLIENT\n");
+                        err_in_client = 1;
                         goto err;
                     }
                     /*
@@ -1897,6 +2011,7 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
                 if (r < 0) {
                     if (!BIO_should_retry(s_ssl_bio)) {
                         fprintf(stderr, "ERROR in SERVER\n");
+                        err_in_server = 1;
                         goto err;
                     }
                     /* Ignore "BIO_should_retry". */
@@ -1917,6 +2032,7 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
                 if (r < 0) {
                     if (!BIO_should_retry(s_ssl_bio)) {
                         fprintf(stderr, "ERROR in SERVER\n");
+                        err_in_server = 1;
                         goto err;
                     }
                     /* blah, blah */
@@ -2084,6 +2200,11 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
     BIO_free(s_ssl_bio);
     BIO_free(c_ssl_bio);
 
+    if (should_negotiate != NULL && strcmp(should_negotiate, "fail-client") == 0)
+        ret = (err_in_client != 0) ? 0 : 1;
+    else if (should_negotiate != NULL && strcmp(should_negotiate, "fail-server") == 0)
+        ret = (err_in_server != 0) ? 0 : 1;
+
     return ret;
 }
 
@@ -2109,6 +2230,8 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
     int c_write, s_write;
     int do_server = 0, do_client = 0;
     int max_frag = 5 * 1024;
+    int err_in_client = 0;
+    int err_in_server = 0;
 
     bufsiz = count > 40 * 1024 ? 40 * 1024 : count;
 
@@ -2201,6 +2324,7 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
                             c_w = 1;
                     } else {
                         fprintf(stderr, "ERROR in CLIENT\n");
+                        err_in_client = 1;
                         ERR_print_errors(bio_err);
                         goto err;
                     }
@@ -2229,6 +2353,7 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
                             c_w = 1;
                     } else {
                         fprintf(stderr, "ERROR in CLIENT\n");
+                        err_in_client = 1;
                         ERR_print_errors(bio_err);
                         goto err;
                     }
@@ -2265,6 +2390,7 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
                             s_w = 1;
                     } else {
                         fprintf(stderr, "ERROR in SERVER\n");
+                        err_in_server = 1;
                         ERR_print_errors(bio_err);
                         goto err;
                     }
@@ -2300,6 +2426,7 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
                             s_w = 1;
                     } else {
                         fprintf(stderr, "ERROR in SERVER\n");
+                        err_in_server = 1;
                         ERR_print_errors(bio_err);
                         goto err;
                     }
@@ -2370,6 +2497,11 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
     OPENSSL_free(cbuf);
     OPENSSL_free(sbuf);
 
+    if (should_negotiate != NULL && strcmp(should_negotiate, "fail-client") == 0)
+        ret = (err_in_client != 0) ? 0 : 1;
+    else if (should_negotiate != NULL && strcmp(should_negotiate, "fail-server") == 0)
+        ret = (err_in_server != 0) ? 0 : 1;
+
     return (ret);
 }
 


More information about the openssl-commits mailing list