xref: /aosp_15_r20/external/libcups/cups/tls-boringssl.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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