1 /*
2 * TLS support code for CUPS using Google BoringSSL.
3 *
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
14 */
15
16 /**** This file is included from tls.c ****/
17
18 /*
19 * Local globals...
20 */
21
22 #include "cups-private.h"
23 #include "debug-internal.h"
24 #include "http.h"
25 #include "thread-private.h"
26 #include <openssl/err.h>
27 #include <openssl/ssl.h>
28
29 #include <sys/stat.h>
30
31 static char *tls_keypath = NULL;
32 /* Server cert keychain path */
33 static int tls_options = -1,/* Options for TLS connections */
34 tls_min_version = _HTTP_TLS_1_0,
35 tls_max_version = _HTTP_TLS_MAX;
36
37
38 /*
39 * Local functions...
40 */
41
42 static BIO_METHOD * _httpBIOMethods(void);
43 static int http_bio_write(BIO *h, const char *buf, int num);
44 static int http_bio_read(BIO *h, char *buf, int size);
45 static long http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
46
47 static BIO_METHOD * http_bio_methods;
48
49 /*
50 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
51 *
52 * @since CUPS 2.0/OS 10.10@
53 */
54
55 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)56 cupsMakeServerCredentials(
57 const char *path, /* I - Path to keychain/directory */
58 const char *common_name, /* I - Common name */
59 int num_alt_names, /* I - Number of subject alternate names */
60 const char **alt_names, /* I - Subject Alternate Names */
61 time_t expiration_date) /* I - Expiration date */
62 {
63 int pid, /* Process ID of command */
64 status; /* Status of command */
65 char command[1024], /* Command */
66 *argv[12], /* Command-line arguments */
67 *envp[1000], /* Environment variables */
68 infofile[1024], /* Type-in information for cert */
69 seedfile[1024]; /* Random number seed file */
70 int envc, /* Number of environment variables */
71 bytes; /* Bytes written */
72 cups_file_t *fp; /* Seed/info file */
73 int infofd; /* Info file descriptor */
74 char temp[1024], /* Temporary directory name */
75 crtfile[1024], /* Certificate filename */
76 keyfile[1024]; /* Private key filename */
77
78 DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date));
79
80 return 0;
81 }
82
83
84 /*
85 * '_httpCreateCredentials()' - Create credentials in the internal format.
86 */
87
88 http_tls_credentials_t /* O - Internal credentials */
_httpCreateCredentials(cups_array_t * credentials)89 _httpCreateCredentials(
90 cups_array_t *credentials) /* I - Array of credentials */
91 {
92 (void)credentials;
93
94 return (NULL);
95 }
96
97
98 /*
99 * '_httpFreeCredentials()' - Free internal credentials.
100 */
101
102 void
_httpFreeCredentials(http_tls_credentials_t credentials)103 _httpFreeCredentials(
104 http_tls_credentials_t credentials) /* I - Internal credentials */
105 {
106 (void)credentials;
107 }
108
109
110 /*
111 * '_httpBIOMethods()' - Get the OpenSSL BIO methods for HTTP connections.
112 */
113
114 static BIO_METHOD * /* O - BIO methods for OpenSSL */
_httpBIOMethods(void)115 _httpBIOMethods(void)
116 {
117 return http_bio_methods;
118 }
119
120
121 /*
122 * 'http_bio_ctrl()' - Control the HTTP connection.
123 */
124
125 static long /* O - Result/data */
http_bio_ctrl(BIO * h,int cmd,long arg1,void * arg2)126 http_bio_ctrl(BIO *h, /* I - BIO data */
127 int cmd, /* I - Control command */
128 long arg1, /* I - First argument */
129 void *arg2) /* I - Second argument */
130 {
131 switch (cmd)
132 {
133 default :
134 return (0);
135
136 case BIO_CTRL_RESET :
137 BIO_set_data(h, NULL);
138 return (0);
139
140 case BIO_C_SET_FILE_PTR :
141 BIO_set_data(h, arg2);
142 BIO_set_init(h, 1);
143 return (1);
144
145 case BIO_C_GET_FILE_PTR :
146 if (arg2)
147 {
148 *((void **)arg2) = BIO_get_data(h);
149 return (1);
150 }
151 else
152 return (0);
153
154 case BIO_CTRL_DUP :
155 case BIO_CTRL_FLUSH :
156 return (1);
157 }
158 }
159
160
161 /*
162 * 'http_bio_read()' - Read data for OpenSSL.
163 */
164
165 static int /* O - Bytes read */
http_bio_read(BIO * h,char * buf,int size)166 http_bio_read(BIO *h, /* I - BIO data */
167 char *buf, /* I - Buffer */
168 int size) /* I - Number of bytes to read */
169 {
170 http_t *http; /* HTTP connection */
171
172
173 http = (http_t *)BIO_get_data(h);
174
175 if (!http->blocking)
176 {
177 /*
178 * Make sure we have data before we read...
179 */
180
181 while (!_httpWait(http, http->wait_value, 0))
182 {
183 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
184 continue;
185
186 http->error = ETIMEDOUT;
187
188 return (-1);
189 }
190 }
191
192 return (recv(http->fd, buf, size, 0));
193 }
194
195
196 /*
197 * 'http_bio_write()' - Write data for OpenSSL.
198 */
199
200 static int /* O - Bytes written */
http_bio_write(BIO * h,const char * buf,int num)201 http_bio_write(BIO *h, /* I - BIO data */
202 const char *buf, /* I - Buffer to write */
203 int num) /* I - Number of bytes to write */
204 {
205 return (send(((http_t *)BIO_get_data(h))->fd, buf, num, 0));
206 }
207
208
209 /*
210 * '_httpTLSInitialize()' - Initialize the TLS stack.
211 */
212
213 void
_httpTLSInitialize(void)214 _httpTLSInitialize(void)
215 {
216 SSL_library_init();
217
218 http_bio_methods = BIO_meth_new(BIO_TYPE_SSL, "http");
219 BIO_meth_set_write(http_bio_methods, http_bio_write);
220 BIO_meth_set_read(http_bio_methods, http_bio_read);
221 BIO_meth_set_ctrl(http_bio_methods, http_bio_ctrl);
222 }
223
224
225 /*
226 * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes.
227 */
228
229 size_t /* O - Bytes available */
_httpTLSPending(http_t * http)230 _httpTLSPending(http_t *http) /* I - HTTP connection */
231 {
232 return (SSL_pending(http->tls));
233 }
234
235
236 /*
237 * '_httpTLSRead()' - Read from a SSL/TLS connection.
238 */
239
240 int /* O - Bytes read */
_httpTLSRead(http_t * http,char * buf,int len)241 _httpTLSRead(http_t *http, /* I - Connection to server */
242 char *buf, /* I - Buffer to store data */
243 int len) /* I - Length of buffer */
244 {
245 return (SSL_read((SSL *)(http->tls), buf, len));
246 }
247
248
249 /*
250 * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options.
251 */
252
253 void
_httpTLSSetOptions(int options,int min_version,int max_version)254 _httpTLSSetOptions(int options, int min_version, int max_version) /* I - Options */
255 {
256 tls_options = options;
257 tls_min_version = min_version;
258 tls_max_version = max_version;
259 }
260
261
262 /*
263 * '_httpTLSStart()' - Set up SSL/TLS support on a connection.
264 */
265
266 int /* O - 0 on success, -1 on failure */
_httpTLSStart(http_t * http)267 _httpTLSStart(http_t *http) /* I - Connection to server */
268 {
269 char hostname[256], /* Hostname */
270 *hostptr; /* Pointer into hostname */
271
272 SSL_CTX *context; /* Context for encryption */
273 BIO *bio; /* BIO data */
274 const char *message = NULL;/* Error message */
275
276 DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http));
277
278 if (tls_options < 0)
279 {
280 DEBUG_puts("4_httpTLSStart: Setting defaults.");
281 _cupsSetDefaults();
282 DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
283 }
284
285 if (http->mode == _HTTP_MODE_SERVER && !tls_keypath)
286 {
287 DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called.");
288 http->error = errno = EINVAL;
289 http->status = HTTP_STATUS_ERROR;
290 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1);
291
292 return (-1);
293 }
294
295 context = SSL_CTX_new(TLS_method());
296 SSL_CTX_set_min_proto_version(context, tls_min_version);
297 SSL_CTX_set_max_proto_version(context, tls_max_version);
298
299 bio = BIO_new(_httpBIOMethods());
300 BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
301
302 http->tls = SSL_new(context);
303 SSL_set_bio(http->tls, bio, bio);
304
305 /* http->tls retains an internal reference to the SSL_CTX. */
306 SSL_CTX_free(context);
307
308 if (http->mode == _HTTP_MODE_CLIENT)
309 {
310 SSL_set_connect_state(http->tls);
311
312 /*
313 * Client: get the hostname to use for TLS...
314 */
315
316 if (httpAddrLocalhost(http->hostaddr))
317 {
318 strlcpy(hostname, "localhost", sizeof(hostname));
319 }
320 else
321 {
322 /*
323 * Otherwise make sure the hostname we have does not end in a trailing dot.
324 */
325
326 strlcpy(hostname, http->hostname, sizeof(hostname));
327 if ((hostptr = hostname + strlen(hostname) - 1) >= hostname &&
328 *hostptr == '.')
329 *hostptr = '\0';
330 }
331 SSL_set_tlsext_host_name(http->tls, hostname);
332 }
333 else
334 {
335 /* @@@ TODO @@@ */
336 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, "Server not supported", 0);
337 }
338
339
340 if (SSL_do_handshake(http->tls) != 1)
341 {
342 unsigned long error; /* Error code */
343 char buf[256];
344
345 while ((error = ERR_get_error()) != 0)
346 {
347 ERR_error_string_n(error, buf, sizeof(buf));
348 DEBUG_printf(("8http_setup_ssl: %s", buf));
349 }
350
351 SSL_free(http->tls);
352 http->tls = NULL;
353
354 http->error = errno;
355 http->status = HTTP_STATUS_ERROR;
356
357 if (!message)
358 message = _("Unable to establish a secure connection to host.");
359
360 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1);
361
362 return (-1);
363 }
364
365 _cups_globals_t *cg = _cupsGlobals();
366 if (cg->server_cert_cb)
367 {
368 int error = 0;
369 X509 *peer_certificate = SSL_get_peer_certificate(http->tls);
370 if (peer_certificate)
371 {
372 ASN1_BIT_STRING *key = X509_get0_pubkey_bitstr(peer_certificate);
373 cups_array_t *credentials = cupsArrayNew(NULL, NULL);
374
375 if (credentials != NULL)
376 {
377 httpAddCredential(credentials, key->data, key->length);
378 error = cg->server_cert_cb(http, http->tls, credentials, cg->server_cert_data);
379 httpFreeCredentials(credentials);
380 }
381 X509_free(peer_certificate);
382 }
383
384 if (error != 0)
385 {
386 SSL_free(http->tls);
387 http->tls = NULL;
388 http->error = errno = EINVAL;
389 http->status = HTTP_STATUS_ERROR;
390 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Client rejected the server certificate."), 1);
391 }
392
393 return (error);
394 }
395
396 return (0);
397 }
398
399
400 /*
401 * '_httpTLSStop()' - Shut down SSL/TLS on a connection.
402 */
403
404 void
_httpTLSStop(http_t * http)405 _httpTLSStop(http_t *http) /* I - Connection to server */
406 {
407 unsigned long error; /* Error code */
408
409 switch (SSL_shutdown(http->tls))
410 {
411 case 1 :
412 break;
413
414 case -1 :
415 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
416 "Fatal error during SSL shutdown!", 0);
417 default :
418 while ((error = ERR_get_error()) != 0)
419 {
420 char buf[256];
421 ERR_error_string_n(error, buf, sizeof(buf));
422 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, buf, 0);
423 }
424 break;
425 }
426
427 SSL_free(http->tls);
428 http->tls = NULL;
429 }
430
431 /*
432 * '_httpTLSWrite()' - Write to a SSL/TLS connection.
433 */
434
435 int /* O - Bytes written */
_httpTLSWrite(http_t * http,const char * buf,int len)436 _httpTLSWrite(http_t *http, /* I - Connection to server */
437 const char *buf, /* I - Buffer holding data */
438 int len) /* I - Length of buffer */
439 {
440 int result; /* Return value */
441
442
443 DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len));
444
445 result = SSL_write((SSL *)(http->tls), buf, len);
446
447 DEBUG_printf(("3http_write_ssl: Returning %d.", result));
448
449 return result;
450 }
451