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