]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/tls-sspi.c
Support the latest HTTP Digest authentication specification (Issue #4862)
[thirdparty/cups.git] / cups / tls-sspi.c
index 27cf0e721b7d2e98f5dfe27a54a6c8427fa1d43b..ead461d1b38b806e0d5f4c39b48c969d2abb275a 100644 (file)
@@ -1,19 +1,20 @@
 /*
- * "$Id$"
+ * TLS support for CUPS on Windows using the Security Support Provider
+ * Interface (SSPI).
  *
- * TLS support for CUPS on Windows using SSPI.
- *
- * Copyright 2010-2014 by Apple Inc.
+ * Copyright 2010-2017 by Apple Inc.
  *
  * 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
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
 
+/**** This file is included from tls.c ****/
+
 /*
  * Include necessary headers...
  */
 #  define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID  0x00002000 /* Expired X509 Cert. */
 #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */
 
+
+/*
+ * Local globals...
+ */
+
+static int             tls_options = -1,/* Options for TLS connections */
+                       tls_min_version = _HTTP_TLS_1_0,
+                       tls_max_version = _HTTP_TLS_MAX;
+
+
 /*
  * Local functions...
  */
@@ -66,7 +77,7 @@ static DWORD  http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWOR
 /*
  * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 int                                    /* O - 1 on success, 0 on failure */
@@ -102,7 +113,7 @@ cupsMakeServerCredentials(
  * Note: The server credentials are used by all threads in the running process.
  * This function is threadsafe.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 int                                    /* O - 1 on success, 0 on failure */
@@ -125,7 +136,7 @@ cupsSetServerCredentials(
  * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
  *                           an encrypted connection.
  *
- * @since CUPS 1.5/OS X 10.7@
+ * @since CUPS 1.5/macOS 10.7@
  */
 
 int                                    /* O - Status of call (0 = success) */
@@ -165,7 +176,7 @@ _httpCreateCredentials(
 /*
  * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 int                                    /* O - 1 if valid, 0 otherwise */
@@ -230,7 +241,7 @@ httpCredentialsAreValidForName(
 /*
  * 'httpCredentialsGetTrust()' - Return the trust of credentials.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 http_trust_t                           /* O - Level of trust */
@@ -251,6 +262,9 @@ httpCredentialsGetTrust(
   if (!cert)
     return (HTTP_TRUST_UNKNOWN);
 
+  if (cg->any_root < 0)
+    _cupsSetDefaults();
+
   if (cg->any_root)
     certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
 
@@ -272,7 +286,7 @@ httpCredentialsGetTrust(
 /*
  * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 time_t                                 /* O - Expiration date of credentials */
@@ -309,7 +323,7 @@ httpCredentialsGetExpiration(
 /*
  * 'httpCredentialsString()' - Return a string representing the credentials.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 size_t                                 /* O - Total size of credentials string */
@@ -339,7 +353,6 @@ httpCredentialsString(
     SYSTEMTIME         systime;        /* System time */
     struct tm          tm;             /* UNIX date/time */
     time_t             expiration;     /* Expiration date of cert */
-    _cups_md5_state_t  md5_state;      /* MD5 state */
     unsigned char      md5_digest[16]; /* MD5 result */
 
     FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime);
@@ -366,9 +379,7 @@ httpCredentialsString(
     else
       strlcpy(cert_name, "unknown", sizeof(cert_name));
 
-    _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", cert_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]);
 
@@ -399,7 +410,7 @@ _httpFreeCredentials(
 /*
  * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -523,7 +534,7 @@ cleanup:
 /*
  * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
  *
- * @since CUPS 2.0@
+ * @since CUPS 2.0/OS 10.10@
  */
 
 int                                    /* O - -1 on error, 0 on success */
@@ -532,7 +543,6 @@ httpSaveCredentials(
     cups_array_t *credentials,         /* I - Credentials */
     const char   *common_name)         /* I - Common name for credentials */
 {
-  _http_sspi_t *sspi = http->tls;      /* SSPI data */
   HCERTSTORE   store = NULL;           /* Certificate store */
   PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */
   PCCERT_CONTEXT createdContext = NULL;        /* Context created by us */
@@ -540,7 +550,7 @@ httpSaveCredentials(
   PBYTE                p = NULL;               /* Temporary storage */
   HCRYPTPROV   hProv = (HCRYPTPROV)NULL;
                                        /* Handle to a CSP */
-  CERT_NAME_BLOB sib;                  /* Arbitrary array of bytes */
+  CRYPT_KEY_PROV_INFO ckp;             /* Handle to crypto key */
   int          ret = -1;               /* Return value */
 #ifdef DEBUG
   char         error[1024];            /* Error message buffer */
@@ -557,7 +567,7 @@ httpSaveCredentials(
     return (-1);
   }
 
-  createdContext = http_sspi_create_credential(credentials);
+  createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials));
   if (!createdContext)
   {
     DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1.");
@@ -895,6 +905,22 @@ _httpTLSRead(http_t *http,         /* I - HTTP connection */
 }
 
 
+/*
+ * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
+ */
+
+void
+_httpTLSSetOptions(int options)                /* I - Options */
+{
+  if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
+  {
+    tls_options     = options;
+    tls_min_version = min_version;
+    tls_max_version = max_version;
+  }
+}
+
+
 /*
  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
  */
@@ -906,7 +932,14 @@ _httpTLSStart(http_t *http)                /* I - HTTP connection */
        *hostptr;                       /* Pointer into hostname */
 
 
-  DEBUG_printf(("7_httpTLSStart(http=%p)", http));
+  DEBUG_printf(("3_httpTLSStart(http=%p)", http));
+
+  if (tls_options < 0)
+  {
+    DEBUG_puts("4_httpTLSStart: Setting defaults.");
+    _cupsSetDefaults();
+    DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
+  }
 
   if ((http->tls = http_sspi_alloc()) == NULL)
     return (-1);
@@ -1726,11 +1759,47 @@ http_sspi_find_credentials(
   SchannelCred.paCred    = &storedContext;
 
  /*
-  * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client.
+  * Set supported protocols (can also be overriden in the registry...)
   */
 
+#ifdef SP_PROT_TLS1_2_SERVER
   if (http->mode == _HTTP_MODE_SERVER)
-    SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
+  {
+    if (tls_options & _HTTP_TLS_DENY_TLS10)
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER;
+    else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER;
+    else
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER;
+  }
+  else
+  {
+    if (tls_options & _HTTP_TLS_DENY_TLS10)
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT;
+    else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT;
+    else
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT;
+  }
+
+#else
+  if (http->mode == _HTTP_MODE_SERVER)
+  {
+    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_min_version == _HTTP_TLS_SSL3)
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
+    else
+      SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
+  }
+#endif /* SP_PROT_TLS1_2_SERVER */
+
+  /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */
 
  /*
   * Create an SSPI credential.
@@ -2274,6 +2343,9 @@ http_sspi_verify(
                                        /* Number of ites in rgszUsages */
   DWORD                        count;          /* 32 bit count variable */
   DWORD                        status;         /* Return value */
+#ifdef DEBUG
+  char                 error[1024];    /* Error message string */
+#endif /* DEBUG */
 
 
   if (!cert)
@@ -2312,11 +2384,7 @@ http_sspi_verify(
   {
     status = GetLastError();
 
-#ifdef DEBUG
-    char error[1024];                  /* Error message string */
-
     DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status)));
-#endif /* DEBUG */
 
     LocalFree(commonNameUnicode);
     return (status);
@@ -2343,11 +2411,7 @@ http_sspi_verify(
   {
     status = GetLastError();
 
-#ifdef DEBUG
-    char error[1024];                  /* Error message string */
-
     DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status)));
-#endif /* DEBUG */
   }
   else if (policyStatus.dwError)
     status = policyStatus.dwError;
@@ -2362,8 +2426,3 @@ http_sspi_verify(
 
   return (status);
 }
-
-
-/*
- * End of "$Id$".
- */