2 * TLS support code for CUPS using GNU TLS.
4 * Copyright © 2007-2019 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
11 /**** This file is included from tls.c ****/
14 * Include necessary headers...
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
;
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
);
51 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
53 * @since CUPS 2.0/OS 10.10@
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 */
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 */
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
));
85 path
= http_gnutls_default_path(temp
, sizeof(temp
));
87 if (!path
|| !common_name
)
89 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
93 http_gnutls_make_path(crtfile
, sizeof(crtfile
), path
, common_name
, "crt");
94 http_gnutls_make_path(keyfile
, sizeof(keyfile
), path
, common_name
, "key");
97 * Create the encryption key...
100 DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");
102 gnutls_x509_privkey_init(&key
);
103 gnutls_x509_privkey_generate(key
, GNUTLS_PK_RSA
, 2048, 0);
105 DEBUG_puts("1cupsMakeServerCredentials: Key pair created.");
111 bytes
= sizeof(buffer
);
113 if ((result
= gnutls_x509_privkey_export(key
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
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
);
120 else if ((fp
= cupsFileOpen(keyfile
, "w")) != NULL
)
122 DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile
));
123 cupsFileWrite(fp
, (char *)buffer
, bytes
);
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
);
135 * Create the self-signed certificate...
138 DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate.");
140 language
= cupsLangDefault();
141 curtime
= time(NULL
);
142 serial
[0] = curtime
>> 24;
143 serial
[1] = curtime
>> 16;
144 serial
[2] = curtime
>> 8;
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);
152 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
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
,
160 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME
, 0,
162 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_LOCALITY_NAME
, 0,
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
, '.'))
175 * Add common_name.local to the list, too...
178 char localname
[256]; /* hostname.local */
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
);
183 gnutls_x509_crt_set_subject_alt_name(crt
, GNUTLS_SAN_DNSNAME
, "localhost", 9, GNUTLS_FSAN_APPEND
);
184 if (num_alt_names
> 0)
186 int i
; /* Looping var */
188 for (i
= 0; i
< num_alt_names
; i
++)
190 if (strcmp(alt_names
[i
], "localhost"))
192 gnutls_x509_crt_set_subject_alt_name(crt
, GNUTLS_SAN_DNSNAME
, alt_names
[i
], (unsigned)strlen(alt_names
[i
]), GNUTLS_FSAN_APPEND
);
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);
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
);
204 gnutls_x509_crt_sign(crt
, crt
, key
);
210 bytes
= sizeof(buffer
);
211 if ((result
= gnutls_x509_crt_export(crt
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
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
);
219 else if ((fp
= cupsFileOpen(crtfile
, "w")) != NULL
)
221 DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile
));
222 cupsFileWrite(fp
, (char *)buffer
, bytes
);
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
);
238 gnutls_x509_crt_deinit(crt
);
239 gnutls_x509_privkey_deinit(key
);
241 DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");
248 * 'cupsSetServerCredentials()' - Set the default server credentials.
250 * Note: The server credentials are used by all threads in the running process.
251 * This function is threadsafe.
253 * @since CUPS 2.0/OS 10.10@
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 */
262 char temp
[1024]; /* Default path buffer */
265 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
268 * Use defaults as needed...
272 path
= http_gnutls_default_path(temp
, sizeof(temp
));
275 * Range check input...
278 if (!path
|| !common_name
)
280 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
284 _cupsMutexLock(&tls_mutex
);
291 _cupsStrFree(tls_keypath
);
294 _cupsStrFree(tls_common_name
);
297 * Save the new values...
300 tls_keypath
= _cupsStrAlloc(path
);
301 tls_auto_create
= auto_create
;
302 tls_common_name
= _cupsStrAlloc(common_name
);
304 _cupsMutexUnlock(&tls_mutex
);
311 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
312 * an encrypted connection.
314 * @since CUPS 1.5/macOS 10.7@
317 int /* O - Status of call (0 = success) */
319 http_t
*http
, /* I - Connection to server */
320 cups_array_t
**credentials
) /* O - Array of credentials */
322 unsigned count
; /* Number of certificates */
323 const gnutls_datum_t
*certs
; /* Certificates */
326 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http
, credentials
));
331 if (!http
|| !http
->tls
|| !credentials
)
334 *credentials
= cupsArrayNew(NULL
, NULL
);
335 certs
= gnutls_certificate_get_peers(http
->tls
, &count
);
337 DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs
, count
));
343 httpAddCredential(*credentials
, certs
->data
, certs
->size
);
354 * '_httpCreateCredentials()' - Create credentials in the internal format.
357 http_tls_credentials_t
/* O - Internal credentials */
358 _httpCreateCredentials(
359 cups_array_t
*credentials
) /* I - Array of credentials */
368 * '_httpFreeCredentials()' - Free internal credentials.
372 _httpFreeCredentials(
373 http_tls_credentials_t credentials
) /* I - Internal credentials */
380 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
382 * @since CUPS 2.0/OS 10.10@
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 */
390 gnutls_x509_crt_t cert
; /* Certificate */
391 int result
= 0; /* Result */
394 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
397 result
= gnutls_x509_crt_check_hostname(cert
, common_name
) != 0;
401 gnutls_x509_crl_iter_t iter
= NULL
;
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 */
408 _cupsMutexLock(&tls_mutex
);
410 if (gnutls_x509_crl_get_crt_count(tls_crl
) > 0)
412 cserial_size
= sizeof(cserial
);
413 gnutls_x509_crt_get_serial(cert
, cserial
, &cserial_size
);
415 rserial_size
= sizeof(rserial
);
417 while (!gnutls_x509_crl_iter_crt_serial(tls_crl
, &iter
, rserial
, &rserial_size
, NULL
))
419 if (cserial_size
== rserial_size
&& !memcmp(cserial
, rserial
, rserial_size
))
425 rserial_size
= sizeof(rserial
);
427 gnutls_x509_crl_iter_deinit(iter
);
430 _cupsMutexUnlock(&tls_mutex
);
433 gnutls_x509_crt_deinit(cert
);
441 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
443 * @since CUPS 2.0/OS 10.10@
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 */
451 http_trust_t trust
= HTTP_TRUST_OK
;
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 */
461 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No common name specified."), 1);
462 return (HTTP_TRUST_UNKNOWN
);
465 if ((cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
))) == NULL
)
467 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unable to create credentials from array."), 1);
468 return (HTTP_TRUST_UNKNOWN
);
471 if (cg
->any_root
< 0)
474 http_gnutls_load_crl();
478 * Look this common name up in the default keychains...
481 httpLoadCredentials(NULL
, &tcreds
, common_name
);
485 char credentials_str
[1024], /* String for incoming credentials */
486 tcreds_str
[1024]; /* String for saved credentials */
488 httpCredentialsString(credentials
, credentials_str
, sizeof(credentials_str
));
489 httpCredentialsString(tcreds
, tcreds_str
, sizeof(tcreds_str
));
491 if (strcmp(credentials_str
, tcreds_str
))
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...
498 if (!cg
->trust_first
)
501 * Do not trust certificates on first use...
504 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Trust on first use is disabled."), 1);
506 trust
= HTTP_TRUST_INVALID
;
508 else if (httpCredentialsGetExpiration(credentials
) <= httpCredentialsGetExpiration(tcreds
))
511 * The new credentials are not newly issued...
514 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("New credentials are older than stored credentials."), 1);
516 trust
= HTTP_TRUST_INVALID
;
518 else if (!httpCredentialsAreValidForName(credentials
, common_name
))
521 * The common name does not match the issued certificate...
524 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("New credentials are not valid for name."), 1);
526 trust
= HTTP_TRUST_INVALID
;
528 else if (httpCredentialsGetExpiration(tcreds
) < time(NULL
))
531 * Save the renewed credentials...
534 trust
= HTTP_TRUST_RENEWED
;
536 httpSaveCredentials(NULL
, credentials
, common_name
);
540 httpFreeCredentials(tcreds
);
542 else if (cg
->validate_certs
&& !httpCredentialsAreValidForName(credentials
, common_name
))
544 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No stored credentials, not valid for name."), 1);
545 trust
= HTTP_TRUST_INVALID
;
547 else if (!cg
->trust_first
)
550 * See if we have a site CA certificate we can compare...
553 if (!httpLoadCredentials(NULL
, &tcreds
, "site"))
555 if (cupsArrayCount(credentials
) != (cupsArrayCount(tcreds
) + 1))
558 * Certificate isn't directly generated from the CA cert...
561 trust
= HTTP_TRUST_INVALID
;
566 * Do a tail comparison of the two certificates...
569 http_credential_t
*a
, *b
; /* Certificates */
571 for (a
= (http_credential_t
*)cupsArrayFirst(tcreds
), b
= (http_credential_t
*)cupsArrayIndex(credentials
, 1);
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
))
578 trust
= HTTP_TRUST_INVALID
;
581 if (trust
!= HTTP_TRUST_OK
)
582 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Credentials do not validate against site CA certificate."), 1);
586 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Trust on first use is disabled."), 1);
587 trust
= HTTP_TRUST_INVALID
;
591 if (trust
== HTTP_TRUST_OK
&& !cg
->expired_certs
)
593 time_t curtime
; /* Current date/time */
596 if (curtime
< gnutls_x509_crt_get_activation_time(cert
) ||
597 curtime
> gnutls_x509_crt_get_expiration_time(cert
))
599 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Credentials have expired."), 1);
600 trust
= HTTP_TRUST_EXPIRED
;
604 if (trust
== HTTP_TRUST_OK
&& !cg
->any_root
&& cupsArrayCount(credentials
) == 1)
606 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Self-signed credentials are blocked."), 1);
607 trust
= HTTP_TRUST_INVALID
;
610 gnutls_x509_crt_deinit(cert
);
617 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
619 * @since CUPS 2.0/OS 10.10@
622 time_t /* O - Expiration date of credentials */
623 httpCredentialsGetExpiration(
624 cups_array_t
*credentials
) /* I - Credentials */
626 gnutls_x509_crt_t cert
; /* Certificate */
627 time_t result
= 0; /* Result */
630 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
633 result
= gnutls_x509_crt_get_expiration_time(cert
);
634 gnutls_x509_crt_deinit(cert
);
642 * 'httpCredentialsString()' - Return a string representing the credentials.
644 * @since CUPS 2.0/OS 10.10@
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 */
653 http_credential_t
*first
; /* First certificate */
654 gnutls_x509_crt_t cert
; /* Certificate */
657 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
665 if ((first
= (http_credential_t
*)cupsArrayFirst(credentials
)) != NULL
&&
666 (cert
= http_gnutls_create_credential(first
)) != NULL
)
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 */
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)
679 strlcpy(name
, "unknown", sizeof(name
));
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)
685 strlcpy(issuer
, "unknown", sizeof(issuer
));
687 expiration
= gnutls_x509_crt_get_expiration_time(cert
);
688 sigalg
= gnutls_x509_crt_get_signature_algorithm(cert
);
690 cupsHashData("md5", first
->data
, first
->datalen
, md5_digest
, sizeof(md5_digest
));
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]);
694 gnutls_x509_crt_deinit(cert
);
697 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
699 return (strlen(buffer
));
704 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
706 * @since CUPS 2.0/OS 10.10@
709 int /* O - 0 on success, -1 on error */
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 */
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? */
727 if (!credentials
|| !common_name
)
731 path
= http_gnutls_default_path(temp
, sizeof(temp
));
735 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
737 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
740 while (cupsFileGets(fp
, line
, sizeof(line
)))
742 if (!strcmp(line
, "-----BEGIN CERTIFICATE-----"))
747 * Missing END CERTIFICATE...
750 httpFreeCredentials(*credentials
);
757 else if (!strcmp(line
, "-----END CERTIFICATE-----"))
759 if (!in_certificate
|| !num_data
)
765 httpFreeCredentials(*credentials
);
771 *credentials
= cupsArrayNew(NULL
, NULL
);
773 if (httpAddCredential(*credentials
, data
, num_data
))
775 httpFreeCredentials(*credentials
);
783 else if (in_certificate
)
793 else if ((num_data
+ strlen(line
)) >= alloc_data
)
795 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
796 /* Expanded buffer */
800 httpFreeCredentials(*credentials
);
809 decoded
= alloc_data
- num_data
;
810 httpDecode64_2((char *)data
+ num_data
, &decoded
, line
);
811 num_data
+= (size_t)decoded
;
820 * Missing END CERTIFICATE...
823 httpFreeCredentials(*credentials
);
830 return (*credentials
? 0 : -1);
835 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
837 * @since CUPS 2.0/OS 10.10@
840 int /* O - -1 on error, 0 on success */
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 */
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 */
856 if (!credentials
|| !common_name
)
860 path
= http_gnutls_default_path(temp
, sizeof(temp
));
864 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
865 snprintf(nfilename
, sizeof(nfilename
), "%s.N", filename
);
867 if ((fp
= cupsFileOpen(nfilename
, "w")) == NULL
)
870 fchmod(cupsFileNumber(fp
), 0600);
872 for (cred
= (http_credential_t
*)cupsArrayFirst(credentials
);
874 cred
= (http_credential_t
*)cupsArrayNext(credentials
))
876 cupsFilePuts(fp
, "-----BEGIN CERTIFICATE-----\n");
877 for (ptr
= cred
->data
, remaining
= (ssize_t
)cred
->datalen
; remaining
> 0; remaining
-= 45, ptr
+= 45)
879 httpEncode64_2(line
, sizeof(line
), (char *)ptr
, remaining
> 45 ? 45 : remaining
);
880 cupsFilePrintf(fp
, "%s\n", line
);
882 cupsFilePuts(fp
, "-----END CERTIFICATE-----\n");
887 return (rename(nfilename
, filename
));
892 * 'http_gnutls_create_credential()' - Create a single credential in the internal format.
895 static gnutls_x509_crt_t
/* O - Certificate */
896 http_gnutls_create_credential(
897 http_credential_t
*credential
) /* I - Credential */
899 int result
; /* Result from GNU TLS */
900 gnutls_x509_crt_t cert
; /* Certificate */
901 gnutls_datum_t datum
; /* Data record */
904 DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential
));
909 if ((result
= gnutls_x509_crt_init(&cert
)) < 0)
911 DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result
)));
915 datum
.data
= credential
->data
;
916 datum
.size
= credential
->datalen
;
918 if ((result
= gnutls_x509_crt_import(cert
, &datum
, GNUTLS_X509_FMT_DER
)) < 0)
920 DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result
)));
922 gnutls_x509_crt_deinit(cert
);
931 * 'http_gnutls_default_path()' - Get the default credential store path.
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 */
938 _cups_globals_t
*cg
= _cupsGlobals();
939 /* Pointer to library globals */
942 if (cg
->home
&& getuid())
944 snprintf(buffer
, bufsize
, "%s/.cups", cg
->home
);
945 if (access(buffer
, 0))
947 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
948 if (mkdir(buffer
, 0700))
950 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
955 snprintf(buffer
, bufsize
, "%s/.cups/ssl", cg
->home
);
956 if (access(buffer
, 0))
958 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
959 if (mkdir(buffer
, 0700))
961 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
967 strlcpy(buffer
, CUPS_SERVERROOT
"/ssl", bufsize
);
969 DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer
));
976 * 'http_gnutls_load_crl()' - Load the certificate revocation list, if any.
980 http_gnutls_load_crl(void)
982 _cupsMutexLock(&tls_mutex
);
984 if (!gnutls_x509_crl_init(&tls_crl
))
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 */
996 http_gnutls_make_path(filename
, sizeof(filename
), CUPS_SERVERROOT
, "site", "crl");
998 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
1000 while (cupsFileGets(fp
, line
, sizeof(line
)))
1002 if (!strcmp(line
, "-----BEGIN X509 CRL-----"))
1007 * Missing END X509 CRL...
1013 else if (!strcmp(line
, "-----END X509 CRL-----"))
1025 datum
.size
= num_data
;
1027 gnutls_x509_crl_import(tls_crl
, &datum
, GNUTLS_X509_FMT_PEM
);
1033 if (alloc_data
== 0)
1035 data
= malloc(2048);
1041 else if ((num_data
+ strlen(line
)) >= alloc_data
)
1043 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
1044 /* Expanded buffer */
1053 decoded
= alloc_data
- num_data
;
1054 httpDecode64_2((char *)data
+ num_data
, &decoded
, line
);
1055 num_data
+= (size_t)decoded
;
1066 _cupsMutexUnlock(&tls_mutex
);
1071 * 'http_gnutls_make_path()' - Format a filename for a certificate or key file.
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 */
1082 char *bufptr
, /* Pointer into buffer */
1083 *bufend
= buffer
+ bufsize
- 1; /* End of buffer */
1086 snprintf(buffer
, bufsize
, "%s/", dirname
);
1087 bufptr
= buffer
+ strlen(buffer
);
1089 while (*filename
&& bufptr
< bufend
)
1091 if (_cups_isalnum(*filename
) || *filename
== '-' || *filename
== '.')
1092 *bufptr
++ = *filename
;
1099 if (bufptr
< bufend
)
1102 strlcpy(bufptr
, ext
, (size_t)(bufend
- bufptr
+ 1));
1109 * 'http_gnutls_read()' - Read function for the GNU TLS library.
1112 static ssize_t
/* O - Number of bytes read or -1 on error */
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 */
1118 http_t
*http
; /* HTTP connection */
1119 ssize_t bytes
; /* Bytes read */
1122 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
1124 http
= (http_t
*)ptr
;
1126 if (!http
->blocking
|| http
->timeout_value
> 0.0)
1129 * Make sure we have data before we read...
1132 while (!_httpWait(http
, http
->wait_value
, 0))
1134 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
1137 http
->error
= ETIMEDOUT
;
1142 bytes
= recv(http
->fd
, data
, length
, 0);
1143 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
1149 * 'http_gnutls_write()' - Write function for the GNU TLS library.
1152 static ssize_t
/* O - Number of bytes written or -1 on error */
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 */
1158 ssize_t bytes
; /* Bytes written */
1161 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
1163 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
1164 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
1171 * '_httpTLSInitialize()' - Initialize the TLS stack.
1175 _httpTLSInitialize(void)
1178 * Initialize GNU TLS...
1181 gnutls_global_init();
1186 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
1189 size_t /* O - Bytes available */
1190 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
1192 return (gnutls_record_check_pending(http
->tls
));
1197 * '_httpTLSRead()' - Read from a SSL/TLS connection.
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 */
1205 ssize_t result
; /* Return value */
1208 result
= gnutls_record_recv(http
->tls
, buf
, (size_t)len
);
1210 if (result
< 0 && !errno
)
1213 * Convert GNU TLS error to errno value...
1218 case GNUTLS_E_INTERRUPTED
:
1222 case GNUTLS_E_AGAIN
:
1234 return ((int)result
);
1239 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
1243 _httpTLSSetOptions(int options
, /* I - Options */
1244 int min_version
, /* I - Minimum TLS version */
1245 int max_version
) /* I - Maximum TLS version */
1247 if (!(options
& _HTTP_TLS_SET_DEFAULT
) || tls_options
< 0)
1249 tls_options
= options
;
1250 tls_min_version
= min_version
;
1251 tls_max_version
= max_version
;
1257 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
1260 int /* O - 0 on success, -1 on failure */
1261 _httpTLSStart(http_t
*http
) /* I - Connection to server */
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 */
1285 DEBUG_printf(("3_httpTLSStart(http=%p)", http
));
1287 if (tls_options
< 0)
1289 DEBUG_puts("4_httpTLSStart: Setting defaults.");
1291 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options
));
1294 if (http
->mode
== _HTTP_MODE_SERVER
&& !tls_keypath
)
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);
1304 credentials
= (gnutls_certificate_credentials_t
*)
1305 malloc(sizeof(gnutls_certificate_credentials_t
));
1306 if (credentials
== NULL
)
1308 DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
1310 http
->error
= errno
;
1311 http
->status
= HTTP_STATUS_ERROR
;
1312 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
1317 gnutls_certificate_allocate_credentials(credentials
);
1318 status
= gnutls_init(&http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_CLIENT
: GNUTLS_SERVER
);
1320 status
= gnutls_set_default_priority(http
->tls
);
1325 http
->status
= HTTP_STATUS_ERROR
;
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);
1330 gnutls_deinit(http
->tls
);
1331 gnutls_certificate_free_credentials(*credentials
);
1338 if (http
->mode
== _HTTP_MODE_CLIENT
)
1341 * Client: get the hostname to use for TLS...
1344 if (httpAddrLocalhost(http
->hostaddr
))
1346 strlcpy(hostname
, "localhost", sizeof(hostname
));
1351 * Otherwise make sure the hostname we have does not end in a trailing dot.
1354 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1355 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1360 status
= gnutls_server_name_set(http
->tls
, GNUTLS_NAME_DNS
, hostname
, strlen(hostname
));
1365 * Server: get certificate and private key...
1368 char crtfile
[1024], /* Certificate file */
1369 keyfile
[1024]; /* Private key file */
1370 int have_creds
= 0; /* Have credentials? */
1372 if (http
->fields
[HTTP_FIELD_HOST
])
1375 * Use hostname for TLS upgrade...
1378 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
1383 * Resolve hostname from connection address...
1386 http_addr_t addr
; /* Connection address */
1387 socklen_t addrlen
; /* Length of address */
1389 addrlen
= sizeof(addr
);
1390 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
1392 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
1395 else if (httpAddrLocalhost(&addr
))
1399 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
1400 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
1404 if (isdigit(hostname
[0] & 255) || hostname
[0] == '[')
1405 hostname
[0] = '\0'; /* Don't allow numeric addresses */
1410 * First look in the CUPS keystore...
1413 http_gnutls_make_path(crtfile
, sizeof(crtfile
), tls_keypath
, hostname
, "crt");
1414 http_gnutls_make_path(keyfile
, sizeof(keyfile
), tls_keypath
, hostname
, "key");
1416 if (access(crtfile
, R_OK
) || access(keyfile
, R_OK
))
1419 * No CUPS-managed certs, look for CA certs...
1422 char cacrtfile
[1024], cakeyfile
[1024]; /* CA cert files */
1424 snprintf(cacrtfile
, sizeof(cacrtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostname
);
1425 snprintf(cakeyfile
, sizeof(cakeyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostname
);
1427 if ((access(cacrtfile
, R_OK
) || access(cakeyfile
, R_OK
)) && (hostptr
= strchr(hostname
, '.')) != NULL
)
1430 * Try just domain name...
1434 if (strchr(hostptr
, '.'))
1436 snprintf(cacrtfile
, sizeof(cacrtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr
);
1437 snprintf(cakeyfile
, sizeof(cakeyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostptr
);
1441 if (!access(cacrtfile
, R_OK
) && !access(cakeyfile
, R_OK
))
1444 * Use the CA certs...
1447 strlcpy(crtfile
, cacrtfile
, sizeof(crtfile
));
1448 strlcpy(keyfile
, cakeyfile
, sizeof(keyfile
));
1452 have_creds
= !access(crtfile
, R_OK
) && !access(keyfile
, R_OK
);
1454 else if (tls_common_name
)
1457 * First look in the CUPS keystore...
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");
1463 if (access(crtfile
, R_OK
) || access(keyfile
, R_OK
))
1466 * No CUPS-managed certs, look for CA certs...
1469 char cacrtfile
[1024], cakeyfile
[1024]; /* CA cert files */
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
);
1474 if ((access(cacrtfile
, R_OK
) || access(cakeyfile
, R_OK
)) && (hostptr
= strchr(tls_common_name
, '.')) != NULL
)
1477 * Try just domain name...
1481 if (strchr(hostptr
, '.'))
1483 snprintf(cacrtfile
, sizeof(cacrtfile
), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr
);
1484 snprintf(cakeyfile
, sizeof(cakeyfile
), "/etc/letsencrypt/live/%s/privkey.pem", hostptr
);
1488 if (!access(cacrtfile
, R_OK
) && !access(cakeyfile
, R_OK
))
1491 * Use the CA certs...
1494 strlcpy(crtfile
, cacrtfile
, sizeof(crtfile
));
1495 strlcpy(keyfile
, cakeyfile
, sizeof(keyfile
));
1499 have_creds
= !access(crtfile
, R_OK
) && !access(keyfile
, R_OK
);
1502 if (!have_creds
&& tls_auto_create
&& (hostname
[0] || tls_common_name
))
1504 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname
[0] ? hostname
: tls_common_name
));
1506 if (!cupsMakeServerCredentials(tls_keypath
, hostname
[0] ? hostname
: tls_common_name
, 0, NULL
, time(NULL
) + 365 * 86400))
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);
1517 DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile
, keyfile
));
1519 status
= gnutls_certificate_set_x509_key_file(*credentials
, crtfile
, keyfile
, GNUTLS_X509_FMT_PEM
);
1523 status
= gnutls_credentials_set(http
->tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
1528 http
->status
= HTTP_STATUS_ERROR
;
1530 DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status
)));
1531 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1533 gnutls_deinit(http
->tls
);
1534 gnutls_certificate_free_credentials(*credentials
);
1541 strlcpy(priority_string
, "NORMAL", sizeof(priority_string
));
1543 if (tls_max_version
< _HTTP_TLS_MAX
)
1546 * Require specific TLS versions...
1549 strlcat(priority_string
, ":-VERS-TLS-ALL", sizeof(priority_string
));
1550 for (version
= tls_min_version
; version
<= tls_max_version
; version
++)
1552 strlcat(priority_string
, ":+", sizeof(priority_string
));
1553 strlcat(priority_string
, versions
[version
], sizeof(priority_string
));
1556 else if (tls_min_version
== _HTTP_TLS_SSL3
)
1559 * Allow all versions of TLS and SSL/3.0...
1562 strlcat(priority_string
, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string
));
1567 * Require a minimum version...
1570 strlcat(priority_string
, ":+VERS-TLS-ALL", sizeof(priority_string
));
1571 for (version
= 0; version
< tls_min_version
; version
++)
1573 strlcat(priority_string
, ":-", sizeof(priority_string
));
1574 strlcat(priority_string
, versions
[version
], sizeof(priority_string
));
1578 if (tls_options
& _HTTP_TLS_ALLOW_RC4
)
1579 strlcat(priority_string
, ":+ARCFOUR-128", sizeof(priority_string
));
1581 strlcat(priority_string
, ":!ARCFOUR-128", sizeof(priority_string
));
1583 strlcat(priority_string
, ":!ANON-DH", sizeof(priority_string
));
1585 if (tls_options
& _HTTP_TLS_DENY_CBC
)
1586 strlcat(priority_string
, ":!AES-128-CBC:!AES-256-CBC:!CAMELLIA-128-CBC:!CAMELLIA-256-CBC:!3DES-CBC", sizeof(priority_string
));
1588 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
1589 gnutls_priority_set_direct(http
->tls
, priority_string
, NULL
);
1592 gnutls_priority_t priority
; /* Priority */
1594 gnutls_priority_init(&priority
, priority_string
, NULL
);
1595 gnutls_priority_set(http
->tls
, priority
);
1596 gnutls_priority_deinit(priority
);
1597 #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */
1599 gnutls_transport_set_ptr(http
->tls
, (gnutls_transport_ptr_t
)http
);
1600 gnutls_transport_set_pull_function(http
->tls
, http_gnutls_read
);
1601 #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION
1602 gnutls_transport_set_pull_timeout_function(http
->tls
, (gnutls_pull_timeout_func
)httpWait
);
1603 #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */
1604 gnutls_transport_set_push_function(http
->tls
, http_gnutls_write
);
1607 * Enforce a minimum timeout of 10 seconds for the TLS handshake...
1610 old_timeout
= http
->timeout_value
;
1611 old_cb
= http
->timeout_cb
;
1612 old_data
= http
->timeout_data
;
1614 if (!old_cb
|| old_timeout
< 10.0)
1616 DEBUG_puts("4_httpTLSStart: Setting timeout to 10 seconds.");
1617 httpSetTimeout(http
, 10.0, NULL
, NULL
);
1621 * Do the TLS handshake...
1624 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
1626 DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
1627 status
, gnutls_strerror(status
)));
1629 if (gnutls_error_is_fatal(status
))
1632 http
->status
= HTTP_STATUS_ERROR
;
1634 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1636 gnutls_deinit(http
->tls
);
1637 gnutls_certificate_free_credentials(*credentials
);
1641 httpSetTimeout(http
, old_timeout
, old_cb
, old_data
);
1648 * Restore the previous timeout settings...
1651 httpSetTimeout(http
, old_timeout
, old_cb
, old_data
);
1653 http
->tls_credentials
= credentials
;
1660 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1664 _httpTLSStop(http_t
*http
) /* I - Connection to server */
1666 int error
; /* Error code */
1669 error
= gnutls_bye(http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
1670 if (error
!= GNUTLS_E_SUCCESS
)
1671 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(errno
), 0);
1673 gnutls_deinit(http
->tls
);
1676 if (http
->tls_credentials
)
1678 gnutls_certificate_free_credentials(*(http
->tls_credentials
));
1679 free(http
->tls_credentials
);
1680 http
->tls_credentials
= NULL
;
1686 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1689 int /* O - Bytes written */
1690 _httpTLSWrite(http_t
*http
, /* I - Connection to server */
1691 const char *buf
, /* I - Buffer holding data */
1692 int len
) /* I - Length of buffer */
1694 ssize_t result
; /* Return value */
1697 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
1699 result
= gnutls_record_send(http
->tls
, buf
, (size_t)len
);
1701 if (result
< 0 && !errno
)
1704 * Convert GNU TLS error to errno value...
1709 case GNUTLS_E_INTERRUPTED
:
1713 case GNUTLS_E_AGAIN
:
1725 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
1727 return ((int)result
);