From cd1a5fe0ed22087c6afbe585ab0206c2a4a267aa Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 31 Dec 2016 15:24:38 +0000 Subject: DKIM: Under debug, when signing do an extra check on the dns record that will be used for verification. Bug 1926 --- src/src/dkim.c | 12 ++-- src/src/pdkim/pdkim.c | 153 +++++++++++++++++++++++++++++--------------------- src/src/pdkim/pdkim.h | 3 +- 3 files changed, 99 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/src/dkim.c b/src/src/dkim.c index 70c9547ec..a2574c15b 100644 --- a/src/src/dkim.c +++ b/src/src/dkim.c @@ -607,11 +607,13 @@ while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, dkim_private_key_expanded = big_buffer; } - ctx = pdkim_init_sign( CS dkim_signing_domain, - CS dkim_signing_selector, - CS dkim_private_key_expanded, - PDKIM_ALGO_RSA_SHA256, - dkim->dot_stuffed); + ctx = pdkim_init_sign(CS dkim_signing_domain, + CS dkim_signing_selector, + CS dkim_private_key_expanded, + PDKIM_ALGO_RSA_SHA256, + dkim->dot_stuffed, + &dkim_exim_query_dns_txt + ); dkim_private_key_expanded[0] = '\0'; pdkim_set_optional(ctx, CS dkim_sign_headers_expanded, diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index c4bdb5a93..d3ff03108 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -1300,6 +1300,74 @@ return hdr; } +/* -------------------------------------------------------------------------- */ + +static pdkim_pubkey * +pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx) +{ +uschar * dns_txt_name, * dns_txt_reply; +pdkim_pubkey * p; +const uschar * errstr; + +/* Fetch public key for signing domain, from DNS */ + +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 + || dns_txt_reply[0] == '\0' + ) + { + sig->verify_status = PDKIM_VERIFY_INVALID; + sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE; + return NULL; + } + +DEBUG(D_acl) + { + debug_printf( + "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + " Raw record: "); + pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply)); + } + +if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)) + || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0) + ) + { + sig->verify_status = PDKIM_VERIFY_INVALID; + sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD; + + DEBUG(D_acl) + { + if (p) + debug_printf(" Invalid public key service type '%s'\n", p->srvtype); + else + debug_printf(" Error while parsing public key record\n"); + debug_printf( + "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } + return NULL; + } + +DEBUG(D_acl) debug_printf( + "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + +/* Import public key */ +if ((errstr = exim_rsa_verify_init(&p->key, vctx))) + { + DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr); + sig->verify_status = PDKIM_VERIFY_INVALID; + sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT; + return NULL; + } + +return p; +} + + /* -------------------------------------------------------------------------- */ DLLEXPORT int @@ -1519,8 +1587,6 @@ while (sig) const uschar * errstr; pdkim_pubkey * p; - uschar *dns_txt_name, *dns_txt_reply; - /* Make sure we have all required signature tags */ if (!( sig->domain && *sig->domain && sig->selector && *sig->selector @@ -1552,61 +1618,8 @@ while (sig) goto NEXT_VERIFY; } - /* Fetch public key for signing domain, from DNS */ - - 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 - || dns_txt_reply[0] == '\0') - { - sig->verify_status = PDKIM_VERIFY_INVALID; - sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE; - goto NEXT_VERIFY; - } - - DEBUG(D_acl) - { - debug_printf( - "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" - " Raw record: "); - pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply)); - } - - if ( !(p = pdkim_parse_pubkey_record(ctx, CUS dns_txt_reply)) - || (Ustrcmp(p->srvtype, "*") != 0 && Ustrcmp(p->srvtype, "email") != 0) - ) - { - sig->verify_status = PDKIM_VERIFY_INVALID; - sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD; - - DEBUG(D_acl) - { - if (p) - debug_printf(" Invalid public key service type '%s'\n", p->srvtype); - else - debug_printf(" Error while parsing public key record\n"); - debug_printf( - "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - } + if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx))) goto NEXT_VERIFY; - } - sig->pubkey = p; - - DEBUG(D_acl) debug_printf( - "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - - /* Import public key */ - if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx))) - { - DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr); - sig->verify_status = PDKIM_VERIFY_INVALID; - sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT; - goto NEXT_VERIFY; - } /* Check the signature */ if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata))) @@ -1668,22 +1681,24 @@ return ctx; /* -------------------------------------------------------------------------- */ DLLEXPORT pdkim_ctx * -pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo, - BOOL dot_stuffed) +pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo, + BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *)) { -pdkim_ctx *ctx; -pdkim_signature *sig; +pdkim_ctx * ctx; +pdkim_signature * sig; if (!domain || !selector || !rsa_privkey) return NULL; -ctx = store_get(sizeof(pdkim_ctx)); +ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature)); memset(ctx, 0, sizeof(pdkim_ctx)); ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN; -ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN); +ctx->linebuf = CS (ctx+1); -sig = store_get(sizeof(pdkim_signature)); +DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback; + +sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN); memset(sig, 0, sizeof(pdkim_signature)); sig->bodylength = -1; @@ -1695,6 +1710,18 @@ sig->rsa_privkey = string_copy(US rsa_privkey); sig->algo = algo; exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256); + +DEBUG(D_acl) + { + pdkim_signature s = *sig; + ev_ctx vctx; + + debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + if (!pdkim_key_from_dns(ctx, &s, &vctx)) + debug_printf("WARNING: bad dkim key in dns\n"); + debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } + return ctx; } diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h index 07ba5b5c4..c1c8c262e 100644 --- a/src/src/pdkim/pdkim.h +++ b/src/src/pdkim/pdkim.h @@ -285,7 +285,8 @@ extern "C" { void pdkim_init (void); DLLEXPORT -pdkim_ctx *pdkim_init_sign (char *, char *, char *, int, BOOL); +pdkim_ctx *pdkim_init_sign (char *, char *, char *, int, + BOOL, int(*)(char *, char *)); DLLEXPORT pdkim_ctx *pdkim_init_verify (int(*)(char *, char *), BOOL); -- cgit v1.2.3