4 * TLS support code for CUPS using GNU TLS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
20 * Include necessary headers...
30 static int tls_auto_create
= 0;
31 /* Auto-create self-signed certs? */
32 static char *tls_common_name
= NULL
;
33 /* Default common name */
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 */
44 static gnutls_x509_crt_t
http_gnutls_create_credential(http_credential_t
*credential
);
45 static const char *http_gnutls_default_path(char *buffer
, size_t bufsize
);
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.
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 snprintf(crtfile
, sizeof(crtfile
), "%s/%s.crt", path
, common_name
);
94 snprintf(keyfile
, sizeof(keyfile
), "%s/%s.key", path
, common_name
);
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 if (num_alt_names
> 0)
172 gnutls_x509_crt_set_subject_alternative_name(crt
, GNUTLS_SAN_DNSNAME
, alt_names
[0]);
173 gnutls_x509_crt_set_key_purpose_oid(crt
, GNUTLS_KP_TLS_WWW_SERVER
, 0);
174 gnutls_x509_crt_set_key_usage(crt
, GNUTLS_KEY_KEY_ENCIPHERMENT
);
175 gnutls_x509_crt_set_version(crt
, 3);
177 bytes
= sizeof(buffer
);
178 if (gnutls_x509_crt_get_key_id(crt
, 0, buffer
, &bytes
) >= 0)
179 gnutls_x509_crt_set_subject_key_id(crt
, buffer
, bytes
);
181 gnutls_x509_crt_sign(crt
, crt
, key
);
187 bytes
= sizeof(buffer
);
188 if ((result
= gnutls_x509_crt_export(crt
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
190 DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result
)));
191 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(result
), 0);
192 gnutls_x509_crt_deinit(crt
);
193 gnutls_x509_privkey_deinit(key
);
196 else if ((fp
= cupsFileOpen(crtfile
, "w")) != NULL
)
198 DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile
));
199 cupsFileWrite(fp
, (char *)buffer
, bytes
);
204 DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile
, strerror(errno
)));
205 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
206 gnutls_x509_crt_deinit(crt
);
207 gnutls_x509_privkey_deinit(key
);
215 gnutls_x509_crt_deinit(crt
);
216 gnutls_x509_privkey_deinit(key
);
218 DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");
225 * 'cupsSetServerCredentials()' - Set the default server credentials.
227 * Note: The server credentials are used by all threads in the running process.
228 * This function is threadsafe.
233 int /* O - 1 on success, 0 on failure */
234 cupsSetServerCredentials(
235 const char *path
, /* I - Path to keychain/directory */
236 const char *common_name
, /* I - Default common name for server */
237 int auto_create
) /* I - 1 = automatically create self-signed certificates */
239 char temp
[1024]; /* Default path buffer */
242 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
245 * Use defaults as needed...
249 path
= http_gnutls_default_path(temp
, sizeof(temp
));
252 * Range check input...
255 if (!path
|| !common_name
)
257 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
261 _cupsMutexLock(&tls_mutex
);
268 _cupsStrFree(tls_keypath
);
271 _cupsStrFree(tls_common_name
);
274 * Save the new values...
277 tls_keypath
= _cupsStrAlloc(path
);
278 tls_auto_create
= auto_create
;
279 tls_common_name
= _cupsStrAlloc(common_name
);
281 _cupsMutexUnlock(&tls_mutex
);
288 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
289 * an encrypted connection.
291 * @since CUPS 1.5/OS X 10.7@
294 int /* O - Status of call (0 = success) */
296 http_t
*http
, /* I - Connection to server */
297 cups_array_t
**credentials
) /* O - Array of credentials */
302 if (!http
|| !http
->tls
|| !credentials
)
310 * '_httpCreateCredentials()' - Create credentials in the internal format.
313 http_tls_credentials_t
/* O - Internal credentials */
314 _httpCreateCredentials(
315 cups_array_t
*credentials
) /* I - Array of credentials */
324 * '_httpFreeCredentials()' - Free internal credentials.
328 _httpFreeCredentials(
329 http_tls_credentials_t credentials
) /* I - Internal credentials */
336 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
341 int /* O - 1 if valid, 0 otherwise */
342 httpCredentialsAreValidForName(
343 cups_array_t
*credentials
, /* I - Credentials */
344 const char *common_name
) /* I - Name to check */
346 gnutls_x509_crt_t cert
; /* Certificate */
347 int result
= 0; /* Result */
350 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
353 result
= gnutls_x509_crt_check_hostname(cert
, common_name
) != 0;
354 gnutls_x509_crt_deinit(cert
);
362 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
367 http_trust_t
/* O - Level of trust */
368 httpCredentialsGetTrust(
369 cups_array_t
*credentials
, /* I - Credentials */
370 const char *common_name
) /* I - Common name for trust lookup */
372 http_trust_t trust
= HTTP_TRUST_OK
;
374 gnutls_x509_crt_t cert
; /* Certificate */
375 cups_array_t
*tcreds
= NULL
; /* Trusted credentials */
376 _cups_globals_t
*cg
= _cupsGlobals();
377 /* Per-thread globals */
381 return (HTTP_TRUST_UNKNOWN
);
383 if ((cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
))) == NULL
)
384 return (HTTP_TRUST_UNKNOWN
);
387 * Look this common name up in the default keychains...
390 httpLoadCredentials(NULL
, &tcreds
, common_name
);
394 char credentials_str
[1024], /* String for incoming credentials */
395 tcreds_str
[1024]; /* String for saved credentials */
397 httpCredentialsString(credentials
, credentials_str
, sizeof(credentials_str
));
398 httpCredentialsString(tcreds
, tcreds_str
, sizeof(tcreds_str
));
400 if (strcmp(credentials_str
, tcreds_str
))
403 * Credentials don't match, let's look at the expiration date of the new
404 * credentials and allow if the new ones have a later expiration...
407 if (httpCredentialsGetExpiration(credentials
) <= httpCredentialsGetExpiration(tcreds
) ||
408 !httpCredentialsAreValidForName(credentials
, common_name
))
411 * Either the new credentials are not newly issued, or the common name
412 * does not match the issued certificate...
415 trust
= HTTP_TRUST_INVALID
;
417 else if (httpCredentialsGetExpiration(tcreds
) < time(NULL
))
420 * Save the renewed credentials...
423 trust
= HTTP_TRUST_RENEWED
;
425 httpSaveCredentials(NULL
, credentials
, common_name
);
429 httpFreeCredentials(tcreds
);
431 else if (cg
->validate_certs
&& !httpCredentialsAreValidForName(credentials
, common_name
))
432 trust
= HTTP_TRUST_INVALID
;
434 if (trust
== HTTP_TRUST_OK
&& !cg
->expired_certs
)
436 time_t curtime
; /* Current date/time */
439 if (curtime
< gnutls_x509_crt_get_activation_time(cert
) ||
440 curtime
> gnutls_x509_crt_get_expiration_time(cert
))
441 trust
= HTTP_TRUST_EXPIRED
;
444 if (trust
== HTTP_TRUST_OK
&& !cg
->any_root
&& cupsArrayCount(credentials
) == 1)
445 trust
= HTTP_TRUST_INVALID
;
447 gnutls_x509_crt_deinit(cert
);
454 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
459 time_t /* O - Expiration date of credentials */
460 httpCredentialsGetExpiration(
461 cups_array_t
*credentials
) /* I - Credentials */
463 gnutls_x509_crt_t cert
; /* Certificate */
464 time_t result
= 0; /* Result */
467 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
470 result
= gnutls_x509_crt_get_expiration_time(cert
, common_name
);
471 gnutls_x509_crt_deinit(cert
);
479 * 'httpCredentialsString()' - Return a string representing the credentials.
484 size_t /* O - Total size of credentials string */
485 httpCredentialsString(
486 cups_array_t
*credentials
, /* I - Credentials */
487 char *buffer
, /* I - Buffer or @code NULL@ */
488 size_t bufsize
) /* I - Size of buffer */
490 http_credential_t
*first
; /* First certificate */
491 gnutls_x509_crt_t cert
; /* Certificate */
494 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
499 if (buffer
&& bufsize
> 0)
502 if ((first
= (http_credential_t
*)cupsArrayFirst(credentials
)) != NULL
&&
503 (cert
= http_gnutls_create_credential(first
)) != NULL
)
505 char name
[256]; /* Common name associated with cert */
506 time_t expiration
; /* Expiration date of cert */
507 _cups_md5_state_t md5_state
; /* MD5 state */
508 unsigned char md5_digest
[16]; /* MD5 result */
510 if (gnutls_x509_crt_get_dn_by_oid(cert
, GNUTLS_OID_X520_COMMON_NAME
, 0, 0, name
, sizeof(name
)) < 0)
511 strlcpy(name
, "unknown", sizeof(name
));
513 expiration
= gnutls_x509_crt_get_expiration_time(cert
);
515 _cupsMD5Init(&md5_state
);
516 _cupsMD5Append(&md5_state
, first
->data
, (int)first
->datalen
);
517 _cupsMD5Finish(&md5_state
, md5_digest
);
519 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]);
521 gnutls_x509_crt_deinit(cert
);
524 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
526 return (strlen(buffer
));
531 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
536 int /* O - 0 on success, -1 on error */
538 const char *path
, /* I - Keychain/PKCS#12 path */
539 cups_array_t
**credentials
, /* IO - Credentials */
540 const char *common_name
) /* I - Common name for credentials */
542 cups_file_t
*fp
; /* Certificate file */
543 char filename
[1024], /* filename.crt */
544 temp
[1024], /* Temporary string */
545 line
[256]; /* Base64-encoded line */
546 unsigned char *data
= NULL
; /* Buffer for cert data */
547 size_t alloc_data
= 0, /* Bytes allocated */
548 num_data
= 0; /* Bytes used */
549 int decoded
; /* Bytes decoded */
552 if (!credentials
|| !common_name
)
556 path
= http_gnutls_default_path(temp
, sizeof(temp
));
560 snprintf(filename
, sizeof(filename
), "%s/%s.crt", path
, common_name
);
562 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
565 while (cupsFileGets(fp
, line
, sizeof(line
)))
567 if (!strcmp(line
, "-----BEGIN CERTIFICATE-----"))
572 * Missing END CERTIFICATE...
575 httpFreeCredentials(*credentials
);
580 else if (!strcmp(line
, "-----END CERTIFICATE-----"))
588 httpFreeCredentials(*credentials
);
594 *credentials
= cupsArrayNew(NULL
, NULL
);
596 if (httpAddCredential(*credentials
, data
, num_data
))
598 httpFreeCredentials(*credentials
);
615 else if ((num_data
+ strlen(line
)) >= alloc_data
)
617 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
618 /* Expanded buffer */
622 httpFreeCredentials(*credentials
);
631 decoded
= alloc_data
- num_data
;
632 httpDecode64_2(data
, &decoded
, line
);
642 * Missing END CERTIFICATE...
645 httpFreeCredentials(*credentials
);
652 return (*credentials
? 0 : -1);
657 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
662 int /* O - -1 on error, 0 on success */
664 const char *path
, /* I - Keychain/PKCS#12 path */
665 cups_array_t
*credentials
, /* I - Credentials */
666 const char *common_name
) /* I - Common name for credentials */
668 cups_file_t
*fp
; /* Certificate file */
669 char filename
[1024], /* filename.crt */
670 nfilename
[1024],/* filename.crt.N */
671 temp
[1024], /* Temporary string */
672 line
[61]; /* Base64-encoded line */
673 const unsigned char *ptr
; /* Pointer into certificate */
674 size_t remaining
; /* Bytes left */
675 http_credential_t
*cred
; /* Current credential */
678 if (!credentials
|| !common_name
)
682 path
= http_gnutls_default_path(temp
, sizeof(temp
));
686 snprintf(filename
, sizeof(filename
), "%s/%s.crt", path
, common_name
);
687 snprintf(nfilename
, sizeof(nfilename
), "%s/%s.crt.N", path
, common_name
);
689 if ((fp
= cupsFileOpen(nfilename
, "w")) == NULL
)
692 fchmod(cupsFileNumber(fp
), 0600);
694 for (cred
= (http_credential_t
*)cupsArrayFirst(credentials
);
696 cred
= (http_credential_t
*)cupsArrayNext(credentials
))
698 cupsFilePuts(fp
, "-----BEGIN CERTIFICATE-----\n");
699 for (ptr
= cred
->data
, remaining
= cred
->datalen
; remaining
> 0; remaining
-= 45, ptr
+= 45)
701 httpEncode64_2(line
, sizeof(line
), ptr
, remaining
> 45 ? 45 : remaining
);
702 cupsFilePrintf(fp
, "%s\n", line
);
704 cupsFilePuts(fp
, "-----END CERTIFICATE-----\n");
709 return (rename(nfilename
, filename
));
714 * 'http_gnutls_create_credential()' - Create a single credential in the internal format.
717 static gnutls_x509_crt_t
/* O - Certificate */
718 http_gnutls_create_credential(
719 http_credential_t
*credential
) /* I - Credential */
721 gnutls_crt_t cert
; /* Certificate */
722 gnutls_datum_t datum
; /* Data record */
728 if (gnutls_x509_crt_init(&cert
) < 0)
731 datum
.data
= credential
.data
;
732 datum
.size
= credential
.length
;
734 if (gnutls_x509_crt_import(cert
, &datum
, GNUTLS_X509_FMT_PEM
) < 0)
736 gnutls_x509_crt_deinit(cert
);
745 * 'http_gnutls_default_path()' - Get the default credential store path.
748 static const char * /* O - Path or NULL on error */
749 http_gnutls_default_path(char *buffer
,/* I - Path buffer */
750 size_t bufsize
)/* I - Size of path buffer */
752 const char *home
= getenv("HOME"); /* HOME environment variable */
755 if (getuid() && home
)
757 snprintf(buffer
, bufsize
, "%s/.cups", home
);
758 if (access(buffer
, 0))
760 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
761 if (mkdir(buffer
, 0700))
763 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
768 snprintf(buffer
, bufsize
, "%s/.cups/ssl", home
);
769 if (access(buffer
, 0))
771 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
772 if (mkdir(buffer
, 0700))
774 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
780 strlcpy(buffer
, CUPS_SERVERROOT
"/ssl", bufsize
);
782 DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer
));
789 * 'http_gnutls_read()' - Read function for the GNU TLS library.
792 static ssize_t
/* O - Number of bytes read or -1 on error */
794 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
795 void *data
, /* I - Buffer */
796 size_t length
) /* I - Number of bytes to read */
798 http_t
*http
; /* HTTP connection */
799 ssize_t bytes
; /* Bytes read */
802 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
804 http
= (http_t
*)ptr
;
809 * Make sure we have data before we read...
812 while (!_httpWait(http
, http
->wait_value
, 0))
814 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
817 http
->error
= ETIMEDOUT
;
822 bytes
= recv(http
->fd
, data
, length
, 0);
823 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
829 * 'http_gnutls_write()' - Write function for the GNU TLS library.
832 static ssize_t
/* O - Number of bytes written or -1 on error */
834 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
835 const void *data
, /* I - Data buffer */
836 size_t length
) /* I - Number of bytes to write */
838 ssize_t bytes
; /* Bytes written */
841 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
843 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
844 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
851 * '_httpTLSInitialize()' - Initialize the TLS stack.
855 _httpTLSInitialize(void)
858 * Initialize GNU TLS...
861 gnutls_global_init();
866 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
869 size_t /* O - Bytes available */
870 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
872 return (gnutls_record_check_pending(http
->tls
));
877 * '_httpTLSRead()' - Read from a SSL/TLS connection.
880 int /* O - Bytes read */
881 _httpTLSRead(http_t
*http
, /* I - Connection to server */
882 char *buf
, /* I - Buffer to store data */
883 int len
) /* I - Length of buffer */
885 ssize_t result
; /* Return value */
888 result
= gnutls_record_recv(http
->tls
, buf
, (size_t)len
);
890 if (result
< 0 && !errno
)
893 * Convert GNU TLS error to errno value...
898 case GNUTLS_E_INTERRUPTED
:
902 case GNUTLS_E_AGAIN
:
914 return ((int)result
);
919 * '_httpTLSSetCredentials()' - Set the TLS credentials.
922 int /* O - Status of connection */
923 _httpTLSSetCredentials(http_t
*http
) /* I - Connection to server */
932 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
935 int /* O - 0 on success, -1 on failure */
936 _httpTLSStart(http_t
*http
) /* I - Connection to server */
938 char hostname
[256], /* Hostname */
939 *hostptr
; /* Pointer into hostname */
940 int status
; /* Status of handshake */
941 gnutls_certificate_credentials_t
*credentials
;
942 /* TLS credentials */
945 DEBUG_printf(("7_httpTLSStart(http=%p)", http
));
947 if (http
->mode
== _HTTP_MODE_SERVER
&& !tls_keypath
)
949 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
950 http
->error
= errno
= EINVAL
;
951 http
->status
= HTTP_STATUS_ERROR
;
952 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Server credentials not set."), 1);
957 credentials
= (gnutls_certificate_credentials_t
*)
958 malloc(sizeof(gnutls_certificate_credentials_t
));
959 if (credentials
== NULL
)
961 DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
964 http
->status
= HTTP_STATUS_ERROR
;
965 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
970 gnutls_certificate_allocate_credentials(credentials
);
971 status
= gnutls_init(&http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_CLIENT
: GNUTLS_SERVER
);
973 status
= gnutls_set_default_priority(http
->tls
);
978 http
->status
= HTTP_STATUS_ERROR
;
980 DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status
)));
981 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
983 gnutls_deinit(http
->tls
);
984 gnutls_certificate_free_credentials(*credentials
);
991 if (http
->mode
== _HTTP_MODE_CLIENT
)
994 * Client: get the hostname to use for TLS...
997 if (httpAddrLocalhost(http
->hostaddr
))
999 strlcpy(hostname
, "localhost", sizeof(hostname
));
1004 * Otherwise make sure the hostname we have does not end in a trailing dot.
1007 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1008 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1013 status
= gnutls_server_name_set(http
->tls
, GNUTLS_NAME_DNS
, hostname
, strlen(hostname
));
1018 * Server: get certificate and private key...
1021 char crtfile
[1024], /* Certificate file */
1022 keyfile
[1024]; /* Private key file */
1023 int have_creds
= 0; /* Have credentials? */
1026 if (http
->fields
[HTTP_FIELD_HOST
][0])
1029 * Use hostname for TLS upgrade...
1032 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
1037 * Resolve hostname from connection address...
1040 http_addr_t addr
; /* Connection address */
1041 socklen_t addrlen
; /* Length of address */
1043 addrlen
= sizeof(addr
);
1044 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
1046 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
1049 else if (httpAddrLocalhost(&addr
))
1053 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
1054 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
1058 if (isdigit(hostname
[0] & 255) || hostname
[0] == '[')
1059 hostname
[0] = '\0'; /* Don't allow numeric addresses */
1063 snprintf(crtfile
, sizeof(crtfile
), "%s/%s.crt", tls_keypath
, hostname
);
1064 snprintf(keyfile
, sizeof(keyfile
), "%s/%s.key", tls_keypath
, hostname
);
1066 have_creds
= !access(crtfile
, 0) && !access(keyfile
, 0);
1068 else if (tls_common_name
)
1070 snprintf(crtfile
, sizeof(crtfile
), "%s/%s.crt", tls_keypath
, tls_common_name
);
1071 snprintf(keyfile
, sizeof(keyfile
), "%s/%s.key", tls_keypath
, tls_common_name
);
1073 have_creds
= !access(crtfile
, 0) && !access(keyfile
, 0);
1076 if (!have_creds
&& tls_auto_create
&& (hostname
[0] || tls_common_name
))
1078 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname
[0] ? hostname
: tls_common_name
));
1080 if (!cupsMakeServerCredentials(tls_keypath
, hostname
[0] ? hostname
: tls_common_name
, 0, NULL
, time(NULL
) + 365 * 86400))
1082 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
1083 http
->error
= errno
= EINVAL
;
1084 http
->status
= HTTP_STATUS_ERROR
;
1085 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unable to create server credentials."), 1);
1091 DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile
, keyfile
));
1093 status
= gnutls_certificate_set_x509_key_file(*credentials
, crtfile
, keyfile
, GNUTLS_X509_FMT_PEM
);
1097 status
= gnutls_credentials_set(http
->tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
1102 http
->status
= HTTP_STATUS_ERROR
;
1104 DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status
)));
1105 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1107 gnutls_deinit(http
->tls
);
1108 gnutls_certificate_free_credentials(*credentials
);
1115 gnutls_transport_set_ptr(http
->tls
, (gnutls_transport_ptr_t
)http
);
1116 gnutls_transport_set_pull_function(http
->tls
, http_gnutls_read
);
1117 gnutls_transport_set_pull_timeout_function(http
->tls
, (gnutls_pull_timeout_func
)httpWait
);
1118 gnutls_transport_set_push_function(http
->tls
, http_gnutls_write
);
1120 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
1122 DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
1123 status
, gnutls_strerror(status
)));
1125 if (gnutls_error_is_fatal(status
))
1128 http
->status
= HTTP_STATUS_ERROR
;
1130 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1132 gnutls_deinit(http
->tls
);
1133 gnutls_certificate_free_credentials(*credentials
);
1141 http
->tls_credentials
= credentials
;
1143 // TODO: Put this in the right place; no-op for now, this to get things to compile
1144 // http_tls_set_credentials(http);
1151 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1155 _httpTLSStop(http_t
*http
) /* I - Connection to server */
1157 int error
; /* Error code */
1160 error
= gnutls_bye(http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
1161 if (error
!= GNUTLS_E_SUCCESS
)
1162 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(errno
), 0);
1164 gnutls_deinit(http
->tls
);
1167 if (http
->tls_credentials
)
1169 gnutls_certificate_free_credentials(*(http
->tls_credentials
));
1170 free(http
->tls_credentials
);
1171 http
->tls_credentials
= NULL
;
1177 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1180 int /* O - Bytes written */
1181 _httpTLSWrite(http_t
*http
, /* I - Connection to server */
1182 const char *buf
, /* I - Buffer holding data */
1183 int len
) /* I - Length of buffer */
1185 ssize_t result
; /* Return value */
1188 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
1190 result
= gnutls_record_send(http
->tls
, buf
, (size_t)len
);
1192 if (result
< 0 && !errno
)
1195 * Convert GNU TLS error to errno value...
1200 case GNUTLS_E_INTERRUPTED
:
1204 case GNUTLS_E_AGAIN
:
1216 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
1218 return ((int)result
);