DKIM: reinstate embedded Polarssl SHA routines under older GnuTLS. Bug 1772
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 7 Jan 2016 20:47:13 +0000 (20:47 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 7 Jan 2016 21:12:34 +0000 (21:12 +0000)
We need an incremental build of the hash, and GnuTLS did not expose the
required interfaces until version 2.10.0

src/scripts/MakeLinks
src/src/exim.h
src/src/pdkim/Makefile
src/src/pdkim/crypt_ver.h [new file with mode: 0644]
src/src/pdkim/part-x509parse.c [new file with mode: 0644]
src/src/pdkim/pdkim.c
src/src/pdkim/pdkim.h
src/src/pdkim/sha1.c [new file with mode: 0644]
src/src/pdkim/sha2.c [new file with mode: 0644]

index 10c97d2..4f6747f 100755 (executable)
@@ -82,7 +82,7 @@ cd ..
 # Likewise for the code for the PDKIM library
 mkdir pdkim
 cd pdkim
-for f in README Makefile part-x509parse.c pdkim.c \
+for f in README Makefile crypt_ver.h part-x509parse.c pdkim.c \
   pdkim.h sha1.c sha2.c
 do
   ln -s ../../src/pdkim/$f $f
index f94f00b..385c362 100644 (file)
@@ -11,6 +11,9 @@ that is needed. They don't all need everything, of course, but it's far too
 messy to have each one importing its own list, and anyway, most of them need
 most of these includes. */
 
+#ifndef EXIM_H
+#define EXIM_H
+
 /* Assume most systems have statfs() unless os.h undefines this macro */
 
 #define HAVE_STATFS
@@ -596,4 +599,5 @@ default to EDQUOT if it exists, otherwise ENOSPC. */
   #undef DISABLE_DNSSEC
 #endif
 
+#endif
 /* End of exim.h */
index 7edc390..ec8bb83 100644 (file)
@@ -12,6 +12,9 @@ pdkim.a:         $(OBJ)
 .c.o:;           @echo "$(CC) $*.c"
                 $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -I. $*.c
 
-pdkim.o:            $(HDRS) pdkim.h pdkim.c
+part-x509parse.o:   $(HDRS) crypt_ver.h part-x509parse.c
+pdkim.o:            $(HDRS) crypt_ver.h pdkim.h pdkim.c
+sha1.o:             $(HDRS) crypt_ver.h sha1.c
+sha2.o:             $(HDRS) crypt_ver.h sha2.c
 
 # End
diff --git a/src/src/pdkim/crypt_ver.h b/src/src/pdkim/crypt_ver.h
new file mode 100644 (file)
index 0000000..602d137
--- /dev/null
@@ -0,0 +1,28 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2016 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* RSA and SHA routine selection for PDKIM */
+
+#include "../exim.h"
+
+
+#ifdef USE_GNUTLS
+# define RSA_GNUTLS
+
+# include <gnutls/gnutls.h>
+# if GNUTLS_VERSION_NUMBER >= 0x020a00
+#  define SHA_GNUTLS
+
+# else
+#  define SHA_POLARSSL
+# endif
+
+#else
+# define RSA_OPENSSL
+# define SHA_OPENSSL
+#endif
+
diff --git a/src/src/pdkim/part-x509parse.c b/src/src/pdkim/part-x509parse.c
new file mode 100644 (file)
index 0000000..5788777
--- /dev/null
@@ -0,0 +1,153 @@
+#include "crypt_ver.h"
+
+#ifdef SHA_POLARSSL    /* remainder of file */
+
+#include "polarssl/bignum.h"
+#include "polarssl/part-x509.h"
+#include "polarssl/private-x509parse_c.h"
+
+/* all calls are from src/pdkim/pdkim-rsa.c */
+
+/* *************** begin copy from x509parse.c ********************/
+/*
+ *  X.509 certificate and private key decoding
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The ITU-T X.509 standard defines a certificat format for PKI.
+ *
+ *  http://www.ietf.org/rfc/rfc2459.txt
+ *  http://www.ietf.org/rfc/rfc3279.txt
+ *
+ *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ */
+
+
+/*
+ * ASN.1 DER decoding routines
+ */
+static int asn1_get_len( unsigned char **p,
+                         const unsigned char *end,
+                         int *len )
+{
+    if( ( end - *p ) < 1 )
+        return( POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( ( **p & 0x80 ) == 0 )
+        *len = *(*p)++;
+    else
+    {
+        switch( **p & 0x7F )
+        {
+        case 1:
+            if( ( end - *p ) < 2 )
+                return( POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+            *len = (*p)[1];
+            (*p) += 2;
+            break;
+
+        case 2:
+            if( ( end - *p ) < 3 )
+                return( POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+            *len = ( (*p)[1] << 8 ) | (*p)[2];
+            (*p) += 3;
+            break;
+
+        default:
+            return( POLARSSL_ERR_ASN1_INVALID_LENGTH );
+            break;
+        }
+    }
+
+    if( *len > (int) ( end - *p ) )
+        return( POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+    return( 0 );
+}
+
+/* This function is not exported by PolarSSL 0.14.2
+ * static */
+int asn1_get_tag( unsigned char **p,
+                         const unsigned char *end,
+                         int *len, int tag )
+{
+    if( ( end - *p ) < 1 )
+        return( POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+    if( **p != tag )
+        return( POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+    (*p)++;
+
+    return( asn1_get_len( p, end, len ) );
+}
+
+/* This function is not exported by PolarSSL 0.14.2
+ * static */
+int asn1_get_int( unsigned char **p,
+                         const unsigned char *end,
+                         int *val )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
+        return( ret );
+
+    if( len > (int) sizeof( int ) || ( **p & 0x80 ) != 0 )
+        return( POLARSSL_ERR_ASN1_INVALID_LENGTH );
+
+    *val = 0;
+
+    while( len-- > 0 )
+    {
+        *val = ( *val << 8 ) | **p;
+        (*p)++;
+    }
+
+    return( 0 );
+}
+
+/* This function is not exported by PolarSSL 0.14.2
+ * static */
+int asn1_get_mpi( unsigned char **p,
+                         const unsigned char *end,
+                         mpi *X )
+{
+    int ret, len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
+        return( ret );
+
+    ret = mpi_read_binary( X, *p, len );
+
+    *p += len;
+
+    return( ret );
+}
+/* ***************   end copy from x509parse.c ********************/
+#endif
index 73fe6cb..3840c05 100644 (file)
 # error Need SUPPORT_TLS for DKIM
 #endif
 
+#include "crypt_ver.h"
 
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+# include <openssl/rsa.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+#elif defined(RSA_GNUTLS)
 # include <gnutls/gnutls.h>
 # include <gnutls/x509.h>
 # include <gnutls/abstract.h>
+#endif
+
+#ifdef SHA_GNUTLS
 # include <gnutls/crypto.h>
-#else
-# include <openssl/rsa.h>
-# include <openssl/ssl.h>
-# include <openssl/err.h>
+#elif defined(SHA_POLARSSL)
+# include "polarssl/sha1.h"
+# include "polarssl/sha2.h"
 #endif
 
 #include "pdkim.h"
@@ -785,14 +792,30 @@ DEBUG(D_acl)
          "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
   }
 
-#ifdef USE_GNUTLS
-gnutls_hash_init(&sig->sha_body,
-  sig->algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256);
+#ifdef SHA_OPENSSL
 
-#else
 SHA1_Init  (&sig->sha1_body);
 SHA256_Init(&sig->sha2_body);
-#endif
+
+#elif defined(SHA_GNUTLS)
+
+gnutls_hash_init(&sig->sha_body,
+  sig->algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256);
+
+#elif defined(SHA_POLARSSL)
+
+if (  !(sig->sha1_body = malloc(sizeof(sha1_context)))
+   || !(sig->sha2_body = malloc(sizeof(sha2_context)))
+   )
+  {
+  pdkim_free_sig(sig);
+  return NULL;
+  }
+
+sha1_starts(sig->sha1_body);
+sha2_starts(sig->sha2_body, 0);
+
+#endif /* SHA impl */
 
 return sig;
 }
@@ -978,13 +1001,19 @@ while (sig)
 
   if (canon_len > 0)
     {
-#ifdef USE_GNUTLS
+#ifdef SHA_GNUTLS
     gnutls_hash(sig->sha_body, canon_data, canon_len);
 #else
     if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
       SHA1_Update  (&sig->sha1_body, canon_data, canon_len);
     else
       SHA256_Update(&sig->sha2_body, canon_data, canon_len);
+# elif defined(SHA_POLARSSL)
+      sha1_update(sig->sha1_body, US canon_data, canon_len);
+    else
+      sha2_update(sig->sha2_body, US canon_data, canon_len);
+# endif
 #endif
 
     sig->signed_body_bytes += canon_len;
@@ -1011,13 +1040,19 @@ for (sig = ctx->sig; sig; sig = sig->next)
   {                                    /* Finish hashes */
   uschar bh[32]; /* SHA-256 = 32 Bytes,  SHA-1 = 20 Bytes */
 
-#ifdef USE_GNUTLS
+#ifdef SHA_GNUTLS
   gnutls_hash_output(sig->sha_body, bh);
 #else
   if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
     SHA1_Final  (bh, &sig->sha1_body);
   else
     SHA256_Final(bh, &sig->sha2_body);
+# elif defined(SHA_POLARSSL)
+    sha1_finish(sig->sha1_body, bh);
+  else
+    sha2_finish(sig->sha2_body, bh);
+# endif
 #endif
 
   DEBUG(D_acl)
@@ -1591,26 +1626,39 @@ if (ctx->mode == PDKIM_MODE_SIGN)
 
 while (sig)
   {
-#ifdef USE_GNUTLS
-  gnutls_hash_hd_t sha_headers;
-  uschar * hdata = NULL;
-  int hdata_alloc = 0;
-  int hdata_size = 0;
-#else
+#ifdef SHA_OPENSSL
   SHA_CTX    sha1_headers;
   SHA256_CTX sha2_headers;
+#elif defined(SHA_GNUTLS)
+  gnutls_hash_hd_t sha_headers;
+#elif defined(SHA_POLARSSL)
+  sha1_context sha1_headers;
+  sha2_context sha2_headers;
 #endif
+
   char *sig_hdr;
   char headerhash[32];
 
-#ifdef USE_GNUTLS
+#ifdef RSA_GNUTLS
+  uschar * hdata = NULL;
+  int hdata_alloc = 0;
+  int hdata_size = 0;
+#endif
+
+#ifdef SHA_GNUTLS
   gnutls_hash_init(&sha_headers,
     sig->algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256);
 #else
   if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
     SHA1_Init(&sha1_headers);
   else
     SHA256_Init(&sha2_headers);
+# elif defined(SHA_POLARSSL)
+    sha1_starts(&sha1_headers);
+  else
+    sha2_starts(&sha2_headers, 0);
+# endif
 #endif
 
   DEBUG(D_acl) debug_printf(
@@ -1641,16 +1689,22 @@ while (sig)
        return PDKIM_ERR_OOM;
 
       /* Feed header to the hash algorithm */
-#ifdef USE_GNUTLS
+#ifdef SHA_GNUTLS
       gnutls_hash(sha_headers, rh, strlen(rh));
 #else
       if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
        SHA1_Update  (&sha1_headers, rh, strlen(rh));
       else
        SHA256_Update(&sha2_headers, rh, strlen(rh));
+# elif defined(SHA_POLARSSL)
+       sha1_update(&sha1_headers, US rh, strlen(rh));
+      else
+       sha2_update(&sha2_headers, US rh, strlen(rh));
+# endif
 #endif
 
-#ifdef USE_GNUTLS
+#ifdef RSA_GNUTLS
       /* Remember headers block for signing */
       hdata = string_append(hdata, &hdata_alloc, &hdata_size, 1, rh);
 #endif
@@ -1696,13 +1750,19 @@ while (sig)
            return PDKIM_ERR_OOM;
 
          /* Feed header to the hash algorithm */
-#ifdef USE_GNUTLS
+#ifdef SHA_GNUTLS
          gnutls_hash(sha_headers, rh, strlen(rh));
 #else
          if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
            SHA1_Update  (&sha1_headers, rh, strlen(rh));
          else
            SHA256_Update(&sha2_headers, rh, strlen(rh));
+# elif defined(SHA_POLARSSL)
+           sha1_update(&sha1_headers, US rh, strlen(rh));
+         else
+           sha2_update(&sha2_headers, US rh, strlen(rh));
+# endif
 #endif
 
          DEBUG(D_acl) pdkim_quoteprint(rh, strlen(rh), 1);
@@ -1760,11 +1820,12 @@ while (sig)
     }
 
   /* Finalize header hash */
-#ifdef USE_GNUTLS
+#ifdef SHA_GNUTLS
   gnutls_hash(sha_headers, sig_hdr, strlen(sig_hdr));
   gnutls_hash_output(sha_headers, headerhash);
 #else
   if (sig->algo == PDKIM_ALGO_RSA_SHA1)
+# ifdef SHA_OPENSSL
     {
     SHA1_Update(&sha1_headers, sig_hdr, strlen(sig_hdr));
     SHA1_Final(US headerhash, &sha1_headers);
@@ -1774,6 +1835,17 @@ while (sig)
     SHA256_Update(&sha2_headers, sig_hdr, strlen(sig_hdr));
     SHA256_Final(US headerhash, &sha2_headers);
     }
+# elif defined(SHA_POLARSSL)
+    {
+    sha1_update(&sha1_headers, US sig_hdr, strlen(sig_hdr));
+    sha1_finish(&sha1_headers, US headerhash);
+    }
+  else
+    {
+    sha2_update(&sha2_headers, US sig_hdr, strlen(sig_hdr));
+    sha2_finish(&sha2_headers, US headerhash);
+    }
+# endif
 #endif
 
   DEBUG(D_acl)
@@ -1782,7 +1854,7 @@ while (sig)
     pdkim_hexprint(headerhash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20:32, 1);
     }
 
-#ifdef USE_GNUTLS
+#ifdef RSA_GNUTLS
   if (ctx->mode == PDKIM_MODE_SIGN)
     hdata = string_append(hdata, &hdata_alloc, &hdata_size, 1, sig_hdr);
 #endif
@@ -1792,19 +1864,32 @@ while (sig)
   /* SIGNING ---------------------------------------------------------------- */
   if (ctx->mode == PDKIM_MODE_SIGN)
     {
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+    RSA * rsa;
+    uschar * p, * q;
+    int len;
+#elif defined(RSA_GNUTLS)
     gnutls_x509_privkey_t rsa;
     gnutls_datum_t k;
     int rc;
     size_t sigsize;
-#else
-    RSA * rsa;
-    uschar * p, * q;
-    int len;
 #endif
 
     /* Import private key */
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+
+    if (  !(p = Ustrstr(sig->rsa_privkey, "-----BEGIN RSA PRIVATE KEY-----"))
+       || !(q = Ustrstr(p+=31, "-----END RSA PRIVATE KEY-----"))
+       )
+      return PDKIM_ERR_RSA_PRIVKEY;
+    *q = '\0';
+    if (  (len = b64decode(p, &p)) < 0
+       || !(rsa = d2i_RSAPrivateKey(NULL, CUSS &p, len))
+       )
+      /*XXX todo: get errstring from library */
+      return PDKIM_ERR_RSA_PRIVKEY;
+
+#elif defined(RSA_GNUTLS)
 
     k.data = sig->rsa_privkey;
     k.size = strlen(sig->rsa_privkey);
@@ -1818,36 +1903,32 @@ while (sig)
       return PDKIM_ERR_RSA_PRIVKEY;
       }
 
-#else
-
-    if (  !(p = Ustrstr(sig->rsa_privkey, "-----BEGIN RSA PRIVATE KEY-----"))
-       || !(q = Ustrstr(p+=31, "-----END RSA PRIVATE KEY-----"))
-       )
-      return PDKIM_ERR_RSA_PRIVKEY;
-    *q = '\0';
-    if (  (len = b64decode(p, &p)) < 0
-       || !(rsa = d2i_RSAPrivateKey(NULL, CUSS &p, len))
-       )
-      /*XXX todo: get errstring from library */
-      return PDKIM_ERR_RSA_PRIVKEY;
-
 #endif
 
 
     /* Allocate mem for signature */
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+    sig->sigdata = store_get(RSA_size(rsa));
+#elif defined(RSA_GNUTLS)
     k.data = hdata;
     k.size = hdata_size;
     (void) gnutls_x509_privkey_sign_data(rsa,
       sig->algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
       0, &k, NULL, &sigsize);
     sig->sigdata = store_get(sig->sigdata_len = sigsize);
-#else
-    sig->sigdata = store_get(RSA_size(rsa));
 #endif
 
     /* Do signing */
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+
+    if (RSA_sign(sig->algo == PDKIM_ALGO_RSA_SHA1 ? NID_sha1 : NID_sha256,
+         CUS headerhash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20 : 32,
+         US sig->sigdata, (unsigned int *)&sig->sigdata_len,
+         rsa) != 1)
+      return PDKIM_ERR_RSA_SIGNING;
+    RSA_free(rsa);
+
+#elif defined(RSA_GNUTLS)
 
     if ((rc = gnutls_x509_privkey_sign_data(rsa,
          sig->algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
@@ -1860,15 +1941,6 @@ while (sig)
       }
     gnutls_x509_privkey_deinit(rsa);
 
-#else
-
-    if (RSA_sign(sig->algo == PDKIM_ALGO_RSA_SHA1 ? NID_sha1 : NID_sha256,
-         CUS headerhash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20 : 32,
-         US sig->sigdata, (unsigned int *)&sig->sigdata_len,
-         rsa) != 1)
-      return PDKIM_ERR_RSA_SIGNING;
-    RSA_free(rsa);
-
 #endif
 
 
@@ -1885,17 +1957,17 @@ while (sig)
   /* VERIFICATION ----------------------------------------------------------- */
   else
     {
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+    RSA * rsa;
+    const unsigned char * p;
+#elif defined(RSA_GNUTLS)
     gnutls_pubkey_t rsa;
     gnutls_datum_t k, s;
     int rc;
-#else
-    RSA * rsa;
-    const unsigned char * p;
 #endif
     char *dns_txt_name, *dns_txt_reply;
 
-#ifdef USE_GNUTLS
+#ifdef RSA_GNUTLS
     gnutls_pubkey_init(&rsa);
 #endif
 
@@ -1953,29 +2025,29 @@ while (sig)
        "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
 
     /* Import public key */
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+
+    p = CUS sig->pubkey->key;
+    if (!(rsa = d2i_RSA_PUBKEY(NULL, &p, (long) sig->pubkey->key_len)))
+
+#elif defined(RSA_GNUTLS)
 
     k.data = sig->pubkey->key;
     k.size = sig->pubkey->key_len;
     if ((rc = gnutls_pubkey_import(rsa, &k, GNUTLS_X509_FMT_DER))
        != GNUTLS_E_SUCCESS)
 
-#else
-
-    p = CUS sig->pubkey->key;
-    if (!(rsa = d2i_RSA_PUBKEY(NULL, &p, (long) sig->pubkey->key_len)))
-
 #endif
       {
       DEBUG(D_acl)
        {
-#ifdef USE_GNUTLS
-       debug_printf("gnutls_pubkey_import: %s\n", gnutls_strerror(rc));
-#else
+#ifdef RSA_OPENSSL
        long e;
        ERR_load_crypto_strings();      /*XXX move to a startup routine */
        while ((e = ERR_get_error()))
          debug_printf("Az: %.120s\n", ERR_error_string(e, NULL));
+#elif defined(RSA_GNUTLS)
+       debug_printf("gnutls_pubkey_import: %s\n", gnutls_strerror(rc));
 #endif
        }
 
@@ -1985,7 +2057,14 @@ while (sig)
       }
 
     /* Check the signature */
-#ifdef USE_GNUTLS
+#ifdef RSA_OPENSSL
+
+    if (RSA_verify(sig->algo == PDKIM_ALGO_RSA_SHA1 ? NID_sha1 : NID_sha256,
+         CUS headerhash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20 : 32,
+         US sig->sigdata, (unsigned int)sig->sigdata_len,
+         rsa) != 1)
+
+#elif defined(RSA_GNUTLS)
 
     k.data = headerhash;
     k.size = sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20 : 32;
@@ -1996,16 +2075,9 @@ while (sig)
                  ? GNUTLS_SIGN_RSA_SHA1 : GNUTLS_SIGN_RSA_SHA256,
                0, &k, &s)) < 0)
 
-#else
-
-    if (RSA_verify(sig->algo == PDKIM_ALGO_RSA_SHA1 ? NID_sha1 : NID_sha256,
-         CUS headerhash, sig->algo == PDKIM_ALGO_RSA_SHA1 ? 20 : 32,
-         US sig->sigdata, (unsigned int)sig->sigdata_len,
-         rsa) != 1)
-
 #endif
       {
-#ifdef USE_GNUTLS
+#if defined(RSA_GNUTLS)
       debug_printf("gnutls_pubkey_verify_hash2: %s\n", gnutls_strerror(rc));
 #endif
       sig->verify_status =      PDKIM_VERIFY_FAIL;
@@ -2030,7 +2102,7 @@ NEXT_VERIFY:
        debug_printf("\n");
       }
 
-#ifdef USE_GNUTLS
+#ifdef RSA_GNUTLS
     gnutls_pubkey_deinit(rsa);
 #endif
     free(dns_txt_name);
@@ -2114,13 +2186,22 @@ ctx->sig->algo = algo;
 if (!ctx->sig->domain || !ctx->sig->selector || !ctx->sig->rsa_privkey)
   goto BAIL;
 
-#ifdef USE_GNUTLS
+#ifdef SHA_OPENSSL
+SHA1_Init  (&ctx->sig->sha1_body);
+SHA256_Init(&ctx->sig->sha2_body);
+
+#elif defined(SHA_GNUTLS)
 gnutls_hash_init(&ctx->sig->sha_body,
     algo == PDKIM_ALGO_RSA_SHA1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256);
 
-#else
-SHA1_Init  (&ctx->sig->sha1_body);
-SHA256_Init(&ctx->sig->sha2_body);
+#elif defined(SHA_POLARSSL)
+if (!(ctx->sig->sha1_body = malloc(sizeof(sha1_context))))
+  goto BAIL;
+sha1_starts(ctx->sig->sha1_body);
+
+if (!(ctx->sig->sha2_body = malloc(sizeof(sha2_context))))
+  goto BAIL;
+sha2_starts(ctx->sig->sha2_body, 0);
 
 #endif
 
index c7c7b58..97a03ea 100644 (file)
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef USE_GNUTLS
-# include <gnutls/gnutls.h>
-# include <gnutls/crypto.h>
-#else
-# include <openssl/sha.h>
-#endif
-
 /* -------------------------------------------------------------------------- */
 /* Length of the preallocated buffer for the "answer" from the dns/txt
    callback function. This should match the maximum RDLENGTH from DNS. */
 /* Some required forward declarations, please ignore */
 typedef struct pdkim_stringlist pdkim_stringlist;
 typedef struct pdkim_str pdkim_str;
+typedef struct sha1_context sha1_context;
+typedef struct sha2_context sha2_context;
+#define HAVE_SHA1_CONTEXT
+#define HAVE_SHA2_CONTEXT
 
 /* -------------------------------------------------------------------------- */
 /* Some concessions towards Redmond */
@@ -228,14 +225,17 @@ typedef struct pdkim_signature {
   /* Properties below this point are used internally only ------------- */
 
   /* Per-signature helper variables ----------------------------------- */
-#ifdef USE_GNUTLS
+#ifdef SHA_OPENSSL
+  SHA_CTX      sha1_body;  /* SHA1 block                                */
+  SHA256_CTX   sha2_body;  /* SHA256 block                              */
+#elif defined(SHA_GNUTLS)
   gnutls_hash_hd_t sha_body; /* Either SHA1 or SHA256 block             */
-#else
-  SHA_CTX      sha1_body;    /* SHA1 block                              */
-  SHA256_CTX   sha2_body;    /* SHA256 block                            */
+#elif defined(SHA_POLARSSL)
+  sha1_context *sha1_body; /* SHA1 block                                */
+  sha2_context *sha2_body; /* SHA256 block                              */
 #endif
   unsigned long signed_body_bytes; /* How many body bytes we hashed     */
-  pdkim_stringlist *headers;       /* Raw headers included in the sig   */
+  pdkim_stringlist *headers; /* Raw headers included in the sig         */
   /* Signing specific ------------------------------------------------- */
   char *rsa_privkey;     /* Private RSA key                             */
   char *sign_headers;    /* To-be-signed header names                   */
diff --git a/src/src/pdkim/sha1.c b/src/src/pdkim/sha1.c
new file mode 100644 (file)
index 0000000..96f4e7b
--- /dev/null
@@ -0,0 +1,323 @@
+#include "crypt_ver.h"
+
+#ifdef SHA_POLARSSL    /* remainder of file */
+
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_SHA1_C)
+
+#include "polarssl/sha1.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-1 context setup
+ * Called from pdkim_parse_sig_header() pdkim_feed_finish() pdkim_init_sign()
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+static void sha1_process( sha1_context *ctx, const unsigned char data[64] )
+{
+    unsigned long temp, W[16], A, B, C, D, E;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ * Called from pdkim_feed_finish() & pdkim_finish_bodyhash()
+ */
+void sha1_update( sha1_context *ctx, const unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ * Called from pdkim_feed_finish() & pdkim_finish_bodyhash()
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_BE( high, msglen, 0 );
+    PUT_ULONG_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, (unsigned char *) sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_ULONG_BE( ctx->state[0], output,  0 );
+    PUT_ULONG_BE( ctx->state[1], output,  4 );
+    PUT_ULONG_BE( ctx->state[2], output,  8 );
+    PUT_ULONG_BE( ctx->state[3], output, 12 );
+    PUT_ULONG_BE( ctx->state[4], output, 16 );
+}
+
+#endif
+#endif
diff --git a/src/src/pdkim/sha2.c b/src/src/pdkim/sha2.c
new file mode 100644 (file)
index 0000000..6ab6cb9
--- /dev/null
@@ -0,0 +1,453 @@
+#include "crypt_ver.h"
+
+#ifdef SHA_POLARSSL    /* remainder of file */
+
+/*
+ *  FIPS-180-2 compliant SHA-256 implementation
+ *
+ *  Copyright (C) 2006-2010, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_SHA2_C)
+
+#include "polarssl/sha2.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-256 context setup
+ */
+void sha2_starts( sha2_context *ctx, int is224 )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    if( is224 == 0 )
+    {
+        /* SHA-256 */
+        ctx->state[0] = 0x6A09E667;
+        ctx->state[1] = 0xBB67AE85;
+        ctx->state[2] = 0x3C6EF372;
+        ctx->state[3] = 0xA54FF53A;
+        ctx->state[4] = 0x510E527F;
+        ctx->state[5] = 0x9B05688C;
+        ctx->state[6] = 0x1F83D9AB;
+        ctx->state[7] = 0x5BE0CD19;
+    }
+    else
+    {
+        /* SHA-224 */
+        ctx->state[0] = 0xC1059ED8;
+        ctx->state[1] = 0x367CD507;
+        ctx->state[2] = 0x3070DD17;
+        ctx->state[3] = 0xF70E5939;
+        ctx->state[4] = 0xFFC00B31;
+        ctx->state[5] = 0x68581511;
+        ctx->state[6] = 0x64F98FA7;
+        ctx->state[7] = 0xBEFA4FA4;
+    }
+
+    ctx->is224 = is224;
+}
+
+static void sha2_process( sha2_context *ctx, const unsigned char data[64] )
+{
+    unsigned long temp1, temp2, W[64];
+    unsigned long A, B, C, D, E, F, G, H;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+#define  SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^  SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^  SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t)                                    \
+(                                               \
+    W[t] = S1(W[t -  2]) + W[t -  7] +          \
+           S0(W[t - 15]) + W[t - 16]            \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K)                  \
+{                                               \
+    temp1 = h + S3(e) + F1(e,f,g) + K + x;      \
+    temp2 = S2(a) + F0(a,b,c);                  \
+    d += temp1; h = temp1 + temp2;              \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+    F = ctx->state[5];
+    G = ctx->state[6];
+    H = ctx->state[7];
+
+    P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
+    P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
+    P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
+    P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
+    P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
+    P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
+    P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
+    P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
+    P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
+    P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
+    P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
+    P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
+    P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
+    P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
+    P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
+    P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
+    P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
+    P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
+    P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
+    P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
+    P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
+    P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
+    P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
+    P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
+    P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
+    P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
+    P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
+    P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
+    P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
+    P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
+    P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
+    P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
+    P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
+    P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
+    P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
+    P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
+    P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
+    P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
+    P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
+    P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
+    P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
+    P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
+    P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
+    P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
+    P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
+    P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
+    P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
+    P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
+    P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
+    P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
+    P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
+    P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
+    P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
+    P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
+    P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
+    P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
+    P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
+    P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
+    P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
+    P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
+    P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
+    P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
+    P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
+    P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+    ctx->state[5] += F;
+    ctx->state[6] += G;
+    ctx->state[7] += H;
+}
+
+/*
+ * SHA-256 process buffer
+ */
+void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha2_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha2_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha2_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-256 final digest
+ */
+void sha2_finish( sha2_context *ctx, unsigned char output[32] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_BE( high, msglen, 0 );
+    PUT_ULONG_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha2_update( ctx, (unsigned char *) sha2_padding, padn );
+    sha2_update( ctx, msglen, 8 );
+
+    PUT_ULONG_BE( ctx->state[0], output,  0 );
+    PUT_ULONG_BE( ctx->state[1], output,  4 );
+    PUT_ULONG_BE( ctx->state[2], output,  8 );
+    PUT_ULONG_BE( ctx->state[3], output, 12 );
+    PUT_ULONG_BE( ctx->state[4], output, 16 );
+    PUT_ULONG_BE( ctx->state[5], output, 20 );
+    PUT_ULONG_BE( ctx->state[6], output, 24 );
+
+    if( ctx->is224 == 0 )
+        PUT_ULONG_BE( ctx->state[7], output, 28 );
+}
+
+/*
+ * output = SHA-256( input buffer )
+ */
+void sha2( const unsigned char *input, int ilen,
+           unsigned char output[32], int is224 )
+{
+    sha2_context ctx;
+
+    sha2_starts( &ctx, is224 );
+    sha2_update( &ctx, input, ilen );
+    sha2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+}
+
+/*
+ * output = SHA-256( file contents )
+ */
+int sha2_file( const char *path, unsigned char output[32], int is224 )
+{
+    FILE *f;
+    size_t n;
+    sha2_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha2_starts( &ctx, is224 );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha2_update( &ctx, buf, (int) n );
+
+    sha2_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * SHA-256 HMAC context setup
+ */
+void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen,
+                       int is224 )
+{
+    int i;
+    unsigned char sum[32];
+
+    if( keylen > 64 )
+    {
+        sha2( key, keylen, sum, is224 );
+        keylen = ( is224 ) ? 28 : 32;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha2_starts( ctx, is224 );
+    sha2_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-256 HMAC process buffer
+ */
+void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen )
+{
+    sha2_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-256 HMAC final digest
+ */
+void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] )
+{
+    int is224, hlen;
+    unsigned char tmpbuf[32];
+
+    is224 = ctx->is224;
+    hlen = ( is224 == 0 ) ? 32 : 28;
+
+    sha2_finish( ctx, tmpbuf );
+    sha2_starts( ctx, is224 );
+    sha2_update( ctx, ctx->opad, 64 );
+    sha2_update( ctx, tmpbuf, hlen );
+    sha2_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * SHA-256 HMAC context reset
+ */
+void sha2_hmac_reset( sha2_context *ctx )
+{
+    sha2_starts( ctx, ctx->is224 );
+    sha2_update( ctx, ctx->ipad, 64 );
+}
+
+/*
+ * output = HMAC-SHA-256( hmac key, input buffer )
+ */
+void sha2_hmac( const unsigned char *key, int keylen,
+                const unsigned char *input, int ilen,
+                unsigned char output[32], int is224 )
+{
+    sha2_context ctx;
+
+    sha2_hmac_starts( &ctx, key, keylen, is224 );
+    sha2_hmac_update( &ctx, input, ilen );
+    sha2_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha2_context ) );
+}
+
+
+#endif
+#endif