]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/tls-darwin.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / cups / tls-darwin.c
index e7ba786f9d3f9090ef7655ce15a1bbc63c5e5759..89ac8c206a3e74ea15d225b8690a21dd9f805b6b 100644 (file)
@@ -1,16 +1,10 @@
 /*
  * TLS support code for CUPS on macOS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file.  If this file is
- * missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /**** This file is included from tls.c ****/
@@ -21,7 +15,7 @@
 
 #include <spawn.h>
 
-extern char **environ;
+extern char **environ; /* @private@ */
 
 
 /*
@@ -41,6 +35,8 @@ static int            tls_auto_create = 0;
 static char            *tls_common_name = NULL;
                                        /* Default common name */
 #ifdef HAVE_SECKEYCHAINOPEN
+static int             tls_cups_keychain = 0;
+                                       /* Opened the CUPS keychain? */
 static SecKeychainRef  tls_keychain = NULL;
                                        /* Server cert keychain */
 #else
@@ -51,7 +47,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;
 
 
 /*
@@ -805,7 +803,6 @@ httpCredentialsString(
     CFStringRef                cf_name;        /* CF common name string */
     char               name[256];      /* Common name associated with cert */
     time_t             expiration;     /* Expiration date of cert */
-    _cups_md5_state_t  md5_state;      /* MD5 state */
     unsigned char      md5_digest[16]; /* MD5 result */
 
     if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL)
@@ -818,9 +815,7 @@ httpCredentialsString(
 
     expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970);
 
-    _cupsMD5Init(&md5_state);
-    _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
-    _cupsMD5Finish(&md5_state, md5_digest);
+    cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest));
 
     snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]);
 
@@ -1137,9 +1132,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 */
 {
-  tls_options = options;
+  if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
+  {
+    tls_options     = options;
+    tls_min_version = min_version;
+    tls_max_version = max_version;
+  }
 }
 
 
@@ -1171,7 +1173,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
@@ -1214,17 +1216,24 @@ _httpTLSStart(http_t *http)             /* I - HTTP connection */
 
   if (!error)
   {
-    SSLProtocol minProtocol;
+    static const SSLProtocol protocols[] =     /* Min/max protocol versions */
+    {
+      kSSLProtocol3,
+      kTLSProtocol1,
+      kTLSProtocol11,
+      kTLSProtocol12,
+      kTLSProtocol13,
+      kTLSProtocolMaxSupported
+    };
 
-    if (tls_options & _HTTP_TLS_DENY_TLS10)
-      minProtocol = kTLSProtocol11;
-    else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
-      minProtocol = kSSLProtocol3;
-    else
-      minProtocol = kTLSProtocol1;
+    error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]);
+    DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error));
 
-    error = SSLSetProtocolVersionMin(http->tls, minProtocol);
-    DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error));
+    if (!error)
+    {
+      error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]);
+      DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error));
+    }
   }
 
 #  if HAVE_SSLSETENABLEDCIPHERS
@@ -1322,7 +1331,6 @@ _httpTLSStart(http_t *http)               /* I - HTTP connection */
           case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
           case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA :
           case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA :
-//          case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA :
           case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA :
           case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 :
           case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 :
@@ -1335,6 +1343,14 @@ _httpTLSStart(http_t *http)              /* I - HTTP connection */
           case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA :
           case TLS_DHE_PSK_WITH_AES_128_CBC_SHA :
           case TLS_DHE_PSK_WITH_AES_256_CBC_SHA :
+          case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
+          case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
+             if (tls_options & _HTTP_TLS_DENY_CBC)
+             {
+               DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
+               break;
+             }
+
 //          case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 :
 //          case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 :
           case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 :
@@ -1345,15 +1361,31 @@ _httpTLSStart(http_t *http)             /* I - HTTP connection */
           case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 :
           case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 :
           case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 :
-          case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 :
-          case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
               if (tls_options & _HTTP_TLS_ALLOW_DH)
                enabled[num_enabled ++] = supported[i];
              else
                DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i]));
               break;
 
-          /* Anything else we'll assume is secure */
+          case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA :
+          case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_RSA_WITH_3DES_EDE_CBC_SHA :
+          case TLS_RSA_WITH_AES_128_CBC_SHA :
+          case TLS_RSA_WITH_AES_256_CBC_SHA :
+              if (tls_options & _HTTP_TLS_DENY_CBC)
+             {
+               DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
+               break;
+             }
+
+          /* Anything else we'll assume is "secure" */
           default :
              enabled[num_enabled ++] = supported[i];
              break;
@@ -1747,6 +1779,7 @@ http_cdsa_copy_server(
   CFMutableDictionaryRef query = NULL; /* Query qualifiers */
   CFArrayRef           list = NULL;    /* Keychain list */
   SecKeychainRef       syschain = NULL;/* System keychain */
+  SecKeychainStatus    status = 0;     /* Keychain status */
 
 
   DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name));
@@ -1769,6 +1802,11 @@ http_cdsa_copy_server(
 
   _cupsMutexLock(&tls_mutex);
 
+  err = SecKeychainGetStatus(tls_keychain, &status);
+
+  if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
+    SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
+
   CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
   CFDictionaryAddValue(query, kSecMatchPolicy, policy);
   CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
@@ -1901,9 +1939,15 @@ http_cdsa_open_keychain(
   */
 
   if (!path)
+  {
     path = http_cdsa_default_path(filename, filesize);
+    tls_cups_keychain = 1;
+  }
   else
+  {
     strlcpy(filename, path, filesize);
+    tls_cups_keychain = 0;
+  }
 
  /*
   * Save the interaction setting and disable while we open the keychain...
@@ -1912,7 +1956,7 @@ http_cdsa_open_keychain(
   SecKeychainGetUserInteractionAllowed(&interaction);
   SecKeychainSetUserInteractionAllowed(FALSE);
 
-  if (access(path, R_OK))
+  if (access(path, R_OK) && tls_cups_keychain)
   {
    /*
     * Create a new keychain at the given path...
@@ -1931,7 +1975,7 @@ http_cdsa_open_keychain(
     if (err == noErr)
       err = SecKeychainGetStatus(keychain, &status);
 
-    if (err == noErr && !(status & kSecUnlockStateStatus))
+    if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
       err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
   }