2 * TLS support code for CUPS using GNU TLS.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
13 * This file is subject to the Apple OS-Developed Software exception.
16 /**** This file is included from tls.c ****/
19 * Include necessary headers...
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 */
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
);
54 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
56 * @since CUPS 2.0/OS 10.10@
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 */
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 */
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
));
88 path
= http_gnutls_default_path(temp
, sizeof(temp
));
90 if (!path
|| !common_name
)
92 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
96 http_gnutls_make_path(crtfile
, sizeof(crtfile
), path
, common_name
, "crt");
97 http_gnutls_make_path(keyfile
, sizeof(keyfile
), path
, common_name
, "key");
100 * Create the encryption key...
103 DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");
105 gnutls_x509_privkey_init(&key
);
106 gnutls_x509_privkey_generate(key
, GNUTLS_PK_RSA
, 2048, 0);
108 DEBUG_puts("1cupsMakeServerCredentials: Key pair created.");
114 bytes
= sizeof(buffer
);
116 if ((result
= gnutls_x509_privkey_export(key
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
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
);
123 else if ((fp
= cupsFileOpen(keyfile
, "w")) != NULL
)
125 DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile
));
126 cupsFileWrite(fp
, (char *)buffer
, bytes
);
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
);
138 * Create the self-signed certificate...
141 DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate.");
143 language
= cupsLangDefault();
144 curtime
= time(NULL
);
145 serial
[0] = curtime
>> 24;
146 serial
[1] = curtime
>> 16;
147 serial
[2] = curtime
>> 8;
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);
155 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
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
,
163 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME
, 0,
165 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_LOCALITY_NAME
, 0,
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);
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
);
184 gnutls_x509_crt_sign(crt
, crt
, key
);
190 bytes
= sizeof(buffer
);
191 if ((result
= gnutls_x509_crt_export(crt
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
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
);
199 else if ((fp
= cupsFileOpen(crtfile
, "w")) != NULL
)
201 DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile
));
202 cupsFileWrite(fp
, (char *)buffer
, bytes
);
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
);
218 gnutls_x509_crt_deinit(crt
);
219 gnutls_x509_privkey_deinit(key
);
221 DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");
228 * 'cupsSetServerCredentials()' - Set the default server credentials.
230 * Note: The server credentials are used by all threads in the running process.
231 * This function is threadsafe.
233 * @since CUPS 2.0/OS 10.10@
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 */
242 char temp
[1024]; /* Default path buffer */
245 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
248 * Use defaults as needed...
252 path
= http_gnutls_default_path(temp
, sizeof(temp
));
255 * Range check input...
258 if (!path
|| !common_name
)
260 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
264 _cupsMutexLock(&tls_mutex
);
271 _cupsStrFree(tls_keypath
);
274 _cupsStrFree(tls_common_name
);
277 * Save the new values...
280 tls_keypath
= _cupsStrAlloc(path
);
281 tls_auto_create
= auto_create
;
282 tls_common_name
= _cupsStrAlloc(common_name
);
284 _cupsMutexUnlock(&tls_mutex
);
291 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
292 * an encrypted connection.
294 * @since CUPS 1.5/macOS 10.7@
297 int /* O - Status of call (0 = success) */
299 http_t
*http
, /* I - Connection to server */
300 cups_array_t
**credentials
) /* O - Array of credentials */
302 unsigned count
; /* Number of certificates */
303 const gnutls_datum_t
*certs
; /* Certificates */
306 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http
, credentials
));
311 if (!http
|| !http
->tls
|| !credentials
)
314 *credentials
= cupsArrayNew(NULL
, NULL
);
315 certs
= gnutls_certificate_get_peers(http
->tls
, &count
);
317 DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs
, count
));
323 httpAddCredential(*credentials
, certs
->data
, certs
->size
);
334 * '_httpCreateCredentials()' - Create credentials in the internal format.
337 http_tls_credentials_t
/* O - Internal credentials */
338 _httpCreateCredentials(
339 cups_array_t
*credentials
) /* I - Array of credentials */
348 * '_httpFreeCredentials()' - Free internal credentials.
352 _httpFreeCredentials(
353 http_tls_credentials_t credentials
) /* I - Internal credentials */
360 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
362 * @since CUPS 2.0/OS 10.10@
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 */
370 gnutls_x509_crt_t cert
; /* Certificate */
371 int result
= 0; /* Result */
374 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
377 result
= gnutls_x509_crt_check_hostname(cert
, common_name
) != 0;
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 */
388 _cupsMutexLock(&tls_mutex
);
390 count
= gnutls_x509_crl_get_crt_count(tls_crl
);
394 cserial_size
= sizeof(cserial
);
395 gnutls_x509_crt_get_serial(cert
, cserial
, &cserial_size
);
397 for (i
= 0; i
< count
; i
++)
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
))
408 _cupsMutexUnlock(&tls_mutex
);
411 gnutls_x509_crt_deinit(cert
);
419 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
421 * @since CUPS 2.0/OS 10.10@
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 */
429 http_trust_t trust
= HTTP_TRUST_OK
;
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 */
438 return (HTTP_TRUST_UNKNOWN
);
440 if ((cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
))) == NULL
)
441 return (HTTP_TRUST_UNKNOWN
);
443 if (cg
->any_root
< 0)
446 http_gnutls_load_crl();
450 * Look this common name up in the default keychains...
453 httpLoadCredentials(NULL
, &tcreds
, common_name
);
457 char credentials_str
[1024], /* String for incoming credentials */
458 tcreds_str
[1024]; /* String for saved credentials */
460 httpCredentialsString(credentials
, credentials_str
, sizeof(credentials_str
));
461 httpCredentialsString(tcreds
, tcreds_str
, sizeof(tcreds_str
));
463 if (strcmp(credentials_str
, tcreds_str
))
466 * Credentials don't match, let's look at the expiration date of the new
467 * credentials and allow if the new ones have a later expiration...
470 if (!cg
->trust_first
)
473 * Do not trust certificates on first use...
476 trust
= HTTP_TRUST_INVALID
;
478 else if (httpCredentialsGetExpiration(credentials
) <= httpCredentialsGetExpiration(tcreds
) || !httpCredentialsAreValidForName(credentials
, common_name
))
481 * Either the new credentials are not newly issued, or the common name
482 * does not match the issued certificate...
485 trust
= HTTP_TRUST_INVALID
;
487 else if (httpCredentialsGetExpiration(tcreds
) < time(NULL
))
490 * Save the renewed credentials...
493 trust
= HTTP_TRUST_RENEWED
;
495 httpSaveCredentials(NULL
, credentials
, common_name
);
499 httpFreeCredentials(tcreds
);
501 else if (cg
->validate_certs
&& !httpCredentialsAreValidForName(credentials
, common_name
))
502 trust
= HTTP_TRUST_INVALID
;
504 if (trust
== HTTP_TRUST_OK
&& !cg
->expired_certs
)
506 time_t curtime
; /* Current date/time */
509 if (curtime
< gnutls_x509_crt_get_activation_time(cert
) ||
510 curtime
> gnutls_x509_crt_get_expiration_time(cert
))
511 trust
= HTTP_TRUST_EXPIRED
;
514 if (trust
== HTTP_TRUST_OK
&& !cg
->any_root
&& cupsArrayCount(credentials
) == 1)
515 trust
= HTTP_TRUST_INVALID
;
517 gnutls_x509_crt_deinit(cert
);
524 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
526 * @since CUPS 2.0/OS 10.10@
529 time_t /* O - Expiration date of credentials */
530 httpCredentialsGetExpiration(
531 cups_array_t
*credentials
) /* I - Credentials */
533 gnutls_x509_crt_t cert
; /* Certificate */
534 time_t result
= 0; /* Result */
537 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
540 result
= gnutls_x509_crt_get_expiration_time(cert
);
541 gnutls_x509_crt_deinit(cert
);
549 * 'httpCredentialsString()' - Return a string representing the credentials.
551 * @since CUPS 2.0/OS 10.10@
554 size_t /* O - Total size of credentials string */
555 httpCredentialsString(
556 cups_array_t
*credentials
, /* I - Credentials */
557 char *buffer
, /* I - Buffer or @code NULL@ */
558 size_t bufsize
) /* I - Size of buffer */
560 http_credential_t
*first
; /* First certificate */
561 gnutls_x509_crt_t cert
; /* Certificate */
564 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
569 if (buffer
&& bufsize
> 0)
572 if ((first
= (http_credential_t
*)cupsArrayFirst(credentials
)) != NULL
&&
573 (cert
= http_gnutls_create_credential(first
)) != NULL
)
575 char name
[256]; /* Common name associated with cert */
576 size_t namelen
; /* Length of name */
577 time_t expiration
; /* Expiration date of cert */
578 _cups_md5_state_t md5_state
; /* MD5 state */
579 unsigned char md5_digest
[16]; /* MD5 result */
581 namelen
= sizeof(name
) - 1;
582 if (gnutls_x509_crt_get_dn_by_oid(cert
, GNUTLS_OID_X520_COMMON_NAME
, 0, 0, name
, &namelen
) >= 0)
583 name
[namelen
] = '\0';
585 strlcpy(name
, "unknown", sizeof(name
));
587 expiration
= gnutls_x509_crt_get_expiration_time(cert
);
589 _cupsMD5Init(&md5_state
);
590 _cupsMD5Append(&md5_state
, first
->data
, (int)first
->datalen
);
591 _cupsMD5Finish(&md5_state
, md5_digest
);
593 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]);
595 gnutls_x509_crt_deinit(cert
);
598 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
600 return (strlen(buffer
));
605 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
607 * @since CUPS 2.0/OS 10.10@
610 int /* O - 0 on success, -1 on error */
612 const char *path
, /* I - Keychain/PKCS#12 path */
613 cups_array_t
**credentials
, /* IO - Credentials */
614 const char *common_name
) /* I - Common name for credentials */
616 cups_file_t
*fp
; /* Certificate file */
617 char filename
[1024], /* filename.crt */
618 temp
[1024], /* Temporary string */
619 line
[256]; /* Base64-encoded line */
620 unsigned char *data
= NULL
; /* Buffer for cert data */
621 size_t alloc_data
= 0, /* Bytes allocated */
622 num_data
= 0; /* Bytes used */
623 int decoded
; /* Bytes decoded */
626 if (!credentials
|| !common_name
)
630 path
= http_gnutls_default_path(temp
, sizeof(temp
));
634 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
636 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
639 while (cupsFileGets(fp
, line
, sizeof(line
)))
641 if (!strcmp(line
, "-----BEGIN CERTIFICATE-----"))
646 * Missing END CERTIFICATE...
649 httpFreeCredentials(*credentials
);
654 else if (!strcmp(line
, "-----END CERTIFICATE-----"))
662 httpFreeCredentials(*credentials
);
668 *credentials
= cupsArrayNew(NULL
, NULL
);
670 if (httpAddCredential(*credentials
, data
, num_data
))
672 httpFreeCredentials(*credentials
);
689 else if ((num_data
+ strlen(line
)) >= alloc_data
)
691 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
692 /* Expanded buffer */
696 httpFreeCredentials(*credentials
);
705 decoded
= alloc_data
- num_data
;
706 httpDecode64_2((char *)data
+ num_data
, &decoded
, line
);
707 num_data
+= (size_t)decoded
;
716 * Missing END CERTIFICATE...
719 httpFreeCredentials(*credentials
);
726 return (*credentials
? 0 : -1);
731 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
733 * @since CUPS 2.0/OS 10.10@
736 int /* O - -1 on error, 0 on success */
738 const char *path
, /* I - Keychain/PKCS#12 path */
739 cups_array_t
*credentials
, /* I - Credentials */
740 const char *common_name
) /* I - Common name for credentials */
742 cups_file_t
*fp
; /* Certificate file */
743 char filename
[1024], /* filename.crt */
744 nfilename
[1024],/* filename.crt.N */
745 temp
[1024], /* Temporary string */
746 line
[256]; /* Base64-encoded line */
747 const unsigned char *ptr
; /* Pointer into certificate */
748 ssize_t remaining
; /* Bytes left */
749 http_credential_t
*cred
; /* Current credential */
752 if (!credentials
|| !common_name
)
756 path
= http_gnutls_default_path(temp
, sizeof(temp
));
760 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
761 snprintf(nfilename
, sizeof(nfilename
), "%s.N", filename
);
763 if ((fp
= cupsFileOpen(nfilename
, "w")) == NULL
)
766 fchmod(cupsFileNumber(fp
), 0600);
768 for (cred
= (http_credential_t
*)cupsArrayFirst(credentials
);
770 cred
= (http_credential_t
*)cupsArrayNext(credentials
))
772 cupsFilePuts(fp
, "-----BEGIN CERTIFICATE-----\n");
773 for (ptr
= cred
->data
, remaining
= (ssize_t
)cred
->datalen
; remaining
> 0; remaining
-= 45, ptr
+= 45)
775 httpEncode64_2(line
, sizeof(line
), (char *)ptr
, remaining
> 45 ? 45 : remaining
);
776 cupsFilePrintf(fp
, "%s\n", line
);
778 cupsFilePuts(fp
, "-----END CERTIFICATE-----\n");
783 return (rename(nfilename
, filename
));
788 * 'http_gnutls_create_credential()' - Create a single credential in the internal format.
791 static gnutls_x509_crt_t
/* O - Certificate */
792 http_gnutls_create_credential(
793 http_credential_t
*credential
) /* I - Credential */
795 int result
; /* Result from GNU TLS */
796 gnutls_x509_crt_t cert
; /* Certificate */
797 gnutls_datum_t datum
; /* Data record */
800 DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential
));
805 if ((result
= gnutls_x509_crt_init(&cert
)) < 0)
807 DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result
)));
811 datum
.data
= credential
->data
;
812 datum
.size
= credential
->datalen
;
814 if ((result
= gnutls_x509_crt_import(cert
, &datum
, GNUTLS_X509_FMT_DER
)) < 0)
816 DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result
)));
818 gnutls_x509_crt_deinit(cert
);
827 * 'http_gnutls_default_path()' - Get the default credential store path.
830 static const char * /* O - Path or NULL on error */
831 http_gnutls_default_path(char *buffer
,/* I - Path buffer */
832 size_t bufsize
)/* I - Size of path buffer */
834 const char *home
= getenv("HOME"); /* HOME environment variable */
837 if (getuid() && home
)
839 snprintf(buffer
, bufsize
, "%s/.cups", home
);
840 if (access(buffer
, 0))
842 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
843 if (mkdir(buffer
, 0700))
845 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
850 snprintf(buffer
, bufsize
, "%s/.cups/ssl", home
);
851 if (access(buffer
, 0))
853 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
854 if (mkdir(buffer
, 0700))
856 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
862 strlcpy(buffer
, CUPS_SERVERROOT
"/ssl", bufsize
);
864 DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer
));
871 * 'http_gnutls_load_crl()' - Load the certificate revocation list, if any.
875 http_gnutls_load_crl(void)
877 _cupsMutexLock(&tls_mutex
);
879 if (!gnutls_x509_crl_init(&tls_crl
))
881 cups_file_t
*fp
; /* CRL file */
882 char filename
[1024], /* site.crl */
883 line
[256]; /* Base64-encoded line */
884 unsigned char *data
= NULL
; /* Buffer for cert data */
885 size_t alloc_data
= 0, /* Bytes allocated */
886 num_data
= 0; /* Bytes used */
887 int decoded
; /* Bytes decoded */
888 gnutls_datum_t datum
; /* Data record */
891 http_gnutls_make_path(filename
, sizeof(filename
), CUPS_SERVERROOT
, "site", "crl");
893 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
895 while (cupsFileGets(fp
, line
, sizeof(line
)))
897 if (!strcmp(line
, "-----BEGIN X509 CRL-----"))
902 * Missing END X509 CRL...
908 else if (!strcmp(line
, "-----END X509 CRL-----"))
920 datum
.size
= num_data
;
922 gnutls_x509_crl_import(tls_crl
, &datum
, GNUTLS_X509_FMT_PEM
);
936 else if ((num_data
+ strlen(line
)) >= alloc_data
)
938 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
939 /* Expanded buffer */
948 decoded
= alloc_data
- num_data
;
949 httpDecode64_2((char *)data
+ num_data
, &decoded
, line
);
950 num_data
+= (size_t)decoded
;
961 _cupsMutexUnlock(&tls_mutex
);
966 * 'http_gnutls_make_path()' - Format a filename for a certificate or key file.
969 static const char * /* O - Filename */
970 http_gnutls_make_path(
971 char *buffer
, /* I - Filename buffer */
972 size_t bufsize
, /* I - Size of buffer */
973 const char *dirname
, /* I - Directory */
974 const char *filename
, /* I - Filename (usually hostname) */
975 const char *ext
) /* I - Extension */
977 char *bufptr
, /* Pointer into buffer */
978 *bufend
= buffer
+ bufsize
- 1; /* End of buffer */
981 snprintf(buffer
, bufsize
, "%s/", dirname
);
982 bufptr
= buffer
+ strlen(buffer
);
984 while (*filename
&& bufptr
< bufend
)
986 if (_cups_isalnum(*filename
) || *filename
== '-' || *filename
== '.')
987 *bufptr
++ = *filename
;
997 strlcpy(bufptr
, ext
, (size_t)(bufend
- bufptr
+ 1));
1004 * 'http_gnutls_read()' - Read function for the GNU TLS library.
1007 static ssize_t
/* O - Number of bytes read or -1 on error */
1009 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
1010 void *data
, /* I - Buffer */
1011 size_t length
) /* I - Number of bytes to read */
1013 http_t
*http
; /* HTTP connection */
1014 ssize_t bytes
; /* Bytes read */
1017 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
1019 http
= (http_t
*)ptr
;
1021 if (!http
->blocking
)
1024 * Make sure we have data before we read...
1027 while (!_httpWait(http
, http
->wait_value
, 0))
1029 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
1032 http
->error
= ETIMEDOUT
;
1037 bytes
= recv(http
->fd
, data
, length
, 0);
1038 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
1044 * 'http_gnutls_write()' - Write function for the GNU TLS library.
1047 static ssize_t
/* O - Number of bytes written or -1 on error */
1049 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
1050 const void *data
, /* I - Data buffer */
1051 size_t length
) /* I - Number of bytes to write */
1053 ssize_t bytes
; /* Bytes written */
1056 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
1058 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
1059 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
1066 * '_httpTLSInitialize()' - Initialize the TLS stack.
1070 _httpTLSInitialize(void)
1073 * Initialize GNU TLS...
1076 gnutls_global_init();
1081 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
1084 size_t /* O - Bytes available */
1085 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
1087 return (gnutls_record_check_pending(http
->tls
));
1092 * '_httpTLSRead()' - Read from a SSL/TLS connection.
1095 int /* O - Bytes read */
1096 _httpTLSRead(http_t
*http
, /* I - Connection to server */
1097 char *buf
, /* I - Buffer to store data */
1098 int len
) /* I - Length of buffer */
1100 ssize_t result
; /* Return value */
1103 result
= gnutls_record_recv(http
->tls
, buf
, (size_t)len
);
1105 if (result
< 0 && !errno
)
1108 * Convert GNU TLS error to errno value...
1113 case GNUTLS_E_INTERRUPTED
:
1117 case GNUTLS_E_AGAIN
:
1129 return ((int)result
);
1134 * '_httpTLSSetCredentials()' - Set the TLS credentials.
1137 int /* O - Status of connection */
1138 _httpTLSSetCredentials(http_t
*http
) /* I - Connection to server */
1147 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
1151 _httpTLSSetOptions(int options
) /* I - Options */
1153 tls_options
= options
;
1158 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
1161 int /* O - 0 on success, -1 on failure */
1162 _httpTLSStart(http_t
*http
) /* I - Connection to server */
1164 char hostname
[256], /* Hostname */
1165 *hostptr
; /* Pointer into hostname */
1166 int status
; /* Status of handshake */
1167 gnutls_certificate_credentials_t
*credentials
;
1168 /* TLS credentials */
1169 char priority_string
[1024];
1170 /* Priority string */
1173 DEBUG_printf(("3_httpTLSStart(http=%p)", http
));
1175 if (tls_options
< 0)
1177 DEBUG_puts("4_httpTLSStart: Setting defaults.");
1179 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options
));
1182 if (http
->mode
== _HTTP_MODE_SERVER
&& !tls_keypath
)
1184 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
1185 http
->error
= errno
= EINVAL
;
1186 http
->status
= HTTP_STATUS_ERROR
;
1187 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Server credentials not set."), 1);
1192 credentials
= (gnutls_certificate_credentials_t
*)
1193 malloc(sizeof(gnutls_certificate_credentials_t
));
1194 if (credentials
== NULL
)
1196 DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
1198 http
->error
= errno
;
1199 http
->status
= HTTP_STATUS_ERROR
;
1200 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
1205 gnutls_certificate_allocate_credentials(credentials
);
1206 status
= gnutls_init(&http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_CLIENT
: GNUTLS_SERVER
);
1208 status
= gnutls_set_default_priority(http
->tls
);
1213 http
->status
= HTTP_STATUS_ERROR
;
1215 DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status
)));
1216 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1218 gnutls_deinit(http
->tls
);
1219 gnutls_certificate_free_credentials(*credentials
);
1226 if (http
->mode
== _HTTP_MODE_CLIENT
)
1229 * Client: get the hostname to use for TLS...
1232 if (httpAddrLocalhost(http
->hostaddr
))
1234 strlcpy(hostname
, "localhost", sizeof(hostname
));
1239 * Otherwise make sure the hostname we have does not end in a trailing dot.
1242 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1243 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1248 status
= gnutls_server_name_set(http
->tls
, GNUTLS_NAME_DNS
, hostname
, strlen(hostname
));
1253 * Server: get certificate and private key...
1256 char crtfile
[1024], /* Certificate file */
1257 keyfile
[1024]; /* Private key file */
1258 int have_creds
= 0; /* Have credentials? */
1260 if (http
->fields
[HTTP_FIELD_HOST
][0])
1263 * Use hostname for TLS upgrade...
1266 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
1271 * Resolve hostname from connection address...
1274 http_addr_t addr
; /* Connection address */
1275 socklen_t addrlen
; /* Length of address */
1277 addrlen
= sizeof(addr
);
1278 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
1280 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
1283 else if (httpAddrLocalhost(&addr
))
1287 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
1288 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
1292 if (isdigit(hostname
[0] & 255) || hostname
[0] == '[')
1293 hostname
[0] = '\0'; /* Don't allow numeric addresses */
1298 * First look for CA certs...
1301 snprintf(crtfile
, sizeof(crtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostname
);
1302 snprintf(keyfile
, sizeof(keyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostname
);
1304 if ((access(crtfile
, R_OK
) || access(keyfile
, R_OK
)) && (hostptr
= strchr(hostname
, '.')) != NULL
)
1307 * Try just domain name...
1311 if (strchr(hostptr
, '.'))
1313 snprintf(crtfile
, sizeof(crtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr
);
1314 snprintf(keyfile
, sizeof(keyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostptr
);
1318 if (access(crtfile
, R_OK
) || access(keyfile
, R_OK
))
1321 * Then look in the CUPS keystore...
1324 http_gnutls_make_path(crtfile
, sizeof(crtfile
), tls_keypath
, hostname
, "crt");
1325 http_gnutls_make_path(keyfile
, sizeof(keyfile
), tls_keypath
, hostname
, "key");
1328 have_creds
= !access(crtfile
, R_OK
) && !access(keyfile
, R_OK
);
1330 else if (tls_common_name
)
1333 * First look for CA certs...
1336 snprintf(crtfile
, sizeof(crtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", tls_common_name
);
1337 snprintf(keyfile
, sizeof(keyfile
), "/etc/letsencrypt/live/%s/privkey.pem", tls_common_name
);
1339 if ((access(crtfile
, R_OK
) || access(keyfile
, R_OK
)) && (hostptr
= strchr(tls_common_name
, '.')) != NULL
)
1342 * Try just domain name...
1346 if (strchr(hostptr
, '.'))
1348 snprintf(crtfile
, sizeof(crtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr
);
1349 snprintf(keyfile
, sizeof(keyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostptr
);
1353 if (access(crtfile
, R_OK
) || access(keyfile
, R_OK
))
1356 * Then look in the CUPS keystore...
1359 http_gnutls_make_path(crtfile
, sizeof(crtfile
), tls_keypath
, tls_common_name
, "crt");
1360 http_gnutls_make_path(keyfile
, sizeof(keyfile
), tls_keypath
, tls_common_name
, "key");
1363 have_creds
= !access(crtfile
, R_OK
) && !access(keyfile
, R_OK
);
1366 if (!have_creds
&& tls_auto_create
&& (hostname
[0] || tls_common_name
))
1368 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname
[0] ? hostname
: tls_common_name
));
1370 if (!cupsMakeServerCredentials(tls_keypath
, hostname
[0] ? hostname
: tls_common_name
, 0, NULL
, time(NULL
) + 365 * 86400))
1372 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
1373 http
->error
= errno
= EINVAL
;
1374 http
->status
= HTTP_STATUS_ERROR
;
1375 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unable to create server credentials."), 1);
1381 DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile
, keyfile
));
1384 status
= gnutls_certificate_set_x509_key_file(*credentials
, crtfile
, keyfile
, GNUTLS_X509_FMT_PEM
);
1388 status
= gnutls_credentials_set(http
->tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
1393 http
->status
= HTTP_STATUS_ERROR
;
1395 DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status
)));
1396 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1398 gnutls_deinit(http
->tls
);
1399 gnutls_certificate_free_credentials(*credentials
);
1406 strlcpy(priority_string
, "NORMAL", sizeof(priority_string
));
1408 if (tls_options
& _HTTP_TLS_DENY_TLS10
)
1409 strlcat(priority_string
, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string
));
1410 else if (tls_options
& _HTTP_TLS_ALLOW_SSL3
)
1411 strlcat(priority_string
, ":+VERS-TLS-ALL", sizeof(priority_string
));
1413 strlcat(priority_string
, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string
));
1415 if (!(tls_options
& _HTTP_TLS_ALLOW_RC4
))
1416 strlcat(priority_string
, ":-ARCFOUR-128", sizeof(priority_string
));
1418 if (!(tls_options
& _HTTP_TLS_ALLOW_DH
))
1419 strlcat(priority_string
, ":!ANON-DH", sizeof(priority_string
));
1421 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
1422 gnutls_priority_set_direct(http
->tls
, priority_string
, NULL
);
1425 gnutls_priority_t priority
; /* Priority */
1427 gnutls_priority_init(&priority
, priority_string
, NULL
);
1428 gnutls_priority_set(http
->tls
, priority
);
1429 gnutls_priority_deinit(priority
);
1430 #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */
1432 gnutls_transport_set_ptr(http
->tls
, (gnutls_transport_ptr_t
)http
);
1433 gnutls_transport_set_pull_function(http
->tls
, http_gnutls_read
);
1434 #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION
1435 gnutls_transport_set_pull_timeout_function(http
->tls
, (gnutls_pull_timeout_func
)httpWait
);
1436 #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */
1437 gnutls_transport_set_push_function(http
->tls
, http_gnutls_write
);
1439 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
1441 DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
1442 status
, gnutls_strerror(status
)));
1444 if (gnutls_error_is_fatal(status
))
1447 http
->status
= HTTP_STATUS_ERROR
;
1449 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1451 gnutls_deinit(http
->tls
);
1452 gnutls_certificate_free_credentials(*credentials
);
1460 http
->tls_credentials
= credentials
;
1467 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1471 _httpTLSStop(http_t
*http
) /* I - Connection to server */
1473 int error
; /* Error code */
1476 error
= gnutls_bye(http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
1477 if (error
!= GNUTLS_E_SUCCESS
)
1478 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(errno
), 0);
1480 gnutls_deinit(http
->tls
);
1483 if (http
->tls_credentials
)
1485 gnutls_certificate_free_credentials(*(http
->tls_credentials
));
1486 free(http
->tls_credentials
);
1487 http
->tls_credentials
= NULL
;
1493 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1496 int /* O - Bytes written */
1497 _httpTLSWrite(http_t
*http
, /* I - Connection to server */
1498 const char *buf
, /* I - Buffer holding data */
1499 int len
) /* I - Length of buffer */
1501 ssize_t result
; /* Return value */
1504 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
1506 result
= gnutls_record_send(http
->tls
, buf
, (size_t)len
);
1508 if (result
< 0 && !errno
)
1511 * Convert GNU TLS error to errno value...
1516 case GNUTLS_E_INTERRUPTED
:
1520 case GNUTLS_E_AGAIN
:
1532 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
1534 return ((int)result
);