Changelog inside domainkeys.c tx Manvendra Banghui www.indimail.org diff -ruN libdomainkeys-0.69-original/Makefile libdomainkeys-0.69-mbanghui-ssl-1.1/Makefile --- libdomainkeys-0.69-original/Makefile 2006-01-18 01:28:58.000000000 +0100 +++ libdomainkeys-0.69-mbanghui-ssl-1.1/Makefile 2017-08-29 14:41:39.000000000 +0200 @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-DBIND_8_COMPAT -O2 +CFLAGS=-DBIND_8_COMPAT -O2 -DDOMAIN_KEYS #CFLAGS += -DDK_DEBUG -DDK_HASH_BUFF -Wall #CFLAGS += -DUNIXWARE INCS=-I. diff -ruN libdomainkeys-0.69-original/domainkeys.c libdomainkeys-0.69-mbanghui-ssl-1.1/domainkeys.c --- libdomainkeys-0.69-original/domainkeys.c 2008-04-01 00:50:39.000000000 +0200 +++ libdomainkeys-0.69-mbanghui-ssl-1.1/domainkeys.c 2017-08-31 07:05:46.000000000 +0200 @@ -1,41 +1,111 @@ +/* + * $Log: domainkeys.c,v $ + * Revision 1.19 2017-08-09 22:07:51+05:30 Cprogrammer + * initialize EVP_MD_CTX variable + * + * Revision 1.18 2017-08-08 23:56:03+05:30 Cprogrammer + * openssl 1.1.0 port + * + * Revision 1.17 2014-03-24 12:29:35+05:30 Cprogrammer + * fixed dkparse822() + * + * Revision 1.16 2013-08-17 16:00:19+05:30 Cprogrammer + * added case for duplicate DomainKey-Signature header + * + * Revision 1.15 2013-08-12 11:55:29+05:30 Cprogrammer + * moved dk_strdup() to dns_text.c + * + * Revision 1.14 2011-07-29 09:28:18+05:30 Cprogrammer + * fixed gcc 4.6 warnings + * + * Revision 1.13 2009-03-27 16:49:55+05:30 Cprogrammer + * moved out dns_text function + * + * Revision 1.12 2009-03-20 22:29:44+05:30 Cprogrammer + * sender address fix patch + * added dk_set_seleheaders() to select headers for signing + * fixed issue with verification of multi-line headers + * + * Revision 1.11 2009-03-14 16:30:46+05:30 Cprogrammer + * Added dk_remdupe() to turn on/off ignoring hashing in duplicate headers when signing + * Added dk_selector() to return the selector name used or NULL if there isn't one + * Added test to dk_message() to detect stray CRs + * Fixed parent domain handling + * Added dk_compare_trace(), dk_enable_trace() and dk_get_trace() + * Performance improvments (see source for DK_HASH_BUFF) + * Fixed dkt_generate to remove the last ':' char and report accurate length of string returned + * Fixed memory leak in dk_headers() + * Incompatible changes made: dk_free requires an additional parameter, used to specify the OpenSSL Err + * Added dk_setopts() and dk_getopts() + * Deprecated dk_enable_trace() and dk_remdupe() in favor of using dk_setopts() + * Added dk_shutdown() to be used at application shutdown (frees dklib and openssl memory when done) + * Added dk_settxt() to bypass dns lookups and set query responses manually + * Added dk_domain() to return the domain name used (dk->domain) + * Added dk_granularity() to retrieve the value of (g=) tag in DNS lookup (called after dk_end) + * Added DK_STAT_GRANULARITY status enumeration + * Fixed dktest.c to check for DK_STAT_GRANULARITY + * Fixed dk_headers() to always return the proper length of a null terminated header list, even with a + * Added dk->granularity pointer to DK struct + * + * Revision 1.10 2008-08-03 18:25:22+05:30 Cprogrammer + * use proper proto + * + * Revision 1.9 2008-05-21 16:03:57+05:30 Cprogrammer + * fixed BIO_flush() + * + * Revision 1.8 2005-08-23 17:30:40+05:30 Cprogrammer + * gcc 4 compliance + * + * Revision 1.7 2005-05-16 16:31:44+05:30 Cprogrammer + * corrected code indentation + * + * Revision 1.6 2005-04-01 19:54:02+05:30 Cprogrammer + * libdomainkeys-0.64 + * + * Revision 1.5 2004-10-25 13:23:42+05:30 Cprogrammer + * libdomainkeys-0.63 + * + * Revision 1.4 2004-10-22 20:24:36+05:30 Cprogrammer + * added RCS id + * + * Revision 1.3 2004-10-21 21:55:41+05:30 Cprogrammer + * code beautified + * + * Revision 1.2 2004-10-20 17:30:20+05:30 Cprogrammer + * domainkeys-0.62 + * + * Revision 1.1 2004-08-13 00:16:33+05:30 Cprogrammer + * Initial revision + * + */ +#ifdef DOMAIN_KEYS #include #include -#include -// added by nhatier for compilation under MSVC -#ifdef _MSC_VER #include - #define strncasecmp strnicmp - #define strcasecmp stricmp - #define snprintf _snprintf -#else - #ifndef _STRINGS_H - #include - #endif - #ifndef _STRING_H - #include - #endif -#endif -// end added by nhatier -extern char *dns_text(char *); +#include +#include +#include +#include "dktrace.h" + +EVP_MD_CTX *evptr = NULL; /*- the hash */ /* STARTHEAD */ -/* This is libdomainkeys. It's Copyright (c) 2004 Yahoo, Inc. +/* + * This is libdomainkeys. It's Copyright (c) 2004 Yahoo, Inc. * This code incorporates intellectual property owned by * Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License * Agreement: http://domainkeys.sourceforge.net/license/softwarelicense1-0.html */ -#include -#include -#include +#include "dktrace.h" #ifdef SWIG -%module domainkeys -%{ +%module domainkeys % +{ #include "domainkeys.h" %} #endif - -#include "dktrace.h" +char *dns_text(char *); +char *dk_strdup(const char *); /* Performance/Debug options. * Uncomment below or use -D switch in gcc @@ -45,140 +115,143 @@ * canocalized message, reducing calls to the crypto library (from dkhash()), * but can use up slightly more memory */ -//#define DK_DEBUG 1 -#define DK_HASH_BUFF 1 - - #define DKMARK ('D' | 'K'<<8 | 'E'<<16 | 'Y'<<24) #define DK_SIGNING_SIGN 0 #define DK_SIGNING_VERIFY 1 #define DK_SIGNING_NOSIGN 2 #define DK_SIGNING_NOVERIFY 3 -#define DK_MALLOC(s) OPENSSL_malloc(s) -#define DK_MFREE(s) OPENSSL_free(s); s = NULL; +#define DK_MALLOC(s) OPENSSL_malloc(s) +#define DK_REALLOC(s, n) OPENSSL_realloc(s, n) +#define DK_MFREE(s) OPENSSL_free(s); s = NULL; #define DKERR(x) ((dk->errline=__LINE__),(dk->errfile=__FILE__),(x)) +#define DK_HASH_BUFF 1 #define DK_BLOCK 1024 //default size of malloc'd block - +/*- #define DK_DEBUG 1 *//*- Dumps whatever dkhash() hashes in to stderr */ /* * Option Flags for dk_setopts * OR together or run dk_setopts several times * All option flags are OFF by default -*/ + */ #define DKOPT_TRACE_h 0x01 //enables tracking character count in pre-canon header #define DKOPT_TRACE_H 0x02 //enables tracking character count in post-canon header #define DKOPT_TRACE_b 0x04 //enables tracking character count in pre-canon body #define DKOPT_TRACE_B 0x08 //enables tracking character count in post-canon header -#define DKOPT_RDUPE 0x10 //enables skipping duplicate headers when generateing a signature +#define DKOPT_RDUPE 0x10 //enables skipping duplicate headers when generateing a signature +#define DKOPT_SELHEAD 0x20 //enables select headers when generating a signature typedef enum { - DK_STAT_OK, /* Function completed successfully */ - DK_STAT_BADSIG, /* Signature was available but failed to verify against domain specified key */ - DK_STAT_NOSIG, /* No signature available in message */ - DK_STAT_NOKEY, /* No public key available (permanent failure) */ - DK_STAT_BADKEY, /* Unusable key, public if verifying, private if signing */ - DK_STAT_CANTVRFY, /* Cannot get domain key to verify signature (temporary failure) */ - DK_STAT_SYNTAX, /* Message is not valid syntax. Signature could not be created/checked */ - DK_STAT_NORESOURCE, /* Could not get critical resource (temporary failure) */ - DK_STAT_ARGS, /* Arguments are not usable. */ - DK_STAT_REVOKED, /* Key has been revoked. */ - DK_STAT_INTERNAL, /* cannot call this routine in this context. Internal error. */ - DK_STAT_GRANULARITY, /* Granularity mismatch: sender doesn't match g= option. */ + DK_STAT_OK, /*- Function completed successfully */ + DK_STAT_BADSIG, /*- Signature was available but failed to verify against domain specified key */ + DK_STAT_NOSIG, /*- No signature available in message */ + DK_STAT_NOKEY, /*- No public key available (permanent failure) */ + DK_STAT_BADKEY, /*- Unusable key, public if verifying, private if signing */ + DK_STAT_CANTVRFY, /*- Cannot get domain key to verify signature (temporary failure) */ + DK_STAT_SYNTAX, /*- Message is not valid syntax. Signature could not be created/checked */ + DK_STAT_NORESOURCE, /*- Could not get critical resource (temporary failure) */ + DK_STAT_ARGS, /*- Arguments are not usable. */ + DK_STAT_REVOKED, /*- Key has been revoked. */ + DK_STAT_INTERNAL, /*- cannot call this routine in this context. Internal error. */ + DK_STAT_GRANULARITY, /*- Granularity mismatch: sender doesn't match g= option. */ + DK_STAT_DUPLICATE, /*- Duplicate DomainKey-Header */ } DK_STAT; typedef enum { - DK_FLAG_TESTING = 1, /* set when in testing mode. */ - DK_FLAG_SIGNSALL = 2, /* domain signs all outgoing email. */ - DK_FLAG_SET = 4, /* flags set from a successful DNS query */ - DK_FLAG_G = 8, /* g tag was present in the selector. */ + DK_FLAG_TESTING = 1, /*- set when in testing mode. */ + DK_FLAG_SIGNSALL = 2, /*- domain signs all outgoing email. */ + DK_FLAG_SET = 4, /*- flags set from a successful DNS query */ + DK_FLAG_G = 8, /*- g tag was present in the selector. */ } DK_FLAGS; + typedef enum { - DK_TXT_KEY = 0, - DK_TXT_POLICY + DK_TXT_KEY = 0, + DK_TXT_POLICY } DK_TXT; typedef enum { - DK_CANON_SIMPLE = 0, - DK_CANON_NOFWS = 1, + DK_CANON_SIMPLE = 0, + DK_CANON_NOFWS = 1, } DK_CANON; + /* STARTSTRUCT */ typedef struct { /* STARTPRIV */ - const EVP_MD *md; + const EVP_MD *md; /* STOPPRIV */ - } DK_LIB; /* STOPSTRUCT */ -//UnixWare Fix -Tim /* STARTSTRUCT */ typedef struct { /* STARTPRIV */ - int dkmarker; /* in case somebody casts in */ - EVP_MD_CTX mdctx; /* the hash */ - int signing; /* our current signing/verifying state */ - int in_headers; /* true if we're still processing headers */ - char *header; /* points to a malloc'ed block for header. */ - int headerlen; /* total length of the header. */ - int headermax; /* length of malloc'ed block */ - int headerlinelen; /* current column of the header */ - int start_signed; /* offset into header of the start of the headers. */ - char *from; /* saved copy of From: header */ - char *sender; /* saved copy of Sender: header */ - char *dksign; /* saved copy of DK-Sig: header */ - char *dktrace; /* saved copy of DK-Trace: header */ - char *domain; /* d= */ - char *selector; /* s= */ - char *signature; /* b= */ - char *granularity; /* g= */ - char *keyrec; /* caller supplied TXT key record */ - char *policyrec; /* caller supplied TXT policy record */ - int canon; /* c= canonicalization being applied. */ - int state; /* state variable for canonicalization */ - char *headers; /* h= */ - int errline; /* source line of most recent error */ - char *errfile; /* source file of most recent error */ - char *sender_beforesign; /* saved copy of Sender: header */ - int opts; /* trace and rdupe flags */ - char last_char; /* the last character processed by dk_message() */ + int dkmarker; /*- in case somebody casts in */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX mdctx; /*- the hash */ +#else + EVP_MD_CTX *mdctx; /*- the hash */ +#endif + int signing; /*- our current signing/verifying state */ + int in_headers; /*- true if we're still processing headers */ + char *header; /*- points to a malloc'ed block for header. */ + int headerlen; /*- total length of the header. */ + int headermax; /*- length of malloc'ed block */ + int headerlinelen; /*- current column of the header */ + int start_signed; /*- offset into header of the start of the headers. */ + char *from; /*- saved copy of From: header */ + char *sender; /*- saved copy of Sender: header */ + char *dksign; /*- saved copy of DK-Sig: header */ + char *dktrace; /*- saved copy of DK-Trace: header */ + char *domain; /*- d= */ + char *selector; /*- s= */ + char *signature; /*- b= */ + char *granularity; /*- g= */ + char *keyrec; /*- caller supplied TXT key record */ + char *policyrec; /*- caller supplied TXT policy record */ + int canon; /*- c= canonicalization being applied. */ + int state; /*- state variable for canonicalization */ + char *headers; /*- h= */ + int errline; /*- source line of most recent error */ + char *errfile; /*- source file of most recent error */ + char *sender_beforesign; /*- saved copy of Sender: header */ + int opts; /*- trace and rdupe flags */ + char last_char; /*- the last character processed by dk_message() */ #ifdef DK_HASH_BUFF - char *hash_buff; /* buffer for hashing */ - int hash_buff_len; /* length of hashing buffer */ + char *hash_buff; /*- buffer for hashing */ + int hash_buff_len; /*- length of hashing buffer */ #endif - DK_TRACE *trace; /* pointer to trace count table */ - DK_TRACE *traceheader; /* pointer to trace count table from DK-Trace:*/ + DK_TRACE *trace; /*- pointer to trace count table */ + DK_TRACE *traceheader; /*- pointer to trace count table from DK-Trace:*/ + char *sel_headers; /*- selected headers */ /* STOPPRIV */ } DK; /* STOPSTRUCT */ - - /* STARTPRIV */ -static char *errors[] = -{ - "DK_STAT_OK: Function completed successfully", - "DK_STAT_BADSIG: Signature was available but failed to verify against domain specified key", - "DK_STAT_NOSIG: No signature available in message", - "DK_STAT_NOKEY: No public key available (permanent failure)", - "DK_STAT_BADKEY: Unusable key, public if verifying, private if signing.", - "DK_STAT_CANTVRFY: Cannot get domain key to verify signature (temporary failure)", - "DK_STAT_SYNTAX: Message is not valid syntax. Signature could not be created/checked", - "DK_STAT_NORESOURCE: Could not get critical resource (temporary failure)", - "DK_STAT_ARGS: Arguments are not usable.", - "DK_STAT_REVOKED: Key has been revoked.", - "DK_STAT_INTERNAL: cannot call this routine in this context. Internal error.", - "DK_STAT_GRANULARITY: Granularity mismatch: sender doesn't match g= option." +static char *errors[] = { + "DK_STAT_OK: Function completed successfully", + "DK_STAT_BADSIG: Signature was available but failed to verify against domain specified key", + "DK_STAT_NOSIG: No signature available in message", + "DK_STAT_NOKEY: No public key available (permanent failure)", + "DK_STAT_BADKEY: Unusable key, public if verifying, private if signing.", + "DK_STAT_CANTVRFY: Cannot get domain key to verify signature (temporary failure)", + "DK_STAT_SYNTAX: Message is not valid syntax. Signature could not be created/checked", + "DK_STAT_NORESOURCE: Could not get critical resource (temporary failure)", + "DK_STAT_ARGS: Arguments are not usable.", + "DK_STAT_REVOKED: Key has been revoked.", + "DK_STAT_INTERNAL: cannot call this routine in this context. Internal error.", + "DK_STAT_GRANULARITY: Granularity mismatch: sender doesn't match g= option.", + "DK_STAT_DUPLICATE: duplicate Domainkey-Signature in message", }; /* STOPPRIV */ /* STOPHEAD */ -//prototype for dk_from -char* dk_from(DK *); -int dk_headers(DK *, char *); +char *dk_from(DK *); +int dk_headers(DK *, char *); +static char *strncasestr(const char *, const char *, size_t slen); char* dk_strdup(const char* s) { char* new = DK_MALLOC(strlen(s)+1); @@ -190,21 +263,24 @@ } /* HEADER */ -/* returns the source file from which an error was returned. */ -char * dk_errfile(DK *dk) +/*- returns the source file from which an error was returned. */ +char * +dk_errfile(DK *dk) { - return dk->errfile; + return dk->errfile; } /* HEADER */ -/* returns the source line number from which an error was returned. */ -int dk_errline(DK *dk) +/*- returns the source line number from which an error was returned. */ +int +dk_errline(DK *dk) { - return dk->errline; + return dk->errline; } /* HEADER */ -/* Per-process, one-time initialization +/* + * Per-process, one-time initialization * Returns library structure for subsequent dk_sign or dk_verify calls. * Consult statp before using. * @@ -213,139 +289,134 @@ * NOTE: DK_LIB pointers are safe to use over multiple threads * DK pointers are NOT safe to use over multiple threads */ -DK_LIB *dk_init(DK_STAT *statp) +DK_LIB * +dk_init(DK_STAT *statp) { - DK_LIB *dklib; + DK_LIB *dklib; - dklib = DK_MALLOC(sizeof(DK_LIB)); - if (!dklib) - { - if (statp) - { - *statp = DK_STAT_NORESOURCE; - } - return NULL; - } - dklib->md = EVP_sha1(); - if (!dklib->md) - { - if (statp) - { - *statp = DK_STAT_INTERNAL; - } - DK_MFREE(dklib); - return NULL; - } - if (statp) - { - *statp = DK_STAT_OK; - } - return dklib; + if (!(dklib = DK_MALLOC(sizeof(DK_LIB)))) + { + if (statp) + *statp = DK_STAT_NORESOURCE; + return NULL; + } + if (!(dklib->md = EVP_sha1())) + { + if (statp) + *statp = DK_STAT_INTERNAL; + DK_MFREE(dklib); + return NULL; + } + if (statp) + *statp = DK_STAT_OK; + return dklib; } /* HEADER */ -/* Per-process, one-time cleanup +/* + * Per-process, one-time cleanup * Should be called just before the application ends. * the dklib pointer is not valid anymore after this call * This function should be called even if dk_init failed. * It's safe to call dk_shutdown with a NULL pointer */ -void dk_shutdown(DK_LIB * dklib) +void +dk_shutdown(DK_LIB *dklib) { - if (dklib) - { - DK_MFREE(dklib); - } - CRYPTO_cleanup_all_ex_data(); + if (dklib) + DK_MFREE(dklib); + CRYPTO_cleanup_all_ex_data(); } -/* start a new header */ -static DK_STAT dkinit_new_header(DK *dk) +/* + * start a new header + */ +static DK_STAT +dkinit_new_header(DK *dk) { - dk->headermax = DK_BLOCK; - dk->header = DK_MALLOC(DK_BLOCK); - if (!dk->header) - { - return DKERR(DK_STAT_NORESOURCE); - } - memset(dk->header,0,DK_BLOCK); - dk->headerlen = 0; - dk->headerlinelen = 1; /* always store the first char. */ - dk->in_headers = 1; - dk->start_signed = 0; - dk->from = NULL; - dk->sender = NULL; - dk->dksign = NULL; - dk->dktrace = NULL; - dk->domain = NULL; - dk->selector = NULL; - dk->signature = NULL; - dk->canon = DK_CANON_SIMPLE; - dk->state = 0; - dk->headers = 0; - dk->sender_beforesign = NULL; - dk->opts = 0; - dk->last_char = '\0'; - dk->trace = NULL; - dk->traceheader = NULL; - dk->granularity = NULL; - dk->keyrec = NULL; - dk->policyrec = NULL; + dk->headermax = DK_BLOCK; + if (!(dk->header = DK_MALLOC(dk->headermax))) + return DKERR(DK_STAT_NORESOURCE); + memset(dk->header, 0, DK_BLOCK); + dk->headerlen = 0; + dk->headerlinelen = 1; /*- always store the first char. */ + dk->in_headers = 1; + dk->start_signed = 0; + dk->from = NULL; + dk->sender = NULL; + dk->dksign = NULL; + dk->dktrace = NULL; + dk->domain = NULL; + dk->selector = NULL; + dk->signature = NULL; + dk->canon = DK_CANON_SIMPLE; + dk->state = 0; + dk->headers = 0; + dk->sender_beforesign = NULL; + dk->opts = 0; + dk->last_char = '\0'; + dk->trace = NULL; + dk->traceheader = NULL; + dk->granularity = NULL; + dk->keyrec = NULL; + dk->policyrec = NULL; + dk->sel_headers = NULL; #ifdef DK_HASH_BUFF - dk->hash_buff = DK_MALLOC(DK_BLOCK); - if (!dk->hash_buff) - { - return DKERR(DK_STAT_NORESOURCE); - } - memset(dk->hash_buff,0,DK_BLOCK); - dk->hash_buff_len = 0; + dk->hash_buff = DK_MALLOC(DK_BLOCK); + if (!dk->hash_buff) + return DKERR(DK_STAT_NORESOURCE); + memset(dk->hash_buff, 0, DK_BLOCK); + dk->hash_buff_len = 0; #endif - return DKERR(DK_STAT_OK); + return DKERR(DK_STAT_OK); } /* HEADER */ -/* Set dk options, use instead of dk_remdupe and dk_enable_trace +/* + * Set dk options, use instead of dk_remdupe and dk_enable_trace * Can be called multiple times. * use after dk_sign()/dk_verify() - * * the bits field can be an OR of any of the following - *DKOPT_TRACE_h Trace pre-canon header - *DKOPT_TRACE_H Trace post-canon header - *DKOPT_TRACE_b Trace pre-canon body - *DKOPT_TRACE_B Trace post-canon body - *DKOPT_RDUPE Exclude duplicate headers from hash (Signing only) - */ -DK_STAT dk_setopts(DK *dk, int bits) -{ - if (!dk) - return DK_STAT_ARGS; - if ((dk->headerlen == 0)&&((dk->signing == DK_SIGNING_NOVERIFY)||(dk->signing == DK_SIGNING_SIGN))) - { - dk->opts |= bits; - if ((bits & (DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)) && !dk->trace) - { - dk->trace = DK_MALLOC(sizeof(DK_TRACE)); - if (!dk->trace) - return DKERR(DK_STAT_NORESOURCE); - dkt_init(dk->trace); - } - if ((dk->signing != DK_SIGNING_SIGN) && (bits & DKOPT_RDUPE)) - { - return DKERR(DK_STAT_INTERNAL); //cant do rdupe in verify mode - } - return DKERR(DK_STAT_OK); - } - return DKERR(DK_STAT_INTERNAL); + * DKOPT_TRACE_h Trace pre-canon header + * DKOPT_TRACE_H Trace post-canon header + * DKOPT_TRACE_b Trace pre-canon body + * DKOPT_TRACE_B Trace post-canon body + * DKOPT_RDUPE Exclude duplicate headers from hash (Signing only) + *DKOPT_SELHEAD Include only selected headers into hash (Signing only) + */ +DK_STAT +dk_setopts(DK *dk, int bits) +{ + if (!dk) + return DK_STAT_ARGS; + if ((dk->headerlen == 0) && ((dk->signing == DK_SIGNING_NOVERIFY) || (dk->signing == DK_SIGNING_SIGN))) + { + dk->opts |= bits; + if ((bits & (DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)) && !dk->trace) + { + dk->trace = DK_MALLOC(sizeof(DK_TRACE)); + if (!dk->trace) + return DKERR(DK_STAT_NORESOURCE); + dkt_init(dk->trace); + } + if ((dk->signing != DK_SIGNING_SIGN) && (bits & DKOPT_RDUPE)) + return DKERR(DK_STAT_INTERNAL); /*- can't do rdupe in verify mode */ + return DKERR(DK_STAT_OK); + } + return DKERR(DK_STAT_INTERNAL); } + /* HEADER */ -/* returns the int holding the options set +/* + * returns the int holding the options set * See dk_setopts for bit flags */ -int dk_getopts(DK *dk) +int +dk_getopts(DK *dk) { - if (!dk) - return 0; - return (dk->opts); + if (!dk) + return 0; + return (dk->opts); } /* HEADER */ @@ -354,342 +425,335 @@ * * use after dk_sign()/dk_verify() */ -DK_STAT dk_enable_trace(DK *dk) +DK_STAT +dk_enable_trace(DK *dk) { - return dk_setopts(dk,(DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)); + return dk_setopts(dk,(DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)); } + /* HEADER */ -/* Prints trace table to *store variable (char string) +/* + * Prints trace table to *store variable (char string) * *dk is the container for the table * *store is a pointer to a character array to output to * store_size is the size of the character array *store - * */ -DK_STAT dk_get_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size) +DK_STAT +dk_get_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size) { - if (!dk) - return DK_STAT_ARGS; - if (dk->trace) - { - if (!dkt_generate(dk->trace, type, store, store_size)) - { - return DK_STAT_NORESOURCE; //not enough buffer space - } - return DKERR(DK_STAT_OK); - } - return DKERR(DK_STAT_INTERNAL); + if (!dk) + return DK_STAT_ARGS; + if (dk->trace) { + if (!dkt_generate(dk->trace, type, store, store_size)) { + return DK_STAT_NORESOURCE; //not enough buffer space + } + return DKERR(DK_STAT_OK); + } + return DKERR(DK_STAT_INTERNAL); } /* HEADER */ -/* Prints difference trace table to *store variable (char string) +/* + * Prints difference trace table to *store variable (char string) * *dk is the container for the table * *store is a pointer to a character array to output to * store_size is the size of the character array *store * return DK_STAT_NOSIG if no DK-Trace header was found */ -DK_STAT dk_compare_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size) +DK_STAT +dk_compare_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size) { - DK_TRACE table; - if (!dk) - return DK_STAT_ARGS; - if (!dk->dktrace || !dk->trace) - return DK_STAT_NOSIG; - dkt_init(&table); - if (!dk->traceheader) //make DK_TRACE from header - { - dk->traceheader = DK_MALLOC(sizeof(DK_TRACE)); - if (!dk->traceheader) - return DKERR(DK_STAT_NORESOURCE); - dkt_init(dk->traceheader); - - if (!dkt_hdrtotrace(dk->dktrace,dk->traceheader)) - { - return DK_STAT_NORESOURCE; - } - } - dkt_diff(dk->traceheader, dk->trace, type, &table); - if (!dkt_generate(&table, type, store, store_size)) - { - return DK_STAT_NORESOURCE; //not enough buffer space - } - return DK_STAT_OK; + DK_TRACE table; + + if (!dk) + return DK_STAT_ARGS; + if (!dk->dktrace || !dk->trace) + return DK_STAT_NOSIG; + dkt_init(&table); + if (!dk->traceheader) //make DK_TRACE from header + { + dk->traceheader = DK_MALLOC(sizeof (DK_TRACE)); + if (!dk->traceheader) + return DKERR(DK_STAT_NORESOURCE); + dkt_init(dk->traceheader); + + if (!dkt_hdrtotrace(dk->dktrace, dk->traceheader)) { + return DK_STAT_NORESOURCE; + } + } + dkt_diff(dk->traceheader, dk->trace, type, &table); + if (!dkt_generate(&table, type, store, store_size)) { + return DK_STAT_NORESOURCE; //not enough buffer space + } + return DK_STAT_OK; } /* HEADER */ -/* Sets the DNS key/policy record manually (no DNS lookup) +/* + * Sets the DNS key/policy record manually (no DNS lookup) * txtrecord needs to be set to "e=perm;" to force a permanent DNS failure * txtrecord needs to be set to "e=temp;" to force a temporary DNS failure * Valid DK_TXT types are: * DK_TXT_KEY (normal selector record; for ._domainkey.) * DK_TXT_POLICY (domain policy record; for _domainkey.) */ -DK_STAT dk_settxt(DK *dk, DK_TXT recordtype, const char *txtrecord) +DK_STAT +dk_settxt(DK *dk, DK_TXT recordtype, const char *txtrecord) { - char **ptr; //pointer to keyrecord/policyrecord pointer - if (!dk|| !txtrecord) - return DK_STAT_ARGS; - switch (recordtype) - { - case DK_TXT_KEY: - ptr = &dk->keyrec; - break; - case DK_TXT_POLICY: - ptr = &dk->policyrec; - break; - default: - return DK_STAT_ARGS; - } - // Free the value iff it is currently set. - if (*ptr) - { - DK_MFREE(*ptr); - } - *ptr = dk_strdup(txtrecord); - return DKERR(DK_STAT_OK); + char **ptr; //pointer to keyrecord/policyrecord pointer + + if (!dk|| !txtrecord) + return DK_STAT_ARGS; + switch (recordtype) + { + case DK_TXT_KEY: + ptr = &dk->keyrec; + break; + case DK_TXT_POLICY: + ptr = &dk->policyrec; + break; + default: + return DK_STAT_ARGS; + } + /*- Free the value iff it is currently set. */ + if (*ptr) + DK_MFREE(*ptr); + *ptr = dk_strdup(txtrecord); + return DKERR(DK_STAT_OK); } -static DK_STAT dkstore_char(DK *dk, char ch) +static DK_STAT +dkstore_char(DK *dk, char ch) { - if (dk->headerlen >= dk->headermax) - { - char *hp; - hp = DK_MALLOC(dk->headermax * 2 + 1024 + 1); /* leave room for null */ - if (!hp) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (dk->headermax) - { - memcpy(hp, dk->header, dk->headerlen); - DK_MFREE(dk->header); - } - dk->header = hp; - dk->headermax = dk->headermax * 2 + 1024; - } - dk->header[dk->headerlen++] = ch; - dk->headerlinelen++; - return DKERR(DK_STAT_OK); + if (dk->headerlen >= dk->headermax) + { + char *hp; + + if (!(hp = DK_MALLOC(dk->headermax * 2 + 1024 + 1))) /*- leave room for null */ + return DKERR(DK_STAT_NORESOURCE); + if (dk->headermax) + { + memcpy(hp, dk->header, dk->headerlen); + DK_MFREE(dk->header); + } + dk->header = hp; + dk->headermax = dk->headermax * 2 + 1024; + } + dk->header[dk->headerlen++] = ch; + dk->headerlinelen++; + return DKERR(DK_STAT_OK); } /* HEADER */ -/* Per-message, may be threaded. +/* + * Per-message, may be threaded. * canon is one of DK_CANON_*. * Returns state structure for operation. Consult statp before using. */ -DK *dk_sign(DK_LIB *dklib, DK_STAT *statp, int canon) +DK * +dk_sign(DK_LIB *dklib, DK_STAT *statp, int canon) { - DK *dk; - - dk = DK_MALLOC(sizeof(DK)); - if (!dk) - { - if (statp) - { - *statp = DKERR(DK_STAT_NORESOURCE); - } - return NULL; - } - dk->dkmarker = DKMARK; - dk->signing = DK_SIGNING_SIGN; - if (dkinit_new_header(dk) != DK_STAT_OK) - { - /* couldn't malloc a header. */ - DK_MFREE(dk); - if (statp) - { - *statp = DKERR(DK_STAT_NORESOURCE); - } - return NULL; - } - dk->canon = canon; /* TC13-simple, TC13-nofws */ - EVP_SignInit(&dk->mdctx, dklib->md); + DK *dk; - if (statp) - { - *statp = DKERR(DK_STAT_OK); - } - return dk; + if (!(dk = DK_MALLOC(sizeof(DK)))) + { + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } + dk->dkmarker = DKMARK; + dk->signing = DK_SIGNING_SIGN; + if (dkinit_new_header(dk) != DK_STAT_OK) + { + /*- couldn't malloc a header. */ + DK_MFREE(dk); + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } + dk->canon = canon; /*- TC13-simple, TC13-nofws */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (!(dk->mdctx = EVP_MD_CTX_new())) { + DK_MFREE(dk); + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } + evptr = dk->mdctx; +#else + evptr = &dk->mdctx; +#endif + EVP_SignInit(evptr, dklib->md); + if (statp) + *statp = DKERR(DK_STAT_OK); + return dk; } /* HEADER */ -/* Per-message, may be threaded. +/* + * Per-message, may be threaded. * Returns state structure for operation. Consult statp before using. */ -DK *dk_verify(DK_LIB *dklib, DK_STAT *statp) +DK * +dk_verify(DK_LIB *dklib, DK_STAT *statp) { - DK *dk; - - dk = DK_MALLOC(sizeof(DK)); - if (!dk) - { - if (statp) - { - *statp = DKERR(DK_STAT_NORESOURCE); - } - return NULL; - } - dk->dkmarker = DKMARK; - dk->signing = DK_SIGNING_NOVERIFY; /* wait to verify until we see DK-Signature. */ - if (dkinit_new_header(dk) != DK_STAT_OK) - { - /* couldn't malloc a header. */ - DK_MFREE(dk); - if (statp) - { - *statp = DKERR(DK_STAT_NORESOURCE); - } - return NULL; - } - EVP_VerifyInit(&dk->mdctx, dklib->md); + DK *dk; - if (statp) - { - *statp = DKERR(DK_STAT_OK); - } - return dk; + if (!(dk = DK_MALLOC(sizeof(DK)))) + { + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } + dk->dkmarker = DKMARK; + dk->signing = DK_SIGNING_NOVERIFY; /*- wait to verify until we see DK-Signature. */ + if (dkinit_new_header(dk) != DK_STAT_OK) + { + /*- couldn't malloc a header. */ + DK_MFREE(dk); + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (!(dk->mdctx = EVP_MD_CTX_new())) { + DK_MFREE(dk); + if (statp) + *statp = DKERR(DK_STAT_NORESOURCE); + return NULL; + } + evptr = dk->mdctx; +#else + evptr = &dk->mdctx; +#endif + EVP_VerifyInit(evptr, dklib->md); + if (statp) + *statp = DKERR(DK_STAT_OK); + return dk; } -/* parse an rfc822 address */ -/* leave it in the dk_address() format; that is, with the existing - * first letter, followed by the address */ -static DK_STAT dkparse822(char *address, unsigned int offset) -{ - int foundangle = 0; /* true if it's in angle brackets */ - int foundat = 0; - char *from, *to; - int level = 1; - - to = address + 1; - from = address + offset; - while (*from) - { /* nuke comments. */ - if (*from == ')') - { - return DK_STAT_SYNTAX; - } - else if (*from == '\\' && from[1]) - { - /* skip backslash-quoted characters */ - *to++ = *from++; - *to++ = *from++; - } - else if (*from == '"') - { - /* we have to ignore parenthesis inside quotes. */ - from++; - for (;;) - { - if (*from == '\0') - { - return DK_STAT_SYNTAX; - } - else if (*from == '"') - { - from++; - break; - } - else if (*from == '\\' && from[1]) - { - *to++ = *from++; - } - *to++ = *from++; - } - } - else if (*from == '(') - { - level = 1; - from++; - while (level) - { - if (*from == '\0') - { - return DK_STAT_SYNTAX; - } - else if (*from == '(') - { - ++level; - } - else if (*from == ')') - { - --level; - } - else if (*from == '\\' && from[1]) - { - ++from; - } - ++from; - } - } - else if (*from == ' ') - { - ++from; - } - else if (*from == '\t') - { - ++from; - } - else - { - *to++ = *from++; - } - } //end while(*from) - *to = '\0'; - from = address + 1; - to = address + 1; - while (*from) - { - if (*from == '@') - { - foundat = 1; - } - if (*from == '\\' && from[1]) - { - *to++ = *from++; - *to++ = *from++; - } - else if (*from == '<') - { - from++; - to = address + 1; - foundangle = 1; - foundat = 0; - } - else if (*from == ',' || *from == ':' ) - { - from++; - to = address + 1; - foundat = 0; - } - else if (foundangle && *from == '>') - { - break; - } - else if (*from == ';') - { - break; - } - else - { - *to++ = *from++; - } - } - *to = '\0'; - if (foundat) - { - return DK_STAT_OK; - } - else if (!address[1]) - { - return DK_STAT_OK; - } - else - { - return DK_STAT_SYNTAX; /* no @ in the address */ - } +/* + * parse an rfc822 address + * + * leave it in the dk_address() format; that is, with the existing + * first letter, followed by the address + */ +static DK_STAT +dkparse822(char *address, unsigned int offset) +{ + int foundangle = 0; /*- true if it's in angle brackets */ + int foundat = 0; + char *from, *to; + int level = 1; + + to = address + 1; + from = address + offset; + while (*from) + { /*- nuke comments. */ + if (*from == ')') + return DK_STAT_SYNTAX; + else + if (*from == '\\' && from[1]) + { + /*- skip backslash-quoted characters */ + *to++ = *from++; + *to++ = *from++; + } else + if (*from == '"') + { + /*- we have to ignore parenthesis inside quotes. */ + from++; + for (;;) + { + if (*from == '\0') + return DK_STAT_SYNTAX; + else + if (*from == '"') + { + from++; + break; + } else + if (*from == '\\' && from[1]) + *to++ = *from++; + *to++ = *from++; + } + } else + if (*from == '(') + { + level = 1; + from++; + while (level) + { + if (*from == '\0') + return DK_STAT_SYNTAX; + else + if (*from == '(') + ++level; + else + if (*from == ')') + --level; + else + if (*from == '\\' && from[1]) + ++from; + ++from; + } + } else + if (*from == ' ') + ++from; + else + if (*from == '\t') + ++from; + else + *to++ = *from++; + } + *to = '\0'; + from = address + 1; + to = address + 1; + while (*from) + { + if (*from == '@') + foundat = 1; + if (*from == '\\' && from[1]) + { + *to++ = *from++; + *to++ = *from++; + } else + if (*from == '<') + { + from++; + to = address + 1; + foundangle = 1; + foundat = 0; + } else + if (*from == ',' || *from == ':') + { + from++; + to = address + 1; + foundat = 0; + } else + if (foundangle && *from == '>') + { + break; + } else + if (foundat && *from == ';') + { + break; + } else + *to++ = *from++; + } + *to = '\0'; + if (foundat) + return DK_STAT_OK; + else + if (!address[1]) + return DK_STAT_OK; + else + return DK_STAT_SYNTAX; /*- no @ in the address */ } -/* Given a list of key=value; pairs, find all the keys found in letters. +/* + * Given a list of key=value; pairs, find all the keys found in letters. * Store the value in the corresponding entry in values[]. * Modifies list to insert nulls in the place of the semicolons which terminate * each of the values except possibly the last. @@ -699,883 +763,785 @@ * of the existing values need spaces, so we always remove them. */ -static DK_STAT dkparselist(char *list, char *letters, char *values[]) +static DK_STAT +dkparselist(char *list, char *letters, char *values[]) { - char key; - int i; - char *value; + char key; + int i; + char *value; + + /*- start with all args unset */ + for (i = 0; letters[i]; i++) + values[i] = NULL; + key = 0; + while (*list) + { + if ((*list == ' ') || (*list == '\t') || (*list == '\r') || (*list == '\n')) + list++; + else + if (*list == '=') + { + char *ws; - /* start with all args unset */ - for (i = 0; letters[i]; i++) - { - values[i] = NULL; - } - key = 0; - while (*list) - { - if ((*list == ' ')||(*list == '\t')||(*list == '\r')||(*list == '\n')) - { - list++; - } - else if (*list == '=') - { - char *ws; - - ++list; - value = list; - ws = list; - while (1) - { - /* copy up to null or semicolon, deleting whitespace as we go */ - *ws = *list; - if ((*list == ' ')||(*list == '\t')||(*list == '\r')||(*list == '\n')) - { - /* ignore */ - } - else if (!*list) - { - break; - } - else if (*list == ';') - { - *ws = '\0'; - list++; - break; - } - else - { - ws++; - } - list++; - } - if (!key) - { - return DK_STAT_SYNTAX; /* we didn't get a key. TC22 */ - } - /* if we find a matching letter, remember the value */ - for (i = 0; letters[i]; i++) - { - if (key == letters[i]) - { - if (values[i]) - { - return DK_STAT_SYNTAX; /* no duplicate keys. TC23 */ - } - values[i] = value; - } - } - key = 0; - } - else - { - if (key) - { - return DK_STAT_SYNTAX; /* they already gave us a key. TC24 */ - } - key = *list++; - if (!islower((int)key)) - { - return DK_STAT_SYNTAX; /* must be lowercase letter. TC25 */ - } - } - } - if (key) - { - return DK_STAT_SYNTAX; /* we ended up with an extra key. TC25-1 */ - } - return DK_STAT_OK; + ++list; + value = list; + ws = list; + while (1) + { + /*- copy up to null or semicolon, deleting whitespace as we go */ + *ws = *list; + if ((*list == ' ') || (*list == '\t') || (*list == '\r') || (*list == '\n')) + { + /*- NOOP */ + } else + if (!*list) + break; + else + if (*list == ';') + { + *ws = '\0'; + list++; + break; + } else + ws++; + list++; + } + if (!key) + return DK_STAT_SYNTAX; /* we didn't get a key. TC22 */ + /*- + * if we find a matching letter, remember the value + */ + for (i = 0; letters[i]; i++) + { + if (key == letters[i]) + { + if (values[i]) + return DK_STAT_SYNTAX; /* no duplicate keys. TC23 */ + values[i] = value; + } + } + key = 0; + } else + { + if (key) + return DK_STAT_SYNTAX; /* they already gave us a key. TC24 */ + key = *list++; + if (!islower((int) key)) + return DK_STAT_SYNTAX; /* must be lowercase letter. TC25 */ + } + } + if (key) + return DK_STAT_SYNTAX; /* we ended up with an extra key. TC25-1 */ + return DK_STAT_OK; } /* HEADER */ -/* DEPRECATED in favor of calling dk_setopts() +/* + * DEPRECATED in favor of calling dk_setopts() * set option to remove dupe headers * should be called after dk_sign(); * any int NOT 0 turns dupe removal on */ -DK_STAT dk_remdupe(DK *dk,int i) +DK_STAT +dk_remdupe(DK *dk, int i) { - if (i != 0) - return dk_setopts(dk,DKOPT_RDUPE); - return DK_STAT_OK; + if (i != 0) + return dk_setopts(dk,DKOPT_RDUPE); + return DK_STAT_OK; } - /* HEADER */ -/* Returns the policy flags belonging to the signing domain. +/* + * Returns the policy flags belonging to the signing domain. * Sender: overrides From:, and the d= entry in the DK-Sig overrides both. * If the policy flags were not successfully fetched, DK_FLAG_SET will not * be set. */ -DK_FLAGS dk_policy(DK *dk) +DK_FLAGS +dk_policy(DK *dk) { - char *query, *results, *flags[2]; - char *domain; - int dkf = 0; - - if (!dk) - return 0; - domain = NULL; - if (dk->dksign) - { - domain = dk->domain; - } - if (!domain) - { - domain = dk_from(dk); - } - if (!domain) - { - return 0; - } - - query = DK_MALLOC(strlen("_domainkey.") + strlen(domain) + 1); - if (query) - { - /* allow user to supply the DNS TXT policy record */ - if (!dk->policyrec) - { - sprintf(query, "_domainkey.%s", domain); - results = dns_text(query); - DK_MFREE(query); - } - else - { - results = dk_strdup(dk->policyrec); - } - - if (!strcmp(results,"e=perm;")) - { - } - else if (!strcmp(results,"e=temp;")) - { - } - else - { - dkparselist(results, "ot", flags); - - if (flags[0] && *flags[0] == '-') /* TC36 */ - { - dkf |= DK_FLAG_SIGNSALL; - } - if (flags[1] && *flags[1] == 'y') /* TC36-1 */ - { - dkf |= DK_FLAG_TESTING; - } - dkf |= DK_FLAG_SET; - } - DK_MFREE(results); - } - return dkf; + char *query, *results, *flags[2]; + char *domain; + int dkf = 0; + + if (!dk) + return 0; + domain = NULL; + if (dk->dksign) + domain = dk->domain; + if (!domain) + domain = dk_from(dk); + if (!domain) + return 0; + if ((query = DK_MALLOC(strlen("_domainkey.") + strlen(domain) + 1))) + { + /* allow user to supply the DNS TXT policy record */ + if (!dk->policyrec) + { + sprintf(query, "_domainkey.%s", domain); + results = dns_text(query); + DK_MFREE(query); + } else + results = dk_strdup(dk->policyrec); + if (!strcmp(results, "e=perm;")) + ; + else + if (!strcmp(results, "e=temp;")) + ; + else + { + dkparselist(results, "ot", flags); + if (flags[0] && *flags[0] == '-') /*- TC36 */ + dkf |= DK_FLAG_SIGNSALL; + if (flags[1] && *flags[1] == 'y') /*- TC36-1 */ + dkf |= DK_FLAG_TESTING; + dkf |= DK_FLAG_SET; + } + DK_MFREE(results); + } + return dkf; } /* -dkhash -Internal function. Hashes in a single character, Will NOT has in ' ' or '\t' -if in NOFWS canon. Otherwise tracks \r and \r\n and hashes -them accordingly with the rest of the message. -Should ONLY be called when - dk->signing == DK_SIGNING_SIGN||DK_SIGNING_VERIFY -otherwise its pointless -*/ -static void dkhash(DK *dk, const unsigned char *ptr) + * Internal function. Hashes in a single character, Will NOT has in ' ' or '\t' + * if in NOFWS canon. Otherwise tracks \r and \r\n and hashes + * them accordingly with the rest of the message. Should ONLY be called when + * dk->signing == DK_SIGNING_SIGN||DK_SIGNING_VERIFY + * otherwise its pointless + */ +static void +dkhash(DK *dk, const unsigned char *ptr) { #ifdef DK_DEBUG - if ((dk->signing != DK_SIGNING_SIGN)&&(dk->signing != DK_SIGNING_VERIFY)) - { - //called when we shouldnt of, this will break the sig - fprintf(stderr,"\nDKHASH() called for \'%c\' in mode: %i\n",*ptr,dk->signing); - } + if ((dk->signing != DK_SIGNING_SIGN) && (dk->signing != DK_SIGNING_VERIFY)) + { + /* called when we shouldnt of, this will break the sig*/ + fprintf(stderr, "\nDKHASH() called for \'%c\' in mode: %i\n", *ptr, dk->signing); + } #endif - if (dk->canon == DK_CANON_NOFWS && (*ptr == ' ' || *ptr == '\t')) - { - return; - } - - if ((dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_H)) - { - if (dk->canon == DK_CANON_NOFWS) - { - if (*ptr != '\r') - { - if (*ptr == '\n') - { - dk->trace->ccounts_H[10]++; - dk->trace->ccounts_H[13]++; - } - else - { - dk->trace->ccounts_H[(int) *ptr]++; - } - } - } - else - { - dk->trace->ccounts_H[(int) *ptr]++; - } - } - - if (*ptr == '\r' && ((dk->state & 1) == 0)) - { - dk->state++; - } - else if (*ptr == '\n' && ((dk->state & 1) == 1)) - { - dk->state++; - } - else - { - while (dk->state >= 2) - { - + if (dk->canon == DK_CANON_NOFWS && (*ptr == ' ' || *ptr == '\t')) + return; + if ((dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_H)) + { + if (dk->canon == DK_CANON_NOFWS) + { + if (*ptr != '\r') + { + if (*ptr == '\n') /*- printf("!added \\r\\n\n"); */ + { + dk->trace->ccounts_H[10]++; + dk->trace->ccounts_H[13]++; + } else /*- printf("!added %c\n",*ptr); */ + dk->trace->ccounts_H[(int) *ptr]++; + } + } + else /*- printf("!added %c\n",*ptr); */ + dk->trace->ccounts_H[(int) *ptr]++; + } + if (*ptr == '\r' && ((dk->state & 1) == 0)) + dk->state++; + else + if (*ptr == '\n' && ((dk->state & 1) == 1)) + dk->state++; + else + { + while (dk->state >= 2) + { #ifndef DK_HASH_BUFF - EVP_DigestUpdate(&dk->mdctx, "\r\n", 2); + EVP_DigestUpdate(evptr, "\r\n", 2); #else - /* buffer hack */ - dk->hash_buff[dk->hash_buff_len++] = '\r'; - dk->hash_buff[dk->hash_buff_len++] = '\n'; - if (dk->hash_buff_len >= (DK_BLOCK - 1)) - { - EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len); - dk->hash_buff_len = 0; - } - /* buffer hack */ + /* buffer hack */ + dk->hash_buff[dk->hash_buff_len++] = '\r'; + dk->hash_buff[dk->hash_buff_len++] = '\n'; + if (dk->hash_buff_len >= (DK_BLOCK - 1)) + { + EVP_DigestUpdate(evptr, dk->hash_buff, dk->hash_buff_len); + dk->hash_buff_len = 0; + } + /* buffer hack */ #endif - if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) - { - dk->trace->ccounts_B[10]++; - dk->trace->ccounts_B[13]++; - } + if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) + { + dk->trace->ccounts_B[10]++; + dk->trace->ccounts_B[13]++; + } #ifdef DK_DEBUG - fprintf(stderr,"\r\n"); + fprintf(stderr, "\r\n"); #endif - dk->state -= 2; - } - if (dk->state) - { - if (dk->canon == DK_CANON_SIMPLE)//if nofws we ignore \r - { + dk->state -= 2; + } + if (dk->state) + { + if (dk->canon == DK_CANON_SIMPLE) //if nofws we ignore \r + { #ifndef DK_HASH_BUFF - EVP_DigestUpdate(&dk->mdctx, "\r", 1); + EVP_DigestUpdate(evptr, "\r", 1); #else - /* buffer hack */ - dk->hash_buff[dk->hash_buff_len++] = '\r'; - if (dk->hash_buff_len >= (DK_BLOCK - 1)) - { - EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len); - dk->hash_buff_len = 0; - } - /* buffer hack */ + /* buffer hack */ + dk->hash_buff[dk->hash_buff_len++] = '\r'; + if (dk->hash_buff_len >= (DK_BLOCK - 1)) + { + EVP_DigestUpdate(evptr, dk->hash_buff, dk->hash_buff_len); + dk->hash_buff_len = 0; + } + /* buffer hack */ #endif - if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) - { - dk->trace->ccounts_B[13]++; - } + if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) + dk->trace->ccounts_B[13]++; #ifdef DK_DEBUG - fprintf(stderr,"\r"); + fprintf(stderr, "\r"); #endif - } - dk->state --; - } + } + dk->state--; + } #ifndef DK_HASH_BUFF - EVP_DigestUpdate(&dk->mdctx, ptr, 1); + EVP_DigestUpdate(evptr, ptr, 1); #else - /* buffer hack */ - dk->hash_buff[dk->hash_buff_len++] = *ptr; - if (dk->hash_buff_len >= (DK_BLOCK - 1)) - { - EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len); - dk->hash_buff_len = 0; - } - /* buffer hack */ + /* buffer hack */ + dk->hash_buff[dk->hash_buff_len++] = *ptr; + if (dk->hash_buff_len >= (DK_BLOCK - 1)) + { + EVP_DigestUpdate(evptr, dk->hash_buff, dk->hash_buff_len); + dk->hash_buff_len = 0; + } + /* buffer hack */ #endif - - if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) - { - dk->trace->ccounts_B[(int) *ptr]++; - } - + if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B)) + dk->trace->ccounts_B[(int) *ptr]++; #ifdef DK_DEBUG - fprintf(stderr,"%c", *ptr); + fprintf(stderr, "%c", *ptr); #endif - } + } } -/* process headers if there's a h=*/ -/* dk->start_signed + 1 is the offset into headers pointing at the first header after DK-Sig */ -/* Changed to fix h= handling, checks if header is listed in h= - * handles duplicate Header items properly. (see section 3.3 h= draft-02) +/* + * process headers if there's a h= + * dk->start_signed + 1 is the offset into headers pointing at the first header after DK-Sig + * Changed to fix h= handling, checks if header is listed in h= + * handles duplicate Header items properly. (see section 3.3 h= draft-02) * We don't "look" for missing headers, maybe later.... -Tim */ -static DK_STAT dkheaders_header(DK *dk) +static DK_STAT +dkheaders_header(DK *dk) { - char *header_line_start,*header_label_end; - char header_list[1024]; - char header_label[1024]; - - char *p; - //search hack redo later? -tim - if (snprintf(header_list,sizeof(header_list),":%s:",dk->headers) >= sizeof(header_list)) - { - //header list is too large for buffer - return DKERR(DK_STAT_SYNTAX); - } + char *p, *header_line_start, *header_label_end; + char *header_label; + static char *header_list; + int header_len; - /*convert to all lowercase*/ - for (p = header_list; p[0] != '\0'; ++p) - { - p[0] = tolower(p[0]); - } + /*- search hack redo later? -tim */ + if (!(header_list = DK_REALLOC(header_list, (header_len = strlen(dk->headers)) + 3))) + { + DK_MFREE(dk); + return(DKERR(DK_STAT_NORESOURCE)); + } + if (!(header_label = DK_MALLOC(header_len + 3))) + { + DK_MFREE(dk); + return(DKERR(DK_STAT_NORESOURCE)); + } + if (snprintf(header_list, header_len + 3, ":%s:", dk->headers) >= header_len + 3) + { + /*header list is too large for buffer */ + DK_MFREE(header_label); + return DKERR(DK_STAT_SYNTAX); + } + /*- convert to all lowercase */ + for (p = header_list; p[0] != '\0'; ++p) + p[0] = tolower(p[0]); + header_label[0] = ':'; + /*- first char in header_line_start is '\0' unless signing */ + header_line_start = dk->header + dk->start_signed; + if (dk->signing != DK_SIGNING_SIGN) + ++header_line_start; + while (1) { + if (header_line_start >= (dk->header + dk->headerlen)) + { + DK_MFREE(header_label); + return DKERR(DK_STAT_OK); /*- done reading headers */ + } + header_label_end = header_line_start; + p = &header_label[1]; + /*- while (p < (header_label + sizeof (header_label) - 2)) { -*/ + while (p < (header_label + header_len - 2)) { + if (header_label_end[0] != ':') { + p[0] = tolower(header_label_end[0]); + ++p; + ++header_label_end; + } else + break; + } + p[0] = ':'; + p[1] = '\0'; + /*- if the header is found in the h= list */ + if (strstr(header_list, header_label) != NULL) { + /* Found listed header, hash it in */ + while (header_line_start[0] != '\0') { + /*- we kept folded headers \r\n as markers -Tim */ + if ((header_line_start[0] == '\n') || (header_line_start[0] == '\r')) { + /* if simple we keep the folded lines */ + /* if nofws we ignore it to unwrap it */ + if (dk->canon == DK_CANON_NOFWS) { + ++header_line_start; + continue; + } + } + dkhash(dk, (unsigned char *) &header_line_start[0]); + ++header_line_start; + } + dkhash(dk, (unsigned char *) "\r"); + dkhash(dk, (unsigned char *) "\n"); + } else /*- skip hashing this header */ + { + while (header_line_start[0] != '\0') + ++header_line_start; + } + /*- goto next header */ + ++header_line_start; + } /*- while(1) */ +} - header_label[0] = ':'; - //first char in header_line_start is '\0' unless signing - header_line_start = dk->header + dk->start_signed; - if (dk->signing != DK_SIGNING_SIGN) - { - ++header_line_start; - } - while (1) - { - if (header_line_start >= (dk->header + dk->headerlen)) - { - return DKERR(DK_STAT_OK); //done reading headers - } - header_label_end = header_line_start; - p = &header_label[1]; - while (p < (header_label + sizeof(header_label) - 2)) - { - if (header_label_end[0] != ':') - { - p[0] = tolower(header_label_end[0]); - ++p; - ++header_label_end; - } - else - { - break; - } - } - p[0] = ':'; - p[1] = '\0'; - //fprintf(stderr,"searching for: %s in %s\n",header_label, header_list); - //if the header is found in the h= list - if (strstr(header_list, header_label) != NULL) - { - //Found listed header, hash it in - while(header_line_start[0] != '\0') - { - //we kept folded headers \r\n as markers -Tim - if ((header_line_start[0] == '\n')||(header_line_start[0] == '\r')) - { - //if simple we keep the folded lines - //if nofws we ignore it to unwrap it - if (dk->canon == DK_CANON_NOFWS) - { - ++header_line_start; - continue; - } - } - dkhash(dk,&header_line_start[0]); - ++header_line_start; - } - dkhash(dk, "\r"); - dkhash(dk, "\n"); - } - else //skip hashing this header - { - while(header_line_start[0] != '\0') - { - ++header_line_start; - } - } - //goto next header - ++header_line_start; - - }//end while -} -/* dkheaders - When Signing (DK_SIGNING_SIGN), Hashes in ALL headers and Greps out Sender:/From: headers - - When Verifying, reads headers until DK-Sig is found - then - If an h= tag is found, Greps out Sender:/From: headers, then calls dkheaders_header - to hash in the listed headers - If NO h= tag is present, it Greps out Sender:/From: headers as well as hashes in the - headers that follow the DK-Sig header. -*/ -static DK_STAT dkheaders(DK *dk) +/* + * When Signing (DK_SIGNING_SIGN), Hashes in ALL headers and Greps out Sender:/From: headers + * When Verifying, reads headers until DK-Sig is found + * then + * If an h= tag is found, Greps out Sender:/From: headers, then calls dkheaders_header + * to hash in the listed headers + * If NO h= tag is present, it Greps out Sender:/From: headers as well as hashes in the + * headers that follow the DK-Sig header. + */ +static DK_STAT +dkheaders(DK *dk) { - int i; + int i; - for (i = 0; i < dk->headerlen; i++) - { - if (dk->headers && dk->signing == DK_SIGNING_VERIFY) //if h= wait till after parsing - { - //NOOP - } - else if (dk->canon == DK_CANON_NOFWS && (dk->header[i] == '\r' || dk->header[i] == '\n')) - { - //NOOP - } - /* Newcode */ - else if ((dk->opts & DKOPT_RDUPE)&&(dk->signing == DK_SIGNING_SIGN)) - { - //NOOP - } - else if ((dk->signing == DK_SIGNING_SIGN)||(dk->signing == DK_SIGNING_VERIFY)) - { - //we wont bother calling dkhash unless we are signing or verifying -Tim - if (dk->header[i]) - { - dkhash(dk, dk->header + i); - } - else //terminate end of header line - { - dkhash(dk, "\r"); - dkhash(dk, "\n"); - } - } - /* Newcode end */ - - if (i==0 || dk->header[i-1] == '\0') - { - if (!strncasecmp(dk->header + i, "From:", 5)) - { - /* Remember the From: and forget the current. */ - if (dk->from) - { - /* if we already got a From: header, fuhgeddabout it. */ - return DKERR(DK_STAT_SYNTAX); - } - dk->from = dk_strdup(dk->header + i); - if (dkparse822(dk->from, 5) != DK_STAT_OK) - { - DK_MFREE(dk->from); - dk->from = 0; - return DKERR(DK_STAT_SYNTAX); - } - } - else if (!strncasecmp(dk->header + i, "Sender:", 7)) - { - if (dk->sender) - { - /* if we already got a Sender: header, fuhgeddabout it. */ - return DKERR(DK_STAT_SYNTAX); - } - if (dk->signing != DK_SIGNING_NOVERIFY) - { - /* only remember the Sender if we're verifying already. */ - dk->sender = dk_strdup(dk->header + i); - if (dkparse822(dk->sender, 7) != DK_STAT_OK) - { - DK_MFREE(dk->sender); - dk->sender = 0; - return DKERR(DK_STAT_SYNTAX); - } - } - else if (!dk->sender_beforesign) - { - dk->sender_beforesign = dk_strdup(dk->header + i); - if (dkparse822(dk->sender_beforesign, 7) != DK_STAT_OK) - { - DK_MFREE(dk->sender_beforesign); - dk->sender_beforesign = 0; - return DKERR(DK_STAT_SYNTAX); - } - } - } - else if (!strncasecmp(dk->header + i, "DomainKey-Trace:", 16)) - { - if (dk->trace && !dk->dktrace)//only set this once - { - dk->dktrace = dk->header + i; - } - } - else if (!strncasecmp(dk->header + i, "DomainKey-Signature:", 20)) - { - int thisheaderlen = strlen(dk->header + i); - - /* Do not sign email that already has a dksign unless the Sender was found first, 3.5.2 TC41, TC41-1*/ - if (dk->signing == DK_SIGNING_SIGN && !dk->sender) - { - return DKERR(DK_STAT_SYNTAX); - } - /* check the outermost (first encountered) signature (need to fix when multiple sigs are present) - * ONLY if we are verifying, if we are signing then ignore it (sender before dk-sig) -Tim - */ - if ((!dk->dksign)&&(dk->signing != DK_SIGNING_SIGN)) - { - char *values[7]; /* dsbchqa */ - dk->dksign = dk->header + i; - /* parse the dksign header .*/ - if (dkparselist(dk->dksign + 20,"dsbchqa", values) != DK_STAT_OK) - { - return DKERR(DK_STAT_SYNTAX); - } - - dk->domain = values[0]; - dk->selector = values[1]; - dk->signature = values[2]; - if (!dk->selector || !dk->domain || !dk->signature) - { - /* we really do need to have a domain, selector and key. TC21 TC40 */ - return DKERR(DK_STAT_NOSIG); - } - - if (!values[3]) - { - dk->canon = DK_CANON_SIMPLE; - } - else if (!strcasecmp(values[3], "simple")) - { - dk->canon = DK_CANON_SIMPLE; - } - else if (!strcasecmp(values[3], "nofws")) - { - dk->canon = DK_CANON_NOFWS; - } - else - { - return DKERR(DK_STAT_SYNTAX); /* TC42 */ - } - - dk->headers = values[4]; - - if (values[5] && strcasecmp(values[5], "dns")) /* TC42-2 */ - { - return DKERR(DK_STAT_SYNTAX); - } - if (values[6] && strcasecmp(values[6], "rsa-sha1")) /* TC42-3 */ - { - return DKERR(DK_STAT_SYNTAX); - } - - } - /* if we're waiting to verify, start now. */ - if (dk->signing == DK_SIGNING_NOVERIFY) - { - dk->signing = DK_SIGNING_VERIFY; /* the signature starts here */ - i += thisheaderlen; - if (dk->start_signed == 0) //we should set it only once right? - { - dk->start_signed = i; - } - } - } - //end trace - } - } - if ((!dk->from)||(!dk_from(dk))) - { - /* No From:, 3.1 says that it's no good.. TC11/TC16 */ - return DKERR(DK_STAT_SYNTAX); - } - if (dk->signing == DK_SIGNING_NOVERIFY) - { - /* No DK-Sig: should return No Signature. */ - return DKERR(DK_STAT_NOSIG); - } - if (dk->headers && dk->signing == DK_SIGNING_VERIFY) - { - return dkheaders_header(dk); - } - if ((dk->signing == DK_SIGNING_SIGN)&&(dk->opts & DKOPT_RDUPE)) //remove dupe headers for sig - { - DK_STAT ret; - dk->headers = DK_MALLOC(dk->headermax); - (void *)dk_headers(dk, dk->headers); - ret = dkheaders_header(dk); - DK_MFREE(dk->headers); - return ret; - } - return DKERR(DK_STAT_OK); + for (i = 0; i < dk->headerlen; i++) { + if (dk->headers && dk->signing == DK_SIGNING_VERIFY) //if h= wait till after parsing + { + /*- NOOP */ + } else + if (dk->canon == DK_CANON_NOFWS && (dk->header[i] == '\r' || dk->header[i] == '\n')) + { + /*- NOOP */ + } else /*- Newcode */ + if ((dk->opts & DKOPT_RDUPE) && (dk->signing == DK_SIGNING_SIGN)) + { + /*- NOOP */ + } else + if ((dk->opts & DKOPT_SELHEAD) && (dk->signing == DK_SIGNING_SIGN)) + { + /*- NOOP */ + } else + if ((dk->signing == DK_SIGNING_SIGN) || (dk->signing == DK_SIGNING_VERIFY)) { + /*- we wont bother calling dkhash unless we are signing or verifying -Tim */ + if (dk->header[i]) + dkhash(dk, (const unsigned char *) dk->header + i); + else /*- terminate end of header line */ + { + dkhash(dk, (const unsigned char *) "\r"); + dkhash(dk, (const unsigned char *) "\n"); + } + } + /*- Newcode end */ + if (i == 0 || dk->header[i - 1] == '\0') { + if (!strncasecmp(dk->header + i, "From:", 5)) { + /* + * Remember the From: and forget the current. + */ + if (dk->from) { + /* + * if we already got a From: header, fuhgeddabout it. + */ + return DKERR(DK_STAT_SYNTAX); + } + dk->from = dk_strdup(dk->header + i); + if (dkparse822(dk->from, 5) != DK_STAT_OK) { + DK_MFREE(dk->from); + dk->from = 0; + return DKERR(DK_STAT_SYNTAX); + } + } else + if (!strncasecmp(dk->header + i, "Sender:", 7)) { + if (dk->sender) { + /* + * if we already got a Sender: header, fuhgeddabout it. + */ + return DKERR(DK_STAT_SYNTAX); + } + if (dk->signing != DK_SIGNING_NOVERIFY) { + /* + * only remember the Sender if we're verifying already. + */ + dk->sender = dk_strdup(dk->header + i); + if (dkparse822(dk->sender, 7) != DK_STAT_OK) { + DK_MFREE(dk->sender); + dk->sender = 0; + return DKERR(DK_STAT_SYNTAX); + } + } else + if (!dk->sender_beforesign) { + dk->sender_beforesign = dk_strdup(dk->header + i); + if (dkparse822(dk->sender_beforesign, 7) != DK_STAT_OK) { + DK_MFREE(dk->sender_beforesign); + dk->sender_beforesign = 0; + return DKERR(DK_STAT_SYNTAX); + } + } + } else + if (!strncasecmp(dk->header + i, "DomainKey-Trace:", 16)) { + if (dk->trace && !dk->dktrace) //only set this once + dk->dktrace = dk->header + i; + } else + if (!strncasecmp(dk->header + i, "DomainKey-Signature:", 20)) { + int thisheaderlen = strlen(dk->header + i); + + /* + * Do not sign email that already has a dksign unless the + * Sender was found first, 3.5.2 TC41, TC41-1 + */ + if (dk->signing == DK_SIGNING_SIGN && !dk->sender) + return DKERR(DK_STAT_DUPLICATE); + /* + * check the outermost (first encountered) signature + * (need to fix when multiple sigs are present) + * ONLY if we are verifying, if we are signing then ignore it + * (sender before dk-sig) -Tim + */ + if (!dk->dksign && dk->signing != DK_SIGNING_SIGN) { + char *values[7]; /* dsbchqa */ + dk->dksign = dk->header + i; + /*- parse the dksign header . */ + if (dkparselist(dk->dksign + 20, "dsbchqa", values) != DK_STAT_OK) + return DKERR(DK_STAT_SYNTAX); + dk->domain = values[0]; + dk->selector = values[1]; + dk->signature = values[2]; + if (!dk->selector || !dk->domain || !dk->signature) + /* + * we really do need to have a domain, selector and key. TC21 TC40 + */ + return DKERR(DK_STAT_NOSIG); + if (!values[3]) + dk->canon = DK_CANON_SIMPLE; + else + if (!strcasecmp(values[3], "simple")) + dk->canon = DK_CANON_SIMPLE; + else + if (!strcasecmp(values[3], "nofws")) + dk->canon = DK_CANON_NOFWS; + else + return DKERR(DK_STAT_SYNTAX); /* TC42 */ + dk->headers = values[4]; + if (values[5] && strcasecmp(values[5], "dns")) /* TC42-2 */ + return DKERR(DK_STAT_SYNTAX); + if (values[6] && strcasecmp(values[6], "rsa-sha1")) /* TC42-3 */ + return DKERR(DK_STAT_SYNTAX); + } + /* + * if we're waiting to verify, start now. + */ + if (dk->signing == DK_SIGNING_NOVERIFY) { + dk->signing = DK_SIGNING_VERIFY; /* the signature starts here */ + i += thisheaderlen; + if (dk->start_signed == 0) //we should set it only once right? + dk->start_signed = i; + } + } /* end trace */ + } + } + if (!dk->from || !dk_from(dk)) /*- No From:, 3.1 says that it's no good.. TC11/TC16 */ + return DKERR(DK_STAT_SYNTAX); + if (dk->signing == DK_SIGNING_NOVERIFY) /*- No DK-Sig: should return No Signature. */ + return DKERR(DK_STAT_NOSIG); + if (dk->headers && dk->signing == DK_SIGNING_VERIFY) + return dkheaders_header(dk); + if (dk->signing == DK_SIGNING_SIGN && + ((dk->opts & DKOPT_RDUPE) || (dk->opts & DKOPT_SELHEAD))) + { /*- remove dupe headers for sig */ + DK_STAT ret; + dk->headers = DK_MALLOC(dk->headermax); + dk_headers(dk, dk->headers); + ret = dkheaders_header(dk); + DK_MFREE(dk->headers); + return ret; + } + return DKERR(DK_STAT_OK); } /* HEADER */ -/* Copies the header names that were signed into the pointer. +/* + * Copies the header names that were signed into the pointer. * Returns the number of bytes copied. * ptr may be NULL, in which case the bytes are just counted, not copied. * Feel free to call this twice; once to get the length, and again to * copy the data. + * If we preserve duplicate headers, actually return something (len) + * If we remove duplicate headers, len may be innacurate (greater than what's + * really needed when calling with ptr == NULL * NOTE: If the return value is 0 then an error occured. - * It's a good idea to check for this + * It's a good idea to check for this */ -int dk_headers(DK *dk, char *ptr) +int +dk_headers(DK *dk, char *ptr) { - register int len = 0; - register int label_len = 0; - int list_size; - char *header_start = NULL; - char *header_end = NULL; - char *h_label = NULL; - char *h_list = NULL; - - char *dupe_list = NULL; - - - if (ptr) //if you dont check if return is 0, ptr can be anything - ptr[0] = 0; - - if ((!dk)||(dk->dkmarker != DKMARK)) - { - return 0; - } - list_size = dk->headermax; - - h_list = (char *) DK_MALLOC(list_size); - if (!h_list) - return 0; - memset(h_list,0,list_size); - h_list[len++] = ':'; - - header_start = dk->header + dk->start_signed; - - for (header_end = header_start; header_end < (dk->header + dk->headerlen); header_end++) - { - if (*header_end == '\0') - { - header_start = header_end+1;//point to start of next line - } - else if (*header_end == ':' && header_start) - { - label_len = (header_end - header_start) + 1; - //grow list array - if ((len+label_len) >= list_size) - { - char *temp = NULL; - list_size += dk->headermax; - temp = DK_MALLOC(list_size); - if (!temp) - { - len = 1; //out of memory? - goto END; - } - memset(temp,0,list_size); - memcpy(temp,h_list,len); - DK_MFREE(h_list); - h_list = temp; - } - - memcpy(h_list + len, header_start, label_len); - len += label_len; - header_start = NULL; - } - } + int len; + int k, m; - if (dk->opts & DKOPT_RDUPE) - { - - h_label = (char *) DK_MALLOC(list_size); - dupe_list = (char *) DK_MALLOC(list_size); - - if (!h_label || !dupe_list) - { - len = 1; - goto END; + if (!dk) + return 0; + if (dk->dkmarker != DKMARK) + return 0; + len = 0; + m = dk->start_signed; + for (k = dk->start_signed; k < dk->headerlen; k++) { + if (dk->header[k] == '\0') + m = k + 1; + else + if (dk->header[k] == ':' && m >= 0) { + if (ptr) { + memcpy(ptr + len, dk->header + m, k - m + 1); + } + len += k - m + 1; + m = -1; + } } - memset(h_label,0,list_size); - memset(dupe_list,0,list_size); - - len = 0; - header_start = h_list; - for (header_end = header_start + 1; *header_end != '\0'; header_end++) - { - if (*header_end == ':') - { - label_len = (header_end - header_start)+1; - memcpy(h_label, header_start, label_len); - h_label[label_len] = 0; - if ((strstr(h_list,h_label) == header_start) && (strstr(header_start + 1,h_label) == NULL) ) - { - memcpy(dupe_list + len ,h_label,label_len); - len += label_len -1; + if ((dk->opts & DKOPT_RDUPE) && (ptr)){ + int headpos = 0; + char *copy = (char *) DK_MALLOC(len + 2); + + copy[0] = ':'; + memcpy(copy + 1, ptr, len - 1); + copy[len] = ':'; + copy[len + 1] = 0; + ptr[0] = 0; + m = 0; + + for (k = 1; k < len + 2; k++) { + if (copy[k] == ':') { + int found = 0; + int sub; + for (sub = 0; sub < len + 2; sub++) { + if ((copy[sub] == ':') && (sub != m)) { + if (!strncmp(copy + sub, copy + m, k - m)) { + found = 1; + break; + } + } + } + if (!found) { + memcpy(ptr + headpos, copy + m + 1, k - m); + headpos += k - m; + ptr[headpos] = 0; + } + m = k; } - header_start = header_end; } + DK_MFREE(copy); + len = headpos; } - len++; - if (ptr) - memcpy(h_list, dupe_list, len); - } - - if ((ptr != NULL)&&(len > 1)) - { - memcpy(ptr,h_list+1,(len-2));//dont count the prefix and postfix'd ":" - ptr[len-2] = 0; - } - END: - if (h_label) - DK_MFREE(h_label); - if (h_list) - DK_MFREE(h_list); - if (dupe_list) - DK_MFREE(dupe_list); - - return --len; + if ((dk->opts & DKOPT_SELHEAD) && (ptr)) { + int headpos = 0; + char *copy = (char *) DK_MALLOC(len + 2); + + copy[0] = ':'; + memcpy(copy + 1, ptr, len - 1); + copy[len] = ':'; + copy[len + 1] = 0; + ptr[0] = 0; + m = 0; + for (k = 1; k < len + 2; k++) { + if (copy[k] == ':') { + int found = 0; + int n = 0, s; + int len_s = strlen(dk->sel_headers); + for (s = 1; s < len_s; s++) { + if (dk->sel_headers[s] == ':') { + if (s - n == k - m) { + if (!strncasecmp(copy + m + 1, dk->sel_headers + n + 1, k - m)) { + found = 1; + break; + } + } + n = s; + } + } + if (found) { + memcpy(ptr + headpos, copy + m + 1, k - m); + headpos += k - m; + ptr[headpos] = 0; + } + m = k; + } + } + len = headpos; + DK_MFREE(copy); + } + if (len && ptr) { + ptr[len - 1] = '\0'; /* change the last colon into a null. */ + } + return len; /*- return size including '\0' */ +} +/* HEADER */ +/* + * Returns a pointer to a null-terminated string containing the granularity + * value found in the selector DNS record, if any, but only after dk_end + * has been called. Otherwise returns NULL. + */ +char * +dk_granularity(DK *dk) +{ + if (!dk) + return NULL; + if (dk->dkmarker != DKMARK) + return NULL; + return dk->granularity; } /* HEADER */ -/* Must NOT include dots inserted for SMTP encapsulation. +/* + * Must NOT include dots inserted for SMTP encapsulation. * Must NOT include CRLF.CRLF which terminates the message. * Otherwise must be exactly that which is sent or received over the SMTP session. * May be called multiple times (not necessary to read an entire message into memory). */ -DK_STAT dk_message(DK *dk, const unsigned char *ptr, size_t len) +DK_STAT +dk_message(DK *dk, const unsigned char *ptr, size_t len) { - DK_STAT st; - int tb=0,th=0; - if (!dk) - { - return DK_STAT_ARGS; - } - if (dk->dkmarker != DKMARK) - { - return DK_STAT_ARGS; - } - if (len && !ptr) - { - return DKERR(DK_STAT_ARGS); - } - if (dk->trace && (dk->opts & DKOPT_TRACE_b)) - tb = 1; - if (dk->trace && (dk->opts & DKOPT_TRACE_h)) - th = 1; + DK_STAT st; + int tb = 0, th = 0; - while (len--) - { - if ((*ptr == '\n') && (dk->last_char != '\r')) - { - //input not formatted correctly - //CR should preceed LF - return DKERR(DK_STAT_SYNTAX); - } - /* parse headers */ - if (!dk->in_headers) - { - dkhash(dk, ptr); //hash body of message - //precanon probably wont be accurate as dk_message() only takes in SMTP format -Tim - if (tb) - dk->trace->ccounts_b[(int) *ptr]++; - } - else if (*ptr == '\n' && dk->headerlinelen != 0) - { - /* beginning a new line, but we can't do anything until we get a char. */ - dk->headerlinelen = 0; - } - else if (*ptr == '\r') - { - /* ignore carriage-returns, even bare ones. We'll add them back in later.*/ - if (dk->last_char == '\r') //keep embedded CR - { - if (dkstore_char(dk, '\r') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - dk->trace->ccounts_h[13]++; - } - } - else if (dk->headerlinelen) - { - - if (dk->last_char == '\r') //keep embedded CR - { - if (dkstore_char(dk, '\r') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - dk->trace->ccounts_h[13]++; - } - - /* if we're not starting a new header, just store it */ - if (dkstore_char(dk, *ptr) != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - dk->trace->ccounts_h[(int) *ptr]++; - } - else if (*ptr == ' ' || *ptr == '\t') - { - /* a new header ... starting with whitespace. Must be continuation */ - /* just remember the whitespace */ - //preserv folded headers for simple canon -Tim - if (dkstore_char(dk, '\r') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (dkstore_char(dk, '\n') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (dkstore_char(dk, *ptr) != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - { - dk->trace->ccounts_h[10]++; - dk->trace->ccounts_h[13]++; - dk->trace->ccounts_h[(int) *ptr]++; - } - - } - else if (*ptr == '\n') - { - /* an empty line terminates header processing */ - /* terminate the previous header */ - if (dkstore_char(dk, '\0') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - { - dk->trace->ccounts_h[10]++; - dk->trace->ccounts_h[13]++; - } - if (tb) - { - dk->trace->ccounts_b[10]++; - dk->trace->ccounts_b[13]++; - } - st = dkheaders(dk); - dk->in_headers = 0; - dkhash(dk, "\r"); - dkhash(dk, "\n"); - - if (st != DK_STAT_OK) - { - return st; - } - } - else - { - /* we're starting a new header. Terminate the previous one. */ - if (dkstore_char(dk, '\0') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - /* remember the first character of a new header. */ - if (dkstore_char(dk, *ptr) != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - if (th) - { - dk->trace->ccounts_h[10]++; - dk->trace->ccounts_h[13]++; - dk->trace->ccounts_h[(int) *ptr]++; - } - } - dk->last_char = *ptr; //remember last character processed - ptr++; - } - return DKERR(DK_STAT_OK); + if (!dk) + return DK_STAT_ARGS; + if (dk->dkmarker != DKMARK) + return DK_STAT_ARGS; + if (len && !ptr) + return DKERR(DK_STAT_ARGS); + if (dk->trace && (dk->opts & DKOPT_TRACE_b)) + tb = 1; + if (dk->trace && (dk->opts & DKOPT_TRACE_h)) + th = 1; + while (len--) { + if ((*ptr == '\n') && (dk->last_char != '\r')) + { + /* + * input not formatted correctly + * CR should preceed LF + */ + return DKERR(DK_STAT_SYNTAX); + } + /*- parse headers */ + if (!dk->in_headers) { + dkhash(dk, ptr); //hash body of message + /* + * precanon probably wont be accurate as dk_message() + * only takes in SMTP format -Tim + */ + if (tb) + dk->trace->ccounts_b[(int) *ptr]++; + } else + if (*ptr == '\n' && dk->headerlinelen != 0) { + /* + * beginning a new line, but we can't do anything until we get a char. + */ + dk->headerlinelen = 0; + } else + if (*ptr == '\r') { + /* + * ignore carriage-returns, even bare ones. We'll add them back in later. + */ + if (dk->last_char == '\r') //keep embedded CR + { + if (dkstore_char(dk, '\r') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + dk->trace->ccounts_h[13]++; + } + } else + if (dk->headerlinelen) { + if (dk->last_char == '\r') //keep embedded CR + { + if (dkstore_char(dk, '\r') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + dk->trace->ccounts_h[13]++; + } + /* + * if we're not starting a new header, just store it + */ + if (dkstore_char(dk, *ptr) != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + dk->trace->ccounts_h[(int) *ptr]++; + } else + if (*ptr == ' ' || *ptr == '\t') { + /* + * a new header ... starting with whitespace. Must be continuation + * just remember the whitespace + * preserv folded headers for simple canon -Tim + */ + if (dkstore_char(dk, '\r') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (dkstore_char(dk, '\n') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (dkstore_char(dk, *ptr) != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + { + dk->trace->ccounts_h[10]++; + dk->trace->ccounts_h[13]++; + dk->trace->ccounts_h[(int) *ptr]++; + } + } else + if (*ptr == '\n') { + /* + * an empty line terminates header processing + * terminate the previous header + */ + if (dkstore_char(dk, '\0') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + { + dk->trace->ccounts_h[10]++; + dk->trace->ccounts_h[13]++; + } + if (tb) + { + dk->trace->ccounts_b[10]++; + dk->trace->ccounts_b[13]++; + } + st = dkheaders(dk); + dk->in_headers = 0; + dkhash(dk, (const unsigned char *) "\r"); + dkhash(dk, (const unsigned char *) "\n"); + if (st != DK_STAT_OK) + return st; + } else { + /* + * we're starting a new header. Terminate the previous one. + */ + if (dkstore_char(dk, '\0') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + /* + * remember the first character of a new header. + */ + if (dkstore_char(dk, *ptr) != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + if (th) + { + dk->trace->ccounts_h[10]++; + dk->trace->ccounts_h[13]++; + dk->trace->ccounts_h[(int) *ptr]++; + } + } + dk->last_char = *ptr; //remember last character processed + ptr++; + } + return DKERR(DK_STAT_OK); } - /* HEADER */ -/* DEPRECATED in favor of calling dk_address(). +/* + * DEPRECATED in favor of calling dk_address(). * Returns a pointer to a null-terminated domain name portion of an RFC 2822 address. * If a Sender: was encountered, it returns that domain. Otherwise, * if a From: was encountered, it returns that domain. Otherwise, @@ -1584,65 +1550,48 @@ * return NULL if the dk is unusable for any reason. * return NULL if the address is unusable for any reason. */ -char *dk_from(DK *dk) +char * +dk_from(DK *dk) { - char *s; + char *s, *ptr; + int i; - if (!dk) - { - return NULL; - } - if (dk->dkmarker != DKMARK) - { - return NULL; - } - - s = NULL; - if (dk->sender) - { - s = dk->sender; /* TC14-1 */ - } - else if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY)) - { - s = dk->sender_beforesign; - } - else if (dk->from) - { - s = dk->from; /* TC14-2 */ - } - if (s && *s && s[1] && s[1] != '@') - { - s = strchr(s, '@') + 1; - if (*s == '\0') - { - //make sure we have an actual domain after @ - s = NULL; - } - } - else - { - s = NULL; - } - return s; + if (!dk) + return NULL; + if (dk->dkmarker != DKMARK) + return NULL; + s = NULL; + if (dk->sender) + s = dk->sender; /*- TC14-1 */ + else + if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY)) + s = dk->sender_beforesign; + else + if (dk->from) + s = dk->from; /*- TC14-2 */ + if (s && *s && s[1] && s[1] != '@') + { + ptr = strchr(s, '@'); + if (*ptr++) + s = ptr; + else + s = NULL; + } else + s = NULL; + return s; } /* HEADER */ -/* Returns a pointer to the selector name used or NULL if there isn't one +/* + * Returns a pointer to the selector name used or NULL if there isn't one * Added by rjp */ -const char *dk_selector(DK *dk) +const char * +dk_selector(DK *dk) { - if (!dk) return NULL; - return (dk->selector); -} - -/* HEADER */ -/* Returns a pointer to the domain name used or NULL if there isn't one - */ -const char *dk_domain(DK *dk) -{ - if (!dk) return NULL; - return (dk->domain); + if (!dk) + return NULL; + return (dk->selector); } /* HEADER */ @@ -1654,40 +1603,18 @@ * "S" if the address came from the Sender: field, and "F" if the * address came from the From: field. */ -char *dk_address(DK *dk) -{ - if ((!dk)||(dk->dkmarker != DKMARK)) - { - return "N"; - } - if (dk->sender) - { - return dk->sender; /* TC14-3 */ - } - if (dk->from) - { - return dk->from; /* TC14-4 */ - } - return "N"; /* TC14-5 */ -} - -/* HEADER */ -/* - * Returns a pointer to a null-terminated string containing the granularity - * value found in the selector DNS record, if any, but only after dk_end - * has been called. Otherwise returns NULL. - */ -char *dk_granularity(DK *dk) +char * +dk_address(DK *dk) { - if (!dk) - { - return NULL; - } - if (dk->dkmarker != DKMARK) - { - return NULL; - } - return dk->granularity; + if (!dk || dk->dkmarker != DKMARK) + return "N"; + if (dk->sender) + return dk->sender; /*- TC14-3 */ + if (dk->sender_beforesign && dk->signing == DK_SIGNING_NOVERIFY) + return dk->sender_beforesign; + if (dk->from) + return dk->from; /*- TC14-4 */ + return "N"; /*- TC14-5 */ } /* HEADER */ @@ -1711,306 +1638,256 @@ * DK_STAT_BADKEY * DK_STAT_CANTVERIFY */ -DK_STAT dk_end(DK *dk, DK_FLAGS *dkf) +DK_STAT +dk_end(DK *dk, DK_FLAGS *dkf) { - if ((!dk)||(dk->dkmarker != DKMARK)) - { - return DK_STAT_ARGS; - } - - /* yes, the only way we can still be in the headers at the end of - the message is if they supplied us with a message that not only - has no body, but also lacks the blank line terminating the - headers. Still, we have to handle it correctly. TC13-nobody */ - if (dk->in_headers) - { - DK_STAT st; - - if (dkstore_char(dk, '\0') != DK_STAT_OK) - { - return DKERR(DK_STAT_NORESOURCE); - } - st = dkheaders(dk); - if (st != DK_STAT_OK) - { - return st; - } - } + if ((!dk) || (dk->dkmarker != DKMARK)) + return DK_STAT_ARGS; - switch (dk->signing) - { - case DK_SIGNING_SIGN: - case DK_SIGNING_VERIFY: - //force hash final CRLF to terminate email + /* + * yes, the only way we can still be in the headers at the end of + * the message is if they supplied us with a message that not only + * has no body, but also lacks the blank line terminating the + * headers. Still, we have to handle it correctly. TC13-nobody + */ + if (dk->in_headers) { + DK_STAT st; + + if (dkstore_char(dk, '\0') != DK_STAT_OK) + return DKERR(DK_STAT_NORESOURCE); + st = dkheaders(dk); + if (st != DK_STAT_OK) + return st; + } + switch (dk->signing) { + case DK_SIGNING_SIGN: + case DK_SIGNING_VERIFY: + /*- force hash final CRLF to terminate email */ #ifdef DK_HASH_BUFF - //clean out hash buffer - dk->hash_buff[dk->hash_buff_len++] = '\r'; - dk->hash_buff[dk->hash_buff_len++] = '\n'; - EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len); - dk->hash_buff_len = 0; + //clean out hash buffer + dk->hash_buff[dk->hash_buff_len++] = '\r'; + dk->hash_buff[dk->hash_buff_len++] = '\n'; + EVP_DigestUpdate(evptr, dk->hash_buff, dk->hash_buff_len); + dk->hash_buff_len = 0; #else - EVP_DigestUpdate(&dk->mdctx, "\r\n", 2); + EVP_DigestUpdate(evptr, "\r\n", 2); + /* + if (dk->trace) + dkt_add(dk->trace, DKT_CANON_BODY, "\r\n", 2); + */ #endif #ifdef DK_DEBUG - fprintf(stderr,"\r\n"); + fprintf(stderr, "\r\n"); #endif - - } - - switch (dk->signing) - { - case DK_SIGNING_SIGN: - case DK_SIGNING_NOSIGN: - if (!dk->from) - { - return DKERR(DK_STAT_SYNTAX); - } - return DKERR(DK_STAT_OK); - case DK_SIGNING_VERIFY: - case DK_SIGNING_NOVERIFY: - { - unsigned char md_value[1024]; - int md_len=0; - char *s = NULL; //pointer to domain portion of email addy - char *sndr = NULL; - char *domainkeys; /* malloc'ed */ - char *txtrec; /* malloc'ed */ - char *pubkeyvals[4]; - int i; - DK_STAT st; - - BIO *bio, *b64; - EVP_PKEY *publickey; - - /* make sure that we got a header */ - if (!dk->dksign) - { - return DKERR(DK_STAT_NOSIG); /* TC11 */ - } - - /* make sure that domain on the From: matches the d data. TC26 */ - /* Or is a subdomain of the d data. TC26-1, etc. */ - if (dk->sender) - { - sndr = dk->sender; - } - else if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY)) - { - sndr = dk->sender_beforesign; - } - else - { - sndr = dk->from; - } - - if (!sndr) - { - return DKERR(DK_STAT_SYNTAX); - } - /* we already know that sndr has an '@' in it; otherwise it would not - * have passed dkparse822. */ - - /* sndr can also be a one-character string if the from/sender header - * was there but empty */ - if (!(s = strchr(sndr, '@'))) - { - return DKERR(DK_STAT_SYNTAX); - } - s++; // we skip the tag - - i = (int)strlen(s); - if (strcasecmp(dk->domain, s)) - { - for (; md_len < i; md_len++) - { - if (s[md_len] == '.') - { - if (!strcasecmp(dk->domain, s + md_len + 1)) - { - break; - } - } - } - } - if (md_len == i) - { - return DKERR(DK_STAT_SYNTAX); - } - - /* convert their signature from base64 into binary */ - bio = BIO_new_mem_buf(dk->signature, -1); - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - BIO_push(b64, bio); - md_len = BIO_read(b64, md_value, sizeof(md_value)); - BIO_free_all(b64); - if (md_len >= sizeof(md_value)) - { - return DKERR(DK_STAT_NORESOURCE); - } - - /* allow user to supply the DNS TXT key record */ - if (!dk->keyrec ) - { - /* get the s data and the d data and lookup s._domainkey.d */ - domainkeys = DK_MALLOC(strlen(dk->selector) + strlen(dk->domain) + strlen("._domainkey.") + 1); - if (!domainkeys) - { - return DKERR(DK_STAT_NORESOURCE); - } - sprintf(domainkeys, "%s._domainkey.%s", dk->selector, dk->domain); - txtrec = dns_text(domainkeys); - DK_MFREE(domainkeys); - } - else - { - txtrec = dk_strdup(dk->keyrec); - } - - if (!strcmp(txtrec,"e=perm;")) /* TC31 */ - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_NOKEY); - } - - if (!strcmp(txtrec,"e=temp;")) /* TC30 */ - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_CANTVRFY); - } - - if (dkparselist(txtrec, "ptog", pubkeyvals) != DK_STAT_OK) - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_BADKEY); - } - if (dkf) //set this asap - { - /* TC35 and TC37 */ - if (pubkeyvals[1] && *pubkeyvals[1] == 'y') - { - *dkf |= DK_FLAG_TESTING; - } - /* tell them that we got the g= flag. This means that the entire - * address matches, not just the domain name */ - if (pubkeyvals[3] && *pubkeyvals[3]) - { - *dkf |= DK_FLAG_G; - } - *dkf |= DK_FLAG_SET; - } - /* Store the granularity, if any, and check it against the local part - * of the sending address */ - - if (pubkeyvals[3] && *pubkeyvals[3]) - { - dk->granularity = dk_strdup(pubkeyvals[3]); - // Note that sndr has a leading 'F' or 'S' - if (strncasecmp(dk->granularity, sndr+1, strcspn(sndr+1,"@"))) - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_GRANULARITY); - } - } - if (!pubkeyvals[0]) - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_NOKEY); /* TC27 */ - } - - if (!*pubkeyvals[0]) - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_REVOKED); /* TC27 */ - } - - /* convert their public key from base64 into binary */ - bio = BIO_new_mem_buf(pubkeyvals[0], -1); - if (!bio) - { - DK_MFREE(txtrec); - return DKERR(DK_STAT_NORESOURCE); - } - b64 = BIO_new(BIO_f_base64()); - if (!b64) - { - DK_MFREE(txtrec); - BIO_free(bio); - return DKERR(DK_STAT_NORESOURCE); - } - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - BIO_push(b64, bio); - publickey = d2i_PUBKEY_bio(b64, NULL); - BIO_free_all(b64); - DK_MFREE(txtrec); - if (!publickey) - { - return DKERR(DK_STAT_BADKEY); - } - - /* using that key, verify that the digest is properly signed */ - i = EVP_VerifyFinal(&dk->mdctx, md_value, md_len, publickey); - - if (i > 0) - { - st = DK_STAT_OK; - } - else - { - st = DK_STAT_BADSIG; - } - EVP_PKEY_free(publickey); - return DKERR(st); - } - }//End switch - return DK_STAT_ARGS; + } + switch (dk->signing) + { + case DK_SIGNING_SIGN: + case DK_SIGNING_NOSIGN: + if (!dk->from) + return DKERR(DK_STAT_SYNTAX); + return DKERR(DK_STAT_OK); + case DK_SIGNING_VERIFY: + case DK_SIGNING_NOVERIFY: + { + unsigned char md_value[1024]; + int md_len = 0; + char *s = NULL; //pointer to domain portion of email addy + char *ptr; + char *sndr = NULL; + char *domainkeys; /* malloc'ed */ + char *txtrec; /* malloc'ed */ + char *pubkeyvals[4]; + int i; + DK_STAT st; + BIO *bio, *b64; + EVP_PKEY *publickey; + + /* + * make sure that we got a header + */ + if (!dk->dksign) + return DKERR(DK_STAT_NOSIG); /* TC11 */ + /* + * make sure that domain on the From: matches the d data. TC26 + * Or is a subdomain of the d data. TC26-1, etc. + */ + if (dk->sender) + sndr = dk->sender; + else + if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY)) + sndr = dk->sender_beforesign; + else + sndr = dk->from; + if (!sndr) + return DKERR(DK_STAT_SYNTAX); + /* + * we already know that sndr has an '@' in it; otherwise it would not + * have passed dkparse822. + */ + ptr = strchr(sndr, '@'); + if (*ptr++) + s = ptr; /*- we skip the tag */ + else + return DKERR(DK_STAT_SYNTAX); + i = (int) strlen(s); + if (strcasecmp(dk->domain, s)) + { + for (; md_len < i; md_len++) + { + if (s[md_len] == '.' && !strcasecmp(dk->domain, s + md_len + 1)) + break; + } + } + if (md_len == i) + return DKERR(DK_STAT_SYNTAX); + /* + * convert their signature from base64 into binary + */ + bio = BIO_new_mem_buf(dk->signature, -1); + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO_push(b64, bio); + md_len = BIO_read(b64, md_value, sizeof (md_value)); + BIO_free_all(b64); + if (md_len >= sizeof (md_value)) + return DKERR(DK_STAT_NORESOURCE); + /* allow user to supply the DNS TXT key record */ + if (!dk->keyrec) + { + /* + * get the s data and the d data and lookup s._domainkey.d + */ + if (!(domainkeys = DK_MALLOC(strlen(dk->selector) + strlen(dk->domain) + + strlen("._domainkey.") + 1))) + return DKERR(DK_STAT_NORESOURCE); + sprintf(domainkeys, "%s._domainkey.%s", dk->selector, dk->domain); + txtrec = dns_text(domainkeys); + DK_MFREE(domainkeys); + } else + txtrec = dk_strdup(dk->keyrec); + if (!strcmp(txtrec, "e=perm;")) { /* TC31 */ + DK_MFREE(txtrec); + return DKERR(DK_STAT_NOKEY); + } + if (!strcmp(txtrec, "e=temp;")) { /* TC30 */ + DK_MFREE(txtrec); + return DKERR(DK_STAT_CANTVRFY); + } + if (dkparselist(txtrec, "ptog", pubkeyvals) != DK_STAT_OK) { + DK_MFREE(txtrec); + return DKERR(DK_STAT_BADKEY); + } + if (dkf) { + /* + * TC35 and TC37 + */ + if (pubkeyvals[1] && *pubkeyvals[1] == 'y') + *dkf |= DK_FLAG_TESTING; + /* + * tell them that we got the g= flag. This means that the entire + * address matches, not just the domain name + */ + if (pubkeyvals[3] && *pubkeyvals[3]) + *dkf |= DK_FLAG_G; + *dkf |= DK_FLAG_SET; + } + /* + * Store the granularity, if any, and check it against the local part + * of the sending address + */ + if (pubkeyvals[3] && *pubkeyvals[3]) + { + dk->granularity = dk_strdup(pubkeyvals[3]); + /* Note that sndr has a leading 'F' or 'S' */ + if (strncasecmp(dk->granularity, sndr+1, strcspn(sndr+1,"@"))) + { + DK_MFREE(txtrec); + return DKERR(DK_STAT_GRANULARITY); + } + } + if (!pubkeyvals[0]) + { + DK_MFREE(txtrec); + return DKERR(DK_STAT_NOKEY); /* TC27 */ + } + if (!*pubkeyvals[0]) + { + DK_MFREE(txtrec); + return DKERR(DK_STAT_REVOKED); /* TC27 */ + } + /* + * convert their public key from base64 into binary + */ + if (!(bio = BIO_new_mem_buf(pubkeyvals[0], -1))) { + DK_MFREE(txtrec); + return DKERR(DK_STAT_NORESOURCE); + } + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + DK_MFREE(txtrec); + BIO_free(bio); + return DKERR(DK_STAT_NORESOURCE); + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO_push(b64, bio); + publickey = d2i_PUBKEY_bio(b64, NULL); + BIO_free_all(b64); + DK_MFREE(txtrec); + if (!publickey) + return DKERR(DK_STAT_BADKEY); + /* + * using that key, verify that the digest is properly signed + */ + if ((i = EVP_VerifyFinal(evptr, md_value, md_len, publickey)) > 0) + st = DK_STAT_OK; + else + st = DK_STAT_BADSIG; + EVP_PKEY_free(publickey); + return DKERR(st); + } + } /*- switch (dk->signing) */ + return DK_STAT_ARGS; } - - /* HEADER */ /* * DEPRECATED in favor of calling dk_end and dk_policy() directly. * If you pass in NULL for dkf, the policy flags will not be fetched. * If the message verified okay, the policy flags will not be fetched. */ -DK_STAT dk_eom(DK *dk, DK_FLAGS *dkf) +DK_STAT +dk_eom(DK *dk, DK_FLAGS *dkf) { - DK_STAT dkstat; + DK_STAT dkstat; - dkstat = dk_end(dk, dkf); /* TC36* */ - if (dkf && dkstat != DK_STAT_OK) - { - *dkf |= dk_policy(dk); - } - return dkstat; + dkstat = dk_end(dk, dkf); /*- TC36 */ + if (dkf && dkstat != DK_STAT_OK) + *dkf |= dk_policy(dk); + return dkstat; } - /* HEADER */ /* - * + * * privatekey is the private key used to create the signature; It should contain * the entire contents of a PEM-format private key file, thusly it will begin with * -----BEGIN RSA PRIVATE KEY-----. It should be null-terminated. */ -size_t dk_siglen(void *privatekey) +size_t +dk_siglen(void *privatekey) { - BIO *bio; - EVP_PKEY *pkey; - size_t len; - - if (!privatekey) - { - return 0; - } - - bio = BIO_new_mem_buf(privatekey, -1); - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - BIO_free(bio); - - len = (EVP_PKEY_size(pkey) + 2) / 3 * 4; - EVP_PKEY_free(pkey); - return len; + BIO *bio; + EVP_PKEY *pkey; + size_t len; + + if (!privatekey) + return 0; + bio = BIO_new_mem_buf(privatekey, -1); + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + BIO_free(bio); + len = (EVP_PKEY_size(pkey) + 2) / 3 * 4; + EVP_PKEY_free(pkey); + return len; } @@ -2025,83 +1902,73 @@ * If you pass in NULL for buf, you'll get back DK_STAT_NORESOURCE. * If len is not big enough, you'll get back DK_STAT_NORESOURCE. */ -DK_STAT dk_getsig(DK *dk, void *privatekey, unsigned char buf[], size_t len) +DK_STAT +dk_getsig(DK *dk, void *privatekey, unsigned char buf[], size_t len) { - if ((!dk)||(dk->dkmarker != DKMARK)||(!privatekey)) - { - return DK_STAT_ARGS; - } - if (!buf) - { - return DKERR(DK_STAT_NORESOURCE); - } - switch (dk->signing) - { - case DK_SIGNING_SIGN: - case DK_SIGNING_NOSIGN: - { - unsigned int siglen; - unsigned char *sig; - int size; - BIO *bio, *b64; - EVP_PKEY *pkey; - - bio = BIO_new_mem_buf(privatekey, -1); - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - BIO_free(bio); - - if (!pkey) - { - /* their private key is no good TC33 */ - return DKERR(DK_STAT_BADKEY); - } - - siglen = EVP_PKEY_size(pkey); - sig = (unsigned char*) OPENSSL_malloc(siglen); - EVP_SignFinal(&dk->mdctx, sig, &siglen, pkey); - EVP_PKEY_free(pkey); - - bio = BIO_new(BIO_s_mem()); - if (!bio) - { - return DKERR(DK_STAT_NORESOURCE); - } - b64 = BIO_new(BIO_f_base64()); - if (!b64) - { - BIO_free(bio); - return DKERR(DK_STAT_NORESOURCE); - } - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - BIO_push(b64, bio); - if ((size_t)BIO_write(b64, sig, siglen) < siglen) - { - OPENSSL_free(sig); - BIO_free_all(b64); - return DKERR(DK_STAT_NORESOURCE); - } - BIO_flush(b64); - OPENSSL_free(sig); - - size = BIO_read(bio, buf, len); - BIO_free_all(b64); - - if ((size_t)size >= len) - { - return DKERR(DK_STAT_NORESOURCE); /* TC28 */ - } - - buf[size] = '\0'; - return DKERR(DK_STAT_OK); - } - case DK_SIGNING_VERIFY: - case DK_SIGNING_NOVERIFY: - return DKERR(DK_STAT_INTERNAL); - }//end switch - return DK_STAT_ARGS; + if ((!dk) || (dk->dkmarker != DKMARK) || !privatekey) + return DK_STAT_ARGS; + if (!buf) + return DKERR(DK_STAT_NORESOURCE); + switch (dk->signing) + { + case DK_SIGNING_SIGN: + case DK_SIGNING_NOSIGN: + { + unsigned int siglen; + unsigned char *sig; + int size; + BIO *bio, *b64; + EVP_PKEY *pkey; + + bio = BIO_new_mem_buf(privatekey, -1); + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + BIO_free(bio); + if (!pkey) /*- their private key is no good TC33 */ + return DKERR(DK_STAT_BADKEY); + siglen = EVP_PKEY_size(pkey); + sig = (unsigned char *) OPENSSL_malloc(siglen); + EVP_SignFinal(evptr, sig, &siglen, pkey); + EVP_PKEY_free(pkey); + if (!(bio = BIO_new(BIO_s_mem()))) + return DKERR(DK_STAT_NORESOURCE); + if (!(b64 = BIO_new(BIO_f_base64()))) + { + BIO_free(bio); + return DKERR(DK_STAT_NORESOURCE); + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO_push(b64, bio); + if ((size_t) BIO_write(b64, sig, siglen) < siglen) + { + OPENSSL_free(sig); + BIO_free_all(b64); + return DKERR(DK_STAT_NORESOURCE); + } + for (;;) + { + if (BIO_flush(b64) == -1) /*- retry */ + { + if (BIO_should_retry(b64)) + continue; + } else + break; + } + OPENSSL_free(sig); + size = BIO_read(bio, buf, len); + BIO_free_all(b64); + if ((size_t) size >= len) + return DKERR(DK_STAT_NORESOURCE); /*- TC28 */ + buf[size] = '\0'; + return DKERR(DK_STAT_OK); + } + case DK_SIGNING_VERIFY: + case DK_SIGNING_NOVERIFY: + return DKERR(DK_STAT_INTERNAL); + } /*- switch (dk->signing) */ + /*- Not REACHED*/ + return DK_STAT_ARGS; } - /* HEADER */ /* * Free all resources associated with this message. @@ -2111,57 +1978,47 @@ * want to call openssl's ERR_remove_state(0) by yourself * ERR_remove_state(0) is declared in */ -DK_STAT dk_free(DK *dk, int doClearErrState) +DK_STAT +dk_free(DK *dk, int doClearErrState) { - if ((!dk)||(dk->dkmarker != DKMARK)) - { - return DK_STAT_ARGS; - } - if (dk->from) - { - DK_MFREE(dk->from); - } - if (dk->sender) - { - DK_MFREE(dk->sender); - } - if (dk->sender_beforesign) - { - DK_MFREE(dk->sender_beforesign); - } - if (dk->trace) - { - DK_MFREE(dk->trace); - } - if (dk->traceheader) - { - DK_MFREE(dk->trace); - } - if (dk->keyrec) - { - DK_MFREE(dk->keyrec); - } - if (dk->policyrec) - { - DK_MFREE(dk->policyrec); - } - if (dk->granularity) - { - DK_MFREE(dk->granularity); - } + if (!dk) + return DK_STAT_ARGS; + if (dk->dkmarker != DKMARK) + return DK_STAT_ARGS; + if (dk->from) + DK_MFREE(dk->from); + if (dk->sender) + DK_MFREE(dk->sender); + if (dk->sender_beforesign) + DK_MFREE(dk->sender_beforesign); + if (dk->trace || dk->traceheader) + DK_MFREE(dk->trace); + if (dk->keyrec) + DK_MFREE(dk->keyrec); + if (dk->policyrec) + DK_MFREE(dk->policyrec); + if (dk->granularity) + DK_MFREE(dk->granularity); + if (dk->sel_headers) + DK_MFREE(dk->sel_headers); #ifdef DK_HASH_BUFF - DK_MFREE(dk->hash_buff); + DK_MFREE(dk->hash_buff); #endif - EVP_MD_CTX_cleanup(&dk->mdctx); - DK_MFREE(dk->header); /* alloc'ing dk->header is not optional. */ - dk->dkmarker = ~DKMARK; - DK_MFREE(dk); - - if (doClearErrState) - { - ERR_remove_state(0); - } - return DK_STAT_OK; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (evptr) + EVP_MD_CTX_free(evptr); +#else + if (evptr) + EVP_MD_CTX_cleanup(evptr); +#endif + DK_MFREE(dk->header); /*- alloc'ing dk->header is not optional. */ + dk->dkmarker = ~DKMARK; + DK_MFREE(dk); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (doClearErrState) + ERR_remove_state(0); +#endif + return DK_STAT_OK; } /* HEADER */ @@ -2171,17 +2028,104 @@ * contain the name of the DK_STAT constant. From there to the end of * string is a human-readable description of the error. */ -const char *DK_STAT_to_string(DK_STAT st) +const char * +DK_STAT_to_string(DK_STAT st) { - /* TC53 */ - if (st >= (sizeof errors) / (sizeof errors[0])) - { - return "DK_STAT_UNKNOWN: unknown status"; - } - else - { - return errors[st]; - } + /*- TC53 */ + if (st >= (sizeof errors) / (sizeof errors[0])) + return "DK_STAT_UNKNOWN: unknown status"; + else + return errors[st]; } +/* HEADER */ +/* + * if DKOPT_SELHEAD is set and *ptr != NULL set dk->sel_headers. + */ +int +dk_set_selheaders(DK *dk, char *ptr) +{ + int found = 0; + char *copy; + size_t len, add; + + if (!dk || !ptr || !(dk->opts & DKOPT_SELHEAD)) { + return 0; + } + + len = strlen(ptr); + copy = (char *) DK_MALLOC(len + 2); + if (!copy) { + return 0; + } + copy[0] = ':'; + memcpy(copy + 1, ptr, len - 1); + copy[len] = ':'; + copy[len + 1] = 0; + + if (strncasestr(copy, ":From:", len) != NULL) { + found++; + } + if (strncasestr(copy, ":Sender:", len) != NULL) { + found++; + } + DK_MFREE(copy); + + if (dk->sel_headers) { /* if previous value exists */ + DK_MFREE(dk->sel_headers); + } + add = 0; + if (!found) { + add = 5 + 7; /* add room for From: + Sender: */ + } + dk->sel_headers = DK_MALLOC(len + add + 2); + if (!dk->sel_headers) { + return 0; + } + dk->sel_headers[0] = ':'; + memcpy(dk->sel_headers + 1, ptr, len - 1); + dk->sel_headers[len] = ':'; + dk->sel_headers[len + 1] = 0; + if (!found) { + memcpy(dk->sel_headers + len + 1, "Sender:From:", add); + dk->sel_headers[len + 1 + add] = 0; + } + return len + 1 + add; +} + +/* + * Find the first occurrence of find in s, where the search is limited to the + * first slen characters of s, ignore case. + */ +static char * +strncasestr(const char *s, const char *find, size_t slen) +{ + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + c = tolower((unsigned char) c); + len = strlen((char *) find); + do { + do { + if (slen-- < 1 || (sc = *s++) == '\0') + return (NULL); + } while ((char) tolower((unsigned char) sc) != c); + if (len > slen) + return (NULL); + } while (strncasecmp((char *) s, (char *) find, len) != 0); + s--; + } + return ((char *) s); +} +#endif + +void +getversion_domainkeys_c() +{ + static char *x = "$Id: domainkeys.c,v 1.19 2017-08-09 22:07:51+05:30 Cprogrammer Exp mbhangui $"; + + x++; +} +// vim: shiftwidth=2:tabstop=4:softtabstop=4 diff -ruN libdomainkeys-0.69-original/socket.lib libdomainkeys-0.69-mbanghui-ssl-1.1/socket.lib --- libdomainkeys-0.69-original/socket.lib 1970-01-01 01:00:00.000000000 +0100 +++ libdomainkeys-0.69-mbanghui-ssl-1.1/socket.lib 2015-12-15 09:56:37.000000000 +0100 @@ -0,0 +1 @@ +-lresolv