Imported Upstream version 2.2.1
[platform/upstream/cups.git] / cups / tls-gnutls.c
1 /*
2  * TLS support code for CUPS using GNU TLS.
3  *
4  * Copyright 2007-2016 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  * file is 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, 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   tls_options = options;
1230 }
1231
1232
1233 /*
1234  * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
1235  */
1236
1237 int                                     /* O - 0 on success, -1 on failure */
1238 _httpTLSStart(http_t *http)             /* I - Connection to server */
1239 {
1240   char                  hostname[256],  /* Hostname */
1241                         *hostptr;       /* Pointer into hostname */
1242   int                   status;         /* Status of handshake */
1243   gnutls_certificate_credentials_t *credentials;
1244                                         /* TLS credentials */
1245   char                  priority_string[1024];
1246                                         /* Priority string */
1247
1248
1249   DEBUG_printf(("3_httpTLSStart(http=%p)", http));
1250
1251   if (tls_options < 0)
1252   {
1253     DEBUG_puts("4_httpTLSStart: Setting defaults.");
1254     _cupsSetDefaults();
1255     DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
1256   }
1257
1258   if (http->mode == _HTTP_MODE_SERVER && !tls_keypath)
1259   {
1260     DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
1261     http->error  = errno = EINVAL;
1262     http->status = HTTP_STATUS_ERROR;
1263     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
1264
1265     return (-1);
1266   }
1267
1268   credentials = (gnutls_certificate_credentials_t *)
1269                     malloc(sizeof(gnutls_certificate_credentials_t));
1270   if (credentials == NULL)
1271   {
1272     DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
1273                   strerror(errno)));
1274     http->error  = errno;
1275     http->status = HTTP_STATUS_ERROR;
1276     _cupsSetHTTPError(HTTP_STATUS_ERROR);
1277
1278     return (-1);
1279   }
1280
1281   gnutls_certificate_allocate_credentials(credentials);
1282   status = gnutls_init(&http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_CLIENT : GNUTLS_SERVER);
1283   if (!status)
1284     status = gnutls_set_default_priority(http->tls);
1285
1286   if (status)
1287   {
1288     http->error  = EIO;
1289     http->status = HTTP_STATUS_ERROR;
1290
1291     DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status)));
1292     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
1293
1294     gnutls_deinit(http->tls);
1295     gnutls_certificate_free_credentials(*credentials);
1296     free(credentials);
1297     http->tls = NULL;
1298
1299     return (-1);
1300   }
1301
1302   if (http->mode == _HTTP_MODE_CLIENT)
1303   {
1304    /*
1305     * Client: get the hostname to use for TLS...
1306     */
1307
1308     if (httpAddrLocalhost(http->hostaddr))
1309     {
1310       strlcpy(hostname, "localhost", sizeof(hostname));
1311     }
1312     else
1313     {
1314      /*
1315       * Otherwise make sure the hostname we have does not end in a trailing dot.
1316       */
1317
1318       strlcpy(hostname, http->hostname, sizeof(hostname));
1319       if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
1320           *hostptr == '.')
1321         *hostptr = '\0';
1322     }
1323
1324     status = gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, strlen(hostname));
1325   }
1326   else
1327   {
1328    /*
1329     * Server: get certificate and private key...
1330     */
1331
1332     char        crtfile[1024],          /* Certificate file */
1333                 keyfile[1024];          /* Private key file */
1334     int         have_creds = 0;         /* Have credentials? */
1335
1336     if (http->fields[HTTP_FIELD_HOST][0])
1337     {
1338      /*
1339       * Use hostname for TLS upgrade...
1340       */
1341
1342       strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname));
1343     }
1344     else
1345     {
1346      /*
1347       * Resolve hostname from connection address...
1348       */
1349
1350       http_addr_t       addr;           /* Connection address */
1351       socklen_t         addrlen;        /* Length of address */
1352
1353       addrlen = sizeof(addr);
1354       if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen))
1355       {
1356         DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno)));
1357         hostname[0] = '\0';
1358       }
1359       else if (httpAddrLocalhost(&addr))
1360         hostname[0] = '\0';
1361       else
1362       {
1363         httpAddrLookup(&addr, hostname, sizeof(hostname));
1364         DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname));
1365       }
1366     }
1367
1368     if (isdigit(hostname[0] & 255) || hostname[0] == '[')
1369       hostname[0] = '\0';               /* Don't allow numeric addresses */
1370
1371     if (hostname[0])
1372     {
1373      /*
1374       * First look in the CUPS keystore...
1375       */
1376
1377       http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, hostname, "crt");
1378       http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, hostname, "key");
1379
1380       if (access(crtfile, R_OK) || access(keyfile, R_OK))
1381       {
1382        /*
1383         * No CUPS-managed certs, look for CA certs...
1384         */
1385
1386         char cacrtfile[1024], cakeyfile[1024];  /* CA cert files */
1387
1388         snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostname);
1389         snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostname);
1390
1391         if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(hostname, '.')) != NULL)
1392         {
1393          /*
1394           * Try just domain name...
1395           */
1396
1397           hostptr ++;
1398           if (strchr(hostptr, '.'))
1399           {
1400             snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr);
1401             snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr);
1402           }
1403         }
1404
1405         if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK))
1406         {
1407          /*
1408           * Use the CA certs...
1409           */
1410
1411           strlcpy(crtfile, cacrtfile, sizeof(crtfile));
1412           strlcpy(keyfile, cakeyfile, sizeof(keyfile));
1413         }
1414       }
1415
1416       have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK);
1417     }
1418     else if (tls_common_name)
1419     {
1420      /*
1421       * First look in the CUPS keystore...
1422       */
1423
1424       http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, tls_common_name, "crt");
1425       http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, tls_common_name, "key");
1426
1427       if (access(crtfile, R_OK) || access(keyfile, R_OK))
1428       {
1429        /*
1430         * No CUPS-managed certs, look for CA certs...
1431         */
1432
1433         char cacrtfile[1024], cakeyfile[1024];  /* CA cert files */
1434
1435         snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", tls_common_name);
1436         snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", tls_common_name);
1437
1438         if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(tls_common_name, '.')) != NULL)
1439         {
1440          /*
1441           * Try just domain name...
1442           */
1443
1444           hostptr ++;
1445           if (strchr(hostptr, '.'))
1446           {
1447             snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr);
1448             snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr);
1449           }
1450         }
1451
1452         if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK))
1453         {
1454          /*
1455           * Use the CA certs...
1456           */
1457
1458           strlcpy(crtfile, cacrtfile, sizeof(crtfile));
1459           strlcpy(keyfile, cakeyfile, sizeof(keyfile));
1460         }
1461       }
1462
1463       have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK);
1464     }
1465
1466     if (!have_creds && tls_auto_create && (hostname[0] || tls_common_name))
1467     {
1468       DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name));
1469
1470       if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400))
1471       {
1472         DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
1473         http->error  = errno = EINVAL;
1474         http->status = HTTP_STATUS_ERROR;
1475         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
1476
1477         return (-1);
1478       }
1479     }
1480
1481     DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile, keyfile));
1482
1483     if (!status)
1484       status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM);
1485   }
1486
1487   if (!status)
1488     status = gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials);
1489
1490   if (status)
1491   {
1492     http->error  = EIO;
1493     http->status = HTTP_STATUS_ERROR;
1494
1495     DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status)));
1496     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
1497
1498     gnutls_deinit(http->tls);
1499     gnutls_certificate_free_credentials(*credentials);
1500     free(credentials);
1501     http->tls = NULL;
1502
1503     return (-1);
1504   }
1505
1506   strlcpy(priority_string, "NORMAL", sizeof(priority_string));
1507
1508   if (tls_options & _HTTP_TLS_DENY_TLS10)
1509     strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string));
1510   else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
1511     strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string));
1512   else
1513     strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string));
1514
1515   if (!(tls_options & _HTTP_TLS_ALLOW_RC4))
1516     strlcat(priority_string, ":-ARCFOUR-128", sizeof(priority_string));
1517
1518   if (!(tls_options & _HTTP_TLS_ALLOW_DH))
1519     strlcat(priority_string, ":!ANON-DH", sizeof(priority_string));
1520
1521 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
1522   gnutls_priority_set_direct(http->tls, priority_string, NULL);
1523
1524 #else
1525   gnutls_priority_t priority;           /* Priority */
1526
1527   gnutls_priority_init(&priority, priority_string, NULL);
1528   gnutls_priority_set(http->tls, priority);
1529   gnutls_priority_deinit(priority);
1530 #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */
1531
1532   gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http);
1533   gnutls_transport_set_pull_function(http->tls, http_gnutls_read);
1534 #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION
1535   gnutls_transport_set_pull_timeout_function(http->tls, (gnutls_pull_timeout_func)httpWait);
1536 #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */
1537   gnutls_transport_set_push_function(http->tls, http_gnutls_write);
1538
1539   while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS)
1540   {
1541     DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
1542                   status, gnutls_strerror(status)));
1543
1544     if (gnutls_error_is_fatal(status))
1545     {
1546       http->error  = EIO;
1547       http->status = HTTP_STATUS_ERROR;
1548
1549       _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0);
1550
1551       gnutls_deinit(http->tls);
1552       gnutls_certificate_free_credentials(*credentials);
1553       free(credentials);
1554       http->tls = NULL;
1555
1556       return (-1);
1557     }
1558   }
1559
1560   http->tls_credentials = credentials;
1561
1562   return (0);
1563 }
1564
1565
1566 /*
1567  * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1568  */
1569
1570 void
1571 _httpTLSStop(http_t *http)              /* I - Connection to server */
1572 {
1573   int   error;                          /* Error code */
1574
1575
1576   error = gnutls_bye(http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
1577   if (error != GNUTLS_E_SUCCESS)
1578     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(errno), 0);
1579
1580   gnutls_deinit(http->tls);
1581   http->tls = NULL;
1582
1583   if (http->tls_credentials)
1584   {
1585     gnutls_certificate_free_credentials(*(http->tls_credentials));
1586     free(http->tls_credentials);
1587     http->tls_credentials = NULL;
1588   }
1589 }
1590
1591
1592 /*
1593  * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1594  */
1595
1596 int                                     /* O - Bytes written */
1597 _httpTLSWrite(http_t     *http,         /* I - Connection to server */
1598               const char *buf,          /* I - Buffer holding data */
1599               int        len)           /* I - Length of buffer */
1600 {
1601   ssize_t       result;                 /* Return value */
1602
1603
1604   DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
1605
1606   result = gnutls_record_send(http->tls, buf, (size_t)len);
1607
1608   if (result < 0 && !errno)
1609   {
1610    /*
1611     * Convert GNU TLS error to errno value...
1612     */
1613
1614     switch (result)
1615     {
1616       case GNUTLS_E_INTERRUPTED :
1617           errno = EINTR;
1618           break;
1619
1620       case GNUTLS_E_AGAIN :
1621           errno = EAGAIN;
1622           break;
1623
1624       default :
1625           errno = EPIPE;
1626           break;
1627     }
1628
1629     result = -1;
1630   }
1631
1632   DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
1633
1634   return ((int)result);
1635 }