1 #include <sys/types.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 // added by nhatier for compilation under MSVC
5 #ifdef _MSC_VER
6 #include <string.h>
7   #define strncasecmp strnicmp
8   #define strcasecmp stricmp
9   #define snprintf _snprintf
10 #else
11   #ifndef _STRINGS_H
12     #include <strings.h>
13   #endif
14   #ifndef _STRING_H
15     #include <string.h>
16   #endif
17 #endif
18 // end added by nhatier
19 extern char *dns_text(char *);
20 
21 /* STARTHEAD */
22 /* This is libdomainkeys.  It's Copyright (c) 2004 Yahoo, Inc.
23  * This code incorporates intellectual property owned by
24  * Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License
25  * Agreement: http://domainkeys.sourceforge.net/license/softwarelicense1-0.html
26  */
27 #include <openssl/evp.h>
28 #include <openssl/pem.h>
29 #include <openssl/err.h>
30 
31 #ifdef SWIG
32 %module domainkeys
33 %{
34 #include "domainkeys.h"
35 %}
36 #endif
37 
38 #include "dktrace.h"
39 
40 /* Performance/Debug options.
41  * Uncomment below or use -D switch in gcc
42  * DK_DEBUG Dumps whatever dkhash() hashes in to stderr and turns on
43  *  some debug warnings that should never happen
44  * DK_HASH_BUFF Enables code that uses a buffer when processing the
45  *  canocalized message, reducing calls to the crypto library (from dkhash()),
46  *  but can use up slightly more memory
47 */
48 //#define DK_DEBUG 1
49 #define DK_HASH_BUFF 1
50 
51 
52 #define DKMARK ('D' | 'K'<<8 | 'E'<<16 | 'Y'<<24)
53 #define DK_SIGNING_SIGN 0
54 #define DK_SIGNING_VERIFY 1
55 #define DK_SIGNING_NOSIGN 2
56 #define DK_SIGNING_NOVERIFY 3
57 #define DK_MALLOC(s)  OPENSSL_malloc(s)
58 #define DK_MFREE(s)   OPENSSL_free(s); s = NULL;
59 #define DKERR(x) ((dk->errline=__LINE__),(dk->errfile=__FILE__),(x))
60 #define DK_BLOCK 1024 //default size of malloc'd block
61 
62 /*
63  * Option Flags for dk_setopts
64  * OR together or run dk_setopts several times
65  * All option flags are OFF by default
66 */
67 #define DKOPT_TRACE_h 0x01 //enables tracking character count in pre-canon header
68 #define DKOPT_TRACE_H 0x02 //enables tracking character count in post-canon header
69 #define DKOPT_TRACE_b 0x04 //enables tracking character count in pre-canon body
70 #define DKOPT_TRACE_B 0x08 //enables tracking character count in post-canon header
71 #define DKOPT_RDUPE 0x10 //enables skipping duplicate headers when generateing a signature
72 
73 typedef enum
74 {
75   DK_STAT_OK, /* Function completed successfully */
76   DK_STAT_BADSIG, /* Signature was available but failed to verify against domain specified key */
77   DK_STAT_NOSIG, /* No signature available in message */
78   DK_STAT_NOKEY, /* No public key available (permanent failure) */
79   DK_STAT_BADKEY, /* Unusable key, public if verifying, private if signing */
80   DK_STAT_CANTVRFY, /* Cannot get domain key to verify signature (temporary failure) */
81   DK_STAT_SYNTAX, /* Message is not valid syntax. Signature could not be created/checked */
82   DK_STAT_NORESOURCE, /* Could not get critical resource (temporary failure) */
83   DK_STAT_ARGS, /* Arguments are not usable. */
84   DK_STAT_REVOKED,    /* Key has been revoked. */
85   DK_STAT_INTERNAL, /* cannot call this routine in this context.  Internal error. */
86   DK_STAT_GRANULARITY, /* Granularity mismatch: sender doesn't match g= option. */
87 } DK_STAT;
88 
89 typedef enum
90 {
91   DK_FLAG_TESTING = 1,    /* set when in testing mode. */
92   DK_FLAG_SIGNSALL = 2,   /* domain signs all outgoing email. */
93   DK_FLAG_SET = 4,    /* flags set from a successful DNS query */
94   DK_FLAG_G = 8,    /* g tag was present in the selector. */
95 } DK_FLAGS;
96 typedef enum
97 {
98   DK_TXT_KEY = 0,
99   DK_TXT_POLICY
100 } DK_TXT;
101 
102 typedef enum
103 {
104   DK_CANON_SIMPLE = 0,
105   DK_CANON_NOFWS = 1,
106 } DK_CANON;
107 /* STARTSTRUCT */
108 typedef struct
109 {
110 /* STARTPRIV */
111   const EVP_MD *md;
112 /* STOPPRIV */
113 
114 } DK_LIB;
115 /* STOPSTRUCT */
116 
117 //UnixWare Fix -Tim
118 /* STARTSTRUCT */
119 typedef struct
120 {
121 /* STARTPRIV */
122   int dkmarker;     /* in case somebody casts in */
123 #if OPENSSL_VERSION_NUMBER < 0x10100001L
124   EVP_MD_CTX mdctx;   /* the hash */
125 #else
126   EVP_MD_CTX *mdctx;  /* the hash */
127 #endif
128   int signing;      /* our current signing/verifying state */
129   int in_headers;   /* true if we're still processing headers */
130   char *header;     /* points to a malloc'ed block for header. */
131   int headerlen;    /* total length of the header. */
132   int headermax;    /* length of malloc'ed block */
133   int headerlinelen;    /* current column of the header */
134   int start_signed;   /* offset into header of the start of the headers. */
135   char *from;     /* saved copy of From: header */
136   char *sender;     /* saved copy of Sender: header */
137   char *dksign;     /* saved copy of DK-Sig: header */
138   char *dktrace;  /* saved copy of DK-Trace: header */
139   char *domain;     /* d= */
140   char *selector;   /* s= */
141   char *signature;    /* b= */
142   char *granularity;    /* g= */
143   char *keyrec; /* caller supplied TXT key record */
144   char *policyrec; /* caller supplied TXT policy record */
145   int canon;      /* c= canonicalization being applied. */
146   int state;      /* state variable for canonicalization */
147   char *headers;    /* h= */
148   int errline;      /* source line of most recent error */
149   char *errfile;    /* source file of most recent error */
150   char *sender_beforesign; /* saved copy of Sender: header */
151   int opts;  /* trace and rdupe flags */
152   char last_char; /* the last character processed by dk_message() */
153 #ifdef DK_HASH_BUFF
154   char *hash_buff; /* buffer for hashing */
155   int hash_buff_len; /* length of hashing buffer */
156 #endif
157   DK_TRACE *trace; /* pointer to trace count table */
158   DK_TRACE *traceheader; /* pointer to trace count table from DK-Trace:*/
159 /* STOPPRIV */
160 } DK;
161 /* STOPSTRUCT */
162 
163 
164 /* STARTPRIV */
165 static char *errors[] =
166 {
167   "DK_STAT_OK: Function completed successfully",
168   "DK_STAT_BADSIG: Signature was available but failed to verify against domain specified key",
169   "DK_STAT_NOSIG: No signature available in message",
170   "DK_STAT_NOKEY: No public key available (permanent failure)",
171   "DK_STAT_BADKEY: Unusable key, public if verifying, private if signing.",
172   "DK_STAT_CANTVRFY: Cannot get domain key to verify signature (temporary failure)",
173   "DK_STAT_SYNTAX: Message is not valid syntax. Signature could not be created/checked",
174   "DK_STAT_NORESOURCE: Could not get critical resource (temporary failure)",
175   "DK_STAT_ARGS: Arguments are not usable.",
176   "DK_STAT_REVOKED: Key has been revoked.",
177   "DK_STAT_INTERNAL: cannot call this routine in this context.  Internal error.",
178   "DK_STAT_GRANULARITY: Granularity mismatch: sender doesn't match g= option."
179 };
180 /* STOPPRIV */
181 /* STOPHEAD */
182 //prototype for dk_from
183 char* dk_from(DK *);
184 int dk_headers(DK *, char *);
185 
dk_strdup(const char * s)186 char* dk_strdup(const char* s)
187 {
188   char* new = DK_MALLOC(strlen(s)+1);
189   if (new != 0)
190   {
191     strcpy(new, s);
192   }
193   return new;
194 }
195 
196 /* HEADER */
197 /* returns the source file from which an error was returned. */
dk_errfile(DK * dk)198 char * dk_errfile(DK *dk)
199 {
200   return dk->errfile;
201 }
202 
203 /* HEADER */
204 /* returns the source line number from which an error was returned. */
dk_errline(DK * dk)205 int dk_errline(DK *dk)
206 {
207   return dk->errline;
208 }
209 
210 /* HEADER */
211 /* Per-process, one-time initialization
212  * Returns library structure for subsequent dk_sign or dk_verify calls.
213  * Consult statp before using.
214  *
215  * When terminating the PROCESS its a good idea to call dk_shutdown()
216  * When terminating a THREAD it's a good idea to call ERR_remove_state(0); defined in <openssl/err.h>
217  * NOTE: DK_LIB pointers are safe to use over multiple threads
218  *       DK pointers are NOT safe to use over multiple threads
219  */
dk_init(DK_STAT * statp)220 DK_LIB *dk_init(DK_STAT *statp)
221 {
222   DK_LIB *dklib;
223 
224   dklib = DK_MALLOC(sizeof(DK_LIB));
225   if (!dklib)
226   {
227     if (statp)
228     {
229       *statp = DK_STAT_NORESOURCE;
230     }
231     return NULL;
232   }
233   dklib->md = EVP_sha1();
234   if (!dklib->md)
235   {
236     if (statp)
237     {
238       *statp = DK_STAT_INTERNAL;
239     }
240     DK_MFREE(dklib);
241     return NULL;
242   }
243   if (statp)
244   {
245     *statp = DK_STAT_OK;
246   }
247   return dklib;
248 }
249 
250 /* HEADER */
251 /* Per-process, one-time cleanup
252  * Should be called just before the application ends.
253  * the dklib pointer is not valid anymore after this call
254  * This function should be called even if dk_init failed.
255  * It's safe to call dk_shutdown with a NULL pointer
256  */
dk_shutdown(DK_LIB * dklib)257 void dk_shutdown(DK_LIB * dklib)
258 {
259    if (dklib)
260    {
261       DK_MFREE(dklib);
262    }
263    CRYPTO_cleanup_all_ex_data();
264 }
265 
266 /* start a new header */
dkinit_new_header(DK * dk)267 static DK_STAT dkinit_new_header(DK *dk)
268 {
269   dk->headermax = DK_BLOCK;
270   dk->header = DK_MALLOC(DK_BLOCK);
271   if (!dk->header)
272   {
273     return DKERR(DK_STAT_NORESOURCE);
274   }
275   memset(dk->header,0,DK_BLOCK);
276   dk->headerlen = 0;
277   dk->headerlinelen = 1;  /* always store the first char. */
278   dk->in_headers = 1;
279   dk->start_signed = 0;
280   dk->from = NULL;
281   dk->sender = NULL;
282   dk->dksign = NULL;
283   dk->dktrace = NULL;
284   dk->domain = NULL;
285   dk->selector = NULL;
286   dk->signature = NULL;
287   dk->canon = DK_CANON_SIMPLE;
288   dk->state = 0;
289   dk->headers = 0;
290   dk->sender_beforesign = NULL;
291   dk->opts = 0;
292   dk->last_char = '\0';
293   dk->trace = NULL;
294   dk->traceheader = NULL;
295   dk->granularity = NULL;
296   dk->keyrec = NULL;
297   dk->policyrec = NULL;
298 #ifdef DK_HASH_BUFF
299   dk->hash_buff = DK_MALLOC(DK_BLOCK);
300   if (!dk->hash_buff)
301   {
302     return DKERR(DK_STAT_NORESOURCE);
303   }
304   memset(dk->hash_buff,0,DK_BLOCK);
305   dk->hash_buff_len = 0;
306 #endif
307   return DKERR(DK_STAT_OK);
308 }
309 
310 /* HEADER */
311 /* Set dk options, use instead of dk_remdupe and dk_enable_trace
312  * Can be called multiple times.
313  * use after dk_sign()/dk_verify()
314  *
315  * the bits field can be an OR of any of the following
316  *DKOPT_TRACE_h Trace pre-canon header
317  *DKOPT_TRACE_H Trace post-canon header
318  *DKOPT_TRACE_b Trace pre-canon body
319  *DKOPT_TRACE_B Trace post-canon body
320  *DKOPT_RDUPE   Exclude duplicate headers from hash (Signing only)
321  */
dk_setopts(DK * dk,int bits)322 DK_STAT dk_setopts(DK *dk, int bits)
323 {
324   if (!dk)
325     return DK_STAT_ARGS;
326   if ((dk->headerlen == 0)&&((dk->signing == DK_SIGNING_NOVERIFY)||(dk->signing == DK_SIGNING_SIGN)))
327   {
328     dk->opts |= bits;
329     if ((bits & (DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)) && !dk->trace)
330     {
331       dk->trace = DK_MALLOC(sizeof(DK_TRACE));
332       if (!dk->trace)
333         return DKERR(DK_STAT_NORESOURCE);
334       dkt_init(dk->trace);
335     }
336     if ((dk->signing != DK_SIGNING_SIGN) && (bits & DKOPT_RDUPE))
337     {
338       return DKERR(DK_STAT_INTERNAL); //cant do rdupe in verify mode
339     }
340     return DKERR(DK_STAT_OK);
341   }
342   return DKERR(DK_STAT_INTERNAL);
343 }
344 /* HEADER */
345 /* returns the int holding the options set
346  * See dk_setopts for bit flags
347  */
dk_getopts(DK * dk)348 int dk_getopts(DK *dk)
349 {
350   if (!dk)
351     return 0;
352   return (dk->opts);
353 }
354 
355 /* HEADER */
356 /* DEPRECATED in favor of calling dk_setopts().
357  * Enables character trace tracking
358  *
359  * use after dk_sign()/dk_verify()
360  */
dk_enable_trace(DK * dk)361 DK_STAT dk_enable_trace(DK *dk)
362 {
363   return dk_setopts(dk,(DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B));
364 }
365 /* HEADER */
366 /* Prints trace table to *store variable (char string)
367  * *dk is the container for the table
368  * *store is a pointer to a character array to output to
369  * store_size is the size of the character array *store
370  *
371  */
dk_get_trace(DK * dk,DK_TRACE_TYPE type,char * store,int store_size)372 DK_STAT dk_get_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
373 {
374   if (!dk)
375     return DK_STAT_ARGS;
376   if (dk->trace)
377   {
378     if (!dkt_generate(dk->trace, type, store, store_size))
379     {
380       return DK_STAT_NORESOURCE; //not enough buffer space
381     }
382     return DKERR(DK_STAT_OK);
383   }
384   return DKERR(DK_STAT_INTERNAL);
385 }
386 
387 /* HEADER */
388 /* Prints difference trace table to *store variable (char string)
389  * *dk is the container for the table
390  * *store is a pointer to a character array to output to
391  * store_size is the size of the character array *store
392  * return DK_STAT_NOSIG if no DK-Trace header was found
393  */
dk_compare_trace(DK * dk,DK_TRACE_TYPE type,char * store,int store_size)394 DK_STAT dk_compare_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
395 {
396   DK_TRACE table;
397   if (!dk)
398     return DK_STAT_ARGS;
399   if (!dk->dktrace || !dk->trace)
400     return DK_STAT_NOSIG;
401   dkt_init(&table);
402   if (!dk->traceheader) //make DK_TRACE from header
403   {
404     dk->traceheader = DK_MALLOC(sizeof(DK_TRACE));
405     if (!dk->traceheader)
406       return DKERR(DK_STAT_NORESOURCE);
407     dkt_init(dk->traceheader);
408 
409     if (!dkt_hdrtotrace(dk->dktrace,dk->traceheader))
410     {
411       return DK_STAT_NORESOURCE;
412     }
413   }
414   dkt_diff(dk->traceheader, dk->trace, type, &table);
415   if (!dkt_generate(&table, type, store, store_size))
416   {
417     return DK_STAT_NORESOURCE; //not enough buffer space
418   }
419   return DK_STAT_OK;
420 }
421 
422 
423 /* HEADER */
424 /* Sets the DNS key/policy record manually (no DNS lookup)
425  * txtrecord needs to be set to "e=perm;" to force a permanent DNS failure
426  * txtrecord needs to be set to "e=temp;" to force a temporary DNS failure
427  * Valid DK_TXT types are:
428  * DK_TXT_KEY (normal selector record; for <selctor>._domainkey.<domain>)
429  * DK_TXT_POLICY (domain policy record; for _domainkey.<domain>)
430  */
dk_settxt(DK * dk,DK_TXT recordtype,const char * txtrecord)431 DK_STAT dk_settxt(DK *dk, DK_TXT recordtype, const char *txtrecord)
432 {
433   char **ptr; //pointer to keyrecord/policyrecord pointer
434   if (!dk|| !txtrecord)
435     return DK_STAT_ARGS;
436   switch (recordtype)
437   {
438     case DK_TXT_KEY:
439       ptr = &dk->keyrec;
440       break;
441     case DK_TXT_POLICY:
442       ptr = &dk->policyrec;
443       break;
444     default:
445       return DK_STAT_ARGS;
446   }
447   // Free the value iff it is currently set.
448   if (*ptr)
449   {
450     DK_MFREE(*ptr);
451   }
452   *ptr = dk_strdup(txtrecord);
453   return DKERR(DK_STAT_OK);
454 }
455 
dkstore_char(DK * dk,char ch)456 static DK_STAT dkstore_char(DK *dk, char ch)
457 {
458   if (dk->headerlen >= dk->headermax)
459   {
460     char *hp;
461     hp = DK_MALLOC(dk->headermax * 2 + 1024 + 1); /* leave room for null */
462     if (!hp)
463     {
464       return DKERR(DK_STAT_NORESOURCE);
465     }
466     if (dk->headermax)
467     {
468       memcpy(hp, dk->header, dk->headerlen);
469       DK_MFREE(dk->header);
470     }
471     dk->header = hp;
472     dk->headermax = dk->headermax * 2 + 1024;
473   }
474   dk->header[dk->headerlen++] = ch;
475   dk->headerlinelen++;
476   return DKERR(DK_STAT_OK);
477 }
478 
479 /* HEADER */
480 /* Per-message, may be threaded.
481  * canon is one of DK_CANON_*.
482  * Returns state structure for operation.  Consult statp before using.
483  */
dk_sign(DK_LIB * dklib,DK_STAT * statp,int canon)484 DK *dk_sign(DK_LIB *dklib, DK_STAT *statp, int canon)
485 {
486   DK *dk;
487 
488   dk = DK_MALLOC(sizeof(DK));
489   if (!dk)
490   {
491     if (statp)
492     {
493       *statp = DKERR(DK_STAT_NORESOURCE);
494     }
495     return NULL;
496   }
497   dk->dkmarker = DKMARK;
498   dk->signing = DK_SIGNING_SIGN;
499   if (dkinit_new_header(dk) != DK_STAT_OK)
500   {
501     /* couldn't malloc a header. */
502     DK_MFREE(dk);
503     if (statp)
504     {
505       *statp = DKERR(DK_STAT_NORESOURCE);
506     }
507     return NULL;
508   }
509   dk->canon = canon; /* TC13-simple, TC13-nofws */
510 #if OPENSSL_VERSION_NUMBER < 0x10100001L
511   if (!EVP_SignInit(&dk->mdctx, dklib->md)) {
512     if (statp)
513     {
514       *statp = DKERR(DK_STAT_NORESOURCE);
515     }
516     return NULL;
517   }
518 #else
519   dk->mdctx = EVP_MD_CTX_create();
520   if (!dk->mdctx || !EVP_SignInit(dk->mdctx, dklib->md)) {
521     if (statp)
522     {
523       *statp = DKERR(DK_STAT_NORESOURCE);
524     }
525     return NULL;
526   }
527 #endif
528 
529   if (statp)
530   {
531     *statp = DKERR(DK_STAT_OK);
532   }
533   return dk;
534 }
535 
536 /* HEADER */
537 /* Per-message, may be threaded.
538  * Returns state structure for operation.  Consult statp before using.
539  */
dk_verify(DK_LIB * dklib,DK_STAT * statp)540 DK *dk_verify(DK_LIB *dklib, DK_STAT *statp)
541 {
542   DK *dk;
543 
544   dk = DK_MALLOC(sizeof(DK));
545   if (!dk)
546   {
547     if (statp)
548     {
549       *statp = DKERR(DK_STAT_NORESOURCE);
550     }
551     return NULL;
552   }
553   dk->dkmarker = DKMARK;
554   dk->signing = DK_SIGNING_NOVERIFY; /* wait to verify until we see DK-Signature. */
555   if (dkinit_new_header(dk) != DK_STAT_OK)
556   {
557     /* couldn't malloc a header. */
558     DK_MFREE(dk);
559     if (statp)
560     {
561       *statp = DKERR(DK_STAT_NORESOURCE);
562     }
563     return NULL;
564   }
565 #if OPENSSL_VERSION_NUMBER < 0x10100001L
566   if (!EVP_VerifyInit(&dk->mdctx, dklib->md)) {
567     if (statp)
568     {
569       *statp = DKERR(DK_STAT_NORESOURCE);
570     }
571     return NULL;
572   }
573 #else
574   dk->mdctx = EVP_MD_CTX_create();
575   if (!dk->mdctx || !EVP_VerifyInit(dk->mdctx, dklib->md)) {
576     if (statp)
577     {
578       *statp = DKERR(DK_STAT_NORESOURCE);
579     }
580     return NULL;
581   }
582 #endif
583 
584   if (statp)
585   {
586     *statp = DKERR(DK_STAT_OK);
587   }
588   return dk;
589 }
590 
591 /* parse an rfc822 address */
592 /* leave it in the dk_address() format; that is, with the existing
593  * first letter, followed by the address */
dkparse822(char * address,unsigned int offset)594 static DK_STAT dkparse822(char *address, unsigned int offset)
595 {
596   int foundangle = 0;   /* true if it's in angle brackets */
597   int foundat = 0;
598   char *from, *to;
599   int level = 1;
600 
601   to = address + 1;
602   from = address + offset;
603   while (*from)
604   {   /* nuke comments. */
605     if (*from == ')')
606     {
607       return DK_STAT_SYNTAX;
608     }
609     else if (*from == '\\' && from[1])
610     {
611       /* skip backslash-quoted characters */
612       *to++ = *from++;
613       *to++ = *from++;
614     }
615     else if (*from == '"')
616     {
617       /* we have to ignore parenthesis inside quotes. */
618       from++;
619       for (;;)
620       {
621         if (*from == '\0')
622         {
623           return DK_STAT_SYNTAX;
624         }
625         else if (*from == '"')
626         {
627           from++;
628           break;
629         }
630         else if (*from == '\\' && from[1])
631         {
632           *to++ = *from++;
633         }
634         *to++ = *from++;
635       }
636     }
637     else if (*from == '(')
638     {
639       level = 1;
640       from++;
641       while (level)
642       {
643         if (*from == '\0')
644         {
645           return DK_STAT_SYNTAX;
646         }
647         else if (*from == '(')
648         {
649           ++level;
650         }
651         else if (*from == ')')
652         {
653           --level;
654         }
655         else if (*from == '\\' && from[1])
656         {
657           ++from;
658         }
659         ++from;
660       }
661     }
662     else if (*from == ' ')
663     {
664       ++from;
665     }
666     else if (*from == '\t')
667     {
668       ++from;
669     }
670     else
671     {
672       *to++ = *from++;
673     }
674   } //end while(*from)
675   *to = '\0';
676   from = address + 1;
677   to = address + 1;
678   while (*from)
679   {
680     if (*from == '@')
681     {
682       foundat = 1;
683     }
684     if (*from == '\\' && from[1])
685     {
686       *to++ = *from++;
687       *to++ = *from++;
688     }
689     else if (*from == '<')
690     {
691       from++;
692       to = address + 1;
693       foundangle = 1;
694       foundat = 0;
695     }
696     else if (*from == ',' || *from == ':' )
697     {
698       from++;
699       to = address + 1;
700       foundat = 0;
701     }
702     else if (foundangle && *from == '>')
703     {
704       break;
705     }
706     else if (*from == ';')
707     {
708       break;
709     }
710     else
711     {
712       *to++ = *from++;
713     }
714   }
715   *to = '\0';
716   if (foundat)
717   {
718     return DK_STAT_OK;
719   }
720   else if (!address[1])
721   {
722     return DK_STAT_OK;
723   }
724   else
725   {
726     return DK_STAT_SYNTAX;  /* no @ in the address */
727   }
728 }
729 
730 /* Given a list of key=value; pairs, find all the keys found in letters.
731  * Store the value in the corresponding entry in values[].
732  * Modifies list to insert nulls in the place of the semicolons which terminate
733  * each of the values except possibly the last.
734  * You can only call dkparselist() once on a given list.
735  * Caller must ensure that values[] is as large as strlen(letters)
736  * According to the spec, a value can have embedded spaces in it, however none
737  * of the existing values need spaces, so we always remove them.
738  */
739 
dkparselist(char * list,char * letters,char * values[])740 static DK_STAT dkparselist(char *list, char *letters, char *values[])
741 {
742   char key;
743   int i;
744   char *value;
745 
746   /* start with all args unset */
747   for (i = 0; letters[i]; i++)
748   {
749     values[i] = NULL;
750   }
751   key = 0;
752   while (*list)
753   {
754     if ((*list == ' ')||(*list == '\t')||(*list == '\r')||(*list == '\n'))
755     {
756       list++;
757     }
758     else if (*list == '=')
759     {
760       char *ws;
761 
762       ++list;
763       value = list;
764       ws = list;
765       while (1)
766       {
767         /* copy up to null or semicolon, deleting whitespace as we go */
768         *ws = *list;
769         if ((*list == ' ')||(*list == '\t')||(*list == '\r')||(*list == '\n'))
770         {
771           /* ignore */
772         }
773         else if (!*list)
774         {
775           break;
776         }
777         else if (*list == ';')
778         {
779           *ws = '\0';
780           list++;
781           break;
782         }
783         else
784         {
785           ws++;
786         }
787         list++;
788       }
789       if (!key)
790       {
791         return DK_STAT_SYNTAX; /* we didn't get a key. TC22 */
792       }
793       /* if we find a matching letter, remember the value */
794       for (i = 0; letters[i]; i++)
795       {
796         if (key == letters[i])
797         {
798           if (values[i])
799           {
800             return DK_STAT_SYNTAX; /* no duplicate keys. TC23 */
801           }
802           values[i] = value;
803         }
804       }
805       key = 0;
806     }
807     else
808     {
809       if (key)
810       {
811         return DK_STAT_SYNTAX; /* they already gave us a key. TC24 */
812       }
813       key = *list++;
814       if (!islower((int)key))
815       {
816         return DK_STAT_SYNTAX; /* must be lowercase letter. TC25 */
817       }
818     }
819   }
820   if (key)
821   {
822     return DK_STAT_SYNTAX; /* we ended up with an extra key. TC25-1 */
823   }
824   return DK_STAT_OK;
825 }
826 
827 /* HEADER */
828 /* DEPRECATED in favor of calling dk_setopts()
829  * set option to remove dupe headers
830  * should be called after dk_sign();
831  * any int NOT 0 turns dupe removal on
832  */
dk_remdupe(DK * dk,int i)833 DK_STAT dk_remdupe(DK *dk,int i)
834 {
835   if (i != 0)
836     return dk_setopts(dk,DKOPT_RDUPE);
837   return DK_STAT_OK;
838 }
839 
840 
841 /* HEADER */
842 /* Returns the policy flags belonging to the signing domain.
843  * Sender: overrides From:, and the d= entry in the DK-Sig overrides both.
844  * If the policy flags were not successfully fetched, DK_FLAG_SET will not
845  * be set.
846  */
dk_policy(DK * dk)847 DK_FLAGS dk_policy(DK *dk)
848 {
849   char *query, *results, *flags[2];
850   char *domain;
851   int dkf = 0;
852 
853   if (!dk)
854     return 0;
855   domain = NULL;
856   if (dk->dksign)
857   {
858     domain = dk->domain;
859   }
860   if (!domain)
861   {
862     domain = dk_from(dk);
863   }
864   if (!domain)
865   {
866     return 0;
867   }
868 
869   query = DK_MALLOC(strlen("_domainkey.") + strlen(domain) + 1);
870   if (query)
871   {
872      /* allow user to supply the DNS TXT policy record */
873     if (!dk->policyrec)
874     {
875       sprintf(query, "_domainkey.%s", domain);
876       results = dns_text(query);
877       DK_MFREE(query);
878     }
879     else
880     {
881       results = dk_strdup(dk->policyrec);
882     }
883 
884     if (!strcmp(results,"e=perm;"))
885     {
886     }
887     else if (!strcmp(results,"e=temp;"))
888     {
889     }
890     else
891     {
892       dkparselist(results, "ot", flags);
893 
894       if (flags[0] && *flags[0] == '-')  /* TC36 */
895       {
896         dkf |= DK_FLAG_SIGNSALL;
897       }
898       if (flags[1] && *flags[1] == 'y')  /* TC36-1 */
899       {
900         dkf |= DK_FLAG_TESTING;
901       }
902       dkf |= DK_FLAG_SET;
903     }
904     DK_MFREE(results);
905   }
906   return dkf;
907 }
908 
909 /*
910 dkhash
911 Internal function. Hashes in a single character, Will NOT has in ' ' or '\t'
912 if in NOFWS canon. Otherwise tracks \r and \r\n and hashes
913 them accordingly with the rest of the message.
914 Should ONLY be called when
915   dk->signing == DK_SIGNING_SIGN||DK_SIGNING_VERIFY
916 otherwise its pointless
917 */
dkhash(DK * dk,const unsigned char * ptr)918 static void dkhash(DK *dk, const unsigned char *ptr)
919 {
920 #ifdef DK_DEBUG
921   if ((dk->signing != DK_SIGNING_SIGN)&&(dk->signing != DK_SIGNING_VERIFY))
922   {
923     //called when we shouldnt of, this will break the sig
924     fprintf(stderr,"\nDKHASH() called for \'%c\' in mode: %i\n",*ptr,dk->signing);
925   }
926 #endif
927   if (dk->canon == DK_CANON_NOFWS && (*ptr == ' ' || *ptr == '\t'))
928   {
929     return;
930   }
931 
932   if ((dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_H))
933   {
934     if (dk->canon == DK_CANON_NOFWS)
935     {
936       if (*ptr != '\r')
937       {
938         if (*ptr == '\n')
939         {
940           dk->trace->ccounts_H[10]++;
941           dk->trace->ccounts_H[13]++;
942         }
943         else
944         {
945           dk->trace->ccounts_H[(int) *ptr]++;
946         }
947       }
948     }
949     else
950     {
951       dk->trace->ccounts_H[(int) *ptr]++;
952     }
953   }
954 
955   if (*ptr == '\r' && ((dk->state & 1) == 0))
956   {
957     dk->state++;
958   }
959   else if (*ptr == '\n' && ((dk->state & 1) == 1))
960   {
961     dk->state++;
962   }
963   else
964   {
965     while (dk->state >= 2)
966     {
967 
968 #ifndef DK_HASH_BUFF
969 #if OPENSSL_VERSION_NUMBER < 0x10100001L
970       EVP_DigestUpdate(&dk->mdctx, "\r\n", 2);
971 #else
972       EVP_DigestUpdate(dk->mdctx, "\r\n", 2);
973 #endif
974 #else
975       /* buffer hack */
976       dk->hash_buff[dk->hash_buff_len++] = '\r';
977       dk->hash_buff[dk->hash_buff_len++] = '\n';
978       if (dk->hash_buff_len >= (DK_BLOCK - 1))
979       {
980 #if OPENSSL_VERSION_NUMBER < 0x10100001L
981         EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len);
982 #else
983         EVP_DigestUpdate(dk->mdctx, dk->hash_buff, dk->hash_buff_len);
984 #endif
985         dk->hash_buff_len = 0;
986       }
987       /* buffer hack */
988 #endif
989       if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B))
990       {
991         dk->trace->ccounts_B[10]++;
992         dk->trace->ccounts_B[13]++;
993       }
994 #ifdef DK_DEBUG
995       fprintf(stderr,"\r\n");
996 #endif
997       dk->state -= 2;
998     }
999     if (dk->state)
1000     {
1001       if (dk->canon == DK_CANON_SIMPLE)//if nofws we ignore \r
1002       {
1003 #ifndef DK_HASH_BUFF
1004 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1005         EVP_DigestUpdate(&dk->mdctx, "\r", 1);
1006 #else
1007         EVP_DigestUpdate(dk->mdctx, "\r", 1);
1008 #endif
1009 #else
1010         /* buffer hack */
1011         dk->hash_buff[dk->hash_buff_len++] = '\r';
1012         if (dk->hash_buff_len >= (DK_BLOCK - 1))
1013         {
1014 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1015           EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1016 #else
1017           EVP_DigestUpdate(dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1018 #endif
1019           dk->hash_buff_len = 0;
1020         }
1021         /* buffer hack */
1022 #endif
1023         if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B))
1024         {
1025           dk->trace->ccounts_B[13]++;
1026         }
1027 #ifdef DK_DEBUG
1028         fprintf(stderr,"\r");
1029 #endif
1030       }
1031       dk->state --;
1032     }
1033 #ifndef DK_HASH_BUFF
1034 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1035     EVP_DigestUpdate(&dk->mdctx, ptr, 1);
1036 #else
1037     EVP_DigestUpdate(dk->mdctx, ptr, 1);
1038 #endif
1039 #else
1040     /* buffer hack */
1041     dk->hash_buff[dk->hash_buff_len++] = *ptr;
1042     if (dk->hash_buff_len >= (DK_BLOCK - 1))
1043     {
1044 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1045       EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1046 #else
1047       EVP_DigestUpdate(dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1048 #endif
1049       dk->hash_buff_len = 0;
1050     }
1051     /* buffer hack */
1052 #endif
1053 
1054     if ((!dk->in_headers && dk->trace) && (dk->opts & DKOPT_TRACE_B))
1055     {
1056       dk->trace->ccounts_B[(int) *ptr]++;
1057     }
1058 
1059 #ifdef DK_DEBUG
1060     fprintf(stderr,"%c", *ptr);
1061 #endif
1062   }
1063 }
1064 
1065 /* process headers if there's a h=*/
1066 /* dk->start_signed + 1 is the offset into headers pointing at the first header after DK-Sig */
1067 /* Changed to fix h= handling, checks if header is listed in h=
1068  *  handles duplicate Header items properly. (see section 3.3 h= draft-02)
1069  * We don't "look" for missing headers, maybe later.... -Tim
1070  */
dkheaders_header(DK * dk)1071 static DK_STAT dkheaders_header(DK *dk)
1072 {
1073   char *header_line_start,*header_label_end;
1074   char header_list[1024];
1075   char header_label[1024];
1076 
1077   char *p;
1078   //search hack redo later? -tim
1079   if (snprintf(header_list,sizeof(header_list),":%s:",dk->headers) >= sizeof(header_list))
1080   {
1081     //header list is too large for buffer
1082     return DKERR(DK_STAT_SYNTAX);
1083   }
1084 
1085   /*convert to all lowercase*/
1086   for (p = header_list; p[0] != '\0'; ++p)
1087   {
1088     p[0] = tolower(p[0]);
1089   }
1090 
1091   header_label[0] = ':';
1092   //first char in header_line_start is '\0' unless signing
1093   header_line_start = dk->header + dk->start_signed;
1094   if (dk->signing != DK_SIGNING_SIGN)
1095   {
1096     ++header_line_start;
1097   }
1098   while (1)
1099   {
1100     if (header_line_start >= (dk->header + dk->headerlen))
1101     {
1102       return DKERR(DK_STAT_OK);  //done reading headers
1103     }
1104     header_label_end = header_line_start;
1105     p = &header_label[1];
1106     while (p < (header_label + sizeof(header_label) - 2))
1107     {
1108       if (header_label_end[0] != ':')
1109       {
1110         p[0] = tolower(header_label_end[0]);
1111         ++p;
1112         ++header_label_end;
1113       }
1114       else
1115       {
1116         break;
1117       }
1118     }
1119     p[0] = ':';
1120     p[1] = '\0';
1121     //fprintf(stderr,"searching for: %s in %s\n",header_label, header_list);
1122     //if the header is found in the h= list
1123     if (strstr(header_list, header_label) != NULL)
1124     {
1125       //Found listed header, hash it in
1126       while(header_line_start[0] != '\0')
1127       {
1128         //we kept folded headers \r\n as markers -Tim
1129         if ((header_line_start[0] == '\n')||(header_line_start[0] == '\r'))
1130         {
1131           //if simple we keep the folded lines
1132           //if nofws we ignore it to unwrap it
1133           if (dk->canon == DK_CANON_NOFWS)
1134           {
1135             ++header_line_start;
1136             continue;
1137           }
1138         }
1139         dkhash(dk,&header_line_start[0]);
1140         ++header_line_start;
1141       }
1142       dkhash(dk, "\r");
1143       dkhash(dk, "\n");
1144     }
1145     else //skip hashing this header
1146     {
1147       while(header_line_start[0] != '\0')
1148       {
1149         ++header_line_start;
1150       }
1151     }
1152     //goto next header
1153     ++header_line_start;
1154 
1155   }//end while
1156 }
1157 /* dkheaders
1158   When Signing (DK_SIGNING_SIGN), Hashes in ALL headers and Greps out Sender:/From: headers
1159 
1160   When Verifying, reads headers until DK-Sig is found
1161   then
1162   If an h= tag is found, Greps out Sender:/From: headers, then calls dkheaders_header
1163     to hash in the listed headers
1164   If NO h= tag is present, it Greps out Sender:/From: headers as well as hashes in the
1165     headers that follow the DK-Sig header.
1166 */
dkheaders(DK * dk)1167 static DK_STAT dkheaders(DK *dk)
1168 {
1169   int i;
1170 
1171   for (i = 0; i < dk->headerlen; i++)
1172   {
1173     if (dk->headers && dk->signing == DK_SIGNING_VERIFY) //if h= wait till after parsing
1174     {
1175       //NOOP
1176     }
1177     else if (dk->canon == DK_CANON_NOFWS && (dk->header[i] == '\r' || dk->header[i] == '\n'))
1178     {
1179       //NOOP
1180     }
1181     /* Newcode */
1182     else if ((dk->opts & DKOPT_RDUPE)&&(dk->signing == DK_SIGNING_SIGN))
1183     {
1184       //NOOP
1185     }
1186     else if ((dk->signing == DK_SIGNING_SIGN)||(dk->signing == DK_SIGNING_VERIFY))
1187     {
1188       //we wont bother calling dkhash unless we are signing or verifying -Tim
1189       if (dk->header[i])
1190       {
1191         dkhash(dk, dk->header + i);
1192       }
1193       else //terminate end of header line
1194       {
1195         dkhash(dk, "\r");
1196         dkhash(dk, "\n");
1197       }
1198     }
1199     /* Newcode end */
1200 
1201     if (i==0 || dk->header[i-1] == '\0')
1202     {
1203       if (!strncasecmp(dk->header + i, "From:", 5))
1204       {
1205         /* Remember the From: and forget the current. */
1206         if (dk->from)
1207         {
1208           /* if we already got a From: header, fuhgeddabout it. */
1209           return DKERR(DK_STAT_SYNTAX);
1210         }
1211         dk->from = dk_strdup(dk->header + i);
1212         if (dkparse822(dk->from, 5) != DK_STAT_OK)
1213         {
1214           DK_MFREE(dk->from);
1215           dk->from = 0;
1216           return DKERR(DK_STAT_SYNTAX);
1217         }
1218       }
1219       else if (!strncasecmp(dk->header + i, "Sender:", 7))
1220       {
1221         if (dk->sender)
1222         {
1223           /* if we already got a Sender: header, fuhgeddabout it. */
1224           return DKERR(DK_STAT_SYNTAX);
1225         }
1226         if (dk->signing != DK_SIGNING_NOVERIFY)
1227         {
1228           /* only remember the Sender if we're verifying already. */
1229           dk->sender = dk_strdup(dk->header + i);
1230           if (dkparse822(dk->sender, 7) != DK_STAT_OK)
1231           {
1232             DK_MFREE(dk->sender);
1233             dk->sender = 0;
1234             return DKERR(DK_STAT_SYNTAX);
1235           }
1236         }
1237         else if (!dk->sender_beforesign)
1238         {
1239           dk->sender_beforesign = dk_strdup(dk->header + i);
1240           if (dkparse822(dk->sender_beforesign, 7) != DK_STAT_OK)
1241           {
1242             DK_MFREE(dk->sender_beforesign);
1243             dk->sender_beforesign = 0;
1244             return DKERR(DK_STAT_SYNTAX);
1245           }
1246         }
1247       }
1248       else if (!strncasecmp(dk->header + i, "DomainKey-Trace:", 16))
1249       {
1250         if (dk->trace && !dk->dktrace)//only set this once
1251         {
1252           dk->dktrace = dk->header + i;
1253         }
1254       }
1255       else if (!strncasecmp(dk->header + i, "DomainKey-Signature:", 20))
1256       {
1257         int thisheaderlen = strlen(dk->header + i);
1258 
1259         /* Do not sign email that already has a dksign unless the Sender was found first, 3.5.2 TC41, TC41-1*/
1260         if (dk->signing == DK_SIGNING_SIGN && !dk->sender)
1261         {
1262           return DKERR(DK_STAT_SYNTAX);
1263         }
1264         /* check the outermost (first encountered) signature (need to fix when multiple sigs are present)
1265         * ONLY if we are verifying, if we are signing then ignore it (sender before dk-sig) -Tim
1266         */
1267         if ((!dk->dksign)&&(dk->signing != DK_SIGNING_SIGN))
1268         {
1269           char *values[7];  /* dsbchqa */
1270           dk->dksign = dk->header + i;
1271           /* parse the dksign header .*/
1272           if (dkparselist(dk->dksign + 20,"dsbchqa", values) != DK_STAT_OK)
1273           {
1274             return DKERR(DK_STAT_SYNTAX);
1275           }
1276 
1277           dk->domain = values[0];
1278           dk->selector = values[1];
1279           dk->signature = values[2];
1280           if (!dk->selector || !dk->domain || !dk->signature)
1281           {
1282             /* we really do need to have a domain, selector and key. TC21 TC40 */
1283             return DKERR(DK_STAT_NOSIG);
1284           }
1285 
1286           if (!values[3])
1287           {
1288             dk->canon = DK_CANON_SIMPLE;
1289           }
1290           else if (!strcasecmp(values[3], "simple"))
1291           {
1292             dk->canon = DK_CANON_SIMPLE;
1293           }
1294           else if (!strcasecmp(values[3], "nofws"))
1295           {
1296             dk->canon = DK_CANON_NOFWS;
1297           }
1298           else
1299           {
1300             return DKERR(DK_STAT_SYNTAX); /* TC42 */
1301           }
1302 
1303           dk->headers = values[4];
1304 
1305           if (values[5] && strcasecmp(values[5], "dns")) /* TC42-2 */
1306           {
1307             return DKERR(DK_STAT_SYNTAX);
1308           }
1309           if (values[6] && strcasecmp(values[6], "rsa-sha1")) /* TC42-3 */
1310           {
1311             return DKERR(DK_STAT_SYNTAX);
1312           }
1313 
1314         }
1315         /* if we're waiting to verify, start now. */
1316         if (dk->signing == DK_SIGNING_NOVERIFY)
1317         {
1318           dk->signing = DK_SIGNING_VERIFY; /* the signature starts here */
1319           i += thisheaderlen;
1320           if (dk->start_signed == 0) //we should set it only once right?
1321           {
1322             dk->start_signed = i;
1323           }
1324         }
1325       }
1326       //end trace
1327     }
1328   }
1329   if ((!dk->from)||(!dk_from(dk)))
1330   {
1331     /* No From:, 3.1 says that it's no good..  TC11/TC16 */
1332     return DKERR(DK_STAT_SYNTAX);
1333   }
1334   if (dk->signing == DK_SIGNING_NOVERIFY)
1335   {
1336     /* No DK-Sig: should return No Signature. */
1337     return DKERR(DK_STAT_NOSIG);
1338   }
1339   if (dk->headers && dk->signing == DK_SIGNING_VERIFY)
1340   {
1341     return dkheaders_header(dk);
1342   }
1343   if ((dk->signing == DK_SIGNING_SIGN)&&(dk->opts & DKOPT_RDUPE)) //remove dupe headers for sig
1344   {
1345     DK_STAT ret;
1346     dk->headers = DK_MALLOC(dk->headermax);
1347     (void *)dk_headers(dk, dk->headers);
1348     ret = dkheaders_header(dk);
1349     DK_MFREE(dk->headers);
1350     return ret;
1351   }
1352   return DKERR(DK_STAT_OK);
1353 }
1354 
1355 /* HEADER */
1356 /* Copies the header names that were signed into the pointer.
1357  * Returns the number of bytes copied.
1358  * ptr may be NULL, in which case the bytes are just counted, not copied.
1359  * Feel free to call this twice; once to get the length, and again to
1360  * copy the data.
1361  * NOTE: If the return value is 0 then an error occured.
1362  *	It's a good idea to check for this
1363  */
dk_headers(DK * dk,char * ptr)1364 int dk_headers(DK *dk, char *ptr)
1365 {
1366   register int len = 0;
1367   register int label_len = 0;
1368   int list_size;
1369   char *header_start = NULL;
1370   char *header_end = NULL;
1371   char *h_label = NULL;
1372   char *h_list = NULL;
1373 
1374   char *dupe_list = NULL;
1375 
1376 
1377   if (ptr) //if you dont check if return is 0, ptr can be anything
1378   	ptr[0] = 0;
1379 
1380   if ((!dk)||(dk->dkmarker != DKMARK))
1381   {
1382     return 0;
1383   }
1384   list_size = dk->headermax;
1385 
1386   h_list = (char *) DK_MALLOC(list_size);
1387   if (!h_list)
1388     return 0;
1389   memset(h_list,0,list_size);
1390   h_list[len++] = ':';
1391 
1392   header_start = dk->header + dk->start_signed;
1393 
1394   for (header_end = header_start; header_end < (dk->header + dk->headerlen); header_end++)
1395   {
1396     if (*header_end == '\0')
1397     {
1398       header_start = header_end+1;//point to start of next line
1399     }
1400     else if (*header_end == ':' && header_start)
1401     {
1402       label_len = (header_end - header_start) + 1;
1403 	  //grow list array
1404 	  if ((len+label_len) >= list_size)
1405 	  {
1406 	  	char *temp = NULL;
1407 		list_size += dk->headermax;
1408 		temp = DK_MALLOC(list_size);
1409 		if (!temp)
1410 		{
1411 			len = 1; //out of memory?
1412 			goto END;
1413 		}
1414 		memset(temp,0,list_size);
1415 		memcpy(temp,h_list,len);
1416 		DK_MFREE(h_list);
1417 		h_list = temp;
1418 	  }
1419 
1420       memcpy(h_list + len, header_start, label_len);
1421       len += label_len;
1422       header_start = NULL;
1423     }
1424   }
1425 
1426   if (dk->opts & DKOPT_RDUPE)
1427   {
1428 
1429     h_label = (char *) DK_MALLOC(list_size);
1430 	dupe_list = (char *) DK_MALLOC(list_size);
1431 
1432     if (!h_label || !dupe_list)
1433 	{
1434       len = 1;
1435 	  goto END;
1436 	}
1437     memset(h_label,0,list_size);
1438     memset(dupe_list,0,list_size);
1439 
1440     len = 0;
1441   	header_start = h_list;
1442 	for (header_end = header_start + 1; *header_end != '\0'; header_end++)
1443 	{
1444 		if (*header_end == ':')
1445 		{
1446 			label_len = (header_end - header_start)+1;
1447 	        memcpy(h_label, header_start, label_len);
1448     	    h_label[label_len] = 0;
1449 			if ((strstr(h_list,h_label) == header_start)  && (strstr(header_start + 1,h_label) == NULL) )
1450 			{
1451 				memcpy(dupe_list + len ,h_label,label_len);
1452 				len += label_len -1;
1453 			}
1454 			header_start = header_end;
1455 		}
1456 	}
1457 	len++;
1458 	if (ptr)
1459 		memcpy(h_list, dupe_list, len);
1460   }
1461 
1462   if ((ptr != NULL)&&(len > 1))
1463   {
1464     memcpy(ptr,h_list+1,(len-2));//dont count the prefix and postfix'd ":"
1465     ptr[len-2] = 0;
1466   }
1467   END:
1468   if (h_label)
1469     DK_MFREE(h_label);
1470   if (h_list)
1471     DK_MFREE(h_list);
1472   if (dupe_list)
1473     DK_MFREE(dupe_list);
1474 
1475   return --len;
1476 
1477 }
1478 
1479 /* HEADER */
1480 /* Must NOT include dots inserted for SMTP encapsulation.
1481  * Must NOT include CRLF.CRLF which terminates the message.
1482  * Otherwise must be exactly that which is sent or received over the SMTP session.
1483  * May be called multiple times (not necessary to read an entire message into memory).
1484  */
dk_message(DK * dk,const unsigned char * ptr,size_t len)1485 DK_STAT dk_message(DK *dk, const unsigned char *ptr, size_t len)
1486 {
1487   DK_STAT st;
1488   int tb=0,th=0;
1489   if (!dk)
1490   {
1491     return DK_STAT_ARGS;
1492   }
1493   if (dk->dkmarker != DKMARK)
1494   {
1495     return DK_STAT_ARGS;
1496   }
1497   if (len && !ptr)
1498   {
1499     return DKERR(DK_STAT_ARGS);
1500   }
1501   if (dk->trace && (dk->opts & DKOPT_TRACE_b))
1502     tb = 1;
1503   if (dk->trace && (dk->opts & DKOPT_TRACE_h))
1504     th = 1;
1505 
1506   while (len--)
1507   {
1508     if ((*ptr == '\n') && (dk->last_char != '\r'))
1509     {
1510       //input not formatted correctly
1511       //CR should preceed LF
1512       return DKERR(DK_STAT_SYNTAX);
1513     }
1514     /* parse headers */
1515     if (!dk->in_headers)
1516     {
1517       dkhash(dk, ptr); //hash body of message
1518       //precanon probably wont be accurate as dk_message() only takes in SMTP format -Tim
1519       if (tb)
1520         dk->trace->ccounts_b[(int) *ptr]++;
1521     }
1522     else if (*ptr == '\n' && dk->headerlinelen != 0)
1523     {
1524       /* beginning a new line, but we can't do anything until we get a char. */
1525       dk->headerlinelen = 0;
1526     }
1527     else if (*ptr == '\r')
1528     {
1529       /* ignore carriage-returns, even bare ones.  We'll add them back in later.*/
1530       if (dk->last_char == '\r') //keep embedded CR
1531       {
1532         if (dkstore_char(dk, '\r') != DK_STAT_OK)
1533         {
1534           return DKERR(DK_STAT_NORESOURCE);
1535         }
1536         if (th)
1537           dk->trace->ccounts_h[13]++;
1538       }
1539     }
1540     else if (dk->headerlinelen)
1541     {
1542 
1543       if (dk->last_char == '\r') //keep embedded CR
1544       {
1545         if (dkstore_char(dk, '\r') != DK_STAT_OK)
1546         {
1547           return DKERR(DK_STAT_NORESOURCE);
1548         }
1549         if (th)
1550           dk->trace->ccounts_h[13]++;
1551       }
1552 
1553       /* if we're not starting a new header, just store it */
1554       if (dkstore_char(dk, *ptr) != DK_STAT_OK)
1555       {
1556         return DKERR(DK_STAT_NORESOURCE);
1557       }
1558       if (th)
1559         dk->trace->ccounts_h[(int) *ptr]++;
1560     }
1561     else if (*ptr == ' ' || *ptr == '\t')
1562     {
1563       /* a new header ... starting with whitespace.  Must be continuation */
1564       /* just remember the whitespace */
1565       //preserv folded headers for simple canon -Tim
1566       if (dkstore_char(dk, '\r') != DK_STAT_OK)
1567       {
1568         return DKERR(DK_STAT_NORESOURCE);
1569       }
1570       if (dkstore_char(dk, '\n') != DK_STAT_OK)
1571       {
1572         return DKERR(DK_STAT_NORESOURCE);
1573       }
1574       if (dkstore_char(dk, *ptr) != DK_STAT_OK)
1575       {
1576         return DKERR(DK_STAT_NORESOURCE);
1577       }
1578       if (th)
1579       {
1580         dk->trace->ccounts_h[10]++;
1581         dk->trace->ccounts_h[13]++;
1582         dk->trace->ccounts_h[(int) *ptr]++;
1583       }
1584 
1585     }
1586     else if (*ptr == '\n')
1587     {
1588       /* an empty line terminates header processing */
1589       /* terminate the previous header */
1590       if (dkstore_char(dk, '\0') != DK_STAT_OK)
1591       {
1592         return DKERR(DK_STAT_NORESOURCE);
1593       }
1594       if (th)
1595       {
1596         dk->trace->ccounts_h[10]++;
1597         dk->trace->ccounts_h[13]++;
1598       }
1599       if (tb)
1600       {
1601         dk->trace->ccounts_b[10]++;
1602         dk->trace->ccounts_b[13]++;
1603       }
1604       st = dkheaders(dk);
1605       dk->in_headers = 0;
1606       dkhash(dk, "\r");
1607       dkhash(dk, "\n");
1608 
1609       if (st != DK_STAT_OK)
1610       {
1611         return st;
1612       }
1613     }
1614     else
1615     {
1616       /* we're starting a new header.  Terminate the previous one. */
1617       if (dkstore_char(dk, '\0') != DK_STAT_OK)
1618       {
1619         return DKERR(DK_STAT_NORESOURCE);
1620       }
1621       /* remember the first character of a new header. */
1622       if (dkstore_char(dk, *ptr) != DK_STAT_OK)
1623       {
1624         return DKERR(DK_STAT_NORESOURCE);
1625       }
1626       if (th)
1627       {
1628         dk->trace->ccounts_h[10]++;
1629         dk->trace->ccounts_h[13]++;
1630         dk->trace->ccounts_h[(int) *ptr]++;
1631       }
1632     }
1633     dk->last_char = *ptr; //remember last character processed
1634     ptr++;
1635   }
1636   return DKERR(DK_STAT_OK);
1637 }
1638 
1639 /* HEADER */
1640 /* DEPRECATED in favor of calling dk_address().
1641  * Returns a pointer to a null-terminated domain name portion of an RFC 2822 address.
1642  * If a Sender: was encountered, it returns that domain.  Otherwise,
1643  * if a From: was encountered, it returns that domain.  Otherwise,
1644  * return NULL.
1645  * return NULL if no domain name found in the address.
1646  * return NULL if the dk is unusable for any reason.
1647  * return NULL if the address is unusable for any reason.
1648  */
dk_from(DK * dk)1649 char *dk_from(DK *dk)
1650 {
1651   char *s;
1652 
1653   if (!dk)
1654   {
1655     return NULL;
1656   }
1657   if (dk->dkmarker != DKMARK)
1658   {
1659     return NULL;
1660   }
1661 
1662   s = NULL;
1663   if (dk->sender)
1664   {
1665     s = dk->sender; /* TC14-1 */
1666   }
1667   else if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY))
1668   {
1669     s = dk->sender_beforesign;
1670   }
1671   else if (dk->from)
1672   {
1673     s = dk->from; /* TC14-2 */
1674   }
1675   if (s && *s && s[1] && s[1] != '@')
1676   {
1677     s = strchr(s, '@') + 1;
1678     if (*s == '\0')
1679     {
1680       //make sure we have an actual domain after @
1681       s = NULL;
1682     }
1683   }
1684   else
1685   {
1686     s = NULL;
1687   }
1688   return s;
1689 }
1690 
1691 /* HEADER */
1692 /* Returns a pointer to the selector name used or NULL if there isn't one
1693  * Added by rjp
1694  */
dk_selector(DK * dk)1695 const char *dk_selector(DK *dk)
1696 {
1697   if (!dk) return NULL;
1698   return (dk->selector);
1699 }
1700 
1701 /* HEADER */
1702 /* Returns a pointer to the domain name used or NULL if there isn't one
1703  */
dk_domain(DK * dk)1704 const char *dk_domain(DK *dk)
1705 {
1706   if (!dk) return NULL;
1707   return (dk->domain);
1708 }
1709 
1710 /* HEADER */
1711 /*
1712  * Returns a pointer to a string which begins with "N", "S", or "F",
1713  * corresponding to None, Sender: and From:, respectively.
1714  * This single character is followed by a null-terminated RFC 2822 address.
1715  * The first character is "N" if no valid address has been seen yet,
1716  * "S" if the address came from the Sender: field, and "F" if the
1717  * address came from the From: field.
1718  */
dk_address(DK * dk)1719 char *dk_address(DK *dk)
1720 {
1721   if ((!dk)||(dk->dkmarker != DKMARK))
1722   {
1723     return "N";
1724   }
1725   if (dk->sender)
1726   {
1727     return dk->sender; /* TC14-3 */
1728   }
1729   if (dk->from)
1730   {
1731     return dk->from; /* TC14-4 */
1732   }
1733   return "N";     /* TC14-5 */
1734 }
1735 
1736 /* HEADER */
1737 /*
1738  * Returns a pointer to a null-terminated string containing the granularity
1739  * value found in the selector DNS record, if any, but only after dk_end
1740  * has been called. Otherwise returns NULL.
1741  */
dk_granularity(DK * dk)1742 char *dk_granularity(DK *dk)
1743 {
1744   if (!dk)
1745   {
1746     return NULL;
1747   }
1748   if (dk->dkmarker != DKMARK)
1749   {
1750     return NULL;
1751   }
1752   return dk->granularity;
1753 }
1754 
1755 /* HEADER */
1756 /*
1757  * Called at end-of-message (before response to DATA-dot, if synchronous with SMTP session).
1758  * If verifying, returns signature validity.
1759  * This does not calculate the signature.  Call dk_getsig() for that.
1760  * Flags are returned indirectly through dkf.
1761  * If you pass in NULL for dkf, the flags will not be fetched.
1762  * If there is a DK-Sig line, the d= entry will be used to fetch the flags.
1763  * Otherwise the Sender: domain will be used to fetch the flags.
1764  * Otherwise the From: domain will be used to fetch the flags.
1765  *
1766  * NOTE: If for some reason dk_end() returns an error (!DK_STAT_OK) dk_policy() should be called
1767  * to get the domain signing policy (o=) and handle accordingly.
1768  * dkf (selector flags) wont be set if dk_end() returns
1769  * DK_STAT_NOSIG
1770  * DK_STAT_NOKEY
1771  * DK_STAT_SYNTAX
1772  * DK_STAT_NORESOURCE
1773  * DK_STAT_BADKEY
1774  * DK_STAT_CANTVERIFY
1775  */
dk_end(DK * dk,DK_FLAGS * dkf)1776 DK_STAT dk_end(DK *dk, DK_FLAGS *dkf)
1777 {
1778   if ((!dk)||(dk->dkmarker != DKMARK))
1779   {
1780     return DK_STAT_ARGS;
1781   }
1782 
1783   /* yes, the only way we can still be in the headers at the end of
1784      the message is if they supplied us with a message that not only
1785      has no body, but also lacks the blank line terminating the
1786      headers.  Still, we have to handle it correctly.  TC13-nobody */
1787   if (dk->in_headers)
1788   {
1789     DK_STAT st;
1790 
1791     if (dkstore_char(dk, '\0') != DK_STAT_OK)
1792     {
1793       return DKERR(DK_STAT_NORESOURCE);
1794     }
1795     st = dkheaders(dk);
1796     if (st != DK_STAT_OK)
1797     {
1798       return st;
1799     }
1800   }
1801 
1802   switch (dk->signing)
1803   {
1804   case DK_SIGNING_SIGN:
1805   case DK_SIGNING_VERIFY:
1806     //force hash final CRLF to terminate email
1807 #ifdef DK_HASH_BUFF
1808     //clean out hash buffer
1809     dk->hash_buff[dk->hash_buff_len++] = '\r';
1810     dk->hash_buff[dk->hash_buff_len++] = '\n';
1811 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1812     EVP_DigestUpdate(&dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1813 #else
1814     EVP_DigestUpdate(dk->mdctx, dk->hash_buff, dk->hash_buff_len);
1815 #endif
1816     dk->hash_buff_len = 0;
1817 #else
1818 #if OPENSSL_VERSION_NUMBER < 0x10100001L
1819     EVP_DigestUpdate(&dk->mdctx, "\r\n", 2);
1820 #else
1821     EVP_DigestUpdate(dk->mdctx, "\r\n", 2);
1822 #endif
1823 #endif
1824 #ifdef DK_DEBUG
1825     fprintf(stderr,"\r\n");
1826 #endif
1827 
1828   }
1829 
1830   switch (dk->signing)
1831   {
1832   case DK_SIGNING_SIGN:
1833   case DK_SIGNING_NOSIGN:
1834     if (!dk->from)
1835     {
1836       return DKERR(DK_STAT_SYNTAX);
1837     }
1838     return DKERR(DK_STAT_OK);
1839   case DK_SIGNING_VERIFY:
1840   case DK_SIGNING_NOVERIFY:
1841     {
1842       unsigned char md_value[1024];
1843       int md_len=0;
1844       char *s = NULL; //pointer to domain portion of email addy
1845       char *sndr = NULL;
1846       char *domainkeys; /* malloc'ed */
1847       char *txtrec; /* malloc'ed */
1848       char *pubkeyvals[4];
1849       int i;
1850       DK_STAT st;
1851 
1852       BIO *bio, *b64;
1853       EVP_PKEY *publickey;
1854 
1855       /* make sure that we got a header */
1856       if (!dk->dksign)
1857       {
1858         return DKERR(DK_STAT_NOSIG); /* TC11 */
1859       }
1860 
1861       /* make sure that domain on the From: matches the d data. TC26 */
1862       /* Or is a subdomain of the d data.  TC26-1, etc. */
1863       if (dk->sender)
1864       {
1865         sndr = dk->sender;
1866       }
1867       else if (dk->sender_beforesign && (dk->signing == DK_SIGNING_NOVERIFY))
1868       {
1869         sndr = dk->sender_beforesign;
1870       }
1871       else
1872       {
1873         sndr = dk->from;
1874       }
1875 
1876       if (!sndr)
1877       {
1878         return DKERR(DK_STAT_SYNTAX);
1879       }
1880       /* we already know that sndr has an '@' in it; otherwise it would not
1881       * have passed dkparse822. */
1882 
1883       /* sndr can also be a one-character string if the from/sender header
1884       * was there but empty */
1885       if (!(s = strchr(sndr, '@')))
1886       {
1887         return DKERR(DK_STAT_SYNTAX);
1888       }
1889       s++; // we skip the tag
1890 
1891       i = (int)strlen(s);
1892       if (strcasecmp(dk->domain, s))
1893       {
1894         for (; md_len < i; md_len++)
1895         {
1896           if (s[md_len] == '.')
1897           {
1898             if (!strcasecmp(dk->domain, s + md_len + 1))
1899             {
1900               break;
1901             }
1902           }
1903         }
1904       }
1905       if (md_len == i)
1906       {
1907         return DKERR(DK_STAT_SYNTAX);
1908       }
1909 
1910       /* convert their signature from base64 into binary */
1911       bio = BIO_new_mem_buf(dk->signature, -1);
1912       b64 = BIO_new(BIO_f_base64());
1913       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1914       BIO_push(b64, bio);
1915       md_len = BIO_read(b64, md_value, sizeof(md_value));
1916       BIO_free_all(b64);
1917       if (md_len >= sizeof(md_value))
1918       {
1919         return DKERR(DK_STAT_NORESOURCE);
1920       }
1921 
1922       /* allow user to supply the DNS TXT key record */
1923       if (!dk->keyrec )
1924       {
1925         /* get the s data and the d data and lookup s._domainkey.d */
1926         domainkeys = DK_MALLOC(strlen(dk->selector) + strlen(dk->domain) + strlen("._domainkey.") + 1);
1927         if (!domainkeys)
1928         {
1929           return DKERR(DK_STAT_NORESOURCE);
1930         }
1931         sprintf(domainkeys, "%s._domainkey.%s", dk->selector, dk->domain);
1932         txtrec = dns_text(domainkeys);
1933         DK_MFREE(domainkeys);
1934       }
1935       else
1936       {
1937         txtrec = dk_strdup(dk->keyrec);
1938       }
1939 
1940       if (!strcmp(txtrec,"e=perm;")) /* TC31 */
1941       {
1942         DK_MFREE(txtrec);
1943         return DKERR(DK_STAT_NOKEY);
1944       }
1945 
1946       if (!strcmp(txtrec,"e=temp;")) /* TC30 */
1947       {
1948         DK_MFREE(txtrec);
1949         return DKERR(DK_STAT_CANTVRFY);
1950       }
1951 
1952       if (dkparselist(txtrec, "ptog", pubkeyvals) != DK_STAT_OK)
1953       {
1954         DK_MFREE(txtrec);
1955         return DKERR(DK_STAT_BADKEY);
1956       }
1957       if (dkf) //set this asap
1958       {
1959         /* TC35 and TC37 */
1960         if (pubkeyvals[1] && *pubkeyvals[1] == 'y')
1961         {
1962           *dkf |= DK_FLAG_TESTING;
1963         }
1964         /* tell them that we got the g= flag.  This means that the entire
1965          * address matches, not just the domain name */
1966         if (pubkeyvals[3] && *pubkeyvals[3])
1967         {
1968           *dkf |= DK_FLAG_G;
1969         }
1970         *dkf |= DK_FLAG_SET;
1971       }
1972       /* Store the granularity, if any, and check it against the local part
1973        * of the sending address */
1974 
1975       if (pubkeyvals[3] && *pubkeyvals[3])
1976       {
1977         dk->granularity = dk_strdup(pubkeyvals[3]);
1978 		// Note that sndr has a leading 'F' or 'S'
1979         if (strncasecmp(dk->granularity, sndr+1, strcspn(sndr+1,"@")))
1980 		{
1981 	        DK_MFREE(txtrec);
1982 	  		return DKERR(DK_STAT_GRANULARITY);
1983 		}
1984       }
1985       if (!pubkeyvals[0])
1986       {
1987         DK_MFREE(txtrec);
1988         return DKERR(DK_STAT_NOKEY); /* TC27 */
1989       }
1990 
1991       if (!*pubkeyvals[0])
1992       {
1993         DK_MFREE(txtrec);
1994         return DKERR(DK_STAT_REVOKED); /* TC27 */
1995       }
1996 
1997       /* convert their public key from base64 into binary */
1998       bio = BIO_new_mem_buf(pubkeyvals[0], -1);
1999       if (!bio)
2000       {
2001         DK_MFREE(txtrec);
2002         return DKERR(DK_STAT_NORESOURCE);
2003       }
2004       b64 = BIO_new(BIO_f_base64());
2005       if (!b64)
2006       {
2007         DK_MFREE(txtrec);
2008         BIO_free(bio);
2009         return DKERR(DK_STAT_NORESOURCE);
2010       }
2011       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
2012       BIO_push(b64, bio);
2013       publickey = d2i_PUBKEY_bio(b64, NULL);
2014       BIO_free_all(b64);
2015       DK_MFREE(txtrec);
2016       if (!publickey)
2017       {
2018         return DKERR(DK_STAT_BADKEY);
2019       }
2020 
2021       /* using that key, verify that the digest is properly signed */
2022 #if OPENSSL_VERSION_NUMBER < 0x10100001L
2023       i = EVP_VerifyFinal(&dk->mdctx, md_value, md_len, publickey);
2024 #else
2025       i = EVP_VerifyFinal(dk->mdctx, md_value, md_len, publickey);
2026 #endif
2027 
2028       if (i > 0)
2029       {
2030         st = DK_STAT_OK;
2031       }
2032       else
2033       {
2034         st = DK_STAT_BADSIG;
2035       }
2036       EVP_PKEY_free(publickey);
2037       return DKERR(st);
2038     }
2039   }//End switch
2040   return DK_STAT_ARGS;
2041 }
2042 
2043 
2044 /* HEADER */
2045 /*
2046  * DEPRECATED in favor of calling dk_end and dk_policy() directly.
2047  * If you pass in NULL for dkf, the policy flags will not be fetched.
2048  * If the message verified okay, the policy flags will not be fetched.
2049  */
dk_eom(DK * dk,DK_FLAGS * dkf)2050 DK_STAT dk_eom(DK *dk, DK_FLAGS *dkf)
2051 {
2052   DK_STAT dkstat;
2053 
2054   dkstat = dk_end(dk, dkf);  /* TC36* */
2055   if (dkf && dkstat != DK_STAT_OK)
2056   {
2057     *dkf |= dk_policy(dk);
2058   }
2059   return dkstat;
2060 }
2061 
2062 
2063 /* HEADER */
2064 /*
2065  *
2066  * privatekey is the private key used to create the signature; It should contain
2067  * the entire contents of a PEM-format private key file, thusly it will begin with
2068  * -----BEGIN RSA PRIVATE KEY-----.  It should be null-terminated.
2069  */
dk_siglen(void * privatekey)2070 size_t dk_siglen(void *privatekey)
2071 {
2072   BIO *bio;
2073   EVP_PKEY *pkey;
2074   size_t len;
2075 
2076   if (!privatekey)
2077   {
2078     return 0;
2079   }
2080 
2081   bio = BIO_new_mem_buf(privatekey, -1);
2082   pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
2083   BIO_free(bio);
2084 
2085   len = (EVP_PKEY_size(pkey) + 2) / 3 * 4;
2086   EVP_PKEY_free(pkey);
2087   return len;
2088 }
2089 
2090 
2091 /* HEADER */
2092 /*
2093  * Sets buf to a null-terminated string.
2094  * If the message is being signed, signature is stored in the buffer.
2095  * If the message is being verified, returns DK_STAT_INTERNAL.
2096  * privatekey is the private key used to create the signature; It should contain
2097  * the entire contents of a PEM-format private key file, thus it will begin with
2098  * -----BEGIN RSA PRIVATE KEY-----.  It should be null-terminated.
2099  * If you pass in NULL for buf, you'll get back DK_STAT_NORESOURCE.
2100  * If len is not big enough, you'll get back DK_STAT_NORESOURCE.
2101  */
dk_getsig(DK * dk,void * privatekey,unsigned char buf[],size_t len)2102 DK_STAT dk_getsig(DK *dk, void *privatekey, unsigned char buf[], size_t len)
2103 {
2104   if ((!dk)||(dk->dkmarker != DKMARK)||(!privatekey))
2105   {
2106     return DK_STAT_ARGS;
2107   }
2108   if (!buf)
2109   {
2110     return DKERR(DK_STAT_NORESOURCE);
2111   }
2112   switch (dk->signing)
2113   {
2114     case DK_SIGNING_SIGN:
2115     case DK_SIGNING_NOSIGN:
2116     {
2117       unsigned int siglen;
2118       unsigned char *sig;
2119       int size;
2120       BIO *bio, *b64;
2121       EVP_PKEY *pkey;
2122 
2123       bio = BIO_new_mem_buf(privatekey, -1);
2124       pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
2125       BIO_free(bio);
2126 
2127       if (!pkey)
2128       {
2129         /* their private key is no good TC33 */
2130         return DKERR(DK_STAT_BADKEY);
2131       }
2132 
2133       siglen = EVP_PKEY_size(pkey);
2134       sig = (unsigned char*) OPENSSL_malloc(siglen);
2135 #if OPENSSL_VERSION_NUMBER < 0x10100001L
2136       EVP_SignFinal(&dk->mdctx, sig, &siglen, pkey);
2137 #else
2138       EVP_SignFinal(dk->mdctx, sig, &siglen, pkey);
2139 #endif
2140       EVP_PKEY_free(pkey);
2141 
2142       bio = BIO_new(BIO_s_mem());
2143       if (!bio)
2144       {
2145         return DKERR(DK_STAT_NORESOURCE);
2146       }
2147       b64 = BIO_new(BIO_f_base64());
2148       if (!b64)
2149       {
2150         BIO_free(bio);
2151         return DKERR(DK_STAT_NORESOURCE);
2152       }
2153       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
2154       BIO_push(b64, bio);
2155       if ((size_t)BIO_write(b64, sig, siglen) < siglen)
2156       {
2157         OPENSSL_free(sig);
2158         BIO_free_all(b64);
2159         return DKERR(DK_STAT_NORESOURCE);
2160       }
2161       BIO_flush(b64);
2162       OPENSSL_free(sig);
2163 
2164       size = BIO_read(bio, buf, len);
2165       BIO_free_all(b64);
2166 
2167       if ((size_t)size >= len)
2168       {
2169         return DKERR(DK_STAT_NORESOURCE); /* TC28 */
2170       }
2171 
2172       buf[size] = '\0';
2173       return DKERR(DK_STAT_OK);
2174     }
2175     case DK_SIGNING_VERIFY:
2176     case DK_SIGNING_NOVERIFY:
2177       return DKERR(DK_STAT_INTERNAL);
2178   }//end switch
2179   return DK_STAT_ARGS;
2180 }
2181 
2182 
2183 /* HEADER */
2184 /*
2185  * Free all resources associated with this message.
2186  * dk is no longer usable.
2187  * if doClearErrState != 0, the OpenSSL ErrorState is freed.
2188  * Set clearErrState=0 if you use other openssl functions and
2189  * want to call openssl's ERR_remove_state(0) by yourself
2190  * ERR_remove_state(0) is declared in <openssl/err.h>
2191  */
dk_free(DK * dk,int doClearErrState)2192 DK_STAT dk_free(DK *dk, int doClearErrState)
2193 {
2194   if ((!dk)||(dk->dkmarker != DKMARK))
2195   {
2196     return DK_STAT_ARGS;
2197   }
2198   if (dk->from)
2199   {
2200     DK_MFREE(dk->from);
2201   }
2202   if (dk->sender)
2203   {
2204     DK_MFREE(dk->sender);
2205   }
2206   if (dk->sender_beforesign)
2207   {
2208     DK_MFREE(dk->sender_beforesign);
2209   }
2210   if (dk->trace)
2211   {
2212     DK_MFREE(dk->trace);
2213   }
2214   if (dk->traceheader)
2215   {
2216     DK_MFREE(dk->trace);
2217   }
2218   if (dk->keyrec)
2219   {
2220     DK_MFREE(dk->keyrec);
2221   }
2222   if (dk->policyrec)
2223   {
2224     DK_MFREE(dk->policyrec);
2225   }
2226   if (dk->granularity)
2227   {
2228     DK_MFREE(dk->granularity);
2229   }
2230 #ifdef DK_HASH_BUFF
2231   DK_MFREE(dk->hash_buff);
2232 #endif
2233 #if OPENSSL_VERSION_NUMBER < 0x10100001L
2234   EVP_MD_CTX_cleanup(&dk->mdctx);
2235 #else
2236   EVP_MD_CTX_free(dk->mdctx);
2237 #endif
2238   DK_MFREE(dk->header);   /* alloc'ing dk->header is not optional. */
2239   dk->dkmarker = ~DKMARK;
2240   DK_MFREE(dk);
2241 
2242   if (doClearErrState)
2243   {
2244      ERR_remove_state(0);
2245   }
2246   return DK_STAT_OK;
2247 }
2248 
2249 /* HEADER */
2250 /*
2251  * return a pointer to a string which describes st.
2252  * The string is structured.  All the characters up to the first colon
2253  * contain the name of the DK_STAT constant.  From there to the end of
2254  * string is a human-readable description of the error.
2255  */
DK_STAT_to_string(DK_STAT st)2256 const char *DK_STAT_to_string(DK_STAT st)
2257 {
2258   /* TC53 */
2259   if (st >= (sizeof errors) / (sizeof errors[0]))
2260   {
2261     return "DK_STAT_UNKNOWN: unknown status";
2262   }
2263   else
2264   {
2265     return errors[st];
2266   }
2267 }
2268 
2269 
2270