Logging: for callout errors likely to be config problems, include the transport in...
[exim.git] / src / src / hash.c
index 059e6d9bb028bda15fc97d265bca0a085b8f5577..95860fc505cf0a5bd1660ab6969bbcdfcb1ac856 100644 (file)
@@ -1,8 +1,9 @@
 /*
  *  Exim - an Internet mail transport agent
  *
- *  Copyright (C) 2016  Exim maintainers
- *  Copyright (c) University of Cambridge 1995 - 2016
+ *  Copyright (c) The Exim Maintainers 2010 - 2022
+ *  Copyright (c) University of Cambridge 1995 - 2009
+ *  SPDX-License-Identifier: GPL-2.0-or-later
  *
  *  Hash interface functions
  */
@@ -25,49 +26,129 @@ typedef struct sha1 {
 sha1;
 #endif /*STAND_ALONE*/
 
-
+#include <assert.h>
 
 /******************************************************************************/
 #ifdef SHA_OPENSSL
+# define HAVE_PARTIAL_SHA
 
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+# if OPENSSL_VERSION_NUMBER < 0x30000000L
 switch (h->method = m)
   {
-  case HASH_SHA1:   h->hashlen = 20; SHA1_Init  (&h->u.sha1); break;
-  case HASH_SHA256: h->hashlen = 32; SHA256_Init(&h->u.sha2); break;
-  default:         h->hashlen = 0; return FALSE;
+  case HASH_SHA1:     h->hashlen = 20; SHA1_Init  (&h->u.sha1);     break;
+  case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break;
+  case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break;
+  case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break;
+#  ifdef EXIM_HAVE_SHA3
+  case HASH_SHA3_224: h->hashlen = 28;
+                     EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_224());
+                     break;
+  case HASH_SHA3_256: h->hashlen = 32;
+                     EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_256());
+                     break;
+  case HASH_SHA3_384: h->hashlen = 48;
+                     EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_384());
+                     break;
+  case HASH_SHA3_512: h->hashlen = 64;
+                     EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_512());
+                     break;
+#  endif
+  default:           h->hashlen = 0; return FALSE;
   }
 return TRUE;
+
+# else
+EVP_MD * md;
+
+h->hashlen = 0;
+if (!(h->u.mctx = EVP_MD_CTX_new())) return FALSE;
+switch (h->method = m)
+  {
+  case HASH_SHA1:     h->hashlen = 20; md = EVP_MD_fetch(NULL, "SHA1", NULL); break;
+  case HASH_SHA2_256: h->hashlen = 32; md = EVP_MD_fetch(NULL, "SHA2-256", NULL); break;
+  case HASH_SHA2_384: h->hashlen = 48; md = EVP_MD_fetch(NULL, "SHA2-384", NULL); break;
+  case HASH_SHA2_512: h->hashlen = 64; md = EVP_MD_fetch(NULL, "SHA2-512", NULL); break;
+  case HASH_SHA3_224: h->hashlen = 28; md = EVP_MD_fetch(NULL, "SHA3-224", NULL); break;
+  case HASH_SHA3_256: h->hashlen = 32; md = EVP_MD_fetch(NULL, "SHA3-256", NULL); break;
+  case HASH_SHA3_384: h->hashlen = 48; md = EVP_MD_fetch(NULL, "SHA3-384", NULL); break;
+  case HASH_SHA3_512: h->hashlen = 64; md = EVP_MD_fetch(NULL, "SHA3-512", NULL); break;
+  default:           return FALSE;
+  }
+if (md && EVP_DigestInit_ex(h->u.mctx, md, NULL))
+  return TRUE;
+
+h->hashlen = 0;
+return FALSE;
+# endif
 }
 
 
 void
 exim_sha_update(hctx * h, const uschar * data, int len)
 {
+# if OPENSSL_VERSION_NUMBER < 0x30000000L
 switch (h->method)
   {
-  case HASH_SHA1:   SHA1_Update  (&h->u.sha1, data, len); break;
-  case HASH_SHA256: SHA256_Update(&h->u.sha2, data, len); break;
+  case HASH_SHA1:     SHA1_Update  (&h->u.sha1,     data, len); break;
+  case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break;
+  case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break;
+  case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break;
+#  ifdef EXIM_HAVE_SHA3
+  case HASH_SHA3_224:
+  case HASH_SHA3_256:
+  case HASH_SHA3_384:
+  case HASH_SHA3_512: EVP_DigestUpdate(h->u.mctx, data, len); break;
+#  endif
+  /* should be blocked by init not handling these, but be explicit to
+  guard against accidents later (and hush up clang -Wswitch) */
+  default: assert(0);
   }
+
+# else
+
+EVP_DigestUpdate(h->u.mctx, data, len);
+# endif
 }
 
 
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen);
+/* Hashing is sufficient to purify any tainted input */
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
+
+# if OPENSSL_VERSION_NUMBER < 0x30000000L
 switch (h->method)
   {
-  case HASH_SHA1:   SHA1_Final  (b->data, &h->u.sha1); break;
-  case HASH_SHA256: SHA256_Final(b->data, &h->u.sha2); break;
+  case HASH_SHA1:     SHA1_Final  (b->data, &h->u.sha1);     break;
+  case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break;
+  case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break;
+  case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break;
+#  ifdef EXIM_HAVE_SHA3
+  case HASH_SHA3_224:
+  case HASH_SHA3_256:
+  case HASH_SHA3_384:
+  case HASH_SHA3_512: EVP_DigestFinal(h->u.mctx, b->data, NULL); break;
+#  endif
+  default: assert(0);
   }
+
+# else
+
+EVP_DigestFinal_ex(h->u.mctx, b->data, NULL);
+EVP_MD_free((EVP_MD *) EVP_MD_CTX_get0_md(h->u.mctx));
+EVP_MD_CTX_free(h->u.mctx);
+
+# endif
 }
 
 
 
 #elif defined(SHA_GNUTLS)
+# define HAVE_PARTIAL_SHA
 /******************************************************************************/
 
 BOOL
@@ -75,10 +156,15 @@ exim_sha_init(hctx * h, hashmethod m)
 {
 switch (h->method = m)
   {
-  case HASH_SHA1:     h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break;
-  case HASH_SHA256:   h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+  case HASH_SHA1:     h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1);   break;
+  case HASH_SHA2_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+  case HASH_SHA2_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA384); break;
+  case HASH_SHA2_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA512); break;
 #ifdef EXIM_HAVE_SHA3
+  case HASH_SHA3_224: h->hashlen = 28; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_224); break;
   case HASH_SHA3_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_256); break;
+  case HASH_SHA3_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_384); break;
+  case HASH_SHA3_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_512); break;
 #endif
   default: h->hashlen = 0; return FALSE;
   }
@@ -96,13 +182,14 @@ gnutls_hash(h->sha, data, len);
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 gnutls_hash_output(h->sha, b->data);
 }
 
 
 
 #elif defined(SHA_GCRYPT)
+# define HAVE_PARTIAL_SHA
 /******************************************************************************/
 
 BOOL
@@ -110,8 +197,13 @@ exim_sha_init(hctx * h, hashmethod m)
 {
 switch (h->method = m)
   {
-  case HASH_SHA1:   h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break;
-  case HASH_SHA256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+  case HASH_SHA1:     h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0);   break;
+  case HASH_SHA2_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+  case HASH_SHA2_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA384, 0); break;
+  case HASH_SHA2_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA512, 0); break;
+  case HASH_SHA3_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA3_256, 0); break;
+  case HASH_SHA3_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA3_384, 0); break;
+  case HASH_SHA3_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA3_512, 0); break;
   default:         h->hashlen = 0; return FALSE;
   }
 return TRUE;
@@ -128,7 +220,7 @@ gcry_md_write(h->sha, data, len);
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
 }
 
@@ -136,15 +228,17 @@ memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
 
 
 #elif defined(SHA_POLARSSL)
+# define HAVE_PARTIAL_SHA
 /******************************************************************************/
 
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+/*XXX extend for sha512 */
 switch (h->method = m)
   {
   case HASH_SHA1:   h->hashlen = 20; sha1_starts(&h->u.sha1);    break;
-  case HASH_SHA256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
+  case HASH_SHA2_256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
   default:         h->hashlen = 0; return FALSE;
   }
 return TRUE;
@@ -157,7 +251,7 @@ exim_sha_update(hctx * h, const uschar * data, int len)
 switch (h->method)
   {
   case HASH_SHA1:   sha1_update(h->u.sha1, US data, len); break;
-  case HASH_SHA256: sha2_update(h->u.sha2, US data, len); break;
+  case HASH_SHA2_256: sha2_update(h->u.sha2, US data, len); break;
   }
 }
 
@@ -165,11 +259,11 @@ switch (h->method)
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen);
+b->data = store_get(b->len = h->hashlen, GET_INTAINTED);
 switch (h->method)
   {
   case HASH_SHA1:   sha1_finish(h->u.sha1, b->data); break;
-  case HASH_SHA256: sha2_finish(h->u.sha2, b->data); break;
+  case HASH_SHA2_256: sha2_finish(h->u.sha2, b->data); break;
   }
 }
 
@@ -218,19 +312,18 @@ Returns:     nothing
 static void
 native_sha1_mid(sha1 *base, const uschar *text)
 {
-int i;
 uint A, B, C, D, E;
 uint W[80];
 
 base->length += 64;
 
-for (i = 0; i < 16; i++)
+for (int i = 0; i < 16; i++)
   {
   W[i] = ((uint)text[0] << 24) | (text[1] << 16) | (text[2] << 8) | text[3];
   text += 4;
   }
 
-for (i = 16; i < 80; i++)
+for (int i = 16; i < 80; i++)
   {
   register unsigned int x = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
   W[i] = (x << 1) | (x >> 31);
@@ -242,7 +335,7 @@ C = base->H[2];
 D = base->H[3];
 E = base->H[4];
 
-for (i = 0; i < 20; i++)
+for (int i = 0; i < 20; i++)
   {
   unsigned int T;
   T = ((A << 5) | (A >> 27)) + ((B & C) | ((~B) & D)) + E + W[i] + 0x5a827999;
@@ -253,7 +346,7 @@ for (i = 0; i < 20; i++)
   A = T;
   }
 
-for (i = 20; i < 40; i++)
+for (int i = 20; i < 40; i++)
   {
   unsigned int T;
   T = ((A << 5) | (A >> 27)) + (B ^ C ^ D) + E + W[i] + 0x6ed9eba1;
@@ -264,7 +357,7 @@ for (i = 20; i < 40; i++)
   A = T;
   }
 
-for (i = 40; i < 60; i++)
+for (int i = 40; i < 60; i++)
   {
   unsigned int T;
   T = ((A << 5) | (A >> 27)) + ((B & C) | (B & D) | (C & D)) + E + W[i] +
@@ -276,7 +369,7 @@ for (i = 40; i < 60; i++)
   A = T;
   }
 
-for (i = 60; i < 80; i++)
+for (int i = 60; i < 80; i++)
   {
   unsigned int T;
   T = ((A << 5) | (A >> 27)) + (B ^ C ^ D) + E + W[i] + 0xca62c1d6;
@@ -315,9 +408,8 @@ Returns:    nothing
 */
 
 static void
-native_sha1_end(sha1 *base, const uschar *text, int length, uschar *digest)
+native_sha1_end(sha1 * base, const uschar * text, int length, uschar * digest)
 {
-int i;
 uschar work[64];
 
 /* Process in chunks of 64 until we have less than 64 bytes left. */
@@ -334,7 +426,7 @@ out to 64, process it, and then set up the final chunk as 56 bytes of
 padding. If it has less than 56 bytes, we pad it out to 56 bytes as the
 final chunk. */
 
-memcpy(work, text, length);
+if (length) memcpy(work, text, length);
 work[length] = 0x80;
 
 if (length > 55)
@@ -345,9 +437,7 @@ if (length > 55)
   memset(work, 0, 56);
   }
 else
-  {
   memset(work+length+1, 0, 55-length);
-  }
 
 /* The final 8 bytes of the final chunk are a 64-bit representation of the
 length of the input string *bits*, before padding, high order word first, and
@@ -370,7 +460,7 @@ native_sha1_mid(base, work);
 
 /* Pass back the result, high-order byte first in each word. */
 
-for (i = 0; i < 5; i++)
+for (int i = 0; i < 5; i++)
   {
   register int x = base->H[i];
   *digest++ = (x >> 24) & 0xff;
@@ -405,7 +495,7 @@ native_sha1_mid(&h->sha1, US data); /* implicit size always 64 */
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 
 native_sha1_end(&h->sha1, NULL, 0, b->data);
 }
@@ -413,16 +503,6 @@ native_sha1_end(&h->sha1, NULL, 0, b->data);
 
 
 #endif
-/******************************************************************************/
-
-/* Common to all library versions */
-int
-exim_sha_hashlen(hctx * h)
-{
-return h->method == HASH_SHA1 ? 20
-     : h->method == HASH_SHA256 ? 32
-     : 0;
-}
 
 
 /******************************************************************************/
@@ -479,6 +559,14 @@ memcpy(digest, b.data, 20);
 
 
 
+#ifdef HAVE_PARTIAL_SHA
+# undef HAVE_PARTIAL_SHA
+void
+exim_sha_update_string(hctx * h, const uschar * s)
+{
+if (s) exim_sha_update(h, s, Ustrlen(s));
+}
+#endif
 
 
 
@@ -488,7 +576,7 @@ memcpy(digest, b.data, 20);
 **************************************************
 *************************************************/
 
-# ifdef STAND_ALONE
+#ifdef STAND_ALONE
 
 /* Test values. The first 128 may contain binary zeros and have increasing
 length. */
@@ -772,7 +860,7 @@ int main(void)
 sha1 base;
 int j;
 int i = 0x01020304;
-uschar *ctest = (uschar *)(&i);
+uschar *ctest = US (&i);
 uschar buffer[256];
 uschar digest[20];
 uschar s[41];
@@ -803,6 +891,6 @@ printf("Computed:  %s\n", s);
 if (strcmp(s, atest) != 0) printf("*** No match ***\n");
 
 }
-# endif        /*STAND_ALONE*/
+#endif /*STAND_ALONE*/
 
 /* End of File */