]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
GNU TLS updates.
authorMichael R Sweet <msweet@msweet.org>
Wed, 30 Oct 2024 13:49:44 +0000 (09:49 -0400)
committerMichael R Sweet <msweet@msweet.org>
Wed, 30 Oct 2024 13:49:44 +0000 (09:49 -0400)
cups/cups.h
cups/testcreds.c
cups/tls-gnutls.c
cups/tls-openssl.c
cups/tls.c

index a81262428fb53041fa9c21058a450b26bc01edbb..72cd74379607ccdc5bc52e0cce51cbf3ac9a4052 100644 (file)
@@ -388,6 +388,7 @@ extern http_t               *cupsConnectDestBlock(cups_dest_t *dest, unsigned flags, int msec
 #  endif // __BLOCKS__
 extern char            *cupsCopyCredentials(const char *path, const char *common_name) _CUPS_PUBLIC;
 extern char            *cupsCopyCredentialsKey(const char *path, const char *common_name) _CUPS_PUBLIC;
+extern char            *cupsCopyCredentialsPublicKey(const char *path, const char *common_name) _CUPS_PUBLIC;
 extern char            *cupsCopyCredentialsRequest(const char *path, const char *common_name) _CUPS_PUBLIC;
 extern int             cupsCopyDest(cups_dest_t *dest, int num_dests, cups_dest_t **dests) _CUPS_PUBLIC;
 extern int             cupsCopyDestConflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int num_options, cups_option_t *options, const char *new_option, const char *new_value, int *num_conflicts, cups_option_t **conflicts, int *num_resolved, cups_option_t **resolved) _CUPS_PUBLIC;
index 5018df874c815ee5ab04c5b8639d15e66b601e23..1e7626a4ca92d719b58ce92fed928ef63c4c2194 100644 (file)
@@ -466,6 +466,16 @@ do_unit_tests(void)
 
       if (data)
       {
+        char   *pubkey;                // Public key
+
+        testBegin("cupsCopyCredentialsPublicKey()");
+        if ((pubkey = cupsCopyCredentialsPublicKey(TEST_CERT_PATH, "altprinter")) != NULL)
+          testEnd(true);
+       else
+         testEndMessage(false, "%s", cupsGetErrorString());
+
+        free(pubkey);
+
         testBegin("cupsSignCredentialsRequest(altprinter w/alt names)");
         if (cupsSignCredentialsRequest(TEST_CERT_PATH, "altprinter", data, "_site_", CUPS_CREDPURPOSE_ALL, CUPS_CREDUSAGE_ALL, /*cb*/NULL, /*cb_data*/NULL, time(NULL) + 30 * 86400))
         {
@@ -500,6 +510,16 @@ do_unit_tests(void)
 
       if (data)
       {
+        char   *pubkey;                // Public key
+
+        testBegin("cupsCopyCredentialsPublicKey()");
+        if ((pubkey = cupsCopyCredentialsPublicKey(TEST_CERT_PATH, "altprinter")) != NULL)
+          testEnd(true);
+       else
+         testEndMessage(false, "%s", cupsGetErrorString());
+
+        free(pubkey);
+
         testBegin("cupsSignCredentialsRequest(altprinter w/o alt names)");
         if (cupsSignCredentialsRequest(TEST_CERT_PATH, "altprinter", data, "_site_", CUPS_CREDPURPOSE_ALL, CUPS_CREDUSAGE_ALL, /*cb*/NULL, /*cb_data*/NULL, time(NULL) + 30 * 86400))
         {
index db5801ca84f5e772621686eb2bb4e93563379387..dcfea91e8a5b4c46b24d054811025eed46114380 100644 (file)
@@ -178,11 +178,13 @@ cupsCreateCredentials(
   bool                 ret = false;    // Return value
   gnutls_x509_crt_t    crt = NULL;     // New certificate
   gnutls_x509_privkey_t        key = NULL;     // Encryption private key
+  gnutls_pubkey_t      pubkey = NULL;  // Encryption public key
   gnutls_x509_crt_t    root_crt = NULL;// Root certificate
   gnutls_x509_privkey_t        root_key = NULL;// Root private key
   char                 defpath[1024],  // Default path
                        crtfile[1024],  // Certificate filename
                        keyfile[1024],  // Private key filename
+                       pubfile[1024],  // Public key filename
                        *root_crtdata,  // Root certificate data
                        *root_keydata;  // Root private key data
   unsigned             gnutls_usage = 0;// GNU TLS keyUsage bits
@@ -208,6 +210,27 @@ cupsCreateCredentials(
 
   http_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
   http_make_path(keyfile, sizeof(keyfile), path, common_name, "key");
+  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
+
+  // Key usage flags...
+  if (usage & CUPS_CREDUSAGE_DIGITAL_SIGNATURE)
+    gnutls_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
+  if (usage & CUPS_CREDUSAGE_NON_REPUDIATION)
+    gnutls_usage |= GNUTLS_KEY_NON_REPUDIATION;
+  if (usage & CUPS_CREDUSAGE_KEY_ENCIPHERMENT)
+    gnutls_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
+  if (usage & CUPS_CREDUSAGE_DATA_ENCIPHERMENT)
+    gnutls_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
+  if (usage & CUPS_CREDUSAGE_KEY_AGREEMENT)
+    gnutls_usage |= GNUTLS_KEY_KEY_AGREEMENT;
+  if (usage & CUPS_CREDUSAGE_KEY_CERT_SIGN)
+    gnutls_usage |= GNUTLS_KEY_KEY_CERT_SIGN;
+  if (usage & CUPS_CREDUSAGE_CRL_SIGN)
+    gnutls_usage |= GNUTLS_KEY_CRL_SIGN;
+  if (usage & CUPS_CREDUSAGE_ENCIPHER_ONLY)
+    gnutls_usage |= GNUTLS_KEY_ENCIPHER_ONLY;
+  if (usage & CUPS_CREDUSAGE_DECIPHER_ONLY)
+    gnutls_usage |= GNUTLS_KEY_DECIPHER_ONLY;
 
   // Create the encryption key...
   DEBUG_puts("1cupsCreateCredentials: Creating key pair.");
@@ -238,6 +261,39 @@ cupsCreateCredentials(
     goto done;
   }
 
+  bytes = sizeof(buffer);
+
+  if ((err = gnutls_pubkey_init(&pubkey)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to create public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((err = gnutls_pubkey_import_privkey(pubkey, key, gnutls_usage, /*flags*/0)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to import public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((err = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to export public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((fp = cupsFileOpen(pubfile, "w")) != NULL)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Writing public key to \"%s\".", keyfile);
+    cupsFileWrite(fp, (char *)buffer, bytes);
+    cupsFileClose(fp);
+  }
+  else
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to create public key file \"%s\": %s", keyfile, strerror(errno));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+    goto done;
+  }
+
   // Create the certificate...
   DEBUG_puts("1cupsCreateCredentials: Generating X.509 certificate.");
 
@@ -310,25 +366,6 @@ cupsCreateCredentials(
   if (purpose & CUPS_CREDPURPOSE_OCSP_SIGNING)
     gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_OCSP_SIGNING, 0);
 
-  if (usage & CUPS_CREDUSAGE_DIGITAL_SIGNATURE)
-    gnutls_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
-  if (usage & CUPS_CREDUSAGE_NON_REPUDIATION)
-    gnutls_usage |= GNUTLS_KEY_NON_REPUDIATION;
-  if (usage & CUPS_CREDUSAGE_KEY_ENCIPHERMENT)
-    gnutls_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
-  if (usage & CUPS_CREDUSAGE_DATA_ENCIPHERMENT)
-    gnutls_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
-  if (usage & CUPS_CREDUSAGE_KEY_AGREEMENT)
-    gnutls_usage |= GNUTLS_KEY_KEY_AGREEMENT;
-  if (usage & CUPS_CREDUSAGE_KEY_CERT_SIGN)
-    gnutls_usage |= GNUTLS_KEY_KEY_CERT_SIGN;
-  if (usage & CUPS_CREDUSAGE_CRL_SIGN)
-    gnutls_usage |= GNUTLS_KEY_CRL_SIGN;
-  if (usage & CUPS_CREDUSAGE_ENCIPHER_ONLY)
-    gnutls_usage |= GNUTLS_KEY_ENCIPHER_ONLY;
-  if (usage & CUPS_CREDUSAGE_DECIPHER_ONLY)
-    gnutls_usage |= GNUTLS_KEY_DECIPHER_ONLY;
-
   gnutls_x509_crt_set_key_usage(crt, gnutls_usage);
   gnutls_x509_crt_set_version(crt, 3);
 
@@ -423,6 +460,8 @@ cupsCreateCredentials(
     gnutls_x509_crt_deinit(crt);
   if (key)
     gnutls_x509_privkey_deinit(key);
+  if (pubkey)
+    gnutls_pubkey_deinit(pubkey);
 
   return (ret);
 }
@@ -502,9 +541,11 @@ cupsCreateCredentialsRequest(
   bool                 ret = false;    // Return value
   gnutls_x509_crq_t    crq = NULL;     // Certificate request
   gnutls_x509_privkey_t        key = NULL;     // Private/public key pair
+  gnutls_pubkey_t      pubkey = NULL;  // Encryption public key
   char                 defpath[1024],  // Default path
                        csrfile[1024],  // Certificate signing request filename
-                       keyfile[1024];  // Private key filename
+                       keyfile[1024],  // Private key filename
+                       pubfile[1024];  // Public key filename
   unsigned             gnutls_usage = 0;// GNU TLS keyUsage bits
   cups_file_t          *fp;            // Key/cert file
   unsigned char                buffer[8192];   // Buffer for key/cert data
@@ -526,6 +567,27 @@ cupsCreateCredentialsRequest(
 
   http_make_path(csrfile, sizeof(csrfile), path, common_name, "csr");
   http_make_path(keyfile, sizeof(keyfile), path, common_name, "ktm");
+  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
+
+  // Key usage flags...
+  if (usage & CUPS_CREDUSAGE_DIGITAL_SIGNATURE)
+    gnutls_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
+  if (usage & CUPS_CREDUSAGE_NON_REPUDIATION)
+    gnutls_usage |= GNUTLS_KEY_NON_REPUDIATION;
+  if (usage & CUPS_CREDUSAGE_KEY_ENCIPHERMENT)
+    gnutls_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
+  if (usage & CUPS_CREDUSAGE_DATA_ENCIPHERMENT)
+    gnutls_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
+  if (usage & CUPS_CREDUSAGE_KEY_AGREEMENT)
+    gnutls_usage |= GNUTLS_KEY_KEY_AGREEMENT;
+  if (usage & CUPS_CREDUSAGE_KEY_CERT_SIGN)
+    gnutls_usage |= GNUTLS_KEY_KEY_CERT_SIGN;
+  if (usage & CUPS_CREDUSAGE_CRL_SIGN)
+    gnutls_usage |= GNUTLS_KEY_CRL_SIGN;
+  if (usage & CUPS_CREDUSAGE_ENCIPHER_ONLY)
+    gnutls_usage |= GNUTLS_KEY_ENCIPHER_ONLY;
+  if (usage & CUPS_CREDUSAGE_DECIPHER_ONLY)
+    gnutls_usage |= GNUTLS_KEY_DECIPHER_ONLY;
 
   // Create the encryption key...
   DEBUG_puts("1cupsCreateCredentialsRequest: Creating key pair.");
@@ -555,7 +617,40 @@ cupsCreateCredentialsRequest(
     goto done;
   }
 
-  // Create the certificate...
+  bytes = sizeof(buffer);
+
+  if ((err = gnutls_pubkey_init(&pubkey)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to create public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((err = gnutls_pubkey_import_privkey(pubkey, key, gnutls_usage, /*flags*/0)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to import public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((err = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to export public key: %s", gnutls_strerror(err));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(err), 0);
+    goto done;
+  }
+  else if ((fp = cupsFileOpen(pubfile, "w")) != NULL)
+  {
+    DEBUG_printf("1cupsCreateCredentials: Writing public key to \"%s\".", keyfile);
+    cupsFileWrite(fp, (char *)buffer, bytes);
+    cupsFileClose(fp);
+  }
+  else
+  {
+    DEBUG_printf("1cupsCreateCredentials: Unable to create public key file \"%s\": %s", keyfile, strerror(errno));
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+    goto done;
+  }
+
+  // Create the certificate signing request...
   DEBUG_puts("1cupsCreateCredentialsRequest: Generating X.509 certificate request.");
 
   if (!organization)
@@ -613,25 +708,6 @@ cupsCreateCredentialsRequest(
   if (purpose & CUPS_CREDPURPOSE_OCSP_SIGNING)
     gnutls_x509_crq_set_key_purpose_oid(crq, GNUTLS_KP_OCSP_SIGNING, 0);
 
-  if (usage & CUPS_CREDUSAGE_DIGITAL_SIGNATURE)
-    gnutls_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
-  if (usage & CUPS_CREDUSAGE_NON_REPUDIATION)
-    gnutls_usage |= GNUTLS_KEY_NON_REPUDIATION;
-  if (usage & CUPS_CREDUSAGE_KEY_ENCIPHERMENT)
-    gnutls_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
-  if (usage & CUPS_CREDUSAGE_DATA_ENCIPHERMENT)
-    gnutls_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
-  if (usage & CUPS_CREDUSAGE_KEY_AGREEMENT)
-    gnutls_usage |= GNUTLS_KEY_KEY_AGREEMENT;
-  if (usage & CUPS_CREDUSAGE_KEY_CERT_SIGN)
-    gnutls_usage |= GNUTLS_KEY_KEY_CERT_SIGN;
-  if (usage & CUPS_CREDUSAGE_CRL_SIGN)
-    gnutls_usage |= GNUTLS_KEY_CRL_SIGN;
-  if (usage & CUPS_CREDUSAGE_ENCIPHER_ONLY)
-    gnutls_usage |= GNUTLS_KEY_ENCIPHER_ONLY;
-  if (usage & CUPS_CREDUSAGE_DECIPHER_ONLY)
-    gnutls_usage |= GNUTLS_KEY_DECIPHER_ONLY;
-
   gnutls_x509_crq_set_key_usage(crq, gnutls_usage);
   gnutls_x509_crq_set_version(crq, 3);
 
@@ -669,6 +745,8 @@ cupsCreateCredentialsRequest(
     gnutls_x509_crq_deinit(crq);
   if (key)
     gnutls_x509_privkey_deinit(key);
+  if (pubkey)
+    gnutls_pubkey_deinit(pubkey);
 
   return (ret);
 }
index b4652ca36ff30bfdbafd1211e08d4aa7014077cd..8a5c5a4cc3c53b246f98305a57415a8989bbbaa8 100644 (file)
@@ -181,6 +181,7 @@ cupsCreateCredentials(
   char         defpath[1024],          // Default path
                crtfile[1024],          // Certificate filename
                keyfile[1024],          // Private key filename
+               pubfile[1024],          // Public key filename
                root_crtfile[1024],     // Root certificate filename
                root_keyfile[1024];     // Root private key filename
   time_t       curtime;                // Current time
@@ -235,7 +236,7 @@ cupsCreateCredentials(
   X509_set_notBefore(cert, notBefore);
   ASN1_TIME_free(notBefore);
 
-  notAfter  = ASN1_TIME_new();
+  notAfter = ASN1_TIME_new();
   ASN1_TIME_set(notAfter, expiration_date);
   X509_set_notAfter(cert, notAfter);
   ASN1_TIME_free(notAfter);
@@ -358,6 +359,7 @@ cupsCreateCredentials(
   // Save them...
   http_make_path(crtfile, sizeof(crtfile), path, common_name, "crt");
   http_make_path(keyfile, sizeof(keyfile), path, common_name, "key");
+  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
 
   if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
   {
@@ -374,6 +376,21 @@ cupsCreateCredentials(
 
   BIO_free(bio);
 
+  if ((bio = BIO_new_file(pubfile, "wb")) == NULL)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+    goto done;
+  }
+
+  if (!PEM_write_bio_PUBKEY(bio, pkey))
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write public key."), true);
+    BIO_free(bio);
+    goto done;
+  }
+
+  BIO_free(bio);
+
   if ((bio = BIO_new_file(crtfile, "wb")) == NULL)
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
@@ -490,7 +507,8 @@ cupsCreateCredentialsRequest(
   char         temp[1024],             // Temporary directory name
                *tempptr,               // Pointer into temporary string
                csrfile[1024],          // Certificate signing request filename
-               keyfile[1024];          // Private key filename
+               keyfile[1024],          // Private key filename
+               pubfile[1024];          // Public key filename
   STACK_OF(X509_EXTENSION) *exts;      // Extensions
   unsigned     i;                      // Looping var
   cups_credpurpose_t purpose_bit;      // Current purpose
@@ -511,6 +529,7 @@ cupsCreateCredentialsRequest(
 
   http_make_path(csrfile, sizeof(csrfile), path, common_name, "csr");
   http_make_path(keyfile, sizeof(keyfile), path, common_name, "ktm");
+  http_make_path(pubfile, sizeof(pubfile), path, common_name, "pub");
 
   // Create the encryption key...
   DEBUG_puts("1cupsCreateCredentialsRequest: Creating key pair.");
@@ -593,6 +612,21 @@ cupsCreateCredentialsRequest(
 
   BIO_free(bio);
 
+  if ((bio = BIO_new_file(pubfile, "wb")) == NULL)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+    goto done;
+  }
+
+  if (!PEM_write_bio_PUBKEY(bio, pkey))
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write public key."), true);
+    BIO_free(bio);
+    goto done;
+  }
+
+  BIO_free(bio);
+
   if ((bio = BIO_new_file(csrfile, "wb")) == NULL)
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
@@ -996,7 +1030,7 @@ cupsSignCredentialsRequest(
   ASN1_INTEGER *serial;                // Serial number
   ASN1_TIME    *notBefore,             // Initial date
                *notAfter;              // Expiration date
-  BIO          *bio;                   // Output file
+  BIO          *bio;                   // Input/output file
   char         temp[1024];             // Temporary string
   int          i, j,                   // Looping vars
                num_exts;               // Number of extensions
index 5ae71bf0f712cfc9825704a5d9a2bcf6d04482c2..02863fe5e9c1484704e8c63046a5d11cf6d89ef8 100644 (file)
@@ -102,11 +102,24 @@ cupsCopyCredentialsKey(
 }
 
 
+//
+// 'cupsCopyCredentialsPublicKey()' - Copy the public key for a X.509 certificate request.
+//
+
+char *                                 // O - PEM-encoded public key
+cupsCopyCredentialsPublicKey(
+    const char *path,                  // I - Directory path for certificate/key store or `NULL` for default
+    const char *common_name)           // I - Common name
+{
+  return (http_copy_file(path, common_name, "pub"));
+}
+
+
 //
 // 'cupsCopyCredentialsRequest()' - Copy the X.509 certificate signing request to a string.
 //
 
-char *
+char *                                 // O - PEM-encoded X.509 certificate signing request
 cupsCopyCredentialsRequest(
     const char *path,                  // I - Directory path for certificate/key store or `NULL` for default
     const char *common_name)           // I - Common name