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