/*- * Copyright 2016 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "config.h" #include "rspamd.h" #include "keypairs_cache.h" #include "keypair_private.h" #include "hash.h" struct rspamd_keypair_elt { struct rspamd_cryptobox_nm *nm; guchar pair[rspamd_cryptobox_HASHBYTES * 2]; }; struct rspamd_keypair_cache { rspamd_lru_hash_t *hash; }; static void rspamd_keypair_destroy (gpointer ptr) { struct rspamd_keypair_elt *elt = (struct rspamd_keypair_elt *)ptr; REF_RELEASE (elt->nm); g_slice_free1 (sizeof (*elt), elt); } static guint rspamd_keypair_hash (gconstpointer ptr) { struct rspamd_keypair_elt *elt = (struct rspamd_keypair_elt *)ptr; return rspamd_cryptobox_fast_hash (elt->pair, sizeof (elt->pair), rspamd_hash_seed ()); } static gboolean rspamd_keypair_equal (gconstpointer p1, gconstpointer p2) { struct rspamd_keypair_elt *e1 = (struct rspamd_keypair_elt *)p1, *e2 = (struct rspamd_keypair_elt *)p2; return memcmp (e1->pair, e2->pair, sizeof (e1->pair)) == 0; } struct rspamd_keypair_cache * rspamd_keypair_cache_new (guint max_items) { struct rspamd_keypair_cache *c; g_assert (max_items > 0); c = g_slice_alloc (sizeof (*c)); c->hash = rspamd_lru_hash_new_full (max_items, NULL, rspamd_keypair_destroy, rspamd_keypair_hash, rspamd_keypair_equal); return c; } void rspamd_keypair_cache_process (struct rspamd_keypair_cache *c, struct rspamd_cryptobox_keypair *lk, struct rspamd_cryptobox_pubkey *rk) { struct rspamd_keypair_elt search, *new; g_assert (lk != NULL); g_assert (rk != NULL); g_assert (rk->alg == lk->alg); g_assert (rk->type == lk->type); g_assert (rk->type == RSPAMD_KEYPAIR_KEX); memset (&search, 0, sizeof (search)); memcpy (search.pair, rk->id, rspamd_cryptobox_HASHBYTES); memcpy (&search.pair[rspamd_cryptobox_HASHBYTES], lk->id, rspamd_cryptobox_HASHBYTES); new = rspamd_lru_hash_lookup (c->hash, &search, time (NULL)); if (rk->nm) { REF_RELEASE (rk->nm); rk->nm = NULL; } if (new == NULL) { new = g_slice_alloc0 (sizeof (*new)); if (posix_memalign ((void **)&new->nm, 32, sizeof (*new->nm)) != 0) { abort (); } REF_INIT_RETAIN (new->nm, rspamd_cryptobox_nm_dtor); memcpy (new->pair, rk->id, rspamd_cryptobox_HASHBYTES); memcpy (&new->pair[rspamd_cryptobox_HASHBYTES], lk->id, rspamd_cryptobox_HASHBYTES); if (rk->alg == RSPAMD_CRYPTOBOX_MODE_25519) { struct rspamd_cryptobox_pubkey_25519 *rk_25519 = RSPAMD_CRYPTOBOX_PUBKEY_25519(rk); struct rspamd_cryptobox_keypair_25519 *sk_25519 = RSPAMD_CRYPTOBOX_KEYPAIR_25519(lk); rspamd_cryptobox_nm (new->nm->nm, rk_25519->pk, sk_25519->sk, rk->alg); } else { struct rspamd_cryptobox_pubkey_nist *rk_nist = RSPAMD_CRYPTOBOX_PUBKEY_NIST(rk); struct rspamd_cryptobox_keypair_nist *sk_nist = RSPAMD_CRYPTOBOX_KEYPAIR_NIST(lk); rspamd_cryptobox_nm (new->nm->nm, rk_nist->pk, sk_nist->sk, rk->alg); } rspamd_lru_hash_insert (c->hash, new, new, time (NULL), -1); } g_assert (new != NULL); rk->nm = new->nm; REF_RETAIN (rk->nm); } void rspamd_keypair_cache_destroy (struct rspamd_keypair_cache *c) { if (c != NULL) { rspamd_lru_hash_destroy (c->hash); g_slice_free1 (sizeof (*c), c); } }