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