Home | History | Annotate | Download | only in cups
      1 /*
      2  * TLS support code for CUPS using GNU TLS.
      3  *
      4  * Copyright 2007-2017 by Apple Inc.
      5  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /**** This file is included from tls.c ****/
     17 
     18 /*
     19  * Include necessary headers...
     20  */
     21 
     22 #include <sys/stat.h>
     23 
     24 
     25 /*
     26  * Local globals...
     27  */
     28 
     29 static int		tls_auto_create = 0;
     30 					/* Auto-create self-signed certs? */
     31 static char		*tls_common_name = NULL;
     32 					/* Default common name */
     33 static gnutls_x509_crl_t tls_crl = NULL;/* Certificate revocation list */
     34 static char		*tls_keypath = NULL;
     35 					/* Server cert keychain path */
     36 static _cups_mutex_t	tls_mutex = _CUPS_MUTEX_INITIALIZER;
     37 					/* Mutex for keychain/certs */
     38 static int		tls_options = -1;/* Options for TLS connections */
     39 
     40 
     41 /*
     42  * Local functions...
     43  */
     44 
     45 static gnutls_x509_crt_t http_gnutls_create_credential(http_credential_t *credential);
     46 static const char	*http_gnutls_default_path(char *buffer, size_t bufsize);
     47 static void		http_gnutls_load_crl(void);
     48 static const char	*http_gnutls_make_path(char *buffer, size_t bufsize, const char *dirname, const char *filename, const char *ext);
     49 static ssize_t		http_gnutls_read(gnutls_transport_ptr_t ptr, void *data, size_t length);
     50 static ssize_t		http_gnutls_write(gnutls_transport_ptr_t ptr, const void *data, size_t length);
     51 
     52 
     53 /*
     54  * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
     55  *
     56  * @since CUPS 2.0/OS 10.10@
     57  */
     58 
     59 int					/* O - 1 on success, 0 on failure */
     60 cupsMakeServerCredentials(
     61     const char *path,			/* I - Path to keychain/directory */
     62     const char *common_name,		/* I - Common name */
     63     int        num_alt_names,		/* I - Number of subject alternate names */
     64     const char **alt_names,		/* I - Subject Alternate Names */
     65     time_t     expiration_date)		/* I - Expiration date */
     66 {
     67   gnutls_x509_crt_t	crt;		/* Self-signed certificate */
     68   gnutls_x509_privkey_t	key;		/* Encryption private key */
     69   char			temp[1024],	/* Temporary directory name */
     70  			crtfile[1024],	/* Certificate filename */
     71 			keyfile[1024];	/* Private key filename */
     72   cups_lang_t		*language;	/* Default language info */
     73   cups_file_t		*fp;		/* Key/cert file */
     74   unsigned char		buffer[8192];	/* Buffer for x509 data */
     75   size_t		bytes;		/* Number of bytes of data */
     76   unsigned char		serial[4];	/* Serial number buffer */
     77   time_t		curtime;	/* Current time */
     78   int			result;		/* Result of GNU TLS calls */
     79 
     80 
     81   DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));
     82 
     83  /*
     84   * Filenames...
     85   */
     86 
     87   if (!path)
     88     path = http_gnutls_default_path(temp, sizeof(temp));
     89 
     90   if (!path || !common_name)
     91   {
     92     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
     93     return (0);
     94   }
     95 
     96   http_gnutls_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
     97   http_gnutls_make_path(keyfile, sizeof(keyfile), path, common_name, "key");
     98 
     99  /*
    100   * Create the encryption key...
    101   */
    102 
    103   DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");
    104 
    105   gnutls_x509_privkey_init(&key);
    106   gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
    107 
    108   DEBUG_puts("1cupsMakeServerCredentials: Key pair created.");
    109 
    110  /*
    111   * Save it...
    112   */
    113 
    114   bytes = sizeof(buffer);
    115 
    116   if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
    117   {
    118     DEBUG_printf(("1cupsMakeServerCredentials: Unable to export private key: %s", gnutls_strerror(result)));
    119     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
    120     gnutls_x509_privkey_deinit(key);
    121     return (0);
    122   }
    123   else if ((fp = cupsFileOpen(keyfile, "w")) != NULL)
    124   {
    125     DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile));
    126     cupsFileWrite(fp, (char *)buffer, bytes);
    127     cupsFileClose(fp);
    128   }
    129   else
    130   {
    131     DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file \"%s\": %s", keyfile, strerror(errno)));
    132     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    133     gnutls_x509_privkey_deinit(key);
    134     return (0);
    135   }
    136 
    137  /*
    138   * Create the self-signed certificate...
    139   */
    140 
    141   DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate.");
    142 
    143   language  = cupsLangDefault();
    144   curtime   = time(NULL);
    145   serial[0] = curtime >> 24;
    146   serial[1] = curtime >> 16;
    147   serial[2] = curtime >> 8;
    148   serial[3] = curtime;
    149 
    150   gnutls_x509_crt_init(&crt);
    151   if (strlen(language->language) == 5)
    152     gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
    153                                   language->language + 3, 2);
    154   else
    155     gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
    156                                   "US", 2);
    157   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
    158                                 common_name, strlen(common_name));
    159   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
    160                                 common_name, strlen(common_name));
    161   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
    162                                 0, "Unknown", 7);
    163   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
    164                                 "Unknown", 7);
    165   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
    166                                 "Unknown", 7);
    167 /*  gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
    168                                 ServerAdmin, strlen(ServerAdmin));*/
    169   gnutls_x509_crt_set_key(crt, key);
    170   gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
    171   gnutls_x509_crt_set_activation_time(crt, curtime);
    172   gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
    173   gnutls_x509_crt_set_ca_status(crt, 0);
    174   if (num_alt_names > 0)
    175     gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, alt_names[0]);
    176   gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
    177   gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
    178   gnutls_x509_crt_set_version(crt, 3);
    179 
    180   bytes = sizeof(buffer);
    181   if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
    182     gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
    183 
    184   gnutls_x509_crt_sign(crt, crt, key);
    185 
    186  /*
    187   * Save it...
    188   */
    189 
    190   bytes = sizeof(buffer);
    191   if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
    192   {
    193     DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result)));
    194     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0);
    195     gnutls_x509_crt_deinit(crt);
    196     gnutls_x509_privkey_deinit(key);
    197     return (0);
    198   }
    199   else if ((fp = cupsFileOpen(crtfile, "w")) != NULL)
    200   {
    201     DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile));
    202     cupsFileWrite(fp, (char *)buffer, bytes);
    203     cupsFileClose(fp);
    204   }
    205   else
    206   {
    207     DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile, strerror(errno)));
    208     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    209     gnutls_x509_crt_deinit(crt);
    210     gnutls_x509_privkey_deinit(key);
    211     return (0);
    212   }
    213 
    214  /*
    215   * Cleanup...
    216   */
    217 
    218   gnutls_x509_crt_deinit(crt);
    219   gnutls_x509_privkey_deinit(key);
    220 
    221   DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");
    222 
    223   return (1);
    224 }
    225 
    226 
    227 /*
    228  * 'cupsSetServerCredentials()' - Set the default server credentials.
    229  *
    230  * Note: The server credentials are used by all threads in the running process.
    231  * This function is threadsafe.
    232  *
    233  * @since CUPS 2.0/OS 10.10@
    234  */
    235 
    236 int					/* O - 1 on success, 0 on failure */
    237 cupsSetServerCredentials(
    238     const char *path,			/* I - Path to keychain/directory */
    239     const char *common_name,		/* I - Default common name for server */
    240     int        auto_create)		/* I - 1 = automatically create self-signed certificates */
    241 {
    242   char	temp[1024];			/* Default path buffer */
    243 
    244 
    245   DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create));
    246 
    247  /*
    248   * Use defaults as needed...
    249   */
    250 
    251   if (!path)
    252     path = http_gnutls_default_path(temp, sizeof(temp));
    253 
    254  /*
    255   * Range check input...
    256   */
    257 
    258   if (!path || !common_name)
    259   {
    260     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
    261     return (0);
    262   }
    263 
    264   _cupsMutexLock(&tls_mutex);
    265 
    266  /*
    267   * Free old values...
    268   */
    269 
    270   if (tls_keypath)
    271     _cupsStrFree(tls_keypath);
    272 
    273   if (tls_common_name)
    274     _cupsStrFree(tls_common_name);
    275 
    276  /*
    277   * Save the new values...
    278   */
    279 
    280   tls_keypath     = _cupsStrAlloc(path);
    281   tls_auto_create = auto_create;
    282   tls_common_name = _cupsStrAlloc(common_name);
    283 
    284   _cupsMutexUnlock(&tls_mutex);
    285 
    286   return (1);
    287 }
    288 
    289 
    290 /*
    291  * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
    292  *                           an encrypted connection.
    293  *
    294  * @since CUPS 1.5/macOS 10.7@
    295  */
    296 
    297 int					/* O - Status of call (0 = success) */
    298 httpCopyCredentials(
    299     http_t	 *http,			/* I - Connection to server */
    300     cups_array_t **credentials)		/* O - Array of credentials */
    301 {
    302   unsigned		count;		/* Number of certificates */
    303   const gnutls_datum_t *certs;		/* Certificates */
    304 
    305 
    306   DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials));
    307 
    308   if (credentials)
    309     *credentials = NULL;
    310 
    311   if (!http || !http->tls || !credentials)
    312     return (-1);
    313 
    314   *credentials = cupsArrayNew(NULL, NULL);
    315   certs        = gnutls_certificate_get_peers(http->tls, &count);
    316 
    317   DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs, count));
    318 
    319   if (certs && count)
    320   {
    321     while (count > 0)
    322     {
    323       httpAddCredential(*credentials, certs->data, certs->size);
    324       certs ++;
    325       count --;
    326     }
    327   }
    328 
    329   return (0);
    330 }
    331 
    332 
    333 /*
    334  * '_httpCreateCredentials()' - Create credentials in the internal format.
    335  */
    336 
    337 http_tls_credentials_t			/* O - Internal credentials */
    338 _httpCreateCredentials(
    339     cups_array_t *credentials)		/* I - Array of credentials */
    340 {
    341   (void)credentials;
    342 
    343   return (NULL);
    344 }
    345 
    346 
    347 /*
    348  * '_httpFreeCredentials()' - Free internal credentials.
    349  */
    350 
    351 void
    352 _httpFreeCredentials(
    353     http_tls_credentials_t credentials)	/* I - Internal credentials */
    354 {
    355   (void)credentials;
    356 }
    357 
    358 
    359 /*
    360  * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
    361  *
    362  * @since CUPS 2.0/OS 10.10@
    363  */
    364 
    365 int					/* O - 1 if valid, 0 otherwise */
    366 httpCredentialsAreValidForName(
    367     cups_array_t *credentials,		/* I - Credentials */
    368     const char   *common_name)		/* I - Name to check */
    369 {
    370   gnutls_x509_crt_t	cert;		/* Certificate */
    371   int			result = 0;	/* Result */
    372 
    373 
    374   cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    375   if (cert)
    376   {
    377     result = gnutls_x509_crt_check_hostname(cert, common_name) != 0;
    378 
    379     if (result)
    380     {
    381       int		i,		/* Looping var */
    382 			count;		/* Number of revoked certificates */
    383       unsigned char	cserial[1024],	/* Certificate serial number */
    384 			rserial[1024];	/* Revoked serial number */
    385       size_t		cserial_size,	/* Size of cert serial number */
    386 			rserial_size;	/* Size of revoked serial number */
    387 
    388       _cupsMutexLock(&tls_mutex);
    389 
    390       count = gnutls_x509_crl_get_crt_count(tls_crl);
    391 
    392       if (count > 0)
    393       {
    394         cserial_size = sizeof(cserial);
    395         gnutls_x509_crt_get_serial(cert, cserial, &cserial_size);
    396 
    397         for (i = 0; i < count; i ++)
    398 	{
    399 	  rserial_size = sizeof(rserial);
    400           if (!gnutls_x509_crl_get_crt_serial(tls_crl, (unsigned)i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, rserial_size))
    401 	  {
    402 	    result = 0;
    403 	    break;
    404 	  }
    405 	}
    406       }
    407 
    408       _cupsMutexUnlock(&tls_mutex);
    409     }
    410 
    411     gnutls_x509_crt_deinit(cert);
    412   }
    413 
    414   return (result);
    415 }
    416 
    417 
    418 /*
    419  * 'httpCredentialsGetTrust()' - Return the trust of credentials.
    420  *
    421  * @since CUPS 2.0/OS 10.10@
    422  */
    423 
    424 http_trust_t				/* O - Level of trust */
    425 httpCredentialsGetTrust(
    426     cups_array_t *credentials,		/* I - Credentials */
    427     const char   *common_name)		/* I - Common name for trust lookup */
    428 {
    429   http_trust_t		trust = HTTP_TRUST_OK;
    430 					/* Trusted? */
    431   gnutls_x509_crt_t	cert;		/* Certificate */
    432   cups_array_t		*tcreds = NULL;	/* Trusted credentials */
    433   _cups_globals_t	*cg = _cupsGlobals();
    434 					/* Per-thread globals */
    435 
    436 
    437   if (!common_name)
    438   {
    439     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No common name specified."), 1);
    440     return (HTTP_TRUST_UNKNOWN);
    441   }
    442 
    443   if ((cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL)
    444   {
    445     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create credentials from array."), 1);
    446     return (HTTP_TRUST_UNKNOWN);
    447   }
    448 
    449   if (cg->any_root < 0)
    450   {
    451     _cupsSetDefaults();
    452     http_gnutls_load_crl();
    453   }
    454 
    455  /*
    456   * Look this common name up in the default keychains...
    457   */
    458 
    459   httpLoadCredentials(NULL, &tcreds, common_name);
    460 
    461   if (tcreds)
    462   {
    463     char	credentials_str[1024],	/* String for incoming credentials */
    464 		tcreds_str[1024];	/* String for saved credentials */
    465 
    466     httpCredentialsString(credentials, credentials_str, sizeof(credentials_str));
    467     httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str));
    468 
    469     if (strcmp(credentials_str, tcreds_str))
    470     {
    471      /*
    472       * Credentials don't match, let's look at the expiration date of the new
    473       * credentials and allow if the new ones have a later expiration...
    474       */
    475 
    476       if (!cg->trust_first)
    477       {
    478        /*
    479         * Do not trust certificates on first use...
    480 	*/
    481 
    482         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
    483 
    484         trust = HTTP_TRUST_INVALID;
    485       }
    486       else if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds))
    487       {
    488        /*
    489         * The new credentials are not newly issued...
    490 	*/
    491 
    492         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are older than stored credentials."), 1);
    493 
    494         trust = HTTP_TRUST_INVALID;
    495       }
    496       else if (!httpCredentialsAreValidForName(credentials, common_name))
    497       {
    498        /*
    499         * The common name does not match the issued certificate...
    500 	*/
    501 
    502         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are not valid for name."), 1);
    503 
    504         trust = HTTP_TRUST_INVALID;
    505       }
    506       else if (httpCredentialsGetExpiration(tcreds) < time(NULL))
    507       {
    508        /*
    509         * Save the renewed credentials...
    510 	*/
    511 
    512 	trust = HTTP_TRUST_RENEWED;
    513 
    514         httpSaveCredentials(NULL, credentials, common_name);
    515       }
    516     }
    517 
    518     httpFreeCredentials(tcreds);
    519   }
    520   else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name))
    521   {
    522     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1);
    523     trust = HTTP_TRUST_INVALID;
    524   }
    525   else if (!cg->trust_first)
    526   {
    527    /*
    528     * See if we have a site CA certificate we can compare...
    529     */
    530 
    531     if (!httpLoadCredentials(NULL, &tcreds, "site"))
    532     {
    533       if (cupsArrayCount(credentials) != (cupsArrayCount(tcreds) + 1))
    534       {
    535        /*
    536         * Certificate isn't directly generated from the CA cert...
    537 	*/
    538 
    539         trust = HTTP_TRUST_INVALID;
    540       }
    541       else
    542       {
    543        /*
    544         * Do a tail comparison of the two certificates...
    545 	*/
    546 
    547         http_credential_t	*a, *b;		/* Certificates */
    548 
    549         for (a = (http_credential_t *)cupsArrayFirst(tcreds), b = (http_credential_t *)cupsArrayIndex(credentials, 1);
    550 	     a && b;
    551 	     a = (http_credential_t *)cupsArrayNext(tcreds), b = (http_credential_t *)cupsArrayNext(credentials))
    552 	  if (a->datalen != b->datalen || memcmp(a->data, b->data, a->datalen))
    553 	    break;
    554 
    555         if (a || b)
    556 	  trust = HTTP_TRUST_INVALID;
    557       }
    558 
    559       if (trust != HTTP_TRUST_OK)
    560 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials do not validate against site CA certificate."), 1);
    561     }
    562     else
    563     {
    564       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
    565       trust = HTTP_TRUST_INVALID;
    566     }
    567   }
    568 
    569   if (trust == HTTP_TRUST_OK && !cg->expired_certs)
    570   {
    571     time_t	curtime;		/* Current date/time */
    572 
    573     time(&curtime);
    574     if (curtime < gnutls_x509_crt_get_activation_time(cert) ||
    575         curtime > gnutls_x509_crt_get_expiration_time(cert))
    576     {
    577       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials have expired."), 1);
    578       trust = HTTP_TRUST_EXPIRED;
    579     }
    580   }
    581 
    582   if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1)
    583   {
    584     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
    585     trust = HTTP_TRUST_INVALID;
    586   }
    587 
    588   gnutls_x509_crt_deinit(cert);
    589 
    590   return (trust);
    591 }
    592 
    593 
    594 /*
    595  * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
    596  *
    597  * @since CUPS 2.0/OS 10.10@
    598  */
    599 
    600 time_t					/* O - Expiration date of credentials */
    601 httpCredentialsGetExpiration(
    602     cups_array_t *credentials)		/* I - Credentials */
    603 {
    604   gnutls_x509_crt_t	cert;		/* Certificate */
    605   time_t		result = 0;	/* Result */
    606 
    607 
    608   cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials));
    609   if (cert)
    610   {
    611     result = gnutls_x509_crt_get_expiration_time(cert);
    612     gnutls_x509_crt_deinit(cert);
    613   }
    614 
    615   return (result);
    616 }
    617 
    618 
    619 /*
    620  * 'httpCredentialsString()' - Return a string representing the credentials.
    621  *
    622  * @since CUPS 2.0/OS 10.10@
    623  */
    624 
    625 size_t					/* O - Total size of credentials string */
    626 httpCredentialsString(
    627     cups_array_t *credentials,		/* I - Credentials */
    628     char         *buffer,		/* I - Buffer or @code NULL@ */
    629     size_t       bufsize)		/* I - Size of buffer */
    630 {
    631   http_credential_t	*first;		/* First certificate */
    632   gnutls_x509_crt_t	cert;		/* Certificate */
    633 
    634 
    635   DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize));
    636 
    637   if (!buffer)
    638     return (0);
    639 
    640   if (buffer && bufsize > 0)
    641     *buffer = '\0';
    642 
    643   if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL &&
    644       (cert = http_gnutls_create_credential(first)) != NULL)
    645   {
    646     char		name[256];	/* Common name associated with cert */
    647     size_t		namelen;	/* Length of name */
    648     time_t		expiration;	/* Expiration date of cert */
    649     _cups_md5_state_t	md5_state;	/* MD5 state */
    650     unsigned char	md5_digest[16];	/* MD5 result */
    651 
    652     namelen = sizeof(name) - 1;
    653     if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &namelen) >= 0)
    654       name[namelen] = '\0';
    655     else
    656       strlcpy(name, "unknown", sizeof(name));
    657 
    658     expiration = gnutls_x509_crt_get_expiration_time(cert);
    659 
    660     _cupsMD5Init(&md5_state);
    661     _cupsMD5Append(&md5_state, first->data, (int)first->datalen);
    662     _cupsMD5Finish(&md5_state, md5_digest);
    663 
    664     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]);
    665 
    666     gnutls_x509_crt_deinit(cert);
    667   }
    668 
    669   DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer));
    670 
    671   return (strlen(buffer));
    672 }
    673 
    674 
    675 /*
    676  * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
    677  *
    678  * @since CUPS 2.0/OS 10.10@
    679  */
    680 
    681 int					/* O - 0 on success, -1 on error */
    682 httpLoadCredentials(
    683     const char   *path,			/* I  - Keychain/PKCS#12 path */
    684     cups_array_t **credentials,		/* IO - Credentials */
    685     const char   *common_name)		/* I  - Common name for credentials */
    686 {
    687   cups_file_t		*fp;		/* Certificate file */
    688   char			filename[1024],	/* filename.crt */
    689 			temp[1024],	/* Temporary string */
    690 			line[256];	/* Base64-encoded line */
    691   unsigned char		*data = NULL;	/* Buffer for cert data */
    692   size_t		alloc_data = 0,	/* Bytes allocated */
    693 			num_data = 0;	/* Bytes used */
    694   int			decoded;	/* Bytes decoded */
    695   int			in_certificate = 0;
    696 					/* In a certificate? */
    697 
    698 
    699   if (!credentials || !common_name)
    700     return (-1);
    701 
    702   if (!path)
    703     path = http_gnutls_default_path(temp, sizeof(temp));
    704   if (!path)
    705     return (-1);
    706 
    707   http_gnutls_make_path(filename, sizeof(filename), path, common_name, "crt");
    708 
    709   if ((fp = cupsFileOpen(filename, "r")) == NULL)
    710     return (-1);
    711 
    712   while (cupsFileGets(fp, line, sizeof(line)))
    713   {
    714     if (!strcmp(line, "-----BEGIN CERTIFICATE-----"))
    715     {
    716       if (in_certificate)
    717       {
    718        /*
    719 	* Missing END CERTIFICATE...
    720 	*/
    721 
    722         httpFreeCredentials(*credentials);
    723 	*credentials = NULL;
    724         break;
    725       }
    726 
    727       in_certificate = 1;
    728     }
    729     else if (!strcmp(line, "-----END CERTIFICATE-----"))
    730     {
    731       if (!in_certificate || !num_data)
    732       {
    733        /*
    734 	* Missing data...
    735 	*/
    736 
    737         httpFreeCredentials(*credentials);
    738 	*credentials = NULL;
    739         break;
    740       }
    741 
    742       if (!*credentials)
    743         *credentials = cupsArrayNew(NULL, NULL);
    744 
    745       if (httpAddCredential(*credentials, data, num_data))
    746       {
    747         httpFreeCredentials(*credentials);
    748 	*credentials = NULL;
    749         break;
    750       }
    751 
    752       num_data       = 0;
    753       in_certificate = 0;
    754     }
    755     else if (in_certificate)
    756     {
    757       if (alloc_data == 0)
    758       {
    759         data       = malloc(2048);
    760 	alloc_data = 2048;
    761 
    762         if (!data)
    763 	  break;
    764       }
    765       else if ((num_data + strlen(line)) >= alloc_data)
    766       {
    767         unsigned char *tdata = realloc(data, alloc_data + 1024);
    768 					/* Expanded buffer */
    769 
    770 	if (!tdata)
    771 	{
    772 	  httpFreeCredentials(*credentials);
    773 	  *credentials = NULL;
    774 	  break;
    775 	}
    776 
    777 	data       = tdata;
    778         alloc_data += 1024;
    779       }
    780 
    781       decoded = alloc_data - num_data;
    782       httpDecode64_2((char *)data + num_data, &decoded, line);
    783       num_data += (size_t)decoded;
    784     }
    785   }
    786 
    787   cupsFileClose(fp);
    788 
    789   if (in_certificate)
    790   {
    791    /*
    792     * Missing END CERTIFICATE...
    793     */
    794 
    795     httpFreeCredentials(*credentials);
    796     *credentials = NULL;
    797   }
    798 
    799   if (data)
    800     free(data);
    801 
    802   return (*credentials ? 0 : -1);
    803 }
    804 
    805 
    806 /*
    807  * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
    808  *
    809  * @since CUPS 2.0/OS 10.10@
    810  */
    811 
    812 int					/* O - -1 on error, 0 on success */
    813 httpSaveCredentials(
    814     const char   *path,			/* I - Keychain/PKCS#12 path */
    815     cups_array_t *credentials,		/* I - Credentials */
    816     const char   *common_name)		/* I - Common name for credentials */
    817 {
    818   cups_file_t		*fp;		/* Certificate file */
    819   char			filename[1024],	/* filename.crt */
    820 			nfilename[1024],/* filename.crt.N */
    821 			temp[1024],	/* Temporary string */
    822 			line[256];	/* Base64-encoded line */
    823   const unsigned char	*ptr;		/* Pointer into certificate */
    824   ssize_t		remaining;	/* Bytes left */
    825   http_credential_t	*cred;		/* Current credential */
    826 
    827 
    828   if (!credentials || !common_name)
    829     return (-1);
    830 
    831   if (!path)
    832     path = http_gnutls_default_path(temp, sizeof(temp));
    833   if (!path)
    834     return (-1);
    835 
    836   http_gnutls_make_path(filename, sizeof(filename), path, common_name, "crt");
    837   snprintf(nfilename, sizeof(nfilename), "%s.N", filename);
    838 
    839   if ((fp = cupsFileOpen(nfilename, "w")) == NULL)
    840     return (-1);
    841 
    842   fchmod(cupsFileNumber(fp), 0600);
    843 
    844   for (cred = (http_credential_t *)cupsArrayFirst(credentials);
    845        cred;
    846        cred = (http_credential_t *)cupsArrayNext(credentials))
    847   {
    848     cupsFilePuts(fp, "-----BEGIN CERTIFICATE-----\n");
    849     for (ptr = cred->data, remaining = (ssize_t)cred->datalen; remaining > 0; remaining -= 45, ptr += 45)
    850     {
    851       httpEncode64_2(line, sizeof(line), (char *)ptr, remaining > 45 ? 45 : remaining);
    852       cupsFilePrintf(fp, "%s\n", line);
    853     }
    854     cupsFilePuts(fp, "-----END CERTIFICATE-----\n");
    855   }
    856 
    857   cupsFileClose(fp);
    858 
    859   return (rename(nfilename, filename));
    860 }
    861 
    862 
    863 /*
    864  * 'http_gnutls_create_credential()' - Create a single credential in the internal format.
    865  */
    866 
    867 static gnutls_x509_crt_t			/* O - Certificate */
    868 http_gnutls_create_credential(
    869     http_credential_t *credential)		/* I - Credential */
    870 {
    871   int			result;			/* Result from GNU TLS */
    872   gnutls_x509_crt_t	cert;			/* Certificate */
    873   gnutls_datum_t	datum;			/* Data record */
    874 
    875 
    876   DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential));
    877 
    878   if (!credential)
    879     return (NULL);
    880 
    881   if ((result = gnutls_x509_crt_init(&cert)) < 0)
    882   {
    883     DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result)));
    884     return (NULL);
    885   }
    886 
    887   datum.data = credential->data;
    888   datum.size = credential->datalen;
    889 
    890   if ((result = gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER)) < 0)
    891   {
    892     DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result)));
    893 
    894     gnutls_x509_crt_deinit(cert);
    895     return (NULL);
    896   }
    897 
    898   return (cert);
    899 }
    900 
    901 
    902 /*
    903  * 'http_gnutls_default_path()' - Get the default credential store path.
    904  */
    905 
    906 static const char *			/* O - Path or NULL on error */
    907 http_gnutls_default_path(char   *buffer,/* I - Path buffer */
    908                          size_t bufsize)/* I - Size of path buffer */
    909 {
    910   const char *home = getenv("HOME");	/* HOME environment variable */
    911 
    912 
    913   if (getuid() && home)
    914   {
    915     snprintf(buffer, bufsize, "%s/.cups", home);
    916     if (access(buffer, 0))
    917     {
    918       DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer));
    919       if (mkdir(buffer, 0700))
    920       {
    921         DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno)));
    922         return (NULL);
    923       }
    924     }
    925 
    926     snprintf(buffer, bufsize, "%s/.cups/ssl", home);
    927     if (access(buffer, 0))
    928     {
    929       DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer));
    930       if (mkdir(buffer, 0700))
    931       {
    932         DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno)));
    933         return (NULL);
    934       }
    935     }
    936   }
    937   else
    938     strlcpy(buffer, CUPS_SERVERROOT "/ssl", bufsize);
    939 
    940   DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer));
    941 
    942   return (buffer);
    943 }
    944 
    945 
    946 /*
    947  * 'http_gnutls_load_crl()' - Load the certificate revocation list, if any.
    948  */
    949 
    950 static void
    951 http_gnutls_load_crl(void)
    952 {
    953   _cupsMutexLock(&tls_mutex);
    954 
    955   if (!gnutls_x509_crl_init(&tls_crl))
    956   {
    957     cups_file_t		*fp;		/* CRL file */
    958     char		filename[1024],	/* site.crl */
    959 			line[256];	/* Base64-encoded line */
    960     unsigned char	*data = NULL;	/* Buffer for cert data */
    961     size_t		alloc_data = 0,	/* Bytes allocated */
    962 			num_data = 0;	/* Bytes used */
    963     int			decoded;	/* Bytes decoded */
    964     gnutls_datum_t	datum;		/* Data record */
    965 
    966 
    967     http_gnutls_make_path(filename, sizeof(filename), CUPS_SERVERROOT, "site", "crl");
    968 
    969     if ((fp = cupsFileOpen(filename, "r")) != NULL)
    970     {
    971       while (cupsFileGets(fp, line, sizeof(line)))
    972       {
    973 	if (!strcmp(line, "-----BEGIN X509 CRL-----"))
    974 	{
    975 	  if (num_data)
    976 	  {
    977 	   /*
    978 	    * Missing END X509 CRL...
    979 	    */
    980 
    981 	    break;
    982 	  }
    983 	}
    984 	else if (!strcmp(line, "-----END X509 CRL-----"))
    985 	{
    986 	  if (!num_data)
    987 	  {
    988 	   /*
    989 	    * Missing data...
    990 	    */
    991 
    992 	    break;
    993 	  }
    994 
    995           datum.data = data;
    996 	  datum.size = num_data;
    997 
    998 	  gnutls_x509_crl_import(tls_crl, &datum, GNUTLS_X509_FMT_PEM);
    999 
   1000 	  num_data = 0;
   1001 	}
   1002 	else
   1003 	{
   1004 	  if (alloc_data == 0)
   1005 	  {
   1006 	    data       = malloc(2048);
   1007 	    alloc_data = 2048;
   1008 
   1009 	    if (!data)
   1010 	      break;
   1011 	  }
   1012 	  else if ((num_data + strlen(line)) >= alloc_data)
   1013 	  {
   1014 	    unsigned char *tdata = realloc(data, alloc_data + 1024);
   1015 					    /* Expanded buffer */
   1016 
   1017 	    if (!tdata)
   1018 	      break;
   1019 
   1020 	    data       = tdata;
   1021 	    alloc_data += 1024;
   1022 	  }
   1023 
   1024 	  decoded = alloc_data - num_data;
   1025 	  httpDecode64_2((char *)data + num_data, &decoded, line);
   1026 	  num_data += (size_t)decoded;
   1027 	}
   1028       }
   1029 
   1030       cupsFileClose(fp);
   1031 
   1032       if (data)
   1033 	free(data);
   1034     }
   1035   }
   1036 
   1037   _cupsMutexUnlock(&tls_mutex);
   1038 }
   1039 
   1040 
   1041 /*
   1042  * 'http_gnutls_make_path()' - Format a filename for a certificate or key file.
   1043  */
   1044 
   1045 static const char *			/* O - Filename */
   1046 http_gnutls_make_path(
   1047     char       *buffer,			/* I - Filename buffer */
   1048     size_t     bufsize,			/* I - Size of buffer */
   1049     const char *dirname,		/* I - Directory */
   1050     const char *filename,		/* I - Filename (usually hostname) */
   1051     const char *ext)			/* I - Extension */
   1052 {
   1053   char	*bufptr,			/* Pointer into buffer */
   1054 	*bufend = buffer + bufsize - 1;	/* End of buffer */
   1055 
   1056 
   1057   snprintf(buffer, bufsize, "%s/", dirname);
   1058   bufptr = buffer + strlen(buffer);
   1059 
   1060   while (*filename && bufptr < bufend)
   1061   {
   1062     if (_cups_isalnum(*filename) || *filename == '-' || *filename == '.')
   1063       *bufptr++ = *filename;
   1064     else
   1065       *bufptr++ = '_';
   1066 
   1067     filename ++;
   1068   }
   1069 
   1070   if (bufptr < bufend)
   1071     *bufptr++ = '.';
   1072 
   1073   strlcpy(bufptr, ext, (size_t)(bufend - bufptr + 1));
   1074 
   1075   return (buffer);
   1076 }
   1077 
   1078 
   1079 /*
   1080  * 'http_gnutls_read()' - Read function for the GNU TLS library.
   1081  */
   1082 
   1083 static ssize_t				/* O - Number of bytes read or -1 on error */
   1084 http_gnutls_read(
   1085     gnutls_transport_ptr_t ptr,		/* I - Connection to server */
   1086     void                   *data,	/* I - Buffer */
   1087     size_t                 length)	/* I - Number of bytes to read */
   1088 {
   1089   http_t	*http;			/* HTTP connection */
   1090   ssize_t	bytes;			/* Bytes read */
   1091 
   1092 
   1093   DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr, data, (int)length));
   1094 
   1095   http = (http_t *)ptr;
   1096 
   1097   if (!http->blocking)
   1098   {
   1099    /*
   1100     * Make sure we have data before we read...
   1101     */
   1102 
   1103     while (!_httpWait(http, http->wait_value, 0))
   1104     {
   1105       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
   1106 	continue;
   1107 
   1108       http->error = ETIMEDOUT;
   1109       return (-1);
   1110     }
   1111   }
   1112 
   1113   bytes = recv(http->fd, data, length, 0);
   1114   DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes));
   1115   return (bytes);
   1116 }
   1117 
   1118 
   1119 /*
   1120  * 'http_gnutls_write()' - Write function for the GNU TLS library.
   1121  */
   1122 
   1123 static ssize_t				/* O - Number of bytes written or -1 on error */
   1124 http_gnutls_write(
   1125     gnutls_transport_ptr_t ptr,		/* I - Connection to server */
   1126     const void             *data,	/* I - Data buffer */
   1127     size_t                 length)	/* I - Number of bytes to write */
   1128 {
   1129   ssize_t bytes;			/* Bytes written */
   1130 
   1131 
   1132   DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr, data,
   1133                 (int)length));
   1134   bytes = send(((http_t *)ptr)->fd, data, length, 0);
   1135   DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes));
   1136 
   1137   return (bytes);
   1138 }
   1139 
   1140 
   1141 /*
   1142  * '_httpTLSInitialize()' - Initialize the TLS stack.
   1143  */
   1144 
   1145 void
   1146 _httpTLSInitialize(void)
   1147 {
   1148  /*
   1149   * Initialize GNU TLS...
   1150   */
   1151 
   1152   gnutls_global_init();
   1153 }
   1154 
   1155 
   1156 /*
   1157  * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
   1158  */
   1159 
   1160 size_t					/* O - Bytes available */
   1161 _httpTLSPending(http_t *http)		/* I - HTTP connection */
   1162 {
   1163   return (gnutls_record_check_pending(http->tls));
   1164 }
   1165 
   1166 
   1167 /*
   1168  * '_httpTLSRead()' - Read from a SSL/TLS connection.
   1169  */
   1170 
   1171 int					/* O - Bytes read */
   1172 _httpTLSRead(http_t *http,		/* I - Connection to server */
   1173 	     char   *buf,		/* I - Buffer to store data */
   1174 	     int    len)		/* I - Length of buffer */
   1175 {
   1176   ssize_t	result;			/* Return value */
   1177 
   1178 
   1179   result = gnutls_record_recv(http->tls, buf, (size_t)len);
   1180 
   1181   if (result < 0 && !errno)
   1182   {
   1183    /*
   1184     * Convert GNU TLS error to errno value...
   1185     */
   1186 
   1187     switch (result)
   1188     {
   1189       case GNUTLS_E_INTERRUPTED :
   1190 	  errno = EINTR;
   1191 	  break;
   1192 
   1193       case GNUTLS_E_AGAIN :
   1194           errno = EAGAIN;
   1195           break;
   1196 
   1197       default :
   1198           errno = EPIPE;
   1199           break;
   1200     }
   1201 
   1202     result = -1;
   1203   }
   1204 
   1205   return ((int)result);
   1206 }
   1207 
   1208 
   1209 /*
   1210  * '_httpTLSSetCredentials()' - Set the TLS credentials.
   1211  */
   1212 
   1213 int					/* O - Status of connection */
   1214 _httpTLSSetCredentials(http_t *http)	/* I - Connection to server */
   1215 {
   1216   (void)http;
   1217 
   1218   return (0);
   1219 }
   1220 
   1221 
   1222 /*
   1223  * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
   1224  */
   1225 
   1226 void
   1227 _httpTLSSetOptions(int options)		/* I - Options */
   1228 {
   1229   if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
   1230     tls_options = options;
   1231 }
   1232 
   1233 
   1234 /*
   1235  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
   1236  */
   1237 
   1238 int					/* O - 0 on success, -1 on failure */
   1239 _httpTLSStart(http_t *http)		/* I - Connection to server */
   1240 {
   1241   char			hostname[256],	/* Hostname */
   1242 			*hostptr;	/* Pointer into hostname */
   1243   int			status;		/* Status of handshake */
   1244   gnutls_certificate_credentials_t *credentials;
   1245 					/* TLS credentials */
   1246   char			priority_string[2048];
   1247 					/* Priority string */
   1248 
   1249 
   1250   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
   1251 
   1252   if (tls_options < 0)
   1253   {
   1254     DEBUG_puts("4_httpTLSStart: Setting defaults.");
   1255     _cupsSetDefaults();
   1256     DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
   1257   }
   1258 
   1259   if (http->mode == _HTTP_MODE_SERVER && !tls_keypath)
   1260   {
   1261     DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
   1262     http->error  = errno = EINVAL;
   1263     http->status = HTTP_STATUS_ERROR;
   1264     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
   1265 
   1266     return (-1);
   1267   }
   1268 
   1269   credentials = (gnutls_certificate_credentials_t *)
   1270                     malloc(sizeof(gnutls_certificate_credentials_t));
   1271   if (credentials == NULL)
   1272   {
   1273     DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
   1274                   strerror(errno)));
   1275     http->error  = errno;
   1276     http->status = HTTP_STATUS_ERROR;
   1277     _cupsSetHTTPError(HTTP_STATUS_ERROR);
   1278 
   1279     return (-1);
   1280   }
   1281 
   1282   gnutls_certificate_allocate_credentials(credentials);
   1283   status = gnutls_init(&http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_CLIENT : GNUTLS_SERVER);
   1284   if (!status)
   1285     status = gnutls_set_default_priority(http->tls);
   1286 
   1287   if (status)
   1288   {
   1289     http->error  = EIO;
   1290     http->status = HTTP_STATUS_ERROR;
   1291 
   1292     DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status)));
   1293     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
   1294 
   1295     gnutls_deinit(http->tls);
   1296     gnutls_certificate_free_credentials(*credentials);
   1297     free(credentials);
   1298     http->tls = NULL;
   1299 
   1300     return (-1);
   1301   }
   1302 
   1303   if (http->mode == _HTTP_MODE_CLIENT)
   1304   {
   1305    /*
   1306     * Client: get the hostname to use for TLS...
   1307     */
   1308 
   1309     if (httpAddrLocalhost(http->hostaddr))
   1310     {
   1311       strlcpy(hostname, "localhost", sizeof(hostname));
   1312     }
   1313     else
   1314     {
   1315      /*
   1316       * Otherwise make sure the hostname we have does not end in a trailing dot.
   1317       */
   1318 
   1319       strlcpy(hostname, http->hostname, sizeof(hostname));
   1320       if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
   1321 	  *hostptr == '.')
   1322 	*hostptr = '\0';
   1323     }
   1324 
   1325     status = gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, strlen(hostname));
   1326   }
   1327   else
   1328   {
   1329    /*
   1330     * Server: get certificate and private key...
   1331     */
   1332 
   1333     char	crtfile[1024],		/* Certificate file */
   1334 		keyfile[1024];		/* Private key file */
   1335     int		have_creds = 0;		/* Have credentials? */
   1336 
   1337     if (http->fields[HTTP_FIELD_HOST][0])
   1338     {
   1339      /*
   1340       * Use hostname for TLS upgrade...
   1341       */
   1342 
   1343       strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
   1344     }
   1345     else
   1346     {
   1347      /*
   1348       * Resolve hostname from connection address...
   1349       */
   1350 
   1351       http_addr_t	addr;		/* Connection address */
   1352       socklen_t		addrlen;	/* Length of address */
   1353 
   1354       addrlen = sizeof(addr);
   1355       if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
   1356       {
   1357 	DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
   1358 	hostname[0] = '\0';
   1359       }
   1360       else if (httpAddrLocalhost(&addr))
   1361 	hostname[0] = '\0';
   1362       else
   1363       {
   1364 	httpAddrLookup(&addr, hostname, sizeof(hostname));
   1365         DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
   1366       }
   1367     }
   1368 
   1369     if (isdigit(hostname[0] & 255) || hostname[0] == '[')
   1370       hostname[0] = '\0';		/* Don't allow numeric addresses */
   1371 
   1372     if (hostname[0])
   1373     {
   1374      /*
   1375       * First look in the CUPS keystore...
   1376       */
   1377 
   1378       http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, hostname, "crt");
   1379       http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, hostname, "key");
   1380 
   1381       if (access(crtfile, R_OK) || access(keyfile, R_OK))
   1382       {
   1383        /*
   1384         * No CUPS-managed certs, look for CA certs...
   1385         */
   1386 
   1387         char cacrtfile[1024], cakeyfile[1024];	/* CA cert files */
   1388 
   1389         snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostname);
   1390         snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostname);
   1391 
   1392         if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(hostname, '.')) != NULL)
   1393         {
   1394          /*
   1395           * Try just domain name...
   1396           */
   1397 
   1398           hostptr ++;
   1399           if (strchr(hostptr, '.'))
   1400           {
   1401             snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr);
   1402             snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr);
   1403           }
   1404         }
   1405 
   1406         if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK))
   1407         {
   1408          /*
   1409           * Use the CA certs...
   1410           */
   1411 
   1412           strlcpy(crtfile, cacrtfile, sizeof(crtfile));
   1413           strlcpy(keyfile, cakeyfile, sizeof(keyfile));
   1414         }
   1415       }
   1416 
   1417       have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK);
   1418     }
   1419     else if (tls_common_name)
   1420     {
   1421      /*
   1422       * First look in the CUPS keystore...
   1423       */
   1424 
   1425       http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, tls_common_name, "crt");
   1426       http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, tls_common_name, "key");
   1427 
   1428       if (access(crtfile, R_OK) || access(keyfile, R_OK))
   1429       {
   1430        /*
   1431         * No CUPS-managed certs, look for CA certs...
   1432         */
   1433 
   1434         char cacrtfile[1024], cakeyfile[1024];	/* CA cert files */
   1435 
   1436         snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", tls_common_name);
   1437         snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", tls_common_name);
   1438 
   1439         if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(tls_common_name, '.')) != NULL)
   1440         {
   1441          /*
   1442           * Try just domain name...
   1443           */
   1444 
   1445           hostptr ++;
   1446           if (strchr(hostptr, '.'))
   1447           {
   1448             snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr);
   1449             snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr);
   1450           }
   1451         }
   1452 
   1453         if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK))
   1454         {
   1455          /*
   1456           * Use the CA certs...
   1457           */
   1458 
   1459           strlcpy(crtfile, cacrtfile, sizeof(crtfile));
   1460           strlcpy(keyfile, cakeyfile, sizeof(keyfile));
   1461         }
   1462       }
   1463 
   1464       have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK);
   1465     }
   1466 
   1467     if (!have_creds && tls_auto_create && (hostname[0] || tls_common_name))
   1468     {
   1469       DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
   1470 
   1471       if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
   1472       {
   1473 	DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
   1474 	http->error  = errno = EINVAL;
   1475 	http->status = HTTP_STATUS_ERROR;
   1476 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
   1477 
   1478 	return (-1);
   1479       }
   1480     }
   1481 
   1482     DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile, keyfile));
   1483 
   1484     if (!status)
   1485       status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM);
   1486   }
   1487 
   1488   if (!status)
   1489     status = gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
   1490 
   1491   if (status)
   1492   {
   1493     http->error  = EIO;
   1494     http->status = HTTP_STATUS_ERROR;
   1495 
   1496     DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status)));
   1497     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
   1498 
   1499     gnutls_deinit(http->tls);
   1500     gnutls_certificate_free_credentials(*credentials);
   1501     free(credentials);
   1502     http->tls = NULL;
   1503 
   1504     return (-1);
   1505   }
   1506 
   1507   strlcpy(priority_string, "NORMAL", sizeof(priority_string));
   1508 
   1509   if (tls_options & _HTTP_TLS_DENY_TLS10)
   1510     strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string));
   1511   else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
   1512     strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string));
   1513   else if (tls_options & _HTTP_TLS_ONLY_TLS10)
   1514     strlcat(priority_string, ":-VERS-TLS-ALL:-VERS-SSL3.0:+VERS-TLS1.0", sizeof(priority_string));
   1515   else
   1516     strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string));
   1517 
   1518   if (tls_options & _HTTP_TLS_ALLOW_RC4)
   1519     strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string));
   1520   else
   1521     strlcat(priority_string, ":!ARCFOUR-128", sizeof(priority_string));
   1522 
   1523   strlcat(priority_string, ":!ANON-DH", sizeof(priority_string));
   1524 
   1525   if (tls_options & _HTTP_TLS_DENY_CBC)
   1526     strlcat(priority_string, ":!AES-128-CBC:!AES-256-CBC:!CAMELLIA-128-CBC:!CAMELLIA-256-CBC:!3DES-CBC", sizeof(priority_string));
   1527 
   1528 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
   1529   gnutls_priority_set_direct(http->tls, priority_string, NULL);
   1530 
   1531 #else
   1532   gnutls_priority_t priority;		/* Priority */
   1533 
   1534   gnutls_priority_init(&priority, priority_string, NULL);
   1535   gnutls_priority_set(http->tls, priority);
   1536   gnutls_priority_deinit(priority);
   1537 #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */
   1538 
   1539   gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http);
   1540   gnutls_transport_set_pull_function(http->tls, http_gnutls_read);
   1541 #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION
   1542   gnutls_transport_set_pull_timeout_function(http->tls, (gnutls_pull_timeout_func)httpWait);
   1543 #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */
   1544   gnutls_transport_set_push_function(http->tls, http_gnutls_write);
   1545 
   1546   while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
   1547   {
   1548     DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
   1549                   status, gnutls_strerror(status)));
   1550 
   1551     if (gnutls_error_is_fatal(status))
   1552     {
   1553       http->error  = EIO;
   1554       http->status = HTTP_STATUS_ERROR;
   1555 
   1556       _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
   1557 
   1558       gnutls_deinit(http->tls);
   1559       gnutls_certificate_free_credentials(*credentials);
   1560       free(credentials);
   1561       http->tls = NULL;
   1562 
   1563       return (-1);
   1564     }
   1565   }
   1566 
   1567   http->tls_credentials = credentials;
   1568 
   1569   return (0);
   1570 }
   1571 
   1572 
   1573 /*
   1574  * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
   1575  */
   1576 
   1577 void
   1578 _httpTLSStop(http_t *http)		/* I - Connection to server */
   1579 {
   1580   int	error;				/* Error code */
   1581 
   1582 
   1583   error = gnutls_bye(http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
   1584   if (error != GNUTLS_E_SUCCESS)
   1585     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(errno), 0);
   1586 
   1587   gnutls_deinit(http->tls);
   1588   http->tls = NULL;
   1589 
   1590   if (http->tls_credentials)
   1591   {
   1592     gnutls_certificate_free_credentials(*(http->tls_credentials));
   1593     free(http->tls_credentials);
   1594     http->tls_credentials = NULL;
   1595   }
   1596 }
   1597 
   1598 
   1599 /*
   1600  * '_httpTLSWrite()' - Write to a SSL/TLS connection.
   1601  */
   1602 
   1603 int					/* O - Bytes written */
   1604 _httpTLSWrite(http_t     *http,		/* I - Connection to server */
   1605 	      const char *buf,		/* I - Buffer holding data */
   1606 	      int        len)		/* I - Length of buffer */
   1607 {
   1608   ssize_t	result;			/* Return value */
   1609 
   1610 
   1611   DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
   1612 
   1613   result = gnutls_record_send(http->tls, buf, (size_t)len);
   1614 
   1615   if (result < 0 && !errno)
   1616   {
   1617    /*
   1618     * Convert GNU TLS error to errno value...
   1619     */
   1620 
   1621     switch (result)
   1622     {
   1623       case GNUTLS_E_INTERRUPTED :
   1624 	  errno = EINTR;
   1625 	  break;
   1626 
   1627       case GNUTLS_E_AGAIN :
   1628           errno = EAGAIN;
   1629           break;
   1630 
   1631       default :
   1632           errno = EPIPE;
   1633           break;
   1634     }
   1635 
   1636     result = -1;
   1637   }
   1638 
   1639   DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
   1640 
   1641   return ((int)result);
   1642 }
   1643