]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add support for MinTLS and MaxTLS options (Issue #5119)
authorMichael R Sweet <michaelrsweet@gmail.com>
Fri, 3 Nov 2017 15:27:04 +0000 (11:27 -0400)
committerMichael R Sweet <michaelrsweet@gmail.com>
Fri, 3 Nov 2017 15:27:04 +0000 (11:27 -0400)
- cups/http-private.h: Move TLS/SSL version options to separate version
  constants, make _httpTLSSetOptions take min/max version numbers.
- cups/tls-*.c: Update _httpTLSSetOptions and _httpTLSStart to use new min/max
  version numbers.
- cups/tlscheck.c: Update _httpTLSSetOptions call.
- cups/usersys.c: Support new SSLOptions values, update _httpTLSSetOptions call.
- scheduler/conf.c: Support new SSLOptions values, update _httpTLSSetOptions
  calls.

CHANGES.md
cups/http-private.h
cups/tls-darwin.c
cups/tls-gnutls.c
cups/tls-sspi.c
cups/tlscheck.c
cups/usersys.c
man/client.conf.man.in
man/cupsd.conf.man.in
scheduler/conf.c

index b710f06ca8c051a50a49e0c1cdb4058fb3a86f8a..ec88104c6a61dd8d6ad415770553ae5696ded8b4 100644 (file)
@@ -1,4 +1,4 @@
-CHANGES - 2.3b1 - 2017-11-01
+CHANGES - 2.3b1 - 2017-11-03
 ============================
 
 
@@ -19,6 +19,9 @@ Changes in CUPS v2.3b1
   printer cannot be found (Issue #5096)
 - The `lpadmin` command now provides a better error message when an unsupported
   System V interface script is used (Issue #5111)
+- The `SSLOptions` directive now supports `MinTLS` and `MaxTLS` options to
+  control the minimum and maximum TLS versions that will be allowed,
+  respectively (Issue #5119)
 - Dropped hard-coded CGI scripting language support (Issue #5124)
 - Fixed the `ippserver` sample code when threading is disabled or unavailable
   (Issue #5154)
index f71e564b259881cc4d6fcb0e182e584e32a5622b..508d67e3be5e3f0a62c4a3e24ea1240a25fdbcf5 100644 (file)
@@ -180,13 +180,17 @@ extern "C" {
 
 #  define _HTTP_TLS_NONE       0       /* No TLS options */
 #  define _HTTP_TLS_ALLOW_RC4  1       /* Allow RC4 cipher suites */
-#  define _HTTP_TLS_ALLOW_SSL3 2       /* Allow SSL 3.0 */
-#  define _HTTP_TLS_ALLOW_DH   4       /* Allow DH/DHE key negotiation */
-#  define _HTTP_TLS_DENY_TLS10 16      /* Deny TLS 1.0 */
-#  define _HTTP_TLS_DENY_CBC   32      /* Deny CBC cipher suites */
-#  define _HTTP_TLS_ONLY_TLS10  64      /* Only use TLS 1.0 */
+#  define _HTTP_TLS_ALLOW_DH   2       /* Allow DH/DHE key negotiation */
+#  define _HTTP_TLS_DENY_CBC   4       /* Deny CBC cipher suites */
 #  define _HTTP_TLS_SET_DEFAULT 128     /* Setting the default TLS options */
 
+#  define _HTTP_TLS_SSL3       0       /* Min/max version is SSL/3.0 */
+#  define _HTTP_TLS_1_0                1       /* Min/max version is TLS/1.0 */
+#  define _HTTP_TLS_1_1                2       /* Min/max version is TLS/1.1 */
+#  define _HTTP_TLS_1_2                3       /* Min/max version is TLS/1.2 */
+#  define _HTTP_TLS_1_3                4       /* Min/max version is TLS/1.3 */
+#  define _HTTP_TLS_MAX                5       /* Highest known TLS version */
+
 
 /*
  * Types and functions for SSL support...
@@ -442,7 +446,7 @@ extern void         _httpTLSInitialize(void);
 extern size_t          _httpTLSPending(http_t *http);
 extern int             _httpTLSRead(http_t *http, char *buf, int len);
 extern int             _httpTLSSetCredentials(http_t *http);
-extern void            _httpTLSSetOptions(int options);
+extern void            _httpTLSSetOptions(int options, int min_version, int max_version);
 extern int             _httpTLSStart(http_t *http);
 extern void            _httpTLSStop(http_t *http);
 extern int             _httpTLSWrite(http_t *http, const char *buf, int len);
index 92430aca0f7f8cc5303260b1fb5a2af7bac00d83..7b28ee47d841a66e86ed0a40c9cedafe06ce1c04 100644 (file)
@@ -53,7 +53,9 @@ static char           *tls_keypath = NULL;
                                        /* Server cert keychain path */
 static _cups_mutex_t   tls_mutex = _CUPS_MUTEX_INITIALIZER;
                                        /* Mutex for keychain/certs */
-static int             tls_options = -1;/* Options for TLS connections */
+static int             tls_options = -1,/* Options for TLS connections */
+                       tls_min_version = _HTTP_TLS_1_0,
+                       tls_max_version = _HTTP_TLS_MAX;
 
 
 /*
@@ -1139,10 +1141,16 @@ _httpTLSRead(http_t *http,              /* I - HTTP connection */
  */
 
 void
-_httpTLSSetOptions(int options)                /* I - Options */
+_httpTLSSetOptions(int options,                /* I - Options */
+                   int min_version,    /* I - Minimum TLS version */
+                   int max_version)    /* I - Maximum TLS version */
 {
   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
-    tls_options = options;
+  {
+    tls_options     = options;
+    tls_min_version = min_version;
+    tls_max_version = max_version;
+  }
 }
 
 
@@ -1174,7 +1182,7 @@ _httpTLSStart(http_t *http)               /* I - HTTP connection */
   {
     DEBUG_puts("4_httpTLSStart: Setting defaults.");
     _cupsSetDefaults();
-    DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
+    DEBUG_printf(("4_httpTLSStart: tls_options=%x, tls_min_version=%d, tls_max_version=%d", tls_options, tls_min_version, tls_max_version));
   }
 
 #ifdef HAVE_SECKEYCHAINOPEN
@@ -1217,22 +1225,23 @@ _httpTLSStart(http_t *http)             /* I - HTTP connection */
 
   if (!error)
   {
-    SSLProtocol minProtocol;
-
-    if (tls_options & _HTTP_TLS_DENY_TLS10)
-      minProtocol = kTLSProtocol11;
-    else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
-      minProtocol = kSSLProtocol3;
-    else
-      minProtocol = kTLSProtocol1;
+    static const SSLProtocol protocols[] =     /* Min/max protocol versions */
+    {
+      kSSLProtocol3,
+      kTLSProtocol1,
+      kTLSProtocol11,
+      kTLSProtocol12,
+      kTLSProtocol13,
+      kTLSProtocolMaxSupported
+    };
 
-    error = SSLSetProtocolVersionMin(http->tls, minProtocol);
-    DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error));
+    error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]);
+    DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error));
 
-    if (!error && (tls_options & _HTTP_TLS_ONLY_TLS10))
+    if (!error)
     {
-      error = SSLSetProtocolVersionMax(http->tls, kTLSProtocol1);
-      DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(kTLSProtocol1), error=%d", (int)error));
+      error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]);
+      DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error));
     }
   }
 
index 2dcb7fe34c4623265affe03205ed4374be119a18..95606f5abb38e8ab2e74060cf6989479ef940ef5 100644 (file)
@@ -35,7 +35,9 @@ static char           *tls_keypath = NULL;
                                        /* Server cert keychain path */
 static _cups_mutex_t   tls_mutex = _CUPS_MUTEX_INITIALIZER;
                                        /* Mutex for keychain/certs */
-static int             tls_options = -1;/* Options for TLS connections */
+static int             tls_options = -1,/* Options for TLS connections */
+                       tls_min_version = _HTTP_TLS_1_0,
+                       tls_max_version = _HTTP_TLS_MAX;
 
 
 /*
@@ -1227,7 +1229,11 @@ void
 _httpTLSSetOptions(int options)                /* I - Options */
 {
   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
-    tls_options = options;
+  {
+    tls_options     = options;
+    tls_min_version = min_version;
+    tls_max_version = max_version;
+  }
 }
 
 
@@ -1245,6 +1251,16 @@ _httpTLSStart(http_t *http)              /* I - Connection to server */
                                        /* TLS credentials */
   char                 priority_string[2048];
                                        /* Priority string */
+  int                  version;        /* Current version */
+  static const char * const versions[] =/* SSL/TLS versions */
+  {
+    "VERS-SSL3.0",
+    "VERS-TLS1.0",
+    "VERS-TLS1.1",
+    "VERS-TLS1.2",
+    "VERS-TLS1.3",
+    "VERS-TLS-ALL"
+  };
 
 
   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
@@ -1506,14 +1522,40 @@ _httpTLSStart(http_t *http)             /* I - Connection to server */
 
   strlcpy(priority_string, "NORMAL", sizeof(priority_string));
 
-  if (tls_options & _HTTP_TLS_DENY_TLS10)
-    strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string));
-  else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+  if (tls_max_version < _HTTP_TLS_MAX)
+  {
+   /*
+    * Require specific TLS versions...
+    */
+
+    strlcat(priority_string, ":-VERS-TLS-ALL", sizeof(priority_string));
+    for (version = tls_min_version; version <= tls_max_version; version ++)
+    {
+      strlcat(priority_string, ":+", sizeof(priority_string));
+      strlcat(priority_string, versions[version], sizeof(priority_string));
+    }
+  }
+  else if (tls_min_version == _HTTP_TLS_SSL3)
+  {
+   /*
+    * Allow all versions of TLS and SSL/3.0...
+    */
+
     strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string));
-  else if (tls_options & _HTTP_TLS_ONLY_TLS10)
-    strlcat(priority_string, ":-VERS-TLS-ALL:-VERS-SSL3.0:+VERS-TLS1.0", sizeof(priority_string));
+  }
   else
-    strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string));
+  {
+   /*
+    * Require a minimum version...
+    */
+
+    strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string));
+    for (version = 0; version < tls_min_version; version ++)
+    {
+      strlcat(priority_string, ":-", sizeof(priority_string));
+      strlcat(priority_string, versions[version], sizeof(priority_string));
+    }
+  }
 
   if (tls_options & _HTTP_TLS_ALLOW_RC4)
     strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string));
index 6eaec4c83acfc6a0d0f298910ce020b7466f3ac4..962ad6d1732d7dc2846f2566298f9e5a069746bd 100644 (file)
@@ -52,7 +52,9 @@
  * Local globals...
  */
 
-static int             tls_options = -1;/* Options for TLS connections */
+static int             tls_options = -1,/* Options for TLS connections */
+                       tls_min_version = _HTTP_TLS_1_0,
+                       tls_max_version = _HTTP_TLS_MAX;
 
 
 /*
@@ -914,7 +916,11 @@ void
 _httpTLSSetOptions(int options)                /* I - Options */
 {
   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
-    tls_options = options;
+  {
+    tls_options     = options;
+    tls_min_version = min_version;
+    tls_max_version = max_version;
+  }
 }
 
 
@@ -1782,14 +1788,14 @@ http_sspi_find_credentials(
 #else
   if (http->mode == _HTTP_MODE_SERVER)
   {
-    if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+    if (tls_min_version == _HTTP_TLS_SSL3)
       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
     else
       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
   }
   else
   {
-    if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+    if (tls_min_version == _HTTP_TLS_SSL3)
       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
     else
       SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
index 997e7aaf7efa75844eb1600c87343bcce49ed712..fa8fdd540f146733b80257a63c0e20d51887ae2c 100644 (file)
@@ -54,6 +54,8 @@ main(int  argc,                               /* I - Number of command-line arguments */
   int          af = AF_UNSPEC,         /* Address family */
                tls_options = _HTTP_TLS_NONE,
                                        /* TLS options */
+               tls_min_version = _HTTP_TLS_1_0,
+               tls_max_version = _HTTP_TLS_MAX,
                verbose = 0;            /* Verbosity */
   ipp_t                *request,               /* IPP Get-Printer-Attributes request */
                *response;              /* IPP Get-Printer-Attributes response */
@@ -88,11 +90,12 @@ main(int  argc,                             /* I - Number of command-line arguments */
     }
     else if (!strcmp(argv[i], "--no-tls10"))
     {
-      tls_options |= _HTTP_TLS_DENY_TLS10;
+      tls_min_version = _HTTP_TLS_1_1;
     }
     else if (!strcmp(argv[i], "--tls10"))
     {
-      tls_options |= _HTTP_TLS_ONLY_TLS10;
+      tls_min_version = _HTTP_TLS_1_0;
+      tls_max_version = _HTTP_TLS_1_0;
     }
     else if (!strcmp(argv[i], "--rc4"))
     {
@@ -148,7 +151,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   if (!port)
     port = 631;
 
-  _httpTLSSetOptions(tls_options);
+  _httpTLSSetOptions(tls_options, tls_min_version, tls_max_version);
 
   http = httpConnect2(server, port, NULL, af, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL);
   if (!http)
index 2a004b540217ee1c6aa9a016c7a87854bb312784..ad3199634f83a589153fcddfbb7d22f7b805fb4a 100644 (file)
@@ -54,7 +54,9 @@
 typedef struct _cups_client_conf_s     /**** client.conf config data ****/
 {
 #ifdef HAVE_SSL
-  int                  ssl_options;    /* SSLOptions values */
+  int                  ssl_options,    /* SSLOptions values */
+                       ssl_min_version,/* Minimum SSL/TLS version */
+                       ssl_max_version;/* Maximum SSL/TLS version */
 #endif /* HAVE_SSL */
   int                  trust_first,    /* Trust on first use? */
                        any_root,       /* Allow any (e.g., self-signed) root */
@@ -957,7 +959,7 @@ _cupsSetDefaults(void)
     cg->validate_certs = cc.validate_certs;
 
 #ifdef HAVE_SSL
-  _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT);
+  _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
 #endif /* HAVE_SSL */
 }
 
@@ -1336,7 +1338,9 @@ cups_set_ssl_options(
   * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
   */
 
-  int  options = _HTTP_TLS_NONE;       /* SSL/TLS options */
+  int  options = _HTTP_TLS_NONE,       /* SSL/TLS options */
+       min_version = _HTTP_TLS_1_0,    /* Minimum SSL/TLS version */
+       max_version = _HTTP_TLS_MAX;    /* Maximum SSL/TLS version */
   char temp[256],                      /* Copy of value */
        *start,                         /* Start of option */
        *end;                           /* End of option */
@@ -1364,20 +1368,38 @@ cups_set_ssl_options(
     if (!_cups_strcasecmp(start, "AllowRC4"))
       options |= _HTTP_TLS_ALLOW_RC4;
     else if (!_cups_strcasecmp(start, "AllowSSL3"))
-      options |= _HTTP_TLS_ALLOW_SSL3;
+      min_version = _HTTP_TLS_SSL3;
     else if (!_cups_strcasecmp(start, "AllowDH"))
       options |= _HTTP_TLS_ALLOW_DH;
     else if (!_cups_strcasecmp(start, "DenyCBC"))
       options |= _HTTP_TLS_DENY_CBC;
     else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
-      options |= _HTTP_TLS_DENY_TLS10;
+      min_version = _HTTP_TLS_1_1;
+    else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
+      max_version = _HTTP_TLS_1_0;
+    else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
+      max_version = _HTTP_TLS_1_1;
+    else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
+      max_version = _HTTP_TLS_1_2;
+    else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
+      max_version = _HTTP_TLS_1_3;
+    else if (!_cups_strcasecmp(start, "MinTLS1.0"))
+      min_version = _HTTP_TLS_1_0;
+    else if (!_cups_strcasecmp(start, "MinTLS1.1"))
+      min_version = _HTTP_TLS_1_1;
+    else if (!_cups_strcasecmp(start, "MinTLS1.2"))
+      min_version = _HTTP_TLS_1_2;
+    else if (!_cups_strcasecmp(start, "MinTLS1.3"))
+      min_version = _HTTP_TLS_1_3;
     else if (!_cups_strcasecmp(start, "None"))
       options = _HTTP_TLS_NONE;
   }
 
-  cc->ssl_options = options;
+  cc->ssl_options     = options;
+  cc->ssl_max_version = max_version;
+  cc->ssl_min_version = min_version;
 
-  DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", (void *)cc, value, options));
+  DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version));
 }
 #endif /* HAVE_SSL */
 
index c9fb91da28538e04124ec4f04f3bcc9f2e3994da..7bbc7d6560d0adf3c8f8b0b4ea2548ae1d728ef4 100644 (file)
@@ -10,7 +10,7 @@
 .\" which should have been included with this file.  If this file is
 .\" file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH client.conf 5 "CUPS" "19 October 2017" "Apple Inc."
+.TH client.conf 5 "CUPS" "3 November 2017" "Apple Inc."
 .SH NAME
 client.conf \- client configuration file for cups
 .SH DESCRIPTION
@@ -56,7 +56,7 @@ Specifies the address and optionally the port to use when connecting to the serv
 \fBServerName \fIhostname-or-ip-address\fR[\fI:port\fR]\fB/version=1.1\fR
 Specifies the address and optionally the port to use when connecting to a server running CUPS 1.3.12 and earlier.
 .TP 5
-\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR]
+\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR]
 .TP 5
 \fBSSLOptions None\fR
 Sets encryption options (only in /etc/cups/client.conf).
@@ -68,6 +68,9 @@ The \fIAllowRC4\fR option enables the 128-bit RC4 cipher suites, which are requi
 The \fIAllowSSL3\fR option enables SSL v3.0, which is required for some older clients that do not support TLS v1.0.
 The \fIDenyCBC\fR option disables all CBC cipher suites.
 The \fIDenyTLS1.0\fR option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
+The \fMinTLS\fR options set the minimum TLS version to support.
+The \fMaxTLS\fR options set the maximum TLS version to support.
+Not all operating systems support TLS 1.3 at this time.
 .TP 5
 \fBTrustOnFirstUse Yes\fR
 .TP 5
index 28eed35e134aa10f3cb64863d96eba3b53d20b08..1c2199949a05fbb8c0156b6728d99f7edef1f392 100644 (file)
@@ -451,10 +451,11 @@ Set the specified environment variable to be passed to child processes.
 Listens on the specified address and port for encrypted connections.
 .\"#SSLOptions
 .TP 5
-\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR]
+.TP 5
+\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR]
 .TP 5
 \fBSSLOptions None\fR
-Sets encryption options.
+Sets encryption options (only in /etc/cups/client.conf).
 By default, CUPS only supports encryption using TLS v1.0 or higher using known secure cipher suites.
 Security is reduced when \fIAllow\fR options are used.
 Security is enhanced when \fIDeny\fR options are used.
@@ -463,6 +464,9 @@ The \fIAllowRC4\fR option enables the 128-bit RC4 cipher suites, which are requi
 The \fIAllowSSL3\fR option enables SSL v3.0, which is required for some older clients that do not support TLS v1.0.
 The \fIDenyCBC\fR option disables all CBC cipher suites.
 The \fIDenyTLS1.0\fR option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
+The \fMinTLS\fR options set the minimum TLS version to support.
+The \fMaxTLS\fR options set the maximum TLS version to support.
+Not all operating systems support TLS 1.3 at this time.
 .\"#SSLPort
 .TP 5
 \fBSSLPort \fIport\fR
index c81a40c95549a93cb0deffb223d282badfa6360a..455646a1398a6be47c0c4bcd00eba52d53e5698d 100644 (file)
@@ -620,7 +620,7 @@ cupsdReadConfiguration(void)
   cupsdSetString(&ServerKeychain, "/Library/Keychains/System.keychain");
 #  endif /* HAVE_GNUTLS */
 
-  _httpTLSSetOptions(0);
+  _httpTLSSetOptions(_HTTP_TLS_NONE, _HTTP_TLS_1_0, _HTTP_TLS_MAX);
 #endif /* HAVE_SSL */
 
   language = cupsLangDefault();
@@ -3003,7 +3003,9 @@ read_cupsd_conf(cups_file_t *fp)  /* I - File to read from */
       * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyCBC] [DenyTLS1.0] [None]
       */
 
-      int      options = 0;            /* SSL/TLS options */
+      int      options = _HTTP_TLS_NONE,/* SSL/TLS options */
+               min_version = _HTTP_TLS_1_0,
+               max_version = _HTTP_TLS_MAX;
 
       if (value)
       {
@@ -3027,24 +3029,40 @@ read_cupsd_conf(cups_file_t *fp)        /* I - File to read from */
          * Compare...
          */
 
-          if (!_cups_strcasecmp(start, "AllowRC4"))
+         if (!_cups_strcasecmp(start, "AllowRC4"))
            options |= _HTTP_TLS_ALLOW_RC4;
-          else if (!_cups_strcasecmp(start, "AllowSSL3"))
-           options |= _HTTP_TLS_ALLOW_SSL3;
+         else if (!_cups_strcasecmp(start, "AllowSSL3"))
+           min_version = _HTTP_TLS_SSL3;
          else if (!_cups_strcasecmp(start, "AllowDH"))
            options |= _HTTP_TLS_ALLOW_DH;
          else if (!_cups_strcasecmp(start, "DenyCBC"))
            options |= _HTTP_TLS_DENY_CBC;
          else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
-           options |= _HTTP_TLS_DENY_TLS10;
-          else if (!_cups_strcasecmp(start, "None"))
-           options = 0;
+           min_version = _HTTP_TLS_1_1;
+         else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
+           max_version = _HTTP_TLS_1_0;
+         else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
+           max_version = _HTTP_TLS_1_1;
+         else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
+           max_version = _HTTP_TLS_1_2;
+         else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
+           max_version = _HTTP_TLS_1_3;
+         else if (!_cups_strcasecmp(start, "MinTLS1.0"))
+           min_version = _HTTP_TLS_1_0;
+         else if (!_cups_strcasecmp(start, "MinTLS1.1"))
+           min_version = _HTTP_TLS_1_1;
+         else if (!_cups_strcasecmp(start, "MinTLS1.2"))
+           min_version = _HTTP_TLS_1_2;
+         else if (!_cups_strcasecmp(start, "MinTLS1.3"))
+           min_version = _HTTP_TLS_1_3;
+         else if (!_cups_strcasecmp(start, "None"))
+           options = _HTTP_TLS_NONE;
          else if (_cups_strcasecmp(start, "NoEmptyFragments"))
            cupsdLogMessage(CUPSD_LOG_WARN, "Unknown SSL option %s at line %d.", start, linenum);
         }
       }
 
-      _httpTLSSetOptions(options);
+      _httpTLSSetOptions(options, min_version, max_version);
     }
 #endif /* HAVE_SSL */
     else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")