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