]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/tlscheck.c
Stop parsing the Emulators keywords in PPD files (Issue #5475)
[thirdparty/cups.git] / cups / tlscheck.c
index 05411cc5e59bd71e1d65ecd1ab6aff80cce889ba..c88e7d09150d89bacf557db0ed00fe4e45d07e9d 100644 (file)
@@ -1,18 +1,10 @@
 /*
- * "$Id$"
- *
  * TLS check program for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2006 by Easy Software Products.
  *
- * 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/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
 #include "cups-private.h"
 
 
+#ifndef HAVE_SSL
+int main(void) { puts("Sorry, no TLS support compiled in."); return (1); }
+#else
+
+/*
+ * Local functions...
+ */
+
+static void    usage(void);
+
+
 /*
  * 'main()' - Main entry.
  */
@@ -30,31 +33,154 @@ int                                        /* O - Exit status */
 main(int  argc,                                /* I - Number of command-line arguments */
      char *argv[])                     /* I - Command-line arguments */
 {
+  int          i;                      /* Looping var */
   http_t       *http;                  /* HTTP connection */
-  const char   *server = argv[1];      /* Hostname from command-line */
-  int          port = 631;             /* Port number */
+  const char   *server = NULL;         /* Hostname from command-line */
+  int          port = 0;               /* Port number */
+  cups_array_t *creds;                 /* Server credentials */
+  char         creds_str[2048];        /* Credentials string */
   const char   *cipherName = "UNKNOWN";/* Cipher suite name */
+  int          dhBits = 0;             /* Diffie-Hellman bits */
   int          tlsVersion = 0;         /* TLS version number */
+  char         uri[1024],              /* Printer URI */
+               scheme[32],             /* URI scheme */
+               host[256],              /* Hostname */
+               userpass[256],          /* Username/password */
+               resource[256];          /* Resource path */
+  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 */
+  ipp_attribute_t *attr;               /* Current attribute */
+  const char   *name;                  /* Attribute name */
+  char         value[1024];            /* Attribute (string) value */
+  static const char * const pattrs[] = /* Requested attributes */
+  {
+    "color-supported",
+    "compression-supported",
+    "document-format-supported",
+    "pages-per-minute",
+    "printer-location",
+    "printer-make-and-model",
+    "printer-state",
+    "printer-state-reasons",
+    "sides-supported",
+    "uri-authentication-supported",
+    "uri-security-supported"
+  };
 
 
-  if (argc < 2 || argc > 3)
+  for (i = 1; i < argc; i ++)
   {
-    puts("Usage: ./tlscheck server [port]");
-    puts("");
-    puts("The default port is 631.");
-    return (1);
+    if (!strcmp(argv[i], "--dh"))
+    {
+      tls_options |= _HTTP_TLS_ALLOW_DH;
+    }
+    else if (!strcmp(argv[i], "--no-cbc"))
+    {
+      tls_options |= _HTTP_TLS_DENY_CBC;
+    }
+    else if (!strcmp(argv[i], "--no-tls10"))
+    {
+      tls_min_version = _HTTP_TLS_1_1;
+    }
+    else if (!strcmp(argv[i], "--tls10"))
+    {
+      tls_min_version = _HTTP_TLS_1_0;
+      tls_max_version = _HTTP_TLS_1_0;
+    }
+    else if (!strcmp(argv[i], "--tls11"))
+    {
+      tls_min_version = _HTTP_TLS_1_1;
+      tls_max_version = _HTTP_TLS_1_1;
+    }
+    else if (!strcmp(argv[i], "--tls12"))
+    {
+      tls_min_version = _HTTP_TLS_1_2;
+      tls_max_version = _HTTP_TLS_1_2;
+    }
+    else if (!strcmp(argv[i], "--tls13"))
+    {
+      tls_min_version = _HTTP_TLS_1_3;
+      tls_max_version = _HTTP_TLS_1_3;
+    }
+    else if (!strcmp(argv[i], "--rc4"))
+    {
+      tls_options |= _HTTP_TLS_ALLOW_RC4;
+    }
+    else if (!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v"))
+    {
+      verbose = 1;
+    }
+    else if (!strcmp(argv[i], "-4"))
+    {
+      af = AF_INET;
+    }
+    else if (!strcmp(argv[i], "-6"))
+    {
+      af = AF_INET6;
+    }
+    else if (argv[i][0] == '-')
+    {
+      printf("tlscheck: Unknown option '%s'.\n", argv[i]);
+      usage();
+    }
+    else if (!server)
+    {
+      if (!strncmp(argv[i], "ipps://", 7))
+      {
+        httpSeparateURI(HTTP_URI_CODING_ALL, argv[i], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource));
+        server = host;
+      }
+      else
+      {
+        server = argv[i];
+        strlcpy(resource, "/ipp/print", sizeof(resource));
+      }
+    }
+    else if (!port && (argv[i][0] == '=' || isdigit(argv[i][0] & 255)))
+    {
+      if (argv[i][0] == '=')
+       port = atoi(argv[i] + 1);
+      else
+       port = atoi(argv[i]);
+    }
+    else
+    {
+      printf("tlscheck: Unexpected argument '%s'.\n", argv[i]);
+      usage();
+    }
   }
 
-  if (argc == 3)
-    port = atoi(argv[2]);
+  if (!server)
+    usage();
 
-  http = httpConnect2(server, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL);
+  if (!port)
+    port = 631;
+
+  _httpTLSSetOptions(tls_options, tls_min_version, tls_max_version);
+
+  http = httpConnect2(server, port, NULL, af, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL);
   if (!http)
   {
     printf("%s: ERROR (%s)\n", server, cupsLastErrorString());
     return (1);
   }
 
+  if (httpCopyCredentials(http, &creds))
+  {
+    strlcpy(creds_str, "Unable to get server X.509 credentials.", sizeof(creds_str));
+  }
+  else
+  {
+    httpCredentialsString(creds, creds_str, sizeof(creds_str));
+    httpFreeCredentials(creds);
+  }
+
 #ifdef __APPLE__
   SSLProtocol protocol;
   SSLCipherSuite cipher;
@@ -410,6 +536,152 @@ main(int  argc,                           /* I - Number of command-line arguments */
        cipherName = "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
        paramsNeeded = 1;
        break;
+    case TLS_RSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA";
+       break;
+    case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_RSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA";
+       break;
+    case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_ECDSA_WITH_NULL_SHA:
+       cipherName = "TLS_ECDH_ECDSA_WITH_NULL_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+       cipherName = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+       cipherName = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+       cipherName = "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+       cipherName = "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+       cipherName = "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_RSA_WITH_NULL_SHA:
+       cipherName = "TLS_ECDH_RSA_WITH_NULL_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+       cipherName = "TLS_ECDH_RSA_WITH_RC4_128_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+       cipherName = "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_RSA_WITH_NULL_SHA:
+       cipherName = "TLS_ECDHE_RSA_WITH_NULL_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+       cipherName = "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+       cipherName = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_anon_WITH_NULL_SHA:
+       cipherName = "TLS_ECDH_anon_WITH_NULL_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_anon_WITH_RC4_128_SHA:
+       cipherName = "TLS_ECDH_anon_WITH_RC4_128_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+       cipherName = "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+       cipherName = "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
+       paramsNeeded = 1;
+       break;
+    case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+       cipherName = "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
+       paramsNeeded = 1;
+       break;
     default :
         snprintf(unknownCipherName, sizeof(unknownCipherName), "UNKNOWN_%04X", cipher);
         cipherName = unknownCipherName;
@@ -419,27 +691,60 @@ main(int  argc,                           /* I - Number of command-line arguments */
   if (cipher == TLS_RSA_WITH_RC4_128_MD5 ||
       cipher == TLS_RSA_WITH_RC4_128_SHA)
   {
-    printf("%s: ERROR (Insecure RC4 negotiated)\n", server);
+    printf("%s: ERROR (Printers MUST NOT negotiate RC4 cipher suites.)\n", server);
     httpClose(http);
     return (1);
   }
 
   if ((err = SSLGetDiffieHellmanParams(http->tls, &params, &paramsLen)) != noErr && paramsNeeded)
   {
-    printf("%s: ERROR (Unable to get Diffie Hellman parameters - %d)\n", server, (int)err);
+    printf("%s: ERROR (Unable to get Diffie-Hellman parameters - %d)\n", server, (int)err);
     httpClose(http);
     return (1);
   }
 
   if (paramsLen < 128 && paramsLen != 0)
   {
-    printf("%s: ERROR (Diffie Hellman parameters only %d bytes/%d bits)\n", server, (int)paramsLen, (int)paramsLen * 8);
+    printf("%s: ERROR (Diffie-Hellman parameters MUST be at least 2048 bits, but Printer uses only %d bits/%d bytes)\n", server, (int)paramsLen * 8, (int)paramsLen);
     httpClose(http);
     return (1);
   }
+
+  dhBits = (int)paramsLen * 8;
 #endif /* __APPLE__ */
 
-  printf("%s: OK (%d.%d, %s)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName);
+  if (dhBits > 0)
+    printf("%s: OK (TLS: %d.%d, %s, %d DH bits)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName, dhBits);
+  else
+    printf("%s: OK (TLS: %d.%d, %s)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName);
+
+  printf("    %s\n", creds_str);
+
+  if (verbose)
+  {
+    httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipps", NULL, host, port, resource);
+    request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
+    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
+
+    response = cupsDoRequest(http, request, resource);
+
+    for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response))
+    {
+      if (ippGetGroupTag(attr) != IPP_TAG_PRINTER)
+        continue;
+
+      if ((name = ippGetName(attr)) == NULL)
+        continue;
+
+      ippAttributeString(attr, value, sizeof(value));
+      printf("    %s=%s\n", name, value);
+    }
+
+    ippDelete(response);
+    puts("");
+  }
 
   httpClose(http);
 
@@ -448,5 +753,31 @@ main(int  argc,                            /* I - Number of command-line arguments */
 
 
 /*
- * End of "$Id$".
+ * 'usage()' - Show program usage.
  */
+
+static void
+usage(void)
+{
+  puts("Usage: ./tlscheck [options] server [port]");
+  puts("       ./tlscheck [options] ipps://server[:port]/path");
+  puts("");
+  puts("Options:");
+  puts("  --dh        Allow DH/DHE key exchange");
+  puts("  --no-cbc    Disable CBC cipher suites");
+  puts("  --no-tls10  Disable TLS/1.0");
+  puts("  --rc4       Allow RC4 encryption");
+  puts("  --tls10     Only use TLS/1.0");
+  puts("  --tls11     Only use TLS/1.1");
+  puts("  --tls12     Only use TLS/1.2");
+  puts("  --tls13     Only use TLS/1.3");
+  puts("  --verbose   Be verbose");
+  puts("  -4          Connect using IPv4 addresses only");
+  puts("  -6          Connect using IPv6 addresses only");
+  puts("  -v          Be verbose");
+  puts("");
+  puts("The default port is 631.");
+
+  exit(1);
+}
+#endif /* !HAVE_SSL */