#include <stdio.h>
#include <string.h>
#include <domainkeys.h>
#include <unistd.h>
#include <stdlib.h>
int optf = 0;
int errorout(DK *dk,DK_STAT st) {
if (optf && dk) fprintf(stderr, "%s(%d):",dk_errfile(dk),dk_errline(dk));
fprintf(stderr, "dktest: %s\n", DK_STAT_to_string(st));
exit(1);
}
int main(int argc, char *argv[]) {
char inbuf[1024];
size_t inlen;
char advice[2048];
size_t advicelen = sizeof(advice);
DK *dk;
DK_LIB *dklib;
char trace_count[BUFSIZ];
DK_STAT st,dkt_st;
char ch;
int opts=0, optv=0, optt=0, opth=0,optr=0, optT = 0,optc=DK_CANON_SIMPLE;
int local_term = -1, i = 0;
char *inp;
char *start;
char *canon = "simple";
char *keyfn = NULL;
char *selector = NULL;
char privkey[2048];
FILE *privkeyf = NULL;
size_t privkeylen;
DK_FLAGS dkf = 0;
DK_TRACE_TYPE dk_trace_tag[4] =
{
DKT_RAW_HEADER,
DKT_CANON_HEADER,
DKT_RAW_BODY,
DKT_CANON_BODY
};
while (1) {
ch = getopt(argc, argv,"s:vt:fb:c:hrT");
if (ch == -1) break;
switch (ch) {
case 'T':
optT = 1;
break;
case 'v':
optv = 1;
break;
case 'f':
optf = 1;
break;
case 'r':
optr = 1;
opth = 1;
break;
case 's':
opts = 1;
keyfn = optarg;
selector = optarg;
while (*optarg) {
if (*optarg == '/')
selector = optarg+1;
optarg++;
}
break;
case 't':
optt = atoi(optarg);
break;
case 'h':
opth = 1;
break;
case 'b':
advicelen = atoi(optarg);
if (advicelen > sizeof(advice)) advicelen = sizeof(advice);
break;
case 'c':
if (!strcmp(optarg, "simple")) optc = DK_CANON_SIMPLE, canon = "simple";
else if (!strcmp(optarg, "nofws")) optc = DK_CANON_NOFWS, canon = "nofws";
else {
fprintf(stderr, "dktest: unrecognized canonicalization.\n");
exit(1);
}
}
}
if (opts) {
privkeyf = fopen(keyfn, "r");
if (!privkeyf) { /*TC10*/
fprintf(stderr, "dktest: can't open private key file %s\n", keyfn);
exit(1);
}
privkeylen = fread(privkey, 1, sizeof(privkey), privkeyf);
if (privkeylen == sizeof(privkey)) { /* TC9 */
fprintf(stderr, "dktest: private key buffer isn't big enough, use a smaller private key or recompile.\n");
exit(1);
}
privkey[privkeylen] = '\0';
fclose(privkeyf);
}
if (optt == 1) errorout(NULL,0); /*TC2*/
if (optt == 2) errorout(NULL,32767); /*TC3*/
dklib = dk_init(&st);
if (st != DK_STAT_OK) errorout(NULL,st);
if (!dklib) errorout(NULL, 200);
if (optv)
{
dk = dk_verify(dklib, &st);
if (st != DK_STAT_OK)
errorout(dk,st);
}
else if (opts)
{
dk = dk_sign(dklib, &st, optc);
if (st != DK_STAT_OK)
errorout(dk,st);
if (optr)
st = dk_setopts(dk,DKOPT_RDUPE);
if (st != DK_STAT_OK)
errorout(dk,st);
}
else
{
fprintf(stderr, "dktest: [-f] [-b#] [-c nofws|simple] [-v|-s selector] [-h] [-t#] [-r] [-T]\n"); /* TC1 */
exit(1);
}
if (optT)//trace
{
//(DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B)
st = dk_setopts(dk,(DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B));
if (st != DK_STAT_OK)
errorout(dk,st);
}
if (optt == 3) errorout(dk,dk_message(NULL, "", 1)); /* TC4 */
if (optt == 4) errorout(dk,dk_message(dk, NULL, 1)); /* TC5 */
if (optt == 5) errorout(dk,dk_message(dk, "", 0)); /* TC6 */
if (optt >= 100 && optt <= 140)
errorout(dk,optt-100); /* TC53 */
st = DK_STAT_OK;
/* This should work with DOS or UNIX text files -Tim
* Reduced calls to dk_message, in lib dkhash called for EVERY char
* DOS formatted input (CRLF line terminated) will have fewer calls
* to dk_message() than UNIX (LF line terminated) input.
*/
while (1)
{
inlen = fread(inbuf, 1, sizeof(inbuf), stdin);
inp = inbuf;
start = inbuf;
i = 0;
//check if local line term is CRLF(DOS) or LF(UNIX,default)
//Anything else will probably not work correctly. -Tim
if (local_term == -1)
{
char *lf = NULL;
if ((lf = strchr(inbuf, (int)'\n')) != NULL)
{//if no newline is found assume UNIX, until we find one
if ((lf != inp ) && (*(--lf) == '\r'))
local_term = 1;
else
local_term = 0;
}
}
if (local_term > 0) //CRLF already
{
if (st==DK_STAT_OK)
st = dk_message(dk,inp,inlen);
if (inlen < sizeof(inbuf))
break;
else
continue;
}
while (inlen--)
{
if (*inp == '\n')
{
if (st==DK_STAT_OK && i)
{
st = dk_message(dk, start, i);
i = 0;
}
inp++;
start = inp;
if (st==DK_STAT_OK)
st = dk_message(dk, "\r\n", 2);
}
else
{
inp++;
i++;
}
if (st != DK_STAT_OK)
break; //stop looping if there was an error
}
if (st==DK_STAT_OK && i)
st = dk_message(dk, start, i);
if ((inp-inbuf < sizeof(inbuf)) || (st != DK_STAT_OK))
break; //if we read in the entire message or encountered an error
}
if (st==DK_STAT_OK) {
if (optt == 10) st = dk_end(dk, &dkf);
else st = dk_eom(dk, &dkf);
}
if (optT)
{
printf("DomainKey-Trace: U=http://domainkeys.sourceforge.net; V=TESTING;\n");
for (i = 0; i < 4; i++)
{
if (dk_get_trace(dk,dk_trace_tag[i],trace_count,sizeof(trace_count)) != DK_STAT_OK)
{
fprintf(stderr,"dktest: Not enough resources for trace buffer output\n");
break;
}
else
{
printf(" %s\n",trace_count);
}
}
if (optv)
{
printf("DomainKey-Trace-Diff:\n");
for (i = 0; i < 4; i++)
{
dkt_st = dk_compare_trace(dk,dk_trace_tag[i],trace_count,sizeof(trace_count));
if (dkt_st == DK_STAT_NOSIG)
{
printf(" No DK-Trace: header found\n");
break;
}
else if (dkt_st != DK_STAT_OK)
{
fprintf(stderr,"dktest: Not enough resources for trace buffer output\n");
break;
}
else
printf(" %s\n",trace_count);
}
}
}
if ((optt == 6 || optt == 10) && optv) {
printf("flags: ");
if (dkf & DK_FLAG_SET) printf("+");
if (dkf & DK_FLAG_TESTING) printf("t");
if (dkf & DK_FLAG_SIGNSALL) printf("s");//wont be set if dk_end() is sucessful
if (dkf & DK_FLAG_G) printf("g");
printf("\n");
} else if (optt == 6 && opts) {
errorout(dk, dk_getsig(dk, NULL, NULL, advicelen)); /* TC14 */
} else if (optt == 7) {
char *from = dk_from(dk);
if (!from) from = "";
printf("%s\n",from); /* TC14-1, TC14-2 */
} else if (optt == 11) {
char *from = dk_address(dk);
printf("%s\n",from); /* TC14-3, TC14-4 */
} else if (optt == 9) {
char *s;
s = malloc(dk_headers(dk, NULL));
dk_headers(dk, s);
printf("%s\n",s);
free(s);
} else if (optt == 8 && opts) {
dk_getsig(dk, privkey, advice, advicelen);
if (st != DK_STAT_OK) errorout(dk,st);
printf("%d %d\n",dk_siglen(privkey), strlen(advice)); /* TC39 */
} else if (opts) {
if (st != DK_STAT_OK) errorout(dk,st);
st = dk_getsig(dk, privkey, advice, advicelen);
if (st != DK_STAT_OK) errorout(dk,st);
printf("Comment: DomainKeys? See http://domainkeys.sourceforge.net/\n"
"DomainKey-Signature: a=rsa-sha1; q=dns; c=%s;\n"
" s=%s; d=%s;\n"
" b=%s;\n", canon, selector, dk_from(dk), advice);
if (opth == 1)
{
if (dk_headers(dk,NULL) < sizeof(inbuf))
{
dk_headers(dk,inbuf);
printf(" h=%s;\n",inbuf);
}
}
} else if (optv) {
char *status = NULL;
switch(st) {
case DK_STAT_OK: status = "good"; break;
case DK_STAT_BADSIG: status = "bad"; break;
case DK_STAT_NOSIG: status = "no signature"; break;
case DK_STAT_NOKEY:
case DK_STAT_CANTVRFY: status = "no key"; break;
case DK_STAT_BADKEY: status = "bad key"; break;
case DK_STAT_INTERNAL:
case DK_STAT_ARGS:
case DK_STAT_SYNTAX: status = "bad format"; break;
case DK_STAT_NORESOURCE: status = "no resources"; break;
case DK_STAT_REVOKED: status = "revoked"; break;
}
printf("Comment: DomainKeys? See http://domainkeys.sourceforge.net/\n"
"DomainKey-Status: %s\n", status);
rewind(stdin);
}
if (st != DK_STAT_OK) errorout(dk,st);
dk_free(dk,1);//cleanup properly (not really necessary for single run process)
dk_shutdown(dklib);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1