40#define MYRSASELECTOR "default"
41#define MYECCSELECTOR "eddy"
45#define strnicmp strncasecmp
50 if (
strnicmp(szHeader,
"X-",2) == 0 ) {
return 0; }
61 char version[] =
"1.4.0";
62 fprintf(
FDLOG,
"qmail-dkim %s \n",version);
63 fprintf(
FDLOG,
"Usage: qmail-dkim [-h|-v|-s] [tags] <msgfile> [<RSAkeyfile> <outfile> <Ed25519keyfile>]\n\n");
64 fprintf(
FDLOG,
"Options:\n\t-h show this help\n");
65 fprintf(
FDLOG,
"\t-s sign the message \n");
66 fprintf(
FDLOG,
"\t-v verify the message\n");
67 fprintf(
FDLOG,
"\t-V verify the message and write result to output file (Pass/Fail)\n\n");
68 fprintf(
FDLOG,
"These tags are available:\n");
69 fprintf(
FDLOG,
"\t-c<canonicalization> - r=relaxed [DEFAULT], s=simple, t=relaxed/simple, u=simple/relaxed\n");
70 fprintf(
FDLOG,
"\t-d<sdid> - Signing Domain Identifier (if not provided it will be determined from the sender/from header)\n");
71 fprintf(
FDLOG,
"\t-i<auid> - Agent User Identifier, usually the sender's email address (optional)\n");
72 fprintf(
FDLOG,
"\t-l - include body length tag (optional)\n");
73 fprintf(
FDLOG,
"\t-q - include query method tag\n");
74 fprintf(
FDLOG,
"\t-t - include a timestamp tag (optional)\n");
75 fprintf(
FDLOG,
"\t-x<expire_time> - the expire time in seconds since epoch (optional, DEFAULT = current time + 604800)\n");
76 fprintf(
FDLOG,
"\t-y<selector> - set RSA selector (DEFAULT: default)\n");
77 fprintf(
FDLOG,
"\t-Y<selector> - set Ed25519 selector (DEFAULT: default)\n");
78 fprintf(
FDLOG,
"\t-z<hash> - set signature algorithm type (1=rsa-sha1, 2=rsa-sha256, 3=both, 4=ed25519, 5=hybrid)\n");
81int main(
int argc,
char* argv[])
84 const char* RSAKeyFile =
"rsa.pem";
85 const char* ECCKeyFile =
"ed25519.pem";
86 const char* MsgFile =
"test.msg";
87 const char* OutFile =
"signed.msg";
89 char RSAPrivKey[4196];
93 char szSignature[8192];
115 int nArgParseState = 0;
124 for (n = 1; n < argc; n++) {
125 if (argv[n][0] ==
'-' && strlen(argv[n]) > 1) {
126 switch (argv[n][1]) {
134 strncpy(opts.
szDomain,(
const char*)(argv[n] + 2),
sizeof(opts.
szDomain) - 1);
143 if (argv[n][2] ==
'-') { opts.
szIdentity[0] =
'\0'; }
163 if (argv[n][2] ==
'-') { opts.
expireTime = 0; }
164 else { opts.
expireTime = t + atoi(argv[n] + 2); }
173 opts.
nHash = atoi(&argv[n][2]);
177 switch (nArgParseState) {
182 RSAKeyFile = argv[n];
188 ECCKeyFile = argv[n];
198 if (opts.
nHash != 4) {
199 FILE* RSAPrivKeyFP = fopen(RSAKeyFile,
"r");
200 if (RSAPrivKeyFP == NULL) {
202 fprintf(
FDLOG,
" qmail-dkim: can't open private key file (%s) \n",RSAKeyFile);
206 nKeyLen = fread(RSAPrivKey,1,
sizeof(RSAPrivKey),RSAPrivKeyFP);
208 fprintf(
FDLOG,
" qmail-dkim: private key file (%s) - length %i \n",RSAKeyFile,nKeyLen);
210 if (nKeyLen >=
sizeof(RSAPrivKey)) {
212 fprintf(
FDLOG,
" qmail-dkim: private key buffer isn't big enough for private key length %i \n",nKeyLen);
216 RSAPrivKey[nKeyLen] =
'\0';
217 fclose(RSAPrivKeyFP);
223 FILE* ECCPrivKeyFP = fopen(ECCKeyFile,
"r");
224 if (ECCPrivKeyFP == NULL) {
226 fprintf(
FDLOG,
" qmail-dkim: can't open Ed25519 private key file (%s) \n",ECCKeyFile);
230 nKeyLen = fread(ECCPrivKey,1,
sizeof(ECCPrivKey),ECCPrivKeyFP);
232 fprintf(
FDLOG,
" qmail-dkim: Ed25519 private key file (%s) - length %i \n",ECCKeyFile,nKeyLen);
234 if (nKeyLen >=
sizeof(ECCPrivKey)) {
236 fprintf(
FDLOG,
" qmail-dkim: ECC private key buffer isn't big enough for ECC private key length %i \n",nKeyLen);
240 ECCPrivKey[nKeyLen] =
'\0';
241 fclose(ECCPrivKeyFP);
246 FILE* MsgFP = fopen(MsgFile,
"rb");
249 fprintf(
FDLOG,
" qmail-dkim: can't open msg file (%s) \n",MsgFile);
257 BufLen = fread(Buffer,1,
sizeof(Buffer),MsgFP);
269 strcpy(szSignature,pSig);
273 FILE*
in = fopen(MsgFile,
"rb");
274 FILE*
out = fopen(OutFile,
"wb+");
277 fprintf(
FDLOG,
" outfile written %s \n",OutFile);
280 fwrite(szSignature,1,strlen(szSignature),
out);
281 fwrite(
"\r\n",1,2,
out);
284 BufLen = fread(Buffer,1,
sizeof(Buffer),
in);
285 if (BufLen > 0) { fwrite(Buffer,1,BufLen,
out); }
295 FILE*
in = fopen(MsgFile,
"rb");
298 fprintf(
FDLOG,
" qmail-dkim: can't open input file\n");
309 BufLen = fread(Buffer,1,
sizeof(Buffer),
in);
322 for (
int i = 0; i < nSigCount; i++) {
323 const char s[] =
"pass";
324 const char f[] =
"fail";
327 fprintf(
FDLOG,
" Signature #%d: ",i + 1);
328 if (pDetails[i].nResult >= 0 ) {
337 printf(
" Fail %s \n",error);
void DKIM_CALL DKIMSignFree(DKIMContext *pSignContext)
int DKIM_CALL DKIMSignInit(DKIMContext *pSignContext, DKIMSignOptions *pOptions)
int DKIM_CALL DKIMVerifyGetDetails(DKIMContext *pVerifyContext, int *nSigCount, DKIMVerifyDetails **pDetails, char *szPractices)
void DKIM_CALL DKIMVerifyFree(DKIMContext *pVerifyContext)
int DKIM_CALL DKIMSignGetSig2(DKIMContext *pSignContext, char *szRSAPrivKey, char *szECCPrivKey, char **pszSignature)
int DKIM_CALL DKIMSignProcess(DKIMContext *pSignContext, char *szBuffer, int nBufLength)
int DKIM_CALL DKIMVerifyProcess(DKIMContext *pVerifyContext, const char *const szBuffer, int nBufLength)
int DKIM_CALL DKIMVerifyInit(DKIMContext *pVerifyContext, DKIMVerifyOptions *pOptions)
int DKIM_CALL DKIMVerifyResults(DKIMContext *pVerifyContext)
#define DKIM_SIGN_RELAXED
#define DKIM_SIGN_RELAXED_SIMPLE
#define DKIM_SIGN_SIMPLE_RELAXED
int _DKIM_ReportResult(const char *ResFile, const char *result, const char *reason)
const char * DKIM_ErrorResult(const int res)
void exit(int fail)
Supported storage methods: (1) authuser:[=]plainpasswd, (2) authuser:hashpasswd, (3) authuser:?...
int DKIM_CALL SignThisHeader(const char *szHeader)
int DKIM_CALL SelectorCallback(const char *szFQDN, char *szBuffer, int nBufLen)
int nIncludeBodyLengthTag
char szRequiredHeaders[256]
DKIMHEADERCALLBACK pfnHeaderCallback
int nIncludeCopiedHeaders
DKIMDNSCALLBACK pfnSelectorCallback