pdkim_strtrim(gstring * str)
{
uschar * p = str->s;
-uschar * q = p + str->ptr;
+uschar * q;
while (*p == '\t' || *p == ' ') /* dump the leading whitespace */
{ str->size--; str->ptr--; str->s++; }
while ( str->ptr > 0
- && (q = str->s + str->ptr - 1), *q == '\t' || *q == ' '
+ && ((q = str->s + str->ptr - 1), (*q == '\t' || *q == ' '))
)
str->ptr--; /* dump trailing whitespace */
/* -------------------------------------------------------------------------- */
/* Matches the name of the passed raw "header" against
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" */
+ the entry in tick. Entries can be prefixed for multi- or over-signing,
+ in which case do not invalidate.
+
+ Returns OK for a match, or fail-code
+*/
static int
header_name_match(const uschar * header, uschar * tick)
{
-uschar * hname;
-uschar * lcopy;
-uschar * p;
-uschar * q;
+const uschar * ticklist = tick;
+int sep = ':';
+BOOL multisign;
+uschar * hname, * p, * ele;
uschar * hcolon = Ustrchr(header, ':'); /* Get header name */
if (!hcolon)
/* if we had strncmpic() we wouldn't need this copy */
hname = string_copyn(header, hcolon-header);
-/* Copy tick-off list locally, so we can punch zeroes into it */
-p = lcopy = string_copy(tick);
-
-for (q = Ustrchr(p, ':'); q; q = Ustrchr(p, ':'))
+while (p = US ticklist, ele = string_nextinlist(&ticklist, &sep, NULL, 0))
{
- *q = '\0';
- if (strcmpic(p, hname) == 0)
- goto found;
-
- p = q+1;
+ switch (*ele)
+ {
+ case '=': case '+': multisign = TRUE; ele++; break;
+ default: multisign = FALSE; break;
}
-if (strcmpic(p, hname) == 0)
- goto found;
-
+ if (strcmpic(ele, hname) == 0)
+ {
+ if (!multisign)
+ *p = '_'; /* Invalidate this header name instance in tick-off list */
+ return PDKIM_OK;
+ }
+ }
return PDKIM_FAIL;
-
-found:
- /* Invalidate header name instance in tick-off list */
- tick[p-lcopy] = '_';
- return PDKIM_OK;
}
if (c == ';' || c == '\0')
{
- if (cur_tag && cur_val)
+ /* We must have both tag and value, and tags must be one char except
+ for the possibility of "bh". */
+
+ if ( cur_tag && cur_val
+ && (cur_tag->ptr == 1 || *cur_tag->s == 'b')
+ )
{
(void) string_from_gstring(cur_val);
pdkim_strtrim(cur_val);
switch (*cur_tag->s)
{
case 'b':
- pdkim_decode_base64(cur_val->s,
- cur_tag->s[1] == 'h' ? &sig->bodyhash : &sig->sighash);
+ switch (cur_tag->s[1])
+ {
+ case '\0': pdkim_decode_base64(cur_val->s, &sig->sighash); break;
+ case 'h': if (cur_tag->ptr == 2)
+ pdkim_decode_base64(cur_val->s, &sig->bodyhash);
+ break;
+ default: break;
+ }
break;
case 'v':
/* We only support version 1, and that is currently the
}
/* Set fallback defaults */
-if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
+if (!pub->version)
+ pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
{
DEBUG(D_acl) debug_printf(" Bad v= field\n");
dns_txt_name = string_sprintf("%s._domainkey.%s.", sig->selector, sig->domain);
-dns_txt_reply = store_get(PDKIM_DNS_TXT_MAX_RECLEN);
-memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
-
-if ( ctx->dns_txt_callback(CS dns_txt_name, CS dns_txt_reply) != PDKIM_OK
+if ( !(dns_txt_reply = ctx->dns_txt_callback(CS dns_txt_name))
|| dns_txt_reply[0] == '\0'
)
{
}
}
- /* Any headers we wanted to sign but were not present must also be listed */
+ /* Any headers we wanted to sign but were not present must also be listed.
+ Ignore elements that have been ticked-off or are marked as never-oversign. */
+
l = sig->sign_headers;
while((s = string_nextinlist(&l, &sep, NULL, 0)))
- if (*s != '_')
+ {
+ if (*s == '+') /* skip oversigning marker */
+ s++;
+ if (*s != '_' && *s != '=')
g = string_append_listele(g, ':', s);
+ }
sig->headernames = string_from_gstring(g);
/* Create signature header with b= omitted */
/* -------------------------------------------------------------------------- */
DLLEXPORT pdkim_ctx *
-pdkim_init_verify(int(*dns_txt_callback)(char *, char *), BOOL dot_stuffing)
+pdkim_init_verify(uschar * (*dns_txt_callback)(char *), BOOL dot_stuffing)
{
pdkim_ctx * ctx;
void
pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
- int(*dns_txt_callback)(char *, char *))
+ uschar * (*dns_txt_callback)(char *))
{
memset(ctx, 0, sizeof(pdkim_ctx));
ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;