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