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