/* -------------------------------------------------------------------------- */
/* Print debugging functions */
static void
-pdkim_quoteprint(const char *data, int len)
+pdkim_quoteprint(const uschar *data, int len)
{
int i;
-const unsigned char *p = (const unsigned char *)data;
-
for (i = 0; i < len; i++)
{
- const int c = p[i];
+ const int c = data[i];
switch (c)
{
case ' ' : debug_printf("{SP}"); break;
}
static void
-pdkim_hexprint(const char *data, int len)
+pdkim_hexprint(const uschar *data, int len)
{
int i;
-const unsigned char *p = (const unsigned char *)data;
-
-for (i = 0 ; i < len; i++)
- debug_printf("%02x", p[i]);
+for (i = 0 ; i < len; i++) debug_printf("%02x", data[i]);
debug_printf("\n");
}
-/* String package: should be replaced by Exim standard ones */
+/* SSS probably want to keep the "stringlist" notion */
static pdkim_stringlist *
pdkim_prepend_stringlist(pdkim_stringlist *base, char *str)
if (!new_entry) return NULL;
memset(new_entry, 0, sizeof(pdkim_stringlist));
if (!(new_entry->value = strdup(str))) return NULL;
-if (base)
- {
- pdkim_stringlist *last = base;
- while (last->next != NULL) { last = last->next; }
- last->next = new_entry;
- return base;
- }
-else
- return new_entry;
+if (base) new_entry->next = base;
+return new_entry;
}
/* -------------------------------------------------------------------------- */
/* A small "growing string" implementation to escape malloc/realloc hell */
+/* String package: should be replaced by Exim standard ones */
+/* SSS Ustrcpy */
static pdkim_str *
pdkim_strnew (const char *cstr)
return p;
}
+
+/*SSS Ustrncat */
+
static char *
pdkim_strncat(pdkim_str *str, const char *data, int len)
{
return str->str;
}
+
+/* SSS Ustrcat */
+
static char *
pdkim_strcat(pdkim_str *str, const char *cstr)
{
return pdkim_strncat(str, cstr, strlen(cstr));
}
+
+
+/* Trim whitespace fore & aft */
+
static char *
pdkim_strtrim(pdkim_str *str)
{
char *p = str->str;
char *q = str->str;
-while ( (*p != '\0') && ((*p == '\t') || (*p == ' ')) ) p++;
-while (*p != '\0') {*q = *p; q++; p++;}
+while (*p == '\t' || *p == ' ') p++; /* skip whitespace */
+while (*p) {*q = *p; q++; p++;} /* dump the leading whitespace */
*q = '\0';
-while ( (q != str->str) && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
- {
+while (q != str->str && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
+ { /* dump trailing whitespace */
*q = '\0';
q--;
}
return str->str;
}
+
+
static char *
pdkim_strclear(pdkim_str *str)
{
return str->str;
}
+
+
static void
pdkim_strfree(pdkim_str *str)
{
}
+static void
+pdkim_stringlist_free(pdkim_stringlist * e)
+{
+while(e)
+ {
+ pdkim_stringlist * c = e;
+ if (e->value) free(e->value);
+ e = e->next;
+ free(c);
+ }
+}
+
+
/* -------------------------------------------------------------------------- */
{
pdkim_signature *next = (pdkim_signature *)sig->next;
- pdkim_stringlist *e = sig->headers;
- while(e)
- {
- pdkim_stringlist *c = e;
- if (e->value) free(e->value);
- e = e->next;
- free(c);
- }
-
+ pdkim_stringlist_free(sig->headers);
if (sig->selector ) free(sig->selector);
if (sig->domain ) free(sig->domain);
if (sig->identity ) free(sig->identity);
{
if (ctx)
{
- pdkim_stringlist *e = ctx->headers;
- while(e)
- {
- pdkim_stringlist *c = e;
- if (e->value) free(e->value);
- e = e->next;
- free(c);
- }
+ pdkim_stringlist_free(ctx->headers);
pdkim_free_sig(ctx->sig);
pdkim_strfree(ctx->cur_header);
free(ctx);
/* -------------------------------------------------------------------------- */
/* Matches the name of the passed raw "header" against
- the passed colon-separated "list", starting at entry
- "start". Returns the position of the header name in
- the list. */
+ the passed colon-separated "tick", and invalidates
+ the entry in tick. Returns OK or fail-code */
+/*XXX might be safer done using a pdkim_stringlist for "tick" */
static int
-header_name_match(const char *header,
- char *tick,
- int do_tick)
+header_name_match(const char * header, char * tick)
{
char *hname;
char *lcopy;
{
rc = PDKIM_OK;
/* Invalidate header name instance in tick-off list */
- if (do_tick) tick[p-lcopy] = '_';
+ tick[p-lcopy] = '_';
goto BAIL;
}
{
rc = PDKIM_OK;
/* Invalidate header name instance in tick-off list */
- if (do_tick) tick[p-lcopy] = '_';
+ tick[p-lcopy] = '_';
}
BAIL:
pdkim_decode_base64(uschar *str, blob * b)
{
int dlen;
-char *res;
dlen = b64decode(str, &b->data);
if (dlen < 0) b->data = NULL;
b->len = dlen;
case 'l':
sig->bodylength = strtol(cur_val->str, NULL, 10); break;
case 'h':
- sig->headernames = string_copy(cur_val->str); break;
+ sig->headernames = string_copy(US cur_val->str); break;
case 'z':
sig->copiedheaders = pdkim_decode_qp(cur_val->str); break;
default:
*q = '\0';
/* Chomp raw header. The final newline must not be added to the signature. */
-q--;
-while (q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
- *q = '\0'; q--; /*XXX questionable code layout; possible bug */
+while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
+ *q = '\0';
DEBUG(D_acl)
{
debug_printf(
"PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- pdkim_quoteprint(sig->rawsig_no_b_val, strlen(sig->rawsig_no_b_val));
+ pdkim_quoteprint(US sig->rawsig_no_b_val, strlen(sig->rawsig_no_b_val));
debug_printf(
- "PDKIM >> Sig size: %4d bits\n", sig->sigdata.len*8);
+ "PDKIM >> Sig size: %4u bits\n", (unsigned) sig->sigdata.len*8);
debug_printf(
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
if (!cur_val)
cur_val = pdkim_strnew(NULL);
- if (c == '\r' || c == '\n')
- goto NEXT_CHAR;
-
if (c == ';' || c == '\0')
{
if (cur_tag->len > 0)
{
pdkim_signature *sig = ctx->sig;
/* Cache relaxed version of data */
-char *relaxed_data = NULL;
-int relaxed_len = 0;
+uschar *relaxed_data = NULL;
+int relaxed_len = 0;
/* Traverse all signatures, updating their hashes. */
while (sig)
{
/* Defaults to simple canon (no further treatment necessary) */
- const char *canon_data = data;
- int canon_len = len;
+ const uschar *canon_data = CUS data;
+ int canon_len = len;
if (sig->canon_body == PDKIM_CANON_RELAXED)
{
if (canon_len > 0)
{
- exim_sha_update(&sig->body_hash, canon_data, canon_len);
+ exim_sha_update(&sig->body_hash, CCS canon_data, canon_len);
sig->signed_body_bytes += canon_len;
DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
}
debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
"PDKIM [%s] bh computed: ",
sig->domain, sig->signed_body_bytes, sig->domain);
- pdkim_hexprint(CS bh.data, bh.len);
+ pdkim_hexprint(CUS bh.data, bh.len);
}
/* SIGNING -------------------------------------------------------------- */
pdkim_signature *sig;
for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
- if (header_name_match(ctx->cur_header->str,
- sig->sign_headers?
- sig->sign_headers:
- PDKIM_DEFAULT_SIGN_HEADERS, 0) == PDKIM_OK)
- {
- pdkim_stringlist *list;
+ {
+ pdkim_stringlist *list;
- /* Add header to the signed headers list (in reverse order) */
- if (!(list = pdkim_prepend_stringlist(sig->headers,
- ctx->cur_header->str)))
- return PDKIM_ERR_OOM;
- sig->headers = list;
- }
+ /* Add header to the signed headers list (in reverse order) */
+ if (!(list = pdkim_prepend_stringlist(sig->headers,
+ ctx->cur_header->str)))
+ return PDKIM_ERR_OOM;
+ sig->headers = list;
+ }
}
/* VERIFICATION ----------------------------------------------------------- */
ctx->past_headers = TRUE;
ctx->seen_lf = 0;
DEBUG(D_acl) debug_printf(
- "PDKIM >> Hashed body data, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
continue;
}
else
/* list of header names can be split between items. */
{
char *n = CS string_copy(sig->headernames);
- char *f = n;
char *i = "h=";
char *s = ";";
/* SIGNING ---------------------------------------------------------------- */
/* When signing, walk through our header list and add them to the hash. As we
- go, construct a list of the header's names to use for the h= parameter. */
+ go, construct a list of the header's names to use for the h= parameter.
+ Then append to that list any remaining header names for which there was no
+ header to sign. */
if (ctx->mode == PDKIM_MODE_SIGN)
{
pdkim_stringlist *p;
+ const uschar * l;
+ uschar * s;
+ int sep = 0;
for (p = sig->headers; p; p = p->next)
- {
- uschar * rh;
- /* Collect header names (Note: colon presence is guaranteed here) */
- uschar * q = Ustrchr(p->value, ':');
+ if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
+ {
+ uschar * rh;
+ /* Collect header names (Note: colon presence is guaranteed here) */
+ uschar * q = Ustrchr(p->value, ':');
- if (!(pdkim_strncat(headernames, p->value,
- (q-US (p->value)) + (p->next ? 1 : 0))))
- return PDKIM_ERR_OOM;
+ if (!(pdkim_strncat(headernames, p->value,
+ (q - US p->value) + (p->next ? 1 : 0))))
+ return PDKIM_ERR_OOM;
- rh = sig->canon_headers == PDKIM_CANON_RELAXED
- ? US pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
- : string_copy(p->value); /* just copy it for simple canon */
- if (!rh)
- return PDKIM_ERR_OOM;
+ rh = sig->canon_headers == PDKIM_CANON_RELAXED
+ ? US pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
+ : string_copy(CUS p->value); /* just copy it for simple canon */
+ if (!rh)
+ return PDKIM_ERR_OOM;
- /* Feed header to the hash algorithm */
- exim_sha_update(&hhash_ctx, rh, strlen(rh));
+ /* Feed header to the hash algorithm */
+ exim_sha_update(&hhash_ctx, CCS rh, Ustrlen(rh));
- /* Remember headers block for signing (when the library cannot do incremental) */
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
+ /* Remember headers block for signing (when the library cannot do incremental) */
+ (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
- DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
- }
+ DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
+ }
+
+ l = US sig->sign_headers;
+ while((s = string_nextinlist(&l, &sep, NULL, 0)))
+ if (*s != '_')
+ { /*SSS string_append_listele() */
+ if (headernames->len > 0 && headernames->str[headernames->len-1] != ':')
+ if (!(pdkim_strncat(headernames, ":", 1)))
+ return PDKIM_ERR_OOM;
+ if (!(pdkim_strncat(headernames, CS s, Ustrlen(s))))
+ return PDKIM_ERR_OOM;
+ }
}
/* VERIFICATION ----------------------------------------------------------- */
if ((q = Ustrchr(p, ':')))
*q = '\0';
+/*XXX walk the list of headers in same order as received. */
for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
if ( hdrs->tag == 0
&& strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
{
uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
? US pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
- : string_copy(hdrs->value); /* just copy it for simple canon */
+ : string_copy(CUS hdrs->value); /* just copy it for simple canon */
if (!rh)
return PDKIM_ERR_OOM;
/* Feed header to the hash algorithm */
- exim_sha_update(&hhash_ctx, rh, strlen(rh));
+ exim_sha_update(&hhash_ctx, CCS rh, Ustrlen(rh));
DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
hdrs->tag = 1;
pdkim_strfree(headernames);
/* Create signature header with b= omitted */
- sig_hdr = pdkim_create_header(ctx->sig, FALSE);
+ sig_hdr = pdkim_create_header(sig, FALSE);
}
/* VERIFICATION ----------------------------------------------------------- */
{
debug_printf(
"PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
- pdkim_quoteprint(sig_hdr, strlen(sig_hdr));
+ pdkim_quoteprint(CUS sig_hdr, strlen(sig_hdr));
debug_printf(
"PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
/* Remember headers block for signing (when the library cannot do incremental) */
if (ctx->mode == PDKIM_MODE_SIGN)
- (void) exim_rsa_data_append(&hdata, &hdata_alloc, sig_hdr);
+ (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
free(sig_hdr);
const uschar * errstr;
/* Import private key */
- if ((errstr = exim_rsa_signing_init(sig->rsa_privkey, &sctx)))
+ if ((errstr = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
{
DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
return PDKIM_ERR_RSA_PRIVKEY;
pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
}
- if (!(sig->signature_header = pdkim_create_header(ctx->sig, TRUE)))
+ if (!(sig->signature_header = pdkim_create_header(sig, TRUE)))
return PDKIM_ERR_OOM;
+
+ /* We only ever sign with one sig, and we free'd "headernames"
+ above. So to keep static-analysers happy, exit the loop explicitly.
+ Perhaps the code would be more clear if signing and verification
+ loops were separated? */
+
+ break;
}
/* VERIFICATION ----------------------------------------------------------- */
debug_printf(
"PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
" Raw record: ");
- pdkim_quoteprint(dns_txt_reply, strlen(dns_txt_reply));
+ pdkim_quoteprint(CUS dns_txt_reply, strlen(dns_txt_reply));
}
if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, dns_txt_reply)))
unsigned long created,
unsigned long expires)
{
+pdkim_signature * sig = ctx->sig;
+
if (identity)
- if (!(ctx->sig->identity = strdup(identity)))
+ if (!(sig->identity = strdup(identity)))
return PDKIM_ERR_OOM;
-if (sign_headers)
- if (!(ctx->sig->sign_headers = strdup(sign_headers)))
- return PDKIM_ERR_OOM;
+if (!(sig->sign_headers = strdup(sign_headers
+ ? sign_headers : PDKIM_DEFAULT_SIGN_HEADERS)))
+ return PDKIM_ERR_OOM;
-ctx->sig->canon_headers = canon_headers;
-ctx->sig->canon_body = canon_body;
-ctx->sig->bodylength = bodylength;
-ctx->sig->created = created;
-ctx->sig->expires = expires;
+sig->canon_headers = canon_headers;
+sig->canon_body = canon_body;
+sig->bodylength = bodylength;
+sig->created = created;
+sig->expires = expires;
return PDKIM_OK;
}