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