]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
cups/hash.c: Put support for MacOS/Win SSL libs back
authorZdenek Dohnal <zdohnal@redhat.com>
Tue, 3 Oct 2023 11:59:40 +0000 (13:59 +0200)
committerZdenek Dohnal <zdohnal@redhat.com>
Tue, 3 Oct 2023 11:59:40 +0000 (13:59 +0200)
- I mustn't remove their support in patch release - this should happen in
2.5 only.
- I have put back support for several hashes as well - they
should be removed in 2.5.
- restrict usage of second block hashing only if OpenSSL/LibreSSL/GnuTLS
  is available

cups/hash.c

index 93ca552c859009f2ae56eb064a8102bee577bdab..c447bab4ea962fdb2c346c339978a25f732f35eb 100644 (file)
 #include "md5-internal.h"
 #ifdef HAVE_OPENSSL
 #  include <openssl/evp.h>
-#else // HAVE_GNUTLS
+#elif defined(HAVE_GNUTLS)
 #  include <gnutls/crypto.h>
+#elif __APPLE__
+#  include <CommonCrypto/CommonDigest.h>
+#elif _WIN32
+#  include <windows.h>
+#  include <bcrypt.h>
 #endif // HAVE_OPENSSL
 
 
@@ -193,17 +198,18 @@ hash_data(const char    *algorithm,       // I - Algorithm
           const void    *b,            // I - Second block or `NULL` for none
           size_t        blen)          // I - Length of second block or `0` for none
 {
+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
   unsigned     hashlen;                // Length of hash
   unsigned char        hashtemp[64];           // Temporary hash buffer
-#ifdef HAVE_OPENSSL
-  const EVP_MD *md = NULL;             // Message digest implementation
-  EVP_MD_CTX   *ctx;                   // Context
-#else // HAVE_GNUTLS
-  gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
-                                       // Algorithm
-  gnutls_hash_hd_t ctx;                        // Context
-#endif // HAVE_OPENSSL
+#else
+  if (strcmp(algorithm, "md5") && (b || blen != 0))
+  {
+    // Second block hashing is not supported without OpenSSL or GnuTLS
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unsupported without GnuTLS or OpenSSL/LibreSSL."), 1);
 
+    return (-1);
+  }
+#endif
 
   if (!strcmp(algorithm, "md5"))
   {
@@ -223,6 +229,10 @@ hash_data(const char    *algorithm,        // I - Algorithm
   }
 
 #ifdef HAVE_OPENSSL
+  const EVP_MD *md = NULL;             // Message digest implementation
+  EVP_MD_CTX   *ctx;                   // Context
+
+
   if (!strcmp(algorithm, "sha"))
   {
     // SHA-1
@@ -244,6 +254,14 @@ hash_data(const char    *algorithm,        // I - Algorithm
   {
     md = EVP_sha512();
   }
+  else if (!strcmp(algorithm, "sha2-512_224"))
+  {
+    md = EVP_sha512_224();
+  }
+  else if (!strcmp(algorithm, "sha2-512_256"))
+  {
+    md = EVP_sha512_256();
+  }
 
   if (md)
   {
@@ -262,7 +280,13 @@ hash_data(const char    *algorithm,        // I - Algorithm
     return ((ssize_t)hashlen);
   }
 
-#else // HAVE_GNUTLS
+#elif defined(HAVE_GNUTLS)
+  gnutls_digest_algorithm_t    alg = GNUTLS_DIG_UNKNOWN;       // Algorithm
+  gnutls_hash_hd_t             ctx;                            // Context
+  unsigned char                temp[64];                       // Temporary hash buffer
+  size_t                       tempsize = 0;                   // Truncate to this size?
+
+
   if (!strcmp(algorithm, "sha"))
   {
     // SHA-1
@@ -284,9 +308,32 @@ hash_data(const char    *algorithm,        // I - Algorithm
   {
     alg = GNUTLS_DIG_SHA512;
   }
+  else if (!strcmp(algorithm, "sha2-512_224"))
+  {
+    alg      = GNUTLS_DIG_SHA512;
+    tempsize = 28;
+  }
+  else if (!strcmp(algorithm, "sha2-512_256"))
+  {
+    alg      = GNUTLS_DIG_SHA512;
+    tempsize = 32;
+  }
 
   if (alg != GNUTLS_DIG_UNKNOWN)
   {
+    if (tempsize > 0)
+    {
+      // Truncate result to tempsize bytes...
+
+      if (hashsize < tempsize)
+        goto too_small;
+
+      gnutls_hash_fast(alg, a, alen, temp);
+      memcpy(hash, temp, tempsize);
+
+      return ((ssize_t)tempsize);
+    }
+
     hashlen = gnutls_hash_get_len(alg);
 
     if (hashlen > hashsize)
@@ -302,7 +349,209 @@ hash_data(const char    *algorithm,       // I - Algorithm
 
     return ((ssize_t)hashlen);
   }
-#endif // HAVE_OPENSSL
+
+#elif __APPLE__
+  if (!strcmp(algorithm, "sha"))
+  {
+    // SHA-1...
+
+    CC_SHA1_CTX        ctx;                    // SHA-1 context
+
+    if (hashsize < CC_SHA1_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA1_Init(&ctx);
+    CC_SHA1_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA1_Final(hash, &ctx);
+
+    return (CC_SHA1_DIGEST_LENGTH);
+  }
+#  ifdef CC_SHA224_DIGEST_LENGTH
+  else if (!strcmp(algorithm, "sha2-224"))
+  {
+    CC_SHA256_CTX      ctx;            // SHA-224 context
+
+    if (hashsize < CC_SHA224_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA224_Init(&ctx);
+    CC_SHA224_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA224_Final(hash, &ctx);
+
+    return (CC_SHA224_DIGEST_LENGTH);
+  }
+#  endif /* CC_SHA224_DIGEST_LENGTH */
+  else if (!strcmp(algorithm, "sha2-256"))
+  {
+    CC_SHA256_CTX      ctx;            // SHA-256 context
+
+    if (hashsize < CC_SHA256_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA256_Init(&ctx);
+    CC_SHA256_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA256_Final(hash, &ctx);
+
+    return (CC_SHA256_DIGEST_LENGTH);
+  }
+  else if (!strcmp(algorithm, "sha2-384"))
+  {
+    CC_SHA512_CTX      ctx;            // SHA-384 context
+
+    if (hashsize < CC_SHA384_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA384_Init(&ctx);
+    CC_SHA384_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA384_Final(hash, &ctx);
+
+    return (CC_SHA384_DIGEST_LENGTH);
+  }
+  else if (!strcmp(algorithm, "sha2-512"))
+  {
+    CC_SHA512_CTX      ctx;            // SHA-512 context
+
+    if (hashsize < CC_SHA512_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA512_Init(&ctx);
+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA512_Final(hash, &ctx);
+
+    return (CC_SHA512_DIGEST_LENGTH);
+  }
+#  ifdef CC_SHA224_DIGEST_LENGTH
+  else if (!strcmp(algorithm, "sha2-512_224"))
+  {
+    CC_SHA512_CTX      ctx;            // SHA-512 context
+    unsigned char      temp[CC_SHA512_DIGEST_LENGTH];
+                                        // SHA-512 hash
+
+    // SHA2-512 truncated to 224 bits (28 bytes)...
+
+    if (hashsize < CC_SHA224_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA512_Init(&ctx);
+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA512_Final(temp, &ctx);
+
+    memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH);
+
+    return (CC_SHA224_DIGEST_LENGTH);
+  }
+#  endif // CC_SHA224_DIGEST_LENGTH
+  else if (!strcmp(algorithm, "sha2-512_256"))
+  {
+    CC_SHA512_CTX      ctx;            // SHA-512 context
+    unsigned char      temp[CC_SHA512_DIGEST_LENGTH];
+                                        // SHA-512 hash
+
+    // SHA2-512 truncated to 256 bits (32 bytes)...
+
+    if (hashsize < CC_SHA256_DIGEST_LENGTH)
+      goto too_small;
+
+    CC_SHA512_Init(&ctx);
+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
+    CC_SHA512_Final(temp, &ctx);
+
+    memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH);
+
+    return (CC_SHA256_DIGEST_LENGTH);
+  }
+
+#elif _WIN32
+  // Use Windows CNG APIs to perform hashing...
+  BCRYPT_ALG_HANDLE    alg;            // Algorithm handle
+  LPCWSTR              algid = NULL;   // Algorithm ID
+  ssize_t              hashlen;        // Hash length
+  NTSTATUS             status;         // Status of hash
+  unsigned char                temp[64];       // Temporary hash buffer
+  size_t               tempsize = 0;   // Truncate to this size?
+
+
+  if (!strcmp(algorithm, "sha"))
+  {
+    algid   = BCRYPT_SHA1_ALGORITHM;
+    hashlen = 20;
+  }
+  else if (!strcmp(algorithm, "sha2-256"))
+  {
+    algid   = BCRYPT_SHA256_ALGORITHM;
+    hashlen = 32;
+  }
+  else if (!strcmp(algorithm, "sha2-384"))
+  {
+    algid   = BCRYPT_SHA384_ALGORITHM;
+    hashlen = 48;
+  }
+  else if (!strcmp(algorithm, "sha2-512"))
+  {
+    algid   = BCRYPT_SHA512_ALGORITHM;
+    hashlen = 64;
+  }
+  else if (!strcmp(algorithm, "sha2-512_224"))
+  {
+    algid   = BCRYPT_SHA512_ALGORITHM;
+    hashlen = tempsize = 28;
+  }
+  else if (!strcmp(algorithm, "sha2-512_256"))
+  {
+    algid   = BCRYPT_SHA512_ALGORITHM;
+    hashlen = tempsize = 32;
+  }
+
+  if (algid)
+  {
+    if (hashsize < (size_t)hashlen)
+      goto too_small;
+
+    if ((status = BCryptOpenAlgorithmProvider(&alg, algid, NULL, 0)) < 0)
+    {
+      DEBUG_printf(("2cupsHashData: BCryptOpenAlgorithmProvider returned %d.", status));
+
+      if (status == STATUS_INVALID_PARAMETER)
+       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad algorithm parameter."), 1);
+      else
+       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to access cryptographic provider."), 1);
+
+      return (-1);
+    }
+
+    if (tempsize > 0)
+    {
+      // Do a truncated SHA2-512 hash...
+      status = BCryptHash(alg, NULL, 0, (PUCHAR)a, (ULONG)alen, temp, sizeof(temp));
+      memcpy(hash, temp, hashlen);
+    }
+    else
+    {
+      // Hash directly to buffer...
+      status = BCryptHash(alg, NULL, 0, (PUCHAR)a, (ULONG)alen, hash, (ULONG)hashlen);
+    }
+
+    BCryptCloseAlgorithmProvider(alg, 0);
+
+    if (status < 0)
+    {
+      DEBUG_printf(("2cupsHashData: BCryptHash returned %d.", status));
+
+      if (status == STATUS_INVALID_PARAMETER)
+       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad hashing parameter."), 1);
+      else
+       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hashing failed."), 1);
+
+      return (-1);
+    }
+
+    return (hashlen);
+  }
+
+#else
+  if (hashsize < 64)
+    goto too_small;
+#endif // __APPLE__
 
   // Unknown hash algorithm...
   _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);