Esempio n. 1
0
http_trust_t				/* O - Level of trust */
httpCredentialsGetTrust(
    cups_array_t *credentials,		/* I - Credentials */
    const char   *common_name)		/* I - Common name for trust lookup */
{
  http_trust_t		trust = HTTP_TRUST_OK;
					/* Trusted? */
  gnutls_x509_crt_t	cert;		/* Certificate */
  cups_array_t		*tcreds = NULL;	/* Trusted credentials */
  _cups_globals_t	*cg = _cupsGlobals();
					/* Per-thread globals */


  if (!common_name)
    return (HTTP_TRUST_UNKNOWN);

  if ((cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
    return (HTTP_TRUST_UNKNOWN);

  if (cg->any_root < 0)
    _cupsSetDefaults();

 /*
  * Look this common name up in the default keychains...
  */

  httpLoadCredentials(NULL, &tcreds, common_name);

  if (tcreds)
  {
    char	credentials_str[1024],	/* String for incoming credentials */
		tcreds_str[1024];	/* String for saved credentials */

    httpCredentialsString(credentials, credentials_str, sizeof(credentials_str));
    httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str));

    if (strcmp(credentials_str, tcreds_str))
    {
     /*
      * Credentials don't match, let's look at the expiration date of the new
      * credentials and allow if the new ones have a later expiration...
      */

      if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds) ||
          !httpCredentialsAreValidForName(credentials, common_name))
      {
       /*
        * Either the new credentials are not newly issued, or the common name
	* does not match the issued certificate...
	*/

        trust = HTTP_TRUST_INVALID;
      }
      else if (httpCredentialsGetExpiration(tcreds) < time(NULL))
      {
       /*
        * Save the renewed credentials...
	*/

	trust = HTTP_TRUST_RENEWED;

        httpSaveCredentials(NULL, credentials, common_name);
      }
    }

    httpFreeCredentials(tcreds);
  }
  else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name))
    trust = HTTP_TRUST_INVALID;

  if (trust == HTTP_TRUST_OK && !cg->expired_certs)
  {
    time_t	curtime;		/* Current date/time */

    time(&curtime);
    if (curtime < gnutls_x509_crt_get_activation_time(cert) ||
        curtime > gnutls_x509_crt_get_expiration_time(cert))
      trust = HTTP_TRUST_EXPIRED;
  }

  if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1)
    trust = HTTP_TRUST_INVALID;

  gnutls_x509_crt_deinit(cert);

  return (trust);
}
Esempio n. 2
0
int					/* O - 0 on success, -1 on error */
httpLoadCredentials(
    const char   *path,			/* I  - Keychain/PKCS#12 path */
    cups_array_t **credentials,		/* IO - Credentials */
    const char   *common_name)		/* I  - Common name for credentials */
{
  cups_file_t		*fp;		/* Certificate file */
  char			filename[1024],	/* filename.crt */
			temp[1024],	/* Temporary string */
			line[256];	/* Base64-encoded line */
  unsigned char		*data = NULL;	/* Buffer for cert data */
  size_t		alloc_data = 0,	/* Bytes allocated */
			num_data = 0;	/* Bytes used */
  int			decoded;	/* Bytes decoded */


  if (!credentials || !common_name)
    return (-1);

  if (!path)
    path = http_gnutls_default_path(temp, sizeof(temp));
  if (!path)
    return (-1);

  http_gnutls_make_path(filename, sizeof(filename), path, common_name, "crt");

  if ((fp = cupsFileOpen(filename, "r")) == NULL)
    return (-1);

  while (cupsFileGets(fp, line, sizeof(line)))
  {
    if (!strcmp(line, "-----BEGIN CERTIFICATE-----"))
    {
      if (num_data)
      {
       /*
	* Missing END CERTIFICATE...
	*/

        httpFreeCredentials(*credentials);
	*credentials = NULL;
        break;
      }
    }
    else if (!strcmp(line, "-----END CERTIFICATE-----"))
    {
      if (!num_data)
      {
       /*
	* Missing data...
	*/

        httpFreeCredentials(*credentials);
	*credentials = NULL;
        break;
      }

      if (!*credentials)
        *credentials = cupsArrayNew(NULL, NULL);

      if (httpAddCredential(*credentials, data, num_data))
      {
        httpFreeCredentials(*credentials);
	*credentials = NULL;
        break;
      }

      num_data = 0;
    }
    else
    {
      if (alloc_data == 0)
      {
        data       = malloc(2048);
	alloc_data = 2048;

        if (!data)
	  break;
      }
      else if ((num_data + strlen(line)) >= alloc_data)
      {
        unsigned char *tdata = realloc(data, alloc_data + 1024);
					/* Expanded buffer */

	if (!tdata)
	{
	  httpFreeCredentials(*credentials);
	  *credentials = NULL;
	  break;
	}

	data       = tdata;
        alloc_data += 1024;
      }

      decoded = alloc_data - num_data;
      httpDecode64_2((char *)data + num_data, &decoded, line);
      num_data += (size_t)decoded;
    }
  }

  cupsFileClose(fp);

  if (num_data)
  {
   /*
    * Missing END CERTIFICATE...
    */

    httpFreeCredentials(*credentials);
    *credentials = NULL;
  }

  if (data)
    free(data);

  return (*credentials ? 0 : -1);
}
Esempio n. 3
0
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 = 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"
  };


  for (i = 1; i < argc; i ++)
  {
    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 (!server)
    usage();

  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;
  char unknownCipherName[256];
  int paramsNeeded = 0;
  const void *params;
  size_t paramsLen;
  OSStatus err;

  if ((err = SSLGetNegotiatedProtocolVersion(http->tls, &protocol)) != noErr)
  {
    printf("%s: ERROR (No protocol version - %d)\n", server, (int)err);
    httpClose(http);
    return (1);
  }

  switch (protocol)
  {
    default :
        tlsVersion = 0;
        break;
    case kSSLProtocol3 :
        tlsVersion = 30;
        break;
    case kTLSProtocol1 :
        tlsVersion = 10;
        break;
    case kTLSProtocol11 :
        tlsVersion = 11;
        break;
    case kTLSProtocol12 :
        tlsVersion = 12;
        break;
  }

  if ((err = SSLGetNegotiatedCipher(http->tls, &cipher)) != noErr)
  {
    printf("%s: ERROR (No cipher suite - %d)\n", server, (int)err);
    httpClose(http);
    return (1);
  }

  switch (cipher)
  {
    case TLS_NULL_WITH_NULL_NULL:
	cipherName = "TLS_NULL_WITH_NULL_NULL";
	break;
    case TLS_RSA_WITH_NULL_MD5:
	cipherName = "TLS_RSA_WITH_NULL_MD5";
	break;
    case TLS_RSA_WITH_NULL_SHA:
	cipherName = "TLS_RSA_WITH_NULL_SHA";
	break;
    case TLS_RSA_WITH_RC4_128_MD5:
	cipherName = "TLS_RSA_WITH_RC4_128_MD5";
	break;
    case TLS_RSA_WITH_RC4_128_SHA:
	cipherName = "TLS_RSA_WITH_RC4_128_SHA";
	break;
    case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
	break;
    case TLS_RSA_WITH_NULL_SHA256:
	cipherName = "TLS_RSA_WITH_NULL_SHA256";
	break;
    case TLS_RSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA256";
	break;
    case TLS_RSA_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA256";
	break;
    case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_RC4_128_MD5:
	cipherName = "TLS_DH_anon_WITH_RC4_128_MD5";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
	cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_PSK_WITH_RC4_128_SHA:
	cipherName = "TLS_PSK_WITH_RC4_128_SHA";
	break;
    case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_PSK_WITH_3DES_EDE_CBC_SHA";
	break;
    case TLS_PSK_WITH_AES_128_CBC_SHA:
	cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA";
	break;
    case TLS_PSK_WITH_AES_256_CBC_SHA:
	cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA";
	break;
    case TLS_DHE_PSK_WITH_RC4_128_SHA:
	cipherName = "TLS_DHE_PSK_WITH_RC4_128_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
	cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
	cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA";
	paramsNeeded = 1;
	break;
    case TLS_RSA_PSK_WITH_RC4_128_SHA:
	cipherName = "TLS_RSA_PSK_WITH_RC4_128_SHA";
	break;
    case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
	cipherName = "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA";
	break;
    case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
	cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA";
	break;
    case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
	cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA";
	break;
    case TLS_PSK_WITH_NULL_SHA:
	cipherName = "TLS_PSK_WITH_NULL_SHA";
	break;
    case TLS_DHE_PSK_WITH_NULL_SHA:
	cipherName = "TLS_DHE_PSK_WITH_NULL_SHA";
	paramsNeeded = 1;
	break;
    case TLS_RSA_PSK_WITH_NULL_SHA:
	cipherName = "TLS_RSA_PSK_WITH_NULL_SHA";
	break;
    case TLS_RSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_RSA_WITH_AES_128_GCM_SHA256";
	break;
    case TLS_RSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_RSA_WITH_AES_256_GCM_SHA384";
	break;
    case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_PSK_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_PSK_WITH_AES_128_GCM_SHA256";
	break;
    case TLS_PSK_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_PSK_WITH_AES_256_GCM_SHA384";
	break;
    case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256";
	break;
    case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384";
	break;
    case TLS_PSK_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA256";
	break;
    case TLS_PSK_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA384";
	break;
    case TLS_PSK_WITH_NULL_SHA256:
	cipherName = "TLS_PSK_WITH_NULL_SHA256";
	break;
    case TLS_PSK_WITH_NULL_SHA384:
	cipherName = "TLS_PSK_WITH_NULL_SHA384";
	break;
    case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_NULL_SHA256:
	cipherName = "TLS_DHE_PSK_WITH_NULL_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_DHE_PSK_WITH_NULL_SHA384:
	cipherName = "TLS_DHE_PSK_WITH_NULL_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256";
	break;
    case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384";
	break;
    case TLS_RSA_PSK_WITH_NULL_SHA256:
	cipherName = "TLS_RSA_PSK_WITH_NULL_SHA256";
	break;
    case TLS_RSA_PSK_WITH_NULL_SHA384:
	cipherName = "TLS_RSA_PSK_WITH_NULL_SHA384";
	break;
    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
	cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
	cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
	cipherName = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
	cipherName = "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
	paramsNeeded = 1;
	break;
    case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
	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;
        break;
  }

  if (cipher == TLS_RSA_WITH_RC4_128_MD5 ||
      cipher == TLS_RSA_WITH_RC4_128_SHA)
  {
    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);
    httpClose(http);
    return (1);
  }

  if (paramsLen < 128 && paramsLen != 0)
  {
    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__ */

  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);

  return (0);
}