2 * "$Id: tls-gnutls.c 12159 2014-09-23 14:56:14Z msweet $"
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.
18 /**** This file is included from tls.c ****/
21 * Include necessary headers...
31 static int tls_auto_create
= 0;
32 /* Auto-create self-signed certs? */
33 static char *tls_common_name
= NULL
;
34 /* Default common name */
35 static char *tls_keypath
= NULL
;
36 /* Server cert keychain path */
37 static _cups_mutex_t tls_mutex
= _CUPS_MUTEX_INITIALIZER
;
38 /* Mutex for keychain/certs */
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 const char *http_gnutls_make_path(char *buffer
, size_t bufsize
, const char *dirname
, const char *filename
, const char *ext
);
48 static ssize_t
http_gnutls_read(gnutls_transport_ptr_t ptr
, void *data
, size_t length
);
49 static ssize_t
http_gnutls_write(gnutls_transport_ptr_t ptr
, const void *data
, size_t length
);
53 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
55 * @since CUPS 2.0/OS 10.10@
58 int /* O - 1 on success, 0 on failure */
59 cupsMakeServerCredentials(
60 const char *path
, /* I - Path to keychain/directory */
61 const char *common_name
, /* I - Common name */
62 int num_alt_names
, /* I - Number of subject alternate names */
63 const char **alt_names
, /* I - Subject Alternate Names */
64 time_t expiration_date
) /* I - Expiration date */
66 gnutls_x509_crt_t crt
; /* Self-signed certificate */
67 gnutls_x509_privkey_t key
; /* Encryption private key */
68 char temp
[1024], /* Temporary directory name */
69 crtfile
[1024], /* Certificate filename */
70 keyfile
[1024]; /* Private key filename */
71 cups_lang_t
*language
; /* Default language info */
72 cups_file_t
*fp
; /* Key/cert file */
73 unsigned char buffer
[8192]; /* Buffer for x509 data */
74 size_t bytes
; /* Number of bytes of data */
75 unsigned char serial
[4]; /* Serial number buffer */
76 time_t curtime
; /* Current time */
77 int result
; /* Result of GNU TLS calls */
80 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
));
87 path
= http_gnutls_default_path(temp
, sizeof(temp
));
89 if (!path
|| !common_name
)
91 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
95 http_gnutls_make_path(crtfile
, sizeof(crtfile
), path
, common_name
, "crt");
96 http_gnutls_make_path(keyfile
, sizeof(keyfile
), path
, common_name
, "key");
99 * Create the encryption key...
102 DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");
104 gnutls_x509_privkey_init(&key
);
105 gnutls_x509_privkey_generate(key
, GNUTLS_PK_RSA
, 2048, 0);
107 DEBUG_puts("1cupsMakeServerCredentials: Key pair created.");
113 bytes
= sizeof(buffer
);
115 if ((result
= gnutls_x509_privkey_export(key
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
117 DEBUG_printf(("1cupsMakeServerCredentials: Unable to export private key: %s", gnutls_strerror(result
)));
118 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(result
), 0);
119 gnutls_x509_privkey_deinit(key
);
122 else if ((fp
= cupsFileOpen(keyfile
, "w")) != NULL
)
124 DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile
));
125 cupsFileWrite(fp
, (char *)buffer
, bytes
);
130 DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file \"%s\": %s", keyfile
, strerror(errno
)));
131 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
132 gnutls_x509_privkey_deinit(key
);
137 * Create the self-signed certificate...
140 DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate.");
142 language
= cupsLangDefault();
143 curtime
= time(NULL
);
144 serial
[0] = curtime
>> 24;
145 serial
[1] = curtime
>> 16;
146 serial
[2] = curtime
>> 8;
149 gnutls_x509_crt_init(&crt
);
150 if (strlen(language
->language
) == 5)
151 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
152 language
->language
+ 3, 2);
154 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COUNTRY_NAME
, 0,
156 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_COMMON_NAME
, 0,
157 common_name
, strlen(common_name
));
158 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_ORGANIZATION_NAME
, 0,
159 common_name
, strlen(common_name
));
160 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME
,
162 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME
, 0,
164 gnutls_x509_crt_set_dn_by_oid(crt
, GNUTLS_OID_X520_LOCALITY_NAME
, 0,
166 /* gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
167 ServerAdmin, strlen(ServerAdmin));*/
168 gnutls_x509_crt_set_key(crt
, key
);
169 gnutls_x509_crt_set_serial(crt
, serial
, sizeof(serial
));
170 gnutls_x509_crt_set_activation_time(crt
, curtime
);
171 gnutls_x509_crt_set_expiration_time(crt
, curtime
+ 10 * 365 * 86400);
172 gnutls_x509_crt_set_ca_status(crt
, 0);
173 if (num_alt_names
> 0)
174 gnutls_x509_crt_set_subject_alternative_name(crt
, GNUTLS_SAN_DNSNAME
, alt_names
[0]);
175 gnutls_x509_crt_set_key_purpose_oid(crt
, GNUTLS_KP_TLS_WWW_SERVER
, 0);
176 gnutls_x509_crt_set_key_usage(crt
, GNUTLS_KEY_KEY_ENCIPHERMENT
);
177 gnutls_x509_crt_set_version(crt
, 3);
179 bytes
= sizeof(buffer
);
180 if (gnutls_x509_crt_get_key_id(crt
, 0, buffer
, &bytes
) >= 0)
181 gnutls_x509_crt_set_subject_key_id(crt
, buffer
, bytes
);
183 gnutls_x509_crt_sign(crt
, crt
, key
);
189 bytes
= sizeof(buffer
);
190 if ((result
= gnutls_x509_crt_export(crt
, GNUTLS_X509_FMT_PEM
, buffer
, &bytes
)) < 0)
192 DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result
)));
193 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(result
), 0);
194 gnutls_x509_crt_deinit(crt
);
195 gnutls_x509_privkey_deinit(key
);
198 else if ((fp
= cupsFileOpen(crtfile
, "w")) != NULL
)
200 DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile
));
201 cupsFileWrite(fp
, (char *)buffer
, bytes
);
206 DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile
, strerror(errno
)));
207 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
208 gnutls_x509_crt_deinit(crt
);
209 gnutls_x509_privkey_deinit(key
);
217 gnutls_x509_crt_deinit(crt
);
218 gnutls_x509_privkey_deinit(key
);
220 DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials.");
227 * 'cupsSetServerCredentials()' - Set the default server credentials.
229 * Note: The server credentials are used by all threads in the running process.
230 * This function is threadsafe.
232 * @since CUPS 2.0/OS 10.10@
235 int /* O - 1 on success, 0 on failure */
236 cupsSetServerCredentials(
237 const char *path
, /* I - Path to keychain/directory */
238 const char *common_name
, /* I - Default common name for server */
239 int auto_create
) /* I - 1 = automatically create self-signed certificates */
241 char temp
[1024]; /* Default path buffer */
244 DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path
, common_name
, auto_create
));
247 * Use defaults as needed...
251 path
= http_gnutls_default_path(temp
, sizeof(temp
));
254 * Range check input...
257 if (!path
|| !common_name
)
259 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
263 _cupsMutexLock(&tls_mutex
);
270 _cupsStrFree(tls_keypath
);
273 _cupsStrFree(tls_common_name
);
276 * Save the new values...
279 tls_keypath
= _cupsStrAlloc(path
);
280 tls_auto_create
= auto_create
;
281 tls_common_name
= _cupsStrAlloc(common_name
);
283 _cupsMutexUnlock(&tls_mutex
);
290 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
291 * an encrypted connection.
293 * @since CUPS 1.5/OS X 10.7@
296 int /* O - Status of call (0 = success) */
298 http_t
*http
, /* I - Connection to server */
299 cups_array_t
**credentials
) /* O - Array of credentials */
301 unsigned count
; /* Number of certificates */
302 const gnutls_datum_t
*certs
; /* Certificates */
305 DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http
, credentials
));
310 if (!http
|| !http
->tls
|| !credentials
)
313 *credentials
= cupsArrayNew(NULL
, NULL
);
314 certs
= gnutls_certificate_get_peers(http
->tls
, &count
);
316 DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs
, count
));
322 httpAddCredential(*credentials
, certs
->data
, certs
->size
);
333 * '_httpCreateCredentials()' - Create credentials in the internal format.
336 http_tls_credentials_t
/* O - Internal credentials */
337 _httpCreateCredentials(
338 cups_array_t
*credentials
) /* I - Array of credentials */
347 * '_httpFreeCredentials()' - Free internal credentials.
351 _httpFreeCredentials(
352 http_tls_credentials_t credentials
) /* I - Internal credentials */
359 * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name.
361 * @since CUPS 2.0/OS 10.10@
364 int /* O - 1 if valid, 0 otherwise */
365 httpCredentialsAreValidForName(
366 cups_array_t
*credentials
, /* I - Credentials */
367 const char *common_name
) /* I - Name to check */
369 gnutls_x509_crt_t cert
; /* Certificate */
370 int result
= 0; /* Result */
373 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
376 result
= gnutls_x509_crt_check_hostname(cert
, common_name
) != 0;
377 gnutls_x509_crt_deinit(cert
);
385 * 'httpCredentialsGetTrust()' - Return the trust of credentials.
387 * @since CUPS 2.0/OS 10.10@
390 http_trust_t
/* O - Level of trust */
391 httpCredentialsGetTrust(
392 cups_array_t
*credentials
, /* I - Credentials */
393 const char *common_name
) /* I - Common name for trust lookup */
395 http_trust_t trust
= HTTP_TRUST_OK
;
397 gnutls_x509_crt_t cert
; /* Certificate */
398 cups_array_t
*tcreds
= NULL
; /* Trusted credentials */
399 _cups_globals_t
*cg
= _cupsGlobals();
400 /* Per-thread globals */
404 return (HTTP_TRUST_UNKNOWN
);
406 if ((cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
))) == NULL
)
407 return (HTTP_TRUST_UNKNOWN
);
410 * Look this common name up in the default keychains...
413 httpLoadCredentials(NULL
, &tcreds
, common_name
);
417 char credentials_str
[1024], /* String for incoming credentials */
418 tcreds_str
[1024]; /* String for saved credentials */
420 httpCredentialsString(credentials
, credentials_str
, sizeof(credentials_str
));
421 httpCredentialsString(tcreds
, tcreds_str
, sizeof(tcreds_str
));
423 if (strcmp(credentials_str
, tcreds_str
))
426 * Credentials don't match, let's look at the expiration date of the new
427 * credentials and allow if the new ones have a later expiration...
430 if (httpCredentialsGetExpiration(credentials
) <= httpCredentialsGetExpiration(tcreds
) ||
431 !httpCredentialsAreValidForName(credentials
, common_name
))
434 * Either the new credentials are not newly issued, or the common name
435 * does not match the issued certificate...
438 trust
= HTTP_TRUST_INVALID
;
440 else if (httpCredentialsGetExpiration(tcreds
) < time(NULL
))
443 * Save the renewed credentials...
446 trust
= HTTP_TRUST_RENEWED
;
448 httpSaveCredentials(NULL
, credentials
, common_name
);
452 httpFreeCredentials(tcreds
);
454 else if (cg
->validate_certs
&& !httpCredentialsAreValidForName(credentials
, common_name
))
455 trust
= HTTP_TRUST_INVALID
;
457 if (trust
== HTTP_TRUST_OK
&& !cg
->expired_certs
)
459 time_t curtime
; /* Current date/time */
462 if (curtime
< gnutls_x509_crt_get_activation_time(cert
) ||
463 curtime
> gnutls_x509_crt_get_expiration_time(cert
))
464 trust
= HTTP_TRUST_EXPIRED
;
467 if (trust
== HTTP_TRUST_OK
&& !cg
->any_root
&& cupsArrayCount(credentials
) == 1)
468 trust
= HTTP_TRUST_INVALID
;
470 gnutls_x509_crt_deinit(cert
);
477 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
479 * @since CUPS 2.0/OS 10.10@
482 time_t /* O - Expiration date of credentials */
483 httpCredentialsGetExpiration(
484 cups_array_t
*credentials
) /* I - Credentials */
486 gnutls_x509_crt_t cert
; /* Certificate */
487 time_t result
= 0; /* Result */
490 cert
= http_gnutls_create_credential((http_credential_t
*)cupsArrayFirst(credentials
));
493 result
= gnutls_x509_crt_get_expiration_time(cert
);
494 gnutls_x509_crt_deinit(cert
);
502 * 'httpCredentialsString()' - Return a string representing the credentials.
504 * @since CUPS 2.0/OS 10.10@
507 size_t /* O - Total size of credentials string */
508 httpCredentialsString(
509 cups_array_t
*credentials
, /* I - Credentials */
510 char *buffer
, /* I - Buffer or @code NULL@ */
511 size_t bufsize
) /* I - Size of buffer */
513 http_credential_t
*first
; /* First certificate */
514 gnutls_x509_crt_t cert
; /* Certificate */
517 DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT
")", credentials
, buffer
, CUPS_LLCAST bufsize
));
522 if (buffer
&& bufsize
> 0)
525 if ((first
= (http_credential_t
*)cupsArrayFirst(credentials
)) != NULL
&&
526 (cert
= http_gnutls_create_credential(first
)) != NULL
)
528 char name
[256]; /* Common name associated with cert */
529 size_t namelen
; /* Length of name */
530 time_t expiration
; /* Expiration date of cert */
531 _cups_md5_state_t md5_state
; /* MD5 state */
532 unsigned char md5_digest
[16]; /* MD5 result */
534 namelen
= sizeof(name
) - 1;
535 if (gnutls_x509_crt_get_dn_by_oid(cert
, GNUTLS_OID_X520_COMMON_NAME
, 0, 0, name
, &namelen
) >= 0)
536 name
[namelen
] = '\0';
538 strlcpy(name
, "unknown", sizeof(name
));
540 expiration
= gnutls_x509_crt_get_expiration_time(cert
);
542 _cupsMD5Init(&md5_state
);
543 _cupsMD5Append(&md5_state
, first
->data
, (int)first
->datalen
);
544 _cupsMD5Finish(&md5_state
, md5_digest
);
546 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]);
548 gnutls_x509_crt_deinit(cert
);
551 DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer
));
553 return (strlen(buffer
));
558 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
560 * @since CUPS 2.0/OS 10.10@
563 int /* O - 0 on success, -1 on error */
565 const char *path
, /* I - Keychain/PKCS#12 path */
566 cups_array_t
**credentials
, /* IO - Credentials */
567 const char *common_name
) /* I - Common name for credentials */
569 cups_file_t
*fp
; /* Certificate file */
570 char filename
[1024], /* filename.crt */
571 temp
[1024], /* Temporary string */
572 line
[256]; /* Base64-encoded line */
573 unsigned char *data
= NULL
; /* Buffer for cert data */
574 size_t alloc_data
= 0, /* Bytes allocated */
575 num_data
= 0; /* Bytes used */
576 int decoded
; /* Bytes decoded */
579 if (!credentials
|| !common_name
)
583 path
= http_gnutls_default_path(temp
, sizeof(temp
));
587 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
589 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
592 while (cupsFileGets(fp
, line
, sizeof(line
)))
594 if (!strcmp(line
, "-----BEGIN CERTIFICATE-----"))
599 * Missing END CERTIFICATE...
602 httpFreeCredentials(*credentials
);
607 else if (!strcmp(line
, "-----END CERTIFICATE-----"))
615 httpFreeCredentials(*credentials
);
621 *credentials
= cupsArrayNew(NULL
, NULL
);
623 if (httpAddCredential(*credentials
, data
, num_data
))
625 httpFreeCredentials(*credentials
);
642 else if ((num_data
+ strlen(line
)) >= alloc_data
)
644 unsigned char *tdata
= realloc(data
, alloc_data
+ 1024);
645 /* Expanded buffer */
649 httpFreeCredentials(*credentials
);
658 decoded
= alloc_data
- num_data
;
659 httpDecode64_2((char *)data
+ num_data
, &decoded
, line
);
660 num_data
+= (size_t)decoded
;
669 * Missing END CERTIFICATE...
672 httpFreeCredentials(*credentials
);
679 return (*credentials
? 0 : -1);
684 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
686 * @since CUPS 2.0/OS 10.10@
689 int /* O - -1 on error, 0 on success */
691 const char *path
, /* I - Keychain/PKCS#12 path */
692 cups_array_t
*credentials
, /* I - Credentials */
693 const char *common_name
) /* I - Common name for credentials */
695 cups_file_t
*fp
; /* Certificate file */
696 char filename
[1024], /* filename.crt */
697 nfilename
[1024],/* filename.crt.N */
698 temp
[1024], /* Temporary string */
699 line
[256]; /* Base64-encoded line */
700 const unsigned char *ptr
; /* Pointer into certificate */
701 ssize_t remaining
; /* Bytes left */
702 http_credential_t
*cred
; /* Current credential */
705 if (!credentials
|| !common_name
)
709 path
= http_gnutls_default_path(temp
, sizeof(temp
));
713 http_gnutls_make_path(filename
, sizeof(filename
), path
, common_name
, "crt");
714 snprintf(nfilename
, sizeof(nfilename
), "%s.N", filename
);
716 if ((fp
= cupsFileOpen(nfilename
, "w")) == NULL
)
719 fchmod(cupsFileNumber(fp
), 0600);
721 for (cred
= (http_credential_t
*)cupsArrayFirst(credentials
);
723 cred
= (http_credential_t
*)cupsArrayNext(credentials
))
725 cupsFilePuts(fp
, "-----BEGIN CERTIFICATE-----\n");
726 for (ptr
= cred
->data
, remaining
= (ssize_t
)cred
->datalen
; remaining
> 0; remaining
-= 45, ptr
+= 45)
728 httpEncode64_2(line
, sizeof(line
), (char *)ptr
, remaining
> 45 ? 45 : remaining
);
729 cupsFilePrintf(fp
, "%s\n", line
);
731 cupsFilePuts(fp
, "-----END CERTIFICATE-----\n");
736 return (rename(nfilename
, filename
));
741 * 'http_gnutls_create_credential()' - Create a single credential in the internal format.
744 static gnutls_x509_crt_t
/* O - Certificate */
745 http_gnutls_create_credential(
746 http_credential_t
*credential
) /* I - Credential */
748 int result
; /* Result from GNU TLS */
749 gnutls_x509_crt_t cert
; /* Certificate */
750 gnutls_datum_t datum
; /* Data record */
753 DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential
));
758 if ((result
= gnutls_x509_crt_init(&cert
)) < 0)
760 DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result
)));
764 datum
.data
= credential
->data
;
765 datum
.size
= credential
->datalen
;
767 if ((result
= gnutls_x509_crt_import(cert
, &datum
, GNUTLS_X509_FMT_DER
)) < 0)
769 DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result
)));
771 gnutls_x509_crt_deinit(cert
);
780 * 'http_gnutls_default_path()' - Get the default credential store path.
783 static const char * /* O - Path or NULL on error */
784 http_gnutls_default_path(char *buffer
,/* I - Path buffer */
785 size_t bufsize
)/* I - Size of path buffer */
787 const char *home
= getenv("HOME"); /* HOME environment variable */
790 if (getuid() && home
)
792 snprintf(buffer
, bufsize
, "%s/.cups", home
);
793 if (access(buffer
, 0))
795 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
796 if (mkdir(buffer
, 0700))
798 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
803 snprintf(buffer
, bufsize
, "%s/.cups/ssl", home
);
804 if (access(buffer
, 0))
806 DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer
));
807 if (mkdir(buffer
, 0700))
809 DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno
)));
815 strlcpy(buffer
, CUPS_SERVERROOT
"/ssl", bufsize
);
817 DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer
));
824 * 'http_gnutls_make_path()' - Format a filename for a certificate or key file.
827 static const char * /* O - Filename */
828 http_gnutls_make_path(
829 char *buffer
, /* I - Filename buffer */
830 size_t bufsize
, /* I - Size of buffer */
831 const char *dirname
, /* I - Directory */
832 const char *filename
, /* I - Filename (usually hostname) */
833 const char *ext
) /* I - Extension */
835 char *bufptr
, /* Pointer into buffer */
836 *bufend
= buffer
+ bufsize
- 1; /* End of buffer */
839 snprintf(buffer
, bufsize
, "%s/", dirname
);
840 bufptr
= buffer
+ strlen(buffer
);
842 while (*filename
&& bufptr
< bufend
)
844 if (_cups_isalnum(*filename
) || *filename
== '-' || *filename
== '.')
845 *bufptr
++ = *filename
;
855 strlcpy(bufptr
, ext
, (size_t)(bufend
- bufptr
+ 1));
862 * 'http_gnutls_read()' - Read function for the GNU TLS library.
865 static ssize_t
/* O - Number of bytes read or -1 on error */
867 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
868 void *data
, /* I - Buffer */
869 size_t length
) /* I - Number of bytes to read */
871 http_t
*http
; /* HTTP connection */
872 ssize_t bytes
; /* Bytes read */
875 DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr
, data
, (int)length
));
877 http
= (http_t
*)ptr
;
882 * Make sure we have data before we read...
885 while (!_httpWait(http
, http
->wait_value
, 0))
887 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
890 http
->error
= ETIMEDOUT
;
895 bytes
= recv(http
->fd
, data
, length
, 0);
896 DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes
));
902 * 'http_gnutls_write()' - Write function for the GNU TLS library.
905 static ssize_t
/* O - Number of bytes written or -1 on error */
907 gnutls_transport_ptr_t ptr
, /* I - Connection to server */
908 const void *data
, /* I - Data buffer */
909 size_t length
) /* I - Number of bytes to write */
911 ssize_t bytes
; /* Bytes written */
914 DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr
, data
,
916 bytes
= send(((http_t
*)ptr
)->fd
, data
, length
, 0);
917 DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes
));
924 * '_httpTLSInitialize()' - Initialize the TLS stack.
928 _httpTLSInitialize(void)
931 * Initialize GNU TLS...
934 gnutls_global_init();
939 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
942 size_t /* O - Bytes available */
943 _httpTLSPending(http_t
*http
) /* I - HTTP connection */
945 return (gnutls_record_check_pending(http
->tls
));
950 * '_httpTLSRead()' - Read from a SSL/TLS connection.
953 int /* O - Bytes read */
954 _httpTLSRead(http_t
*http
, /* I - Connection to server */
955 char *buf
, /* I - Buffer to store data */
956 int len
) /* I - Length of buffer */
958 ssize_t result
; /* Return value */
961 result
= gnutls_record_recv(http
->tls
, buf
, (size_t)len
);
963 if (result
< 0 && !errno
)
966 * Convert GNU TLS error to errno value...
971 case GNUTLS_E_INTERRUPTED
:
975 case GNUTLS_E_AGAIN
:
987 return ((int)result
);
992 * '_httpTLSSetCredentials()' - Set the TLS credentials.
995 int /* O - Status of connection */
996 _httpTLSSetCredentials(http_t
*http
) /* I - Connection to server */
1005 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
1008 int /* O - 0 on success, -1 on failure */
1009 _httpTLSStart(http_t
*http
) /* I - Connection to server */
1011 char hostname
[256], /* Hostname */
1012 *hostptr
; /* Pointer into hostname */
1013 int status
; /* Status of handshake */
1014 gnutls_certificate_credentials_t
*credentials
;
1015 /* TLS credentials */
1018 DEBUG_printf(("7_httpTLSStart(http=%p)", http
));
1020 if (http
->mode
== _HTTP_MODE_SERVER
&& !tls_keypath
)
1022 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
1023 http
->error
= errno
= EINVAL
;
1024 http
->status
= HTTP_STATUS_ERROR
;
1025 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Server credentials not set."), 1);
1030 credentials
= (gnutls_certificate_credentials_t
*)
1031 malloc(sizeof(gnutls_certificate_credentials_t
));
1032 if (credentials
== NULL
)
1034 DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s",
1036 http
->error
= errno
;
1037 http
->status
= HTTP_STATUS_ERROR
;
1038 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
1043 gnutls_certificate_allocate_credentials(credentials
);
1044 status
= gnutls_init(&http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_CLIENT
: GNUTLS_SERVER
);
1046 status
= gnutls_set_default_priority(http
->tls
);
1051 http
->status
= HTTP_STATUS_ERROR
;
1053 DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status
)));
1054 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1056 gnutls_deinit(http
->tls
);
1057 gnutls_certificate_free_credentials(*credentials
);
1064 if (http
->mode
== _HTTP_MODE_CLIENT
)
1067 * Client: get the hostname to use for TLS...
1070 if (httpAddrLocalhost(http
->hostaddr
))
1072 strlcpy(hostname
, "localhost", sizeof(hostname
));
1077 * Otherwise make sure the hostname we have does not end in a trailing dot.
1080 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
1081 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
1086 status
= gnutls_server_name_set(http
->tls
, GNUTLS_NAME_DNS
, hostname
, strlen(hostname
));
1091 * Server: get certificate and private key...
1094 char crtfile
[1024], /* Certificate file */
1095 keyfile
[1024]; /* Private key file */
1096 int have_creds
= 0; /* Have credentials? */
1099 if (http
->fields
[HTTP_FIELD_HOST
][0])
1102 * Use hostname for TLS upgrade...
1105 strlcpy(hostname
, http
->fields
[HTTP_FIELD_HOST
], sizeof(hostname
));
1110 * Resolve hostname from connection address...
1113 http_addr_t addr
; /* Connection address */
1114 socklen_t addrlen
; /* Length of address */
1116 addrlen
= sizeof(addr
);
1117 if (getsockname(http
->fd
, (struct sockaddr
*)&addr
, &addrlen
))
1119 DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno
)));
1122 else if (httpAddrLocalhost(&addr
))
1126 httpAddrLookup(&addr
, hostname
, sizeof(hostname
));
1127 DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname
));
1131 if (isdigit(hostname
[0] & 255) || hostname
[0] == '[')
1132 hostname
[0] = '\0'; /* Don't allow numeric addresses */
1136 http_gnutls_make_path(crtfile
, sizeof(crtfile
), tls_keypath
, hostname
, "crt");
1137 http_gnutls_make_path(keyfile
, sizeof(keyfile
), tls_keypath
, hostname
, "key");
1139 have_creds
= !access(crtfile
, 0) && !access(keyfile
, 0);
1141 else if (tls_common_name
)
1143 http_gnutls_make_path(crtfile
, sizeof(crtfile
), tls_keypath
, tls_common_name
, "crt");
1144 http_gnutls_make_path(keyfile
, sizeof(keyfile
), tls_keypath
, tls_common_name
, "key");
1146 have_creds
= !access(crtfile
, 0) && !access(keyfile
, 0);
1149 if (!have_creds
&& tls_auto_create
&& (hostname
[0] || tls_common_name
))
1151 DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname
[0] ? hostname
: tls_common_name
));
1153 if (!cupsMakeServerCredentials(tls_keypath
, hostname
[0] ? hostname
: tls_common_name
, 0, NULL
, time(NULL
) + 365 * 86400))
1155 DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
1156 http
->error
= errno
= EINVAL
;
1157 http
->status
= HTTP_STATUS_ERROR
;
1158 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unable to create server credentials."), 1);
1164 DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile
, keyfile
));
1166 status
= gnutls_certificate_set_x509_key_file(*credentials
, crtfile
, keyfile
, GNUTLS_X509_FMT_PEM
);
1170 status
= gnutls_credentials_set(http
->tls
, GNUTLS_CRD_CERTIFICATE
, *credentials
);
1175 http
->status
= HTTP_STATUS_ERROR
;
1177 DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status
)));
1178 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1180 gnutls_deinit(http
->tls
);
1181 gnutls_certificate_free_credentials(*credentials
);
1188 gnutls_transport_set_ptr(http
->tls
, (gnutls_transport_ptr_t
)http
);
1189 gnutls_transport_set_pull_function(http
->tls
, http_gnutls_read
);
1190 #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION
1191 gnutls_transport_set_pull_timeout_function(http
->tls
, (gnutls_pull_timeout_func
)httpWait
);
1192 #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */
1193 gnutls_transport_set_push_function(http
->tls
, http_gnutls_write
);
1195 while ((status
= gnutls_handshake(http
->tls
)) != GNUTLS_E_SUCCESS
)
1197 DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)",
1198 status
, gnutls_strerror(status
)));
1200 if (gnutls_error_is_fatal(status
))
1203 http
->status
= HTTP_STATUS_ERROR
;
1205 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, gnutls_strerror(status
), 0);
1207 gnutls_deinit(http
->tls
);
1208 gnutls_certificate_free_credentials(*credentials
);
1216 http
->tls_credentials
= credentials
;
1223 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
1227 _httpTLSStop(http_t
*http
) /* I - Connection to server */
1229 int error
; /* Error code */
1232 error
= gnutls_bye(http
->tls
, http
->mode
== _HTTP_MODE_CLIENT
? GNUTLS_SHUT_RDWR
: GNUTLS_SHUT_WR
);
1233 if (error
!= GNUTLS_E_SUCCESS
)
1234 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gnutls_strerror(errno
), 0);
1236 gnutls_deinit(http
->tls
);
1239 if (http
->tls_credentials
)
1241 gnutls_certificate_free_credentials(*(http
->tls_credentials
));
1242 free(http
->tls_credentials
);
1243 http
->tls_credentials
= NULL
;
1249 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
1252 int /* O - Bytes written */
1253 _httpTLSWrite(http_t
*http
, /* I - Connection to server */
1254 const char *buf
, /* I - Buffer holding data */
1255 int len
) /* I - Length of buffer */
1257 ssize_t result
; /* Return value */
1260 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http
, buf
, len
));
1262 result
= gnutls_record_send(http
->tls
, buf
, (size_t)len
);
1264 if (result
< 0 && !errno
)
1267 * Convert GNU TLS error to errno value...
1272 case GNUTLS_E_INTERRUPTED
:
1276 case GNUTLS_E_AGAIN
:
1288 DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result
));
1290 return ((int)result
);
1295 * End of "$Id: tls-gnutls.c 12159 2014-09-23 14:56:14Z msweet $".