41#define MYRSASELECTOR "default"
42#define MYECCSELECTOR "eddy"
46#define strnicmp strncasecmp
51 if (
strnicmp(szHeader,
"X-",2) == 0 ) {
return 0; }
62 char version[] =
"1.4.1";
63 fprintf(
FDLOG,
"qmail-dkim %s \n",version);
64 fprintf(
FDLOG,
"Usage: qmail-dkim [-h|-v|-s] [tags] <msgfile> [<RSAkeyfile> <outfile> <Ed25519keyfile>]\n\n");
65 fprintf(
FDLOG,
"Options:\n\t-h show this help\n");
66 fprintf(
FDLOG,
"\t-s sign the message \n");
67 fprintf(
FDLOG,
"\t-v verify the message\n");
68 fprintf(
FDLOG,
"\t-V verify the message and write result to output file (Pass/Fail)\n\n");
69 fprintf(
FDLOG,
"These tags are available:\n");
70 fprintf(
FDLOG,
"\t-c<canonicalization> - r=relaxed [DEFAULT], s=simple, t=relaxed/simple, u=simple/relaxed\n");
71 fprintf(
FDLOG,
"\t-d<sdid> - Signing Domain Identifier (if not provided it will be determined from the sender/from header)\n");
72 fprintf(
FDLOG,
"\t-i<auid> - Agent User Identifier, usually the sender's email address (optional)\n");
73 fprintf(
FDLOG,
"\t-l - include body length tag (optional)\n");
74 fprintf(
FDLOG,
"\t-q - include query method tag\n");
75 fprintf(
FDLOG,
"\t-t - include a timestamp tag (optional)\n");
76 fprintf(
FDLOG,
"\t-x<expire_time> - the expire time in seconds since epoch (optional, DEFAULT = current time + 604800)\n");
77 fprintf(
FDLOG,
"\t-y<selector> - set RSA selector (DEFAULT: default)\n");
78 fprintf(
FDLOG,
"\t-Y<selector> - set Ed25519 selector (DEFAULT: default)\n");
79 fprintf(
FDLOG,
"\t-z<hash> - set signature algorithm type (1=rsa-sha1, 2=rsa-sha256, 3=both, 4=ed25519, 5=hybrid)\n");
82int main(
int argc,
char* argv[])
85 const char* RSAKeyFile =
"rsa.pem";
86 const char* ECCKeyFile =
"ed25519.pem";
87 const char* MsgFile =
"test.msg";
88 const char* OutFile =
"signed.msg";
90 char RSAPrivKey[4196];
94 char szSignature[8192];
116 int nArgParseState = 0;
125 for (n = 1; n < argc; n++) {
126 if (argv[n][0] ==
'-' && strlen(argv[n]) > 1) {
127 switch (argv[n][1]) {
135 strncpy(opts.
szDomain,(
const char*)(argv[n] + 2),
sizeof(opts.
szDomain) - 1);
144 if (argv[n][2] ==
'-') { opts.
szIdentity[0] =
'\0'; }
164 if (argv[n][2] ==
'-') { opts.
expireTime = 0; }
165 else { opts.
expireTime = t + atoi(argv[n] + 2); }
174 opts.
nHash = atoi(&argv[n][2]);
178 switch (nArgParseState) {
183 RSAKeyFile = argv[n];
189 ECCKeyFile = argv[n];
199 if (opts.
nHash != 4) {
200 FILE* RSAPrivKeyFP = fopen(RSAKeyFile,
"r");
201 if (RSAPrivKeyFP == NULL) {
203 fprintf(
FDLOG,
" qmail-dkim: can't open private key file (%s) \n",RSAKeyFile);
207 nKeyLen = fread(RSAPrivKey,1,
sizeof(RSAPrivKey),RSAPrivKeyFP);
209 fprintf(
FDLOG,
" qmail-dkim: private key file (%s) - length %i \n",RSAKeyFile,nKeyLen);
211 if (nKeyLen >=
sizeof(RSAPrivKey)) {
213 fprintf(
FDLOG,
" qmail-dkim: private key buffer isn't big enough for private key length %i \n",nKeyLen);
217 RSAPrivKey[nKeyLen] =
'\0';
218 fclose(RSAPrivKeyFP);
224 FILE* ECCPrivKeyFP = fopen(ECCKeyFile,
"r");
225 if (ECCPrivKeyFP == NULL) {
227 fprintf(
FDLOG,
" qmail-dkim: can't open Ed25519 private key file (%s) \n",ECCKeyFile);
231 nKeyLen = fread(ECCPrivKey,1,
sizeof(ECCPrivKey),ECCPrivKeyFP);
233 fprintf(
FDLOG,
" qmail-dkim: Ed25519 private key file (%s) - length %i \n",ECCKeyFile,nKeyLen);
235 if (nKeyLen >=
sizeof(ECCPrivKey)) {
237 fprintf(
FDLOG,
" qmail-dkim: ECC private key buffer isn't big enough for ECC private key length %i \n",nKeyLen);
241 ECCPrivKey[nKeyLen] =
'\0';
242 fclose(ECCPrivKeyFP);
247 FILE*
in = fopen(MsgFile,
"rb");
250 fprintf(
FDLOG,
" qmail-dkim: can't open msg file (%s) \n",MsgFile);
258 BufLen = fread(Buffer,1,
sizeof(Buffer),
in);
273 fseek(
in,0L,SEEK_SET);
274 FILE*
out = fopen(OutFile,
"wb+");
277 fprintf(
FDLOG,
" outfile written %s \n",OutFile);
281 fwrite(szSignature,1,strlen(szSignature),
out);
282 fwrite(
"\r\n",1,2,
out);
286 BufLen = fread(Buffer,1,
sizeof(Buffer),
in);
287 if (BufLen > 0) { fwrite(Buffer,1,BufLen,
out); }
297 FILE*
in = fopen(MsgFile,
"rb");
300 fprintf(
FDLOG,
" qmail-dkim: can't open input file\n");
311 BufLen = fread(Buffer,1,
sizeof(Buffer),
in);
324 for (
int i = 0; i < nSigCount; i++) {
325 const char s[] =
"pass";
326 const char f[] =
"fail";
329 fprintf(
FDLOG,
" Signature #%d: ",i + 1);
330 if (pDetails[i].nResult >= 0 ) {
339 printf(
" Fail %s \n",error);
int DKIMSignInit(DKIMContext *pSignContext, DKIMSignOptions *pOptions)
int DKIMVerifyInit(DKIMContext *pVerifyContext, DKIMVerifyOptions *pOptions)
int DKIMSignGetSig2(DKIMContext *pSignContext, char *szRSAPrivKey, char *szECCPrivKey, char **pszSignature)
void DKIMSignFree(DKIMContext *pSignContext)
int DKIMSignProcess(DKIMContext *pSignContext, char *szBuffer, int nBufLength)
void DKIMVerifyFree(DKIMContext *pVerifyContext)
int DKIMVerifyResults(DKIMContext *pVerifyContext)
int DKIMVerifyGetDetails(DKIMContext *pVerifyContext, int *nSigCount, DKIMVerifyDetails **pDetails, char *szPractices)
int DKIMVerifyProcess(DKIMContext *pVerifyContext, const char *const szBuffer, int nBufLength)
#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)
int SignThisHeader(const char *szHeader)
int SelectorCallback(const char *szFQDN, char *szBuffer, int nBufLen)
int nIncludeBodyLengthTag
char szRequiredHeaders[256]
DKIMHEADERCALLBACK pfnHeaderCallback
int nIncludeCopiedHeaders
DKIMDNSCALLBACK pfnSelectorCallback