@@ -33,7 +33,7 @@ DL_FROM = $(URL_IPFIRE)
DIR_APP = $(DIR_SRC)/cups-$(VER)
TARGET = $(DIR_INFO)/$(THISAPP)
PROG = cups
-PAK_VER = 33
+PAK_VER = 34
DEPS = avahi cups-filters dbus ghostscript
@@ -80,6 +80,8 @@ $(subst %,%_BLAKE2,$(objects)) :
$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
@$(PREBUILD)
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/cups-2.4.2_Fix_default_cupsd_keychain_with_OpenSSL.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/cups-2.4.2_Fix_TLS_certificate_generation_bugs_with_openssl.patch
$(UPDATE_AUTOMAKE)
cd $(DIR_APP) && \
./configure \
@@ -87,9 +89,9 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
--sysconfdir=/var/ipfire \
--localstatedir=/var \
--enable-debug \
- --enable-avahi \
+ --with-dnssd=avahi \
--enable-dbus \
- --enable-gnutls \
+ --with-tls=openssl \
--enable-libusb
cd $(DIR_APP) && make $(MAKETUNING)
new file mode 100644
@@ -0,0 +1,337 @@
+--- cups-2.4.2/cups/tls-openssl.c.orig 2022-05-26 08:17:21.000000000 +0200
++++ cups-2.4.2/cups/tls-openssl.c 2023-04-24 20:13:16.431108315 +0200
+@@ -1,7 +1,7 @@
+ /*
+ * TLS support code for CUPS using OpenSSL/LibreSSL.
+ *
+- * Copyright © 2020-2022 by OpenPrinting
++ * Copyright © 2020-2023 by OpenPrinting
+ * Copyright © 2007-2019 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
+ *
+@@ -35,7 +35,8 @@
+ static time_t http_get_date(X509 *cert, int which);
+ //static void http_load_crl(void);
+ static const char *http_make_path(char *buffer, size_t bufsize, const char *dirname, const char *filename, const char *ext);
+-static void http_x509_add_san(X509 *cert, const char *name);
++static int http_x509_add_ext(X509 *cert, int nid, const char *value);
++static void http_x509_add_san(GENERAL_NAMES *gens, const char *name);
+
+
+ /*
+@@ -79,11 +80,15 @@
+ cups_lang_t *language; // Default language info
+ time_t curtime; // Current time
+ X509_NAME *name; // Subject/issuer name
++ ASN1_INTEGER *serial; // Serial number
++ ASN1_TIME *notBefore, // Initial date
++ *notAfter; // Expiration date
+ BIO *bio; // Output file
+ char temp[1024], // Temporary directory name
+ crtfile[1024], // Certificate filename
+ keyfile[1024]; // Private key filename
+ const char *common_ptr; // Pointer into common name
++ GENERAL_NAMES *gens; // Names for SubjectAltName certificate extension
+
+
+ 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));
+@@ -104,7 +109,7 @@
+ // Create the encryption key...
+ DEBUG_puts("1cupsMakeServerCredentials: Creating key pair.");
+
+- if ((rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL)) == NULL)
++ if ((rsa = RSA_generate_key(3072, RSA_F4, NULL, NULL)) == NULL)
+ {
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create key pair."), 1);
+ return (0);
+@@ -131,25 +136,43 @@
+ return (0);
+ }
+
+- curtime = time(NULL);
+- language = cupsLangDefault();
++ curtime = time(NULL);
++
++ notBefore = ASN1_TIME_new();
++ ASN1_TIME_set(notBefore, curtime);
++ X509_set_notBefore(cert, notBefore);
++ ASN1_TIME_free(notBefore);
++
++ notAfter = ASN1_TIME_new();
++ ASN1_TIME_set(notAfter, expiration_date);
++ X509_set_notAfter(cert, notAfter);
++ ASN1_TIME_free(notAfter);
++
++ serial = ASN1_INTEGER_new();
++ ASN1_INTEGER_set(serial, (int)curtime);
++ X509_set_serialNumber(cert, serial);
++ ASN1_INTEGER_free(serial);
+
+- ASN1_TIME_set(X509_get_notBefore(cert), curtime);
+- ASN1_TIME_set(X509_get_notAfter(cert), expiration_date);
+- ASN1_INTEGER_set(X509_get_serialNumber(cert), (int)curtime);
+ X509_set_pubkey(cert, pkey);
+
+- name = X509_get_subject_name(cert);
++ language = cupsLangDefault();
++ name = X509_NAME_new();
+ if (strlen(language->language) == 5)
+- X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)language->language + 3, -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (unsigned char *)language->language + 3, -1, -1, 0);
+ else
+- X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
+- X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Unknown", -1, -1, 0);
+- X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_commonName, MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_organizationName, MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_organizationalUnitName, MBSTRING_ASC, (unsigned char *)"Unknown", -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_stateOrProvinceName, MBSTRING_ASC, (unsigned char *)"Unknown", -1, -1, 0);
++ X509_NAME_add_entry_by_txt(name, SN_localityName, MBSTRING_ASC, (unsigned char *)"Unknown", -1, -1, 0);
+
+ X509_set_issuer_name(cert, name);
++ X509_set_subject_name(cert, name);
++ X509_NAME_free(name);
+
+- http_x509_add_san(cert, common_name);
++ gens = sk_GENERAL_NAME_new_null();
++ http_x509_add_san(gens, common_name);
+ if ((common_ptr = strstr(common_name, ".local")) == NULL)
+ {
+ // Add common_name.local to the list, too...
+@@ -161,7 +184,7 @@
+ *localptr = '\0';
+ strlcat(localname, ".local", sizeof(localname));
+
+- http_x509_add_san(cert, localname);
++ http_x509_add_san(gens, localname);
+ }
+
+ if (num_alt_names > 0)
+@@ -171,10 +194,22 @@
+ for (i = 0; i < num_alt_names; i ++)
+ {
+ if (strcmp(alt_names[i], "localhost"))
+- http_x509_add_san(cert, alt_names[i]);
++ http_x509_add_san(gens, alt_names[i]);
+ }
+ }
+
++ // Add extension with DNS names and free buffer for GENERAL_NAME
++ X509_add1_ext_i2d(cert, NID_subject_alt_name, gens, 0, X509V3_ADD_DEFAULT);
++ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
++
++ // Add extensions that are required to make Chrome happy...
++ http_x509_add_ext(cert, NID_basic_constraints, "critical,CA:FALSE,pathlen:0");
++ http_x509_add_ext(cert, NID_key_usage, "critical,digitalSignature,keyEncipherment");
++ http_x509_add_ext(cert, NID_ext_key_usage, "1.3.6.1.5.5.7.3.1");
++ http_x509_add_ext(cert, NID_subject_key_identifier, "hash");
++ http_x509_add_ext(cert, NID_authority_key_identifier, "keyid,issuer");
++ X509_set_version(cert, 2); // v3
++
+ X509_sign(cert, pkey, EVP_sha256());
+
+ // Save them...
+@@ -959,6 +994,7 @@
+ const char *cn, // Common name to lookup
+ *cnptr; // Pointer into common name
+ int have_creds = 0; // Have credentials?
++ int key_status, crt_status; // Key and certificate load status
+
+ context = SSL_CTX_new(TLS_server_method());
+
+@@ -1002,6 +1038,8 @@
+ else
+ cn = tls_common_name;
+
++ _cupsMutexLock(&tls_mutex);
++
+ if (cn)
+ {
+ // First look in the CUPS keystore...
+@@ -1042,20 +1080,41 @@
+ {
+ DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", cn));
+
+- if (!cupsMakeServerCredentials(tls_keypath, cn, 0, NULL, time(NULL) + 365 * 86400))
++ if (!cupsMakeServerCredentials(tls_keypath, cn, 0, NULL, time(NULL) + 3650 * 86400))
+ {
+ DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
+ http->error = errno = EINVAL;
+ http->status = HTTP_STATUS_ERROR;
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
+- SSL_CTX_free(context);
++ SSL_CTX_free(context);
++ _cupsMutexUnlock(&tls_mutex);
+
+ return (-1);
+ }
+ }
+
+- SSL_CTX_use_PrivateKey_file(context, keyfile, SSL_FILETYPE_PEM);
+- SSL_CTX_use_certificate_file(context, crtfile, SSL_FILETYPE_PEM);
++ _cupsMutexUnlock(&tls_mutex);
++
++ DEBUG_printf(("4_httpTLSStart: Using private key file '%s'.", keyfile));
++ DEBUG_printf(("4_httpTLSStart: Using certificate file '%s'.", crtfile));
++
++ crt_status = SSL_CTX_use_certificate_chain_file(context, crtfile);
++ key_status = SSL_CTX_use_PrivateKey_file(context, keyfile, SSL_FILETYPE_PEM);
++
++ if (!key_status || !crt_status)
++ {
++ // Unable to load private key or certificate...
++ DEBUG_puts("4_httpTLSStart: Unable to use private key or certificate chain file.");
++ if ((error = ERR_get_error()) != 0)
++ _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, ERR_error_string(error, NULL), 0);
++
++ http->status = HTTP_STATUS_ERROR;
++ http->error = EIO;
++
++ SSL_CTX_free(context);
++
++ return (-1);
++ }
+ }
+
+ // Set TLS options...
+@@ -1068,6 +1127,8 @@
+ strlcat(cipherlist, ":!SHA1:!SHA256:!SHA384", sizeof(cipherlist));
+ strlcat(cipherlist, ":@STRENGTH", sizeof(cipherlist));
+
++ DEBUG_printf(("4_httpTLSStart: cipherlist='%s', tls_min_version=%d, tls_max_version=%d", cipherlist, tls_min_version, tls_max_version));
++
+ SSL_CTX_set_min_proto_version(context, versions[tls_min_version]);
+ SSL_CTX_set_max_proto_version(context, versions[tls_max_version]);
+ SSL_CTX_set_cipher_list(context, cipherlist);
+@@ -1094,7 +1155,8 @@
+
+ if (http->mode == _HTTP_MODE_CLIENT)
+ {
+- // Negotiate as a server...
++ // Negotiate as a client...
++ DEBUG_puts("4_httpTLSStart: Calling SSL_connect...");
+ if (SSL_connect(http->tls) < 1)
+ {
+ // Failed
+@@ -1109,12 +1171,15 @@
+ SSL_free(http->tls);
+ http->tls = NULL;
+
++ DEBUG_printf(("4_httpTLSStart: Returning -1 (%s)", ERR_error_string(error, NULL)));
++
+ return (-1);
+ }
+ }
+ else
+ {
+ // Negotiate as a server...
++ DEBUG_puts("4_httpTLSStart: Calling SSL_accept...");
+ if (SSL_accept(http->tls) < 1)
+ {
+ // Failed
+@@ -1129,10 +1194,14 @@
+ SSL_free(http->tls);
+ http->tls = NULL;
+
++ DEBUG_printf(("4_httpTLSStart: Returning -1 (%s)", ERR_error_string(error, NULL)));
++
+ return (-1);
+ }
+ }
+
++ DEBUG_puts("4_httpTLSStart: Returning 0.");
++
+ return (0);
+ }
+
+@@ -1152,6 +1221,8 @@
+ SSL_shutdown(http->tls);
+ SSL_CTX_free(context);
+ SSL_free(http->tls);
++
++ http->tls = NULL;
+ }
+
+
+@@ -1564,32 +1635,62 @@
+
+
+ //
+-// 'http_x509_add_san()' - Add a subjectAltName extension to an X.509 certificate.
++// 'http_x509_add_ext()' - Add an extension to a certificate.
+ //
+
+-static void
+-http_x509_add_san(X509 *cert, // I - Certificate
+- const char *name) // I - Hostname
++static int // O - 1 on success, 0 on failure
++http_x509_add_ext(X509 *cert, // I - Certificate
++ int nid, // I - Extension ID
++ const char *value) // I - Value
+ {
+- char dns_name[1024]; // DNS: prefixed hostname
+- X509_EXTENSION *san_ext; // Extension for subjectAltName
+- ASN1_OCTET_STRING *san_asn1; // ASN1 string
++ int ret; // Return value
++ X509_EXTENSION *ex = NULL; // Extension
++ X509V3_CTX ctx; // Certificate context
+
+
+- // The subjectAltName value for DNS names starts with a DNS: prefix...
+- snprintf(dns_name, sizeof(dns_name), "DNS: %s", name);
++ DEBUG_printf(("3http_x509_add_ext(cert=%p, nid=%d, value=\"%s\")", (void *)cert, nid, value));
+
+- if ((san_asn1 = ASN1_OCTET_STRING_new()) == NULL)
+- return;
++ // Don't use a configuration database...
++ X509V3_set_ctx_nodb(&ctx);
+
+- ASN1_OCTET_STRING_set(san_asn1, (unsigned char *)dns_name, strlen(dns_name));
+- if ((san_ext = X509_EXTENSION_create_by_NID(NULL, NID_subject_alt_name, 0, san_asn1)) == NULL)
++ // Self-signed certificates use the same issuer and subject...
++ X509V3_set_ctx(&ctx, /*issuer*/cert, /*subject*/cert, /*req*/NULL, /*crl*/NULL, /*flags*/0);
++
++ // Create and add the extension...
++ if ((ex = X509V3_EXT_conf_nid(/*conf*/NULL, &ctx, nid, value)) == NULL)
+ {
+- ASN1_OCTET_STRING_free(san_asn1);
+- return;
++ DEBUG_puts("4http_x509_add_ext: Unable to create extension, returning false.");
++ return (0);
+ }
+
+- X509_add_ext(cert, san_ext, -1);
+- X509_EXTENSION_free(san_ext);
+- ASN1_OCTET_STRING_free(san_asn1);
++ ret = X509_add_ext(cert, ex, -1) != 0;
++
++ DEBUG_printf(("4http_x509_add_ext: X509_add_ext returned %s.", ret ? "true" : "false"));
++
++ // Free the extension and return...
++ X509_EXTENSION_free(ex);
++
++ return (ret);
++}
++
++
++//
++// 'http_x509_add_san()' - Add a subjectAltName to GENERAL_NAMES used for
++// the extension to an X.509 certificate.
++//
++
++static void
++http_x509_add_san(GENERAL_NAMES *gens, // I - Concatenation of DNS names
++ const char *name) // I - Hostname
++{
++ GENERAL_NAME *gen_dns = GENERAL_NAME_new();
++ // DNS: name
++ ASN1_IA5STRING *ia5 = ASN1_IA5STRING_new();
++ // Hostname string
++
++
++ // Set the strings and push it on the GENERAL_NAMES list...
++ ASN1_STRING_set(ia5, name, strlen(name));
++ GENERAL_NAME_set0_value(gen_dns, GEN_DNS, ia5);
++ sk_GENERAL_NAME_push(gens, gen_dns);
+ }
new file mode 100644
@@ -0,0 +1,16 @@
+--- cups-2.4.2/scheduler/conf.c.orig 2022-05-26 08:17:21.000000000 +0200
++++ cups-2.4.2/scheduler/conf.c 2023-04-23 15:37:48.521145700 +0200
+@@ -605,11 +605,11 @@
+ ClassifyOverride = 0;
+
+ #ifdef HAVE_TLS
+-# ifdef HAVE_GNUTLS
++# if defined HAVE_GNUTLS || defined HAVE_OPENSSL
+ cupsdSetString(&ServerKeychain, "ssl");
+ # else
+ cupsdSetString(&ServerKeychain, "/Library/Keychains/System.keychain");
+-# endif /* HAVE_GNUTLS */
++# endif /* HAVE_GNUTLS || HAVE_OPENSSL */
+
+ _httpTLSSetOptions(_HTTP_TLS_NONE, _HTTP_TLS_1_0, _HTTP_TLS_MAX);
+ #endif /* HAVE_TLS */