1From c6cd5e9c10edc68caf6936a3d3274f758e9cd03d Mon Sep 17 00:00:00 2001
2From: Zdenek Dohnal <zdohnal@redhat.com>
3Date: Tue, 3 Oct 2023 13:59:40 +0200
4Subject: [PATCH] cups/hash.c: Put support for MacOS/Win SSL libs back
5
6- I mustn't remove their support in patch release - this should happen in
72.5 only.
8- I have put back support for several hashes as well - they
9should be removed in 2.5.
10- restrict usage of second block hashing only if OpenSSL/LibreSSL/GnuTLS
11  is available
12
13Upstream: https://github.com/OpenPrinting/cups/commit/c6cd5e9c10edc68caf6936a3d3274f758e9cd03d
14Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
15---
16 cups/hash.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++++---
17 1 file changed, 260 insertions(+), 11 deletions(-)
18
19diff --git a/cups/hash.c b/cups/hash.c
20index 93ca552c8..c447bab4e 100644
21--- a/cups/hash.c
22+++ b/cups/hash.c
23@@ -12,8 +12,13 @@
24 #include "md5-internal.h"
25 #ifdef HAVE_OPENSSL
26 #  include <openssl/evp.h>
27-#else // HAVE_GNUTLS
28+#elif defined(HAVE_GNUTLS)
29 #  include <gnutls/crypto.h>
30+#elif __APPLE__
31+#  include <CommonCrypto/CommonDigest.h>
32+#elif _WIN32
33+#  include <windows.h>
34+#  include <bcrypt.h>
35 #endif // HAVE_OPENSSL
36
37
38@@ -193,17 +198,18 @@ hash_data(const char    *algorithm,	// I - Algorithm
39           const void    *b,		// I - Second block or `NULL` for none
40           size_t        blen)		// I - Length of second block or `0` for none
41 {
42+#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
43   unsigned	hashlen;		// Length of hash
44   unsigned char	hashtemp[64];		// Temporary hash buffer
45-#ifdef HAVE_OPENSSL
46-  const EVP_MD	*md = NULL;		// Message digest implementation
47-  EVP_MD_CTX	*ctx;			// Context
48-#else // HAVE_GNUTLS
49-  gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
50-					// Algorithm
51-  gnutls_hash_hd_t ctx;			// Context
52-#endif // HAVE_OPENSSL
53+#else
54+  if (strcmp(algorithm, "md5") && (b || blen != 0))
55+  {
56+    // Second block hashing is not supported without OpenSSL or GnuTLS
57+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unsupported without GnuTLS or OpenSSL/LibreSSL."), 1);
58
59+    return (-1);
60+  }
61+#endif
62
63   if (!strcmp(algorithm, "md5"))
64   {
65@@ -223,6 +229,10 @@ hash_data(const char    *algorithm,	// I - Algorithm
66   }
67
68 #ifdef HAVE_OPENSSL
69+  const EVP_MD	*md = NULL;		// Message digest implementation
70+  EVP_MD_CTX	*ctx;			// Context
71+
72+
73   if (!strcmp(algorithm, "sha"))
74   {
75     // SHA-1
76@@ -244,6 +254,14 @@ hash_data(const char    *algorithm,	// I - Algorithm
77   {
78     md = EVP_sha512();
79   }
80+  else if (!strcmp(algorithm, "sha2-512_224"))
81+  {
82+    md = EVP_sha512_224();
83+  }
84+  else if (!strcmp(algorithm, "sha2-512_256"))
85+  {
86+    md = EVP_sha512_256();
87+  }
88
89   if (md)
90   {
91@@ -262,7 +280,13 @@ hash_data(const char    *algorithm,	// I - Algorithm
92     return ((ssize_t)hashlen);
93   }
94
95-#else // HAVE_GNUTLS
96+#elif defined(HAVE_GNUTLS)
97+  gnutls_digest_algorithm_t	alg = GNUTLS_DIG_UNKNOWN;	// Algorithm
98+  gnutls_hash_hd_t		ctx;				// Context
99+  unsigned char		temp[64];			// Temporary hash buffer
100+  size_t			tempsize = 0;			// Truncate to this size?
101+
102+
103   if (!strcmp(algorithm, "sha"))
104   {
105     // SHA-1
106@@ -284,9 +308,32 @@ hash_data(const char    *algorithm,	// I - Algorithm
107   {
108     alg = GNUTLS_DIG_SHA512;
109   }
110+  else if (!strcmp(algorithm, "sha2-512_224"))
111+  {
112+    alg      = GNUTLS_DIG_SHA512;
113+    tempsize = 28;
114+  }
115+  else if (!strcmp(algorithm, "sha2-512_256"))
116+  {
117+    alg      = GNUTLS_DIG_SHA512;
118+    tempsize = 32;
119+  }
120
121   if (alg != GNUTLS_DIG_UNKNOWN)
122   {
123+    if (tempsize > 0)
124+    {
125+      // Truncate result to tempsize bytes...
126+
127+      if (hashsize < tempsize)
128+        goto too_small;
129+
130+      gnutls_hash_fast(alg, a, alen, temp);
131+      memcpy(hash, temp, tempsize);
132+
133+      return ((ssize_t)tempsize);
134+    }
135+
136     hashlen = gnutls_hash_get_len(alg);
137
138     if (hashlen > hashsize)
139@@ -302,7 +349,209 @@ hash_data(const char    *algorithm,	// I - Algorithm
140
141     return ((ssize_t)hashlen);
142   }
143-#endif // HAVE_OPENSSL
144+
145+#elif __APPLE__
146+  if (!strcmp(algorithm, "sha"))
147+  {
148+    // SHA-1...
149+
150+    CC_SHA1_CTX	ctx;			// SHA-1 context
151+
152+    if (hashsize < CC_SHA1_DIGEST_LENGTH)
153+      goto too_small;
154+
155+    CC_SHA1_Init(&ctx);
156+    CC_SHA1_Update(&ctx, a, (CC_LONG)alen);
157+    CC_SHA1_Final(hash, &ctx);
158+
159+    return (CC_SHA1_DIGEST_LENGTH);
160+  }
161+#  ifdef CC_SHA224_DIGEST_LENGTH
162+  else if (!strcmp(algorithm, "sha2-224"))
163+  {
164+    CC_SHA256_CTX	ctx;		// SHA-224 context
165+
166+    if (hashsize < CC_SHA224_DIGEST_LENGTH)
167+      goto too_small;
168+
169+    CC_SHA224_Init(&ctx);
170+    CC_SHA224_Update(&ctx, a, (CC_LONG)alen);
171+    CC_SHA224_Final(hash, &ctx);
172+
173+    return (CC_SHA224_DIGEST_LENGTH);
174+  }
175+#  endif /* CC_SHA224_DIGEST_LENGTH */
176+  else if (!strcmp(algorithm, "sha2-256"))
177+  {
178+    CC_SHA256_CTX	ctx;		// SHA-256 context
179+
180+    if (hashsize < CC_SHA256_DIGEST_LENGTH)
181+      goto too_small;
182+
183+    CC_SHA256_Init(&ctx);
184+    CC_SHA256_Update(&ctx, a, (CC_LONG)alen);
185+    CC_SHA256_Final(hash, &ctx);
186+
187+    return (CC_SHA256_DIGEST_LENGTH);
188+  }
189+  else if (!strcmp(algorithm, "sha2-384"))
190+  {
191+    CC_SHA512_CTX	ctx;		// SHA-384 context
192+
193+    if (hashsize < CC_SHA384_DIGEST_LENGTH)
194+      goto too_small;
195+
196+    CC_SHA384_Init(&ctx);
197+    CC_SHA384_Update(&ctx, a, (CC_LONG)alen);
198+    CC_SHA384_Final(hash, &ctx);
199+
200+    return (CC_SHA384_DIGEST_LENGTH);
201+  }
202+  else if (!strcmp(algorithm, "sha2-512"))
203+  {
204+    CC_SHA512_CTX	ctx;		// SHA-512 context
205+
206+    if (hashsize < CC_SHA512_DIGEST_LENGTH)
207+      goto too_small;
208+
209+    CC_SHA512_Init(&ctx);
210+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
211+    CC_SHA512_Final(hash, &ctx);
212+
213+    return (CC_SHA512_DIGEST_LENGTH);
214+  }
215+#  ifdef CC_SHA224_DIGEST_LENGTH
216+  else if (!strcmp(algorithm, "sha2-512_224"))
217+  {
218+    CC_SHA512_CTX	ctx;		// SHA-512 context
219+    unsigned char	temp[CC_SHA512_DIGEST_LENGTH];
220+                                        // SHA-512 hash
221+
222+    // SHA2-512 truncated to 224 bits (28 bytes)...
223+
224+    if (hashsize < CC_SHA224_DIGEST_LENGTH)
225+      goto too_small;
226+
227+    CC_SHA512_Init(&ctx);
228+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
229+    CC_SHA512_Final(temp, &ctx);
230+
231+    memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH);
232+
233+    return (CC_SHA224_DIGEST_LENGTH);
234+  }
235+#  endif // CC_SHA224_DIGEST_LENGTH
236+  else if (!strcmp(algorithm, "sha2-512_256"))
237+  {
238+    CC_SHA512_CTX	ctx;		// SHA-512 context
239+    unsigned char	temp[CC_SHA512_DIGEST_LENGTH];
240+                                        // SHA-512 hash
241+
242+    // SHA2-512 truncated to 256 bits (32 bytes)...
243+
244+    if (hashsize < CC_SHA256_DIGEST_LENGTH)
245+      goto too_small;
246+
247+    CC_SHA512_Init(&ctx);
248+    CC_SHA512_Update(&ctx, a, (CC_LONG)alen);
249+    CC_SHA512_Final(temp, &ctx);
250+
251+    memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH);
252+
253+    return (CC_SHA256_DIGEST_LENGTH);
254+  }
255+
256+#elif _WIN32
257+  // Use Windows CNG APIs to perform hashing...
258+  BCRYPT_ALG_HANDLE	alg;		// Algorithm handle
259+  LPCWSTR		algid = NULL;	// Algorithm ID
260+  ssize_t		hashlen;	// Hash length
261+  NTSTATUS		status;		// Status of hash
262+  unsigned char		temp[64];	// Temporary hash buffer
263+  size_t		tempsize = 0;	// Truncate to this size?
264+
265+
266+  if (!strcmp(algorithm, "sha"))
267+  {
268+    algid   = BCRYPT_SHA1_ALGORITHM;
269+    hashlen = 20;
270+  }
271+  else if (!strcmp(algorithm, "sha2-256"))
272+  {
273+    algid   = BCRYPT_SHA256_ALGORITHM;
274+    hashlen = 32;
275+  }
276+  else if (!strcmp(algorithm, "sha2-384"))
277+  {
278+    algid   = BCRYPT_SHA384_ALGORITHM;
279+    hashlen = 48;
280+  }
281+  else if (!strcmp(algorithm, "sha2-512"))
282+  {
283+    algid   = BCRYPT_SHA512_ALGORITHM;
284+    hashlen = 64;
285+  }
286+  else if (!strcmp(algorithm, "sha2-512_224"))
287+  {
288+    algid   = BCRYPT_SHA512_ALGORITHM;
289+    hashlen = tempsize = 28;
290+  }
291+  else if (!strcmp(algorithm, "sha2-512_256"))
292+  {
293+    algid   = BCRYPT_SHA512_ALGORITHM;
294+    hashlen = tempsize = 32;
295+  }
296+
297+  if (algid)
298+  {
299+    if (hashsize < (size_t)hashlen)
300+      goto too_small;
301+
302+    if ((status = BCryptOpenAlgorithmProvider(&alg, algid, NULL, 0)) < 0)
303+    {
304+      DEBUG_printf(("2cupsHashData: BCryptOpenAlgorithmProvider returned %d.", status));
305+
306+      if (status == STATUS_INVALID_PARAMETER)
307+	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad algorithm parameter."), 1);
308+      else
309+	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to access cryptographic provider."), 1);
310+
311+      return (-1);
312+    }
313+
314+    if (tempsize > 0)
315+    {
316+      // Do a truncated SHA2-512 hash...
317+      status = BCryptHash(alg, NULL, 0, (PUCHAR)a, (ULONG)alen, temp, sizeof(temp));
318+      memcpy(hash, temp, hashlen);
319+    }
320+    else
321+    {
322+      // Hash directly to buffer...
323+      status = BCryptHash(alg, NULL, 0, (PUCHAR)a, (ULONG)alen, hash, (ULONG)hashlen);
324+    }
325+
326+    BCryptCloseAlgorithmProvider(alg, 0);
327+
328+    if (status < 0)
329+    {
330+      DEBUG_printf(("2cupsHashData: BCryptHash returned %d.", status));
331+
332+      if (status == STATUS_INVALID_PARAMETER)
333+	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad hashing parameter."), 1);
334+      else
335+	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hashing failed."), 1);
336+
337+      return (-1);
338+    }
339+
340+    return (hashlen);
341+  }
342+
343+#else
344+  if (hashsize < 64)
345+    goto too_small;
346+#endif // __APPLE__
347
348   // Unknown hash algorithm...
349   _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);
350