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