/* 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 ((*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;
const uschar *
exim_dkim_signing_init(const uschar * privkey_pem, es_ctx * sign_ctx)
{
-gnutls_datum_t k = { .data = privkey_pem, .size = Ustrlen(privkey_pem) };
+gnutls_datum_t k = { .data = (void *)privkey_pem, .size = Ustrlen(privkey_pem) };
gnutls_x509_privkey_t x509_key;
int rc;
sign_ctx->keytype =
#ifdef SIGN_HAVE_ED25519
- EVP_PKEY_type(EVP_PKEY_id(sign_ctx->key)) == EVP_PKEY_EC
+ EVP_PKEY_type(EVP_PKEY_id(sign_ctx->key)) == EVP_PKEY_ED25519
? KEYTYPE_ED25519 : KEYTYPE_RSA;
#else
KEYTYPE_RSA;
/* allocate mem for signature (when signing) */
-/* hash & sign data. Could be incremental
+/* hash & sign data. Incremental not supported.
Return: NULL for success with the signaature in the sig blob, or an error string */
switch (hash)
{
+ case HASH_NULL: md = NULL; break; /* Ed25519 signing */
case HASH_SHA1: md = EVP_sha1(); break;
case HASH_SHA2_256: md = EVP_sha256(); break;
case HASH_SHA2_512: md = EVP_sha512(); break;
default: return US"nonhandled hash type";
}
-/* Create the Message Digest Context */
-/*XXX renamed to EVP_MD_CTX_new() in 1.1.0 */
-if( (ctx = EVP_MD_CTX_create())
-
-/* Initialise the DigestSign operation */
- && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
+#ifdef SIGN_HAVE_ED25519
+if ( (ctx = EVP_MD_CTX_new())
+ && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
+ && EVP_DigestSign(ctx, NULL, &siglen, NULL, 0) > 0
+ && (sig->data = store_get(siglen))
- /* Call update with the message */
+ /* Obtain the signature (slen could change here!) */
+ && EVP_DigestSign(ctx, sig->data, &siglen), data->data, data->len > 0
+ )
+ {
+ EVP_MD_CTX_destroy(ctx);
+ sig->len = siglen;
+ return NULL;
+ }
+#else
+/*XXX renamed to EVP_MD_CTX_new() in 1.1.0 */
+if ( (ctx = EVP_MD_CTX_create())
+ && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
&& EVP_DigestSignUpdate(ctx, data->data, data->len) > 0
-
- /* Finalise the DigestSign operation */
- /* First call EVP_DigestSignFinal with a NULL sig parameter to obtain the length of the
- * signature. Length is returned in slen */
&& EVP_DigestSignFinal(ctx, NULL, &siglen) > 0
-
- /* Allocate memory for the signature based on size in slen */
&& (sig->data = store_get(siglen))
-
- /* Obtain the signature (slen could change here!) */
+
+ /* Obtain the signature (slen could change here!) */
&& EVP_DigestSignFinal(ctx, sig->data, &siglen) > 0
)
{
sig->len = siglen;
return NULL;
}
+#endif
if (ctx) EVP_MD_CTX_destroy(ctx);
return US ERR_error_string(ERR_get_error(), NULL);
const uschar * s = pubkey->data;
uschar * ret = NULL;
-if (fmt != KEYFMT_DER) return US"pubkey format not handled";
switch(fmt)
{
case KEYFMT_DER:
- /*XXX ok, this fails for EC:
- error:0609E09C:digital envelope routines:pkey_set_type:unsupported algorithm
- */
-
/*XXX hmm, we never free this */
if (!(verify_ctx->key = d2i_PUBKEY(NULL, &s, pubkey->len)))
ret = US ERR_error_string(ERR_get_error(), NULL);
break;
#ifdef SIGN_HAVE_ED25519
case KEYFMT_ED25519_BARE:
- {
- BIGNUM * x;
- EC_KEY * eck;
- if ( !(x = BN_bin2bn(s, pubkey->len, NULL))
- || !(eck = EC_KEY_new_by_curve_name(NID_ED25519))
- || !EC_KEY_set_public_key_affine_coordinates(eck, x, NULL)
- || !(verify_ctx->key = EVP_PKEY_new())
- || !EVP_PKEY_assign_EC_KEY(verify_ctx->key, eck)
- )
+ if (!(verify_ctx->key = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
+ s, pubkey->len)))
ret = US ERR_error_string(ERR_get_error(), NULL);
- }
break;
#endif
default:
-/* verify signature (of hash)
-(pre-EC coding; of data if "notyet" code, The latter could be incremental)
+/* verify signature (of hash, except Ed25519 where of-data)
(given pubkey & alleged sig)
Return: NULL for success, or an error string */
{
const EVP_MD * md;
-/*XXX OpenSSL does not seem to have Ed25519 support yet. Reportedly BoringSSL does,
-but that's a nonstable API and not recommended (by its owner, Google) for external use. */
-
switch (hash)
{
+ case HASH_NULL: md = NULL; break;
case HASH_SHA1: md = EVP_sha1(); break;
case HASH_SHA2_256: md = EVP_sha256(); break;
case HASH_SHA2_512: md = EVP_sha512(); break;
default: return US"nonhandled hash type";
}
-#ifdef notyet_SIGN_HAVE_ED25519
+#ifdef SIGN_HAVE_ED25519
+if (!md)
{
EVP_MD_CTX * ctx;
- /*XXX renamed to EVP_MD_CTX_new() in 1.1.0 */
- if (
- (ctx = EVP_MD_CTX_create())
-
- /* Initialize `key` with a public key */
+ if ( (ctx = EVP_MD_CTX_new())
&& EVP_DigestVerifyInit(ctx, NULL, md, NULL, verify_ctx->key) > 0
-
- /* add data to be hashed (call multiple times if needed) */
-
- && EVP_DigestVerifyUpdate(ctx, data->data, data->len) > 0
-
- /* finish off the hash and check the offered signature */
-
- && EVP_DigestVerifyFinal(ctx, sig->data, sig->len) > 0
+ && EVP_DigestVerify(ctx, sig->data, sig->len, data->data, data->len) > 0
)
- {
- EVP_MD_CTX_destroy(ctx); /* renamed to _free in 1.1.0 */
- return NULL;
- }
+ { EVP_MD_CTX_free(ctx); return NULL; }
if (ctx) EVP_MD_CTX_free(ctx);
- return US ERR_error_string(ERR_get_error(), NULL);
}
-#else
+else
+#endif
{
EVP_PKEY_CTX * ctx;
{ EVP_PKEY_CTX_free(ctx); return NULL; }
if (ctx) EVP_PKEY_CTX_free(ctx);
- return US ERR_error_string(ERR_get_error(), NULL);
}
-#endif
+return US ERR_error_string(ERR_get_error(), NULL);
}