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