Browse Source

[Feature] Allow to match private and public keys for DKIM signatures

tags/1.7.6
Vsevolod Stakhov 6 years ago
parent
commit
9d6477913e
3 changed files with 77 additions and 4 deletions
  1. 36
    0
      src/libserver/dkim.c
  2. 11
    0
      src/libserver/dkim.h
  3. 30
    4
      src/plugins/dkim_check.c

+ 36
- 0
src/libserver/dkim.c View File

@@ -2997,3 +2997,39 @@ rspamd_dkim_sign (struct rspamd_task *task, const gchar *selector,

return hdr;
}

gboolean
rspamd_dkim_match_keys (rspamd_dkim_key_t *pk,
rspamd_dkim_sign_key_t *sk,
GError **err)
{
const BIGNUM *n1, *n2;

if (pk == NULL || sk == NULL) {
g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL,
"missing public or private key");
return FALSE;
}

if (pk->type != RSPAMD_DKIM_KEY_RSA) {
g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL,
"pubkey is not RSA key");
return FALSE;
}

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
RSA_get0_key (pk->key.key_rsa, &n1, NULL, NULL);
n2 = RSA_get0_key (sk->key_rsa, &n2, NULL, NULL);
#else
n1 = pk->key.key_rsa->n;
n2 = sk->key_rsa->n;
#endif

if (BN_cmp (n1, n2) != 0) {
g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYHASHMISMATCH,
"pubkey does not match private key");
return FALSE;
}

return TRUE;
}

+ 11
- 0
src/libserver/dkim.h View File

@@ -260,6 +260,17 @@ goffset rspamd_dkim_canonize_header_relaxed_str (const gchar *hname,
gchar *out,
gsize outlen);

/**
* Checks public and private keys for match
* @param pk
* @param sk
* @param err
* @return
*/
gboolean rspamd_dkim_match_keys (rspamd_dkim_key_t *pk,
rspamd_dkim_sign_key_t *sk,
GError **err);

/**
* Free DKIM key
* @param key

+ 30
- 4
src/plugins/dkim_check.c View File

@@ -618,7 +618,8 @@ lua_dkim_sign_handler (lua_State *L)
GError *err = NULL;
GString *hdr;
const gchar *selector = NULL, *domain = NULL, *key = NULL, *rawkey = NULL,
*headers = NULL, *sign_type_str = NULL, *arc_cv = NULL;
*headers = NULL, *sign_type_str = NULL, *arc_cv = NULL,
*pubkey = NULL;
rspamd_dkim_sign_context_t *ctx;
rspamd_dkim_sign_key_t *dkim_key;
gsize rawlen = 0, keylen = 0;
@@ -633,11 +634,11 @@ lua_dkim_sign_handler (lua_State *L)
*/
if (!rspamd_lua_parse_table_arguments (L, 2, &err,
"key=V;rawkey=V;*domain=S;*selector=S;no_cache=B;headers=S;"
"sign_type=S;arc_idx=I;arc_cv=S;expire=I",
"sign_type=S;arc_idx=I;arc_cv=S;expire=I;pubkey=S",
&keylen, &key, &rawlen, &rawkey, &domain,
&selector, &no_cache, &headers,
&sign_type_str, &arc_idx, &arc_cv, &expire)) {
msg_err_task ("invalid return value from sign condition: %e",
&sign_type_str, &arc_idx, &arc_cv, &expire, &pubkey)) {
msg_err_task ("cannot parse table arguments: %e",
err);
g_error_free (err);

@@ -766,6 +767,31 @@ lua_dkim_sign_handler (lua_State *L)
}
}

if (pubkey != NULL) {
/* Also check if private and public keys match */
rspamd_dkim_key_t *pk;
gsize keylen = strlen (pubkey);

pk = rspamd_dkim_parse_key (pubkey, &keylen, NULL);

if (pk == NULL) {
msg_warn_task ("cannot parse pubkey from string: %s",
pubkey);
}
else {
GError *te = NULL;

/* We have parsed the key, so try to check keys */
if (!rspamd_dkim_match_keys (pk, dkim_key, &te)) {
msg_warn_task ("public key for %s/%s does not match private key: %e",
domain, selector, te);
g_error_free (te);

/* TODO: add fatal failure possibility */
}
}
}

ctx = rspamd_create_dkim_sign_context (task, dkim_key,
DKIM_CANON_RELAXED, DKIM_CANON_RELAXED,
headers, sign_type, &err);

Loading…
Cancel
Save