- #ifdef PDKIM_DEBUG
- if (ctx->debug_stream) {
- fprintf(ctx->debug_stream,
- "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
- pdkim_quoteprint(ctx->debug_stream, sig_hdr, strlen(sig_hdr), 1);
- fprintf(ctx->debug_stream,
- "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
- }
- #endif
-
- /* Finalize header hash */
- if (sig->algo == PDKIM_ALGO_RSA_SHA1) {
- sha1_update(&(sha1_headers),(unsigned char *)sig_hdr,strlen(sig_hdr));
- sha1_finish(&(sha1_headers),(unsigned char *)headerhash);
- #ifdef PDKIM_DEBUG
- if (ctx->debug_stream) {
- fprintf(ctx->debug_stream, "PDKIM [%s] hh computed: ", sig->domain);
- pdkim_hexprint(ctx->debug_stream, headerhash, 20, 1);
- }
- #endif
+DLLEXPORT int
+pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
+{
+pdkim_signature *sig = ctx->sig;
+
+/* Check if we must still flush a (partial) header. If that is the
+ case, the message has no body, and we must compute a body hash
+ out of '<CR><LF>' */
+if (ctx->cur_header && ctx->cur_header_len)
+ {
+ int rc = pdkim_header_complete(ctx);
+ if (rc != PDKIM_OK) return rc;
+ pdkim_update_bodyhash(ctx, "\r\n", 2);
+ }
+else
+ DEBUG(D_acl) debug_printf(
+ "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+
+/* Build (and/or evaluate) body hash */
+pdkim_finish_bodyhash(ctx);
+
+while (sig)
+ {
+ BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
+ hctx hhash_ctx;
+ uschar * sig_hdr = US"";
+ blob hhash;
+ blob hdata;
+ int hdata_alloc = 0;
+
+ hdata.data = NULL;
+ hdata.len = 0;
+
+ exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256);
+
+ DEBUG(D_acl) debug_printf(
+ "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
+
+ /* 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.
+ Then append to that list any remaining header names for which there was no
+ header to sign. */
+
+ if (ctx->flags & PDKIM_MODE_SIGN)
+ {
+ uschar * headernames = NULL; /* Collected signed header names */
+ int hs = 0, hl = 0;
+ pdkim_stringlist *p;
+ const uschar * l;
+ uschar * s;
+ int sep = 0;
+
+ for (p = sig->headers; p; p = p->next)
+ 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, ':');
+
+ headernames = string_catn(headernames, &hs, &hl,
+ p->value, (q - US p->value) + (p->next ? 1 : 0));
+
+ rh = sig->canon_headers == PDKIM_CANON_RELAXED
+ ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
+ : string_copy(CUS p->value); /* just copy it for simple canon */
+
+ /* Feed header to the hash algorithm */
+ exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(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));
+ }
+
+ l = sig->sign_headers;
+ while((s = string_nextinlist(&l, &sep, NULL, 0)))
+ if (*s != '_')
+ { /*SSS string_append_listele() */
+ if (hl > 0 && headernames[hl-1] != ':')
+ headernames = string_catn(headernames, &hs, &hl, US":", 1);
+
+ headernames = string_cat(headernames, &hs, &hl, s);
+ }
+ headernames[hl] = '\0';
+
+ /* Copy headernames to signature struct */
+ sig->headernames = headernames;
+
+ /* Create signature header with b= omitted */
+ sig_hdr = pdkim_create_header(sig, FALSE);