const uschar * pdkim_keytypes[] = {
[KEYTYPE_RSA] = US"rsa",
#ifdef SIGN_HAVE_ED25519
- [KEYTYPE_ED25519] = US"ed25519", /* Works for 3.6.0 GnuTLS */
+ [KEYTYPE_ED25519] = US"ed25519", /* Works for 3.6.0 GnuTLS, OpenSSL 1.1.1 */
#endif
#ifdef notyet_EC_dkim_extensions /* https://tools.ietf.org/html/draft-srose-dkim-ecc-00 */
break;
case 'a': /* algorithm */
{
- uschar * s = Ustrchr(cur_val->s, '-');
-
- for(i = 0; i < nelem(pdkim_keytypes); i++)
- if (Ustrncmp(cur_val->s, pdkim_keytypes[i], s - cur_val->s) == 0)
- { sig->keytype = i; break; }
- if (sig->keytype < 0)
- log_write(0, LOG_MAIN,
- "DKIM: ignoring signature due to nonhandled keytype in a=%s",
- cur_val->s);
-
- sig->hashtype = pdkim_hashname_to_hashtype(++s, 0);
- break;
+ const uschar * list = cur_val->s;
+ int sep = '-';
+ uschar * elem;
+
+ if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
+ for(i = 0; i < nelem(pdkim_keytypes); i++)
+ if (Ustrcmp(elem, pdkim_keytypes[i]) == 0)
+ { sig->keytype = i; break; }
+ if ((elem = string_nextinlist(&list, &sep, NULL, 0)))
+ for (i = 0; i < nelem(pdkim_hashes); i++)
+ if (Ustrcmp(elem, pdkim_hashes[i].dkim_hashname) == 0)
+ { sig->hashtype = i; break; }
}
case 'c': /* canonicalization */
for (b = ctx->bodyhash; b; b = b->next) /* Finish hashes */
{
- DEBUG(D_acl) debug_printf("PDKIM: finish bodyhash %d/%d/%d len %ld\n",
+ DEBUG(D_acl) debug_printf("PDKIM: finish bodyhash %d/%d/%ld len %ld\n",
b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
exim_sha_finish(&b->body_hash_ctx, &b->bh);
}
/* -------------------------------------------------------------------------- */
+/* According to draft-ietf-dcrup-dkim-crypto-07 "keys are 256 bits" (referring
+to DNS, hence the pubkey). Check for more than 32 bytes; if so assume the
+alternate possible representation (still) being discussed: a
+SubjectPublickeyInfo wrapped key - and drop all but the trailing 32-bytes (it
+should be a DER, with exactly 12 leading bytes - but we could accept a BER also,
+which could be any size). We still rely on the crypto library for checking for
+undersize.
+
+When the RFC is published this should be re-addressed. */
+
+static void
+check_bare_ed25519_pubkey(pdkim_pubkey * p)
+{
+int excess = p->key.len - 32;
+if (excess > 0)
+ {
+ DEBUG(D_acl) debug_printf("PDKIM: unexpected pubkey len %lu\n", p->key.len);
+ p->key.data += excess; p->key.len = 32;
+ }
+}
+
+
static pdkim_pubkey *
pdkim_key_from_dns(pdkim_ctx * ctx, pdkim_signature * sig, ev_ctx * vctx,
const uschar ** errstr)
/* Import public key */
+/* Normally we use the signature a= tag to tell us the pubkey format.
+When signing under debug we do a test-import of the pubkey, and at that
+time we do not have a signature so we must interpret the pubkey k= tag
+instead. Assume writing on the sig is ok in that case. */
+
+if (sig->keytype < 0)
+ {
+ int i;
+ for(i = 0; i < nelem(pdkim_keytypes); i++)
+ if (Ustrcmp(p->keytype, pdkim_keytypes[i]) == 0)
+ { sig->keytype = i; goto k_ok; }
+ DEBUG(D_acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype);
+ sig->verify_status = PDKIM_VERIFY_INVALID;
+ sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
+ return NULL;
+ }
+k_ok:
+
+if (sig->keytype == KEYTYPE_ED25519)
+ check_bare_ed25519_pubkey(p);
+
if ((*errstr = exim_dkim_verify_init(&p->key,
sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER,
vctx)))
if (ctx->flags & PDKIM_MODE_SIGN)
{
hashmethod hm = sig->keytype == KEYTYPE_ED25519
- ? HASH_SHA2_512 : pdkim_hashes[sig->hashtype].exim_hashmethod;
+#if defined(SIGN_OPENSSL)
+ ? HASH_NULL
+#else
+ ? HASH_SHA2_512
+#endif
+ : pdkim_hashes[sig->hashtype].exim_hashmethod;
#ifdef SIGN_HAVE_ED25519
/* For GCrypt, and for EC, we pass the hash-of-headers to the signing
hhash.len = hdata->ptr;
}
-/*XXX extend for non-RSA algos */
-/*- done for GnuTLS */
if ((*err = exim_dkim_sign(&sctx, hm, &hhash, &sig->sighash)))
{
log_write(0, LOG_MAIN|LOG_PANIC, "signing: %s", *err);
else
{
ev_ctx vctx;
+ hashmethod hm;
/* Make sure we have all required signature tags */
if (!( sig->domain && *sig->domain
}
}
+ hm = sig->keytype == KEYTYPE_ED25519
+#if defined(SIGN_OPENSSL)
+ ? HASH_NULL
+#else
+ ? HASH_SHA2_512
+#endif
+ : pdkim_hashes[sig->hashtype].exim_hashmethod;
+
/* Check the signature */
-/*XXX extend for non-RSA algos */
-/*- done for GnuTLS */
- if ((*err = exim_dkim_verify(&vctx,
- pdkim_hashes[sig->hashtype].exim_hashmethod,
- &hhash, &sig->sighash)))
+
+ if ((*err = exim_dkim_verify(&vctx, hm, &hhash, &sig->sighash)))
{
DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
sig->verify_status = PDKIM_VERIFY_FAIL;