From: Jeremy Harris Date: Thu, 7 Jan 2016 20:47:13 +0000 (+0000) Subject: DKIM: reinstate embedded Polarssl SHA routines under older GnuTLS. Bug 1772 X-Git-Tag: exim-4_87_RC3~20 X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=commitdiff_plain;h=cb2243935be366d4605e94a1e55c1dcc933b66cd DKIM: reinstate embedded Polarssl SHA routines under older GnuTLS. Bug 1772 We need an incremental build of the hash, and GnuTLS did not expose the required interfaces until version 2.10.0 --- diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 10c97d288..4f6747f7c 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -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 diff --git a/src/src/exim.h b/src/src/exim.h index f94f00b97..385c3624e 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -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 */ diff --git a/src/src/pdkim/Makefile b/src/src/pdkim/Makefile index 7edc39034..ec8bb8305 100644 --- a/src/src/pdkim/Makefile +++ b/src/src/pdkim/Makefile @@ -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 index 000000000..602d137a3 --- /dev/null +++ b/src/src/pdkim/crypt_ver.h @@ -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 +# 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 index 000000000..5788777f2 --- /dev/null +++ b/src/src/pdkim/part-x509parse.c @@ -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 + * + * 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 diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index 73fe6cbe1..3840c0514 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -30,16 +30,23 @@ # error Need SUPPORT_TLS for DKIM #endif +#include "crypt_ver.h" -#ifdef USE_GNUTLS +#ifdef RSA_OPENSSL +# include +# include +# include +#elif defined(RSA_GNUTLS) # include # include # include +#endif + +#ifdef SHA_GNUTLS # include -#else -# include -# include -# include +#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 diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index c7c7b5837..97a03eabc 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -20,13 +20,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef USE_GNUTLS -# include -# include -#else -# include -#endif - /* -------------------------------------------------------------------------- */ /* Length of the preallocated buffer for the "answer" from the dns/txt callback function. This should match the maximum RDLENGTH from DNS. */ @@ -74,6 +67,10 @@ /* 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 index 000000000..96f4e7b57 --- /dev/null +++ b/src/src/pdkim/sha1.c @@ -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 + * + * 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 +#include + +/* + * 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 index 000000000..6ab6cb906 --- /dev/null +++ b/src/src/pdkim/sha2.c @@ -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 + * + * 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 +#include + +/* + * 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