#include "libcryptobox/keypair.h"
#include "libcryptobox/keypair_private.h"
#include "libutil/str_util.h"
+#include "libutil/printf.h"
/**
* Returns specific private key for different keypair types
struct rspamd_cryptobox_keypair*
-rspamd_keypair_ref (struct rspamd_cryptobox_keypair *kp)
+rspamd__keypair_ref (struct rspamd_cryptobox_keypair *kp)
{
REF_RETAIN (kp);
return kp;
return NULL;
}
+
+const guchar *
+rspamd_pubkey_calculate_nm (struct rspamd_cryptobox_pubkey *p,
+ struct rspamd_cryptobox_keypair *kp)
+{
+ g_assert (kp->alg == p->alg);
+ g_assert (kp->type == p->type);
+ g_assert (p->type == RSPAMD_KEYPAIR_KEX);
+
+ if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) {
+ struct rspamd_cryptobox_pubkey_25519 *rk_25519 =
+ RSPAMD_CRYPTOBOX_PUBKEY_25519(p);
+ struct rspamd_cryptobox_keypair_25519 *sk_25519 =
+ RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp);
+
+ rspamd_cryptobox_nm (p->nm->nm, rk_25519->pk, sk_25519->sk, p->alg);
+ }
+ else {
+ struct rspamd_cryptobox_pubkey_nist *rk_nist =
+ RSPAMD_CRYPTOBOX_PUBKEY_NIST(p);
+ struct rspamd_cryptobox_keypair_nist *sk_nist =
+ RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp);
+
+ rspamd_cryptobox_nm (p->nm->nm, rk_nist->pk, sk_nist->sk, p->alg);
+ }
+
+ return p->nm->nm;
+}
+
+const guchar *
+rspamd_keypair_get_id (struct rspamd_cryptobox_keypair *kp)
+{
+ g_assert (kp != NULL);
+
+ return kp->id;
+}
+
+const guchar *
+rspamd_pubkey_get_id (struct rspamd_cryptobox_pubkey *pk)
+{
+ g_assert (pk != NULL);
+
+ return pk->id;
+}
+
+
+static void
+rspamd_keypair_print_component (guchar *data, gsize datalen,
+ GString *res, guint how, const gchar *description)
+{
+ gint olen, b32_len;
+
+ if (how & RSPAMD_KEYPAIR_HUMAN) {
+ g_string_append_printf (res, "%s: ", description);
+ }
+
+ if (how & RSPAMD_KEYPAIR_BASE32) {
+ b32_len = (datalen * 8 / 5) + 2;
+ g_string_set_size (res, res->len + b32_len);
+ olen = rspamd_encode_base32_buf (data, datalen, res->str + res->len,
+ res->len + b32_len - 1);
+
+ if (olen > 0) {
+ res->len += olen;
+ res->str[res->len] = '\0';
+ }
+ }
+ else if (how & RSPAMD_KEYPAIR_HEX) {
+ rspamd_printf_gstring (res, "%*xs", (gint)datalen, data);
+ }
+ else {
+ g_string_append_len (res, data, datalen);
+ }
+
+ if (how & RSPAMD_KEYPAIR_HUMAN) {
+ g_string_append_c (res, '\n');
+ }
+}
+
+GString *
+rspamd_keypair_print (struct rspamd_cryptobox_keypair *kp, guint how)
+{
+ GString *res;
+ guint len;
+ gpointer p;
+
+ g_assert (kp != NULL);
+
+ res = g_string_sized_new (64);
+
+ if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
+ p = rspamd_cryptobox_keypair_pk (kp, &len);
+ rspamd_keypair_print_component (p, len, res, how, "Public key");
+ }
+ if ((how & RSPAMD_KEYPAIR_PRIVKEY)) {
+ p = rspamd_cryptobox_keypair_sk (kp, &len);
+ rspamd_keypair_print_component (p, len, res, how, "Private key");
+ }
+ if ((how & RSPAMD_KEYPAIR_ID_SHORT)) {
+ rspamd_keypair_print_component (kp->id, 5, res, how, "Short key ID");
+ }
+ if ((how & RSPAMD_KEYPAIR_ID)) {
+ rspamd_keypair_print_component (kp->id, sizeof (kp->id), res, how, "Key ID");
+ }
+
+ return res;
+}
struct _rspamd_http_privbuf *buf;
gboolean new_header;
gboolean encrypted;
- gpointer peer_key;
- struct rspamd_http_keypair *local_key;
+ struct rspamd_cryptobox_pubkey *peer_key;
+ struct rspamd_cryptobox_keypair *local_key;
struct rspamd_http_header *header;
struct http_parser parser;
struct http_parser_settings parser_cb;
return g_quark_from_static_string ("http-error-quark");
}
-static void
-rspamd_http_keypair_dtor (struct rspamd_http_keypair *kp)
-{
- rspamd_explicit_memzero (kp->sk, sizeof (kp->sk));
- rspamd_explicit_memzero (kp->nm, sizeof (kp->nm));
- g_slice_free1 (sizeof (*kp), kp);
-}
-
static void
rspamd_http_privbuf_dtor (gpointer ud)
{
rspamd_http_parse_key (rspamd_ftok_t *data, struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv)
{
- guchar *decoded_id, *decoded_key;
+ guchar *decoded_id;
const gchar *eq_pos;
- gsize id_len, key_len;
- struct rspamd_http_keypair *kp;
+ gsize id_len;
+ struct rspamd_cryptobox_pubkey *pk;
if (priv->local_key == NULL) {
/* In this case we cannot do anything, e.g. we cannot decrypt payload */
if (eq_pos != NULL) {
decoded_id = rspamd_decode_base32 (data->begin, eq_pos - data->begin,
&id_len);
- decoded_key = rspamd_decode_base32 (eq_pos + 1, data->begin + data->len -
- eq_pos - 1, &key_len);
- if (decoded_id != NULL && decoded_key != NULL) {
- if (id_len >= RSPAMD_HTTP_KEY_ID_LEN &&
- key_len >= rspamd_cryptobox_pk_bytes ()) {
- if (memcmp (priv->local_key->id, decoded_id,
+
+ if (decoded_id != NULL && id_len >= RSPAMD_HTTP_KEY_ID_LEN) {
+ pk = rspamd_pubkey_from_base32 (eq_pos + 1,
+ data->begin + data->len - eq_pos - 1,
+ RSPAMD_KEYPAIR_KEX,
+ RSPAMD_CRYPTOBOX_MODE_25519);
+ if (pk != NULL) {
+ if (memcmp (rspamd_keypair_get_id (priv->local_key),
+ decoded_id,
RSPAMD_HTTP_KEY_ID_LEN) == 0) {
- kp = g_slice_alloc0 (sizeof (*kp));
- REF_INIT_RETAIN (kp, rspamd_http_keypair_dtor);
- memcpy (kp->pk, decoded_key, rspamd_cryptobox_pk_bytes ());
- priv->msg->peer_key = kp;
+ priv->msg->peer_key = pk;
if (conn->cache && priv->msg->peer_key) {
rspamd_keypair_cache_process (conn->cache,
}
}
}
+
priv->encrypted = TRUE;
- g_free (decoded_key);
g_free (decoded_id);
}
}
static int
rspamd_http_decrypt_message (struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv,
- struct rspamd_http_keypair *peer_key)
+ struct rspamd_cryptobox_pubkey *peer_key)
{
guchar *nonce, *m;
+ const guchar *nm;
gsize dec_len;
struct rspamd_http_message *msg = priv->msg;
struct rspamd_http_header *hdr, *hdrtmp;
struct http_parser decrypted_parser;
struct http_parser_settings decrypted_cb;
+ enum rspamd_cryptobox_mode mode;
+ mode = rspamd_keypair_alg (priv->local_key);
nonce = msg->body->str;
- m = msg->body->str + rspamd_cryptobox_nonce_bytes () +
- rspamd_cryptobox_mac_bytes ();
- dec_len = msg->body->len - rspamd_cryptobox_nonce_bytes () -
- rspamd_cryptobox_mac_bytes ();
+ m = msg->body->str + rspamd_cryptobox_nonce_bytes (mode) +
+ rspamd_cryptobox_mac_bytes (mode);
+ dec_len = msg->body->len - rspamd_cryptobox_nonce_bytes (mode) -
+ rspamd_cryptobox_mac_bytes (mode);
- if (!peer_key->has_nm) {
- /* We still save NM for the following encryption */
- rspamd_cryptobox_nm (peer_key->nm, peer_key->pk, priv->local_key->sk);
- peer_key->has_nm = TRUE;
+ if ((nm = rspamd_pubkey_get_nm (peer_key)) == NULL) {
+ nm = rspamd_pubkey_calculate_nm (peer_key, priv->local_key);
}
if (!rspamd_cryptobox_decrypt_nm_inplace (m, dec_len, nonce,
- peer_key->nm, m - rspamd_cryptobox_mac_bytes ())) {
+ nm, m - rspamd_cryptobox_mac_bytes (mode), mode)) {
msg_err ("cannot verify encrypted message");
return -1;
}
(struct rspamd_http_connection *)parser->data;
struct rspamd_http_connection_private *priv;
int ret = 0;
- struct rspamd_http_keypair *peer_key = NULL;
+ enum rspamd_cryptobox_mode mode;
priv = conn->priv;
if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) == 0 && priv->encrypted) {
+ mode = rspamd_keypair_alg (priv->local_key);
+
if (priv->local_key == NULL || priv->msg->peer_key == NULL ||
- priv->msg->body->len < rspamd_cryptobox_nonce_bytes () +
- rspamd_cryptobox_mac_bytes ()) {
+ priv->msg->body->len < rspamd_cryptobox_nonce_bytes (mode) +
+ rspamd_cryptobox_mac_bytes (mode)) {
msg_err ("cannot decrypt message");
return -1;
}
/* We have keys, so we can decrypt message */
- peer_key = (struct rspamd_http_keypair *)priv->msg->peer_key;
- ret = rspamd_http_decrypt_message (conn, priv, peer_key);
+ ret = rspamd_http_decrypt_message (conn, priv, priv->msg->peer_key);
if (ret != 0) {
return ret;
rspamd_http_connection_free (struct rspamd_http_connection *conn)
{
struct rspamd_http_connection_private *priv;
- struct rspamd_http_keypair *peer_key;
priv = conn->priv;
rspamd_http_connection_reset (conn);
if (priv->local_key) {
- REF_RELEASE (priv->local_key);
+ rspamd_keypair_unref (priv->local_key);
}
if (priv->peer_key) {
- peer_key = (struct rspamd_http_keypair *)priv->peer_key;
- REF_RELEASE (peer_key);
+ rspamd_pubkey_unref (priv->peer_key);
}
g_slice_free1 (sizeof (struct rspamd_http_connection_private), priv);
gint hdrcount,
guchar *np,
guchar *mp,
- struct rspamd_http_keypair *peer_key)
+ struct rspamd_cryptobox_pubkey *peer_key)
{
struct rspamd_cryptobox_segment *segments;
- guchar *crlfp = mp + rspamd_cryptobox_mac_bytes ();
+ guchar *crlfp;
+ const guchar *nm;
gint i, cnt;
guint outlen;
struct rspamd_http_header *hdr;
+ enum rspamd_cryptobox_mode mode;
+
+ mode = rspamd_keypair_alg (priv->local_key);
+ crlfp = mp + rspamd_cryptobox_mac_bytes (mode);
outlen = priv->out[0].iov_len + priv->out[1].iov_len;
/*
cnt = i;
- if (!peer_key->has_nm) {
- rspamd_cryptobox_nm (peer_key->nm, peer_key->pk, priv->local_key->sk);
- peer_key->has_nm = TRUE;
+ if ((nm = rspamd_pubkey_get_nm (peer_key))) {
+ nm = rspamd_pubkey_calculate_nm (peer_key, priv->local_key);
}
- rspamd_cryptobox_encryptv_nm_inplace (segments,
- cnt,
- np,
- peer_key->nm, mp);
+ rspamd_cryptobox_encryptv_nm_inplace (segments, cnt, np, nm, mp, mode);
/*
* iov[0] = base HTTP request
* iov[4..i] = encrypted HTTP request/reply
*/
priv->out[2].iov_base = np;
- priv->out[2].iov_len = rspamd_cryptobox_nonce_bytes ();
+ priv->out[2].iov_len = rspamd_cryptobox_nonce_bytes (mode);
priv->out[3].iov_base = mp;
- priv->out[3].iov_len = rspamd_cryptobox_mac_bytes ();
+ priv->out[3].iov_len = rspamd_cryptobox_mac_bytes (mode);
- outlen += rspamd_cryptobox_nonce_bytes () + rspamd_cryptobox_mac_bytes ();
+ outlen += rspamd_cryptobox_nonce_bytes (mode) +
+ rspamd_cryptobox_mac_bytes (mode);
for (i = 0; i < cnt; i ++) {
priv->out[i + 4].iov_base = segments[i].data;
gsize bodylen, enclen = 0;
rspamd_fstring_t *buf;
gboolean encrypted = FALSE;
- gchar *b32_key, *b32_id;
guchar nonce[rspamd_cryptobox_MAX_NONCEBYTES], mac[rspamd_cryptobox_MAX_MACBYTES],
id[rspamd_cryptobox_HASHBYTES];
guchar *np = NULL, *mp = NULL, *meth_pos = NULL;
- struct rspamd_http_keypair *peer_key = NULL;
+ struct rspamd_cryptobox_pubkey *peer_key = NULL;
+ enum rspamd_cryptobox_mode mode;
conn->fd = fd;
conn->ud = ud;
}
if (encrypted) {
+ mode = rspamd_keypair_alg (priv->local_key);
+
if (msg->body == NULL || msg->body->len == 0) {
pbody = NULL;
bodylen = 0;
* [iov[n + 2] = encrypted body]
*/
priv->outlen = 7;
- enclen = rspamd_cryptobox_nonce_bytes () +
- rspamd_cryptobox_mac_bytes () +
+ enclen = rspamd_cryptobox_nonce_bytes (mode) +
+ rspamd_cryptobox_mac_bytes (mode) +
4 + /* 2 * CRLF */
bodylen;
}
ENCRYPTED_VERSION);
}
- enclen = rspamd_cryptobox_nonce_bytes () +
- rspamd_cryptobox_mac_bytes () +
+ enclen = rspamd_cryptobox_nonce_bytes (mode) +
+ rspamd_cryptobox_mac_bytes (mode) +
preludelen + /* version [content-length] + 2 * CRLF */
bodylen;
}
}
}
- peer_key = (struct rspamd_http_keypair *)msg->peer_key;
+ peer_key = msg->peer_key;
priv->wr_total = bodylen + buf->len + 2;
hdrcount = 0;
}
if (encrypted) {
- memcpy (id, peer_key->id, sizeof (id));
- b32_key = rspamd_encode_base32 (priv->local_key->pk,
- rspamd_cryptobox_pk_bytes ());
- b32_id = rspamd_encode_base32 (id, RSPAMD_HTTP_KEY_ID_LEN);
+ GString *b32_key, *b32_id;
+
+ memcpy (id, rspamd_pubkey_get_id (peer_key), sizeof (id));
+ b32_key = rspamd_keypair_print (priv->local_key,
+ RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_BASE32);
+ b32_id = rspamd_keypair_print (priv->local_key,
+ RSPAMD_KEYPAIR_ID_SHORT|RSPAMD_KEYPAIR_BASE32);
/* XXX: add some fuzz here */
rspamd_printf_fstring (&buf, "Key: %s=%s\r\n", b32_id, b32_key);
g_free (b32_key);
/* Buf will be used eventually for encryption */
if (encrypted) {
gint meth_offset, nonce_offset, mac_offset;
+ mode = rspamd_keypair_alg (priv->local_key);
- ottery_rand_bytes (nonce, rspamd_cryptobox_nonce_bytes ());
- memset (mac, 0, rspamd_cryptobox_mac_bytes ());
+ ottery_rand_bytes (nonce, rspamd_cryptobox_nonce_bytes (mode));
+ memset (mac, 0, rspamd_cryptobox_mac_bytes (mode));
meth_offset = buf->len;
if (conn->type == RSPAMD_HTTP_SERVER) {
}
nonce_offset = buf->len;
- buf = rspamd_fstring_append (buf, nonce, rspamd_cryptobox_nonce_bytes ());
+ buf = rspamd_fstring_append (buf, nonce,
+ rspamd_cryptobox_nonce_bytes (mode));
mac_offset = buf->len;
- buf = rspamd_fstring_append (buf, mac, rspamd_cryptobox_mac_bytes ());
+ buf = rspamd_fstring_append (buf, mac,
+ rspamd_cryptobox_mac_bytes (mode));
/* Need to be encrypted */
if (conn->type == RSPAMD_HTTP_SERVER) {
rspamd_fstring_free (msg->host);
}
if (msg->peer_key != NULL) {
- rspamd_http_connection_key_unref (msg->peer_key);
+ rspamd_pubkey_unref (msg->peer_key);
}
g_slice_free1 (sizeof (struct rspamd_http_message), msg);
void
rspamd_http_router_set_key (struct rspamd_http_connection_router *router,
- gpointer key)
+ struct rspamd_cryptobox_keypair *key)
{
- struct rspamd_http_keypair *kp = (struct rspamd_http_keypair *)key;
-
g_assert (key != NULL);
- REF_RETAIN (kp);
- router->key = key;
+ router->key = rspamd_keypair_ref (key);
}
void
rspamd_http_router_free (struct rspamd_http_connection_router *router)
{
struct rspamd_http_connection_entry *conn, *tmp;
- struct rspamd_http_keypair *kp;
if (router) {
DL_FOREACH_SAFE (router->conns, conn, tmp)
}
if (router->key) {
- kp = (struct rspamd_http_keypair *)router->key;
- REF_RELEASE (kp);
+ rspamd_keypair_unref (router->key);
}
if (router->cache) {
}
}
-gpointer
-rspamd_http_connection_make_key (gchar *key, gsize keylen)
-{
- guchar *decoded_sk, *decoded_pk;
- gchar *semicolon;
- gsize decoded_len;
- struct rspamd_http_keypair *kp;
- guchar kh[rspamd_cryptobox_HASHBYTES];
-
- semicolon = memchr (key, ':', keylen);
-
- if (semicolon) {
- decoded_sk = rspamd_decode_base32 (key, semicolon - key, &decoded_len);
- decoded_pk = rspamd_decode_base32 (semicolon + 1,
- keylen - (semicolon - key + 1),
- &decoded_len);
- }
- else {
- decoded_sk = rspamd_decode_base32 (key, keylen / 2, &decoded_len);
- decoded_pk = rspamd_decode_base32 (key + keylen / 2,
- keylen / 2,
- &decoded_len);
- }
-
- if (decoded_pk != NULL && decoded_sk != NULL) {
- if (decoded_len == rspamd_cryptobox_pk_bytes ()) {
- kp = g_slice_alloc (sizeof (*kp));
- REF_INIT_RETAIN (kp, rspamd_http_keypair_dtor);
- memcpy (kp->sk, decoded_sk, rspamd_cryptobox_sk_bytes ());
- memcpy (kp->pk, decoded_pk, rspamd_cryptobox_pk_bytes ());
- rspamd_cryptobox_hash (kh, kp->pk, rspamd_cryptobox_pk_bytes (),
- NULL, 0);
- memcpy (kp->id, kh, sizeof (kp->id));
-
- return (gpointer) kp;
- }
- g_free (decoded_pk);
- g_free (decoded_sk);
- }
-
- return NULL;
-}
-
-gpointer
-rspamd_http_connection_gen_key (void)
-{
- struct rspamd_http_keypair *kp;
- guchar kh[rspamd_cryptobox_HASHBYTES];
-
- kp = g_slice_alloc (sizeof (*kp));
- REF_INIT_RETAIN (kp, rspamd_http_keypair_dtor);
-
- rspamd_cryptobox_keypair (kp->pk, kp->sk);
- rspamd_cryptobox_hash (kh, kp->pk, rspamd_cryptobox_pk_bytes (),
- NULL, 0);
- memcpy (kp->id, kh, sizeof (kp->id));
-
- return (gpointer)kp;
-}
-
-static void
-rspamd_http_print_key_component (guchar *data, gsize datalen,
- GString *res, guint how, const gchar *description)
-{
- gchar *b32;
-
- if (how & RSPAMD_KEYPAIR_HUMAN) {
- g_string_append_printf (res, "%s: ", description);
- }
-
- if (how & RSPAMD_KEYPAIR_BASE32) {
- b32 = rspamd_encode_base32 (data, datalen);
- g_string_append_printf (res, "%s", b32);
- g_free (b32);
- }
- else if (how & RSPAMD_KEYPAIR_HEX) {
- rspamd_printf_gstring (res, "%*xs", (gint)datalen, data);
- }
- else {
- g_string_append_len (res, data, datalen);
- }
-
- if (how & RSPAMD_KEYPAIR_HUMAN) {
- g_string_append_c (res, '\n');
- }
-}
-
-GString *
-rspamd_http_connection_print_key (gpointer key, guint how)
-{
- struct rspamd_http_keypair *kp = (struct rspamd_http_keypair *)key;
- GString *res;
-
- g_assert (key != NULL);
-
- res = g_string_new (NULL);
-
- if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
- rspamd_http_print_key_component (kp->pk,
- rspamd_cryptobox_pk_bytes (), res, how,
- "Public key");
- }
- if ((how & RSPAMD_KEYPAIR_PRIVKEY)) {
- rspamd_http_print_key_component (kp->sk, rspamd_cryptobox_sk_bytes (),
- res, how,
- "Private key");
- }
- if ((how & RSPAMD_KEYPAIR_ID)) {
- rspamd_http_print_key_component (kp->id, RSPAMD_HTTP_KEY_ID_LEN, res, how,
- "Key ID");
- }
-
- return res;
-}
-
void
rspamd_http_connection_set_key (struct rspamd_http_connection *conn,
- gpointer key)
+ struct rspamd_cryptobox_keypair *key)
{
struct rspamd_http_connection_private *priv = conn->priv;
- struct rspamd_http_keypair *kp = (struct rspamd_http_keypair *)key;
g_assert (key != NULL);
- REF_RETAIN (kp);
- priv->local_key = kp;
+ priv->local_key = rspamd_keypair_ref (key);
}
gboolean
return FALSE;
}
-void
-rspamd_http_connection_key_unref (gpointer key)
-{
- struct rspamd_http_keypair *kp = (struct rspamd_http_keypair *)key;
-
- g_assert (key != NULL);
- REF_RELEASE (kp);
-}
-
-gpointer
-rspamd_http_connection_key_ref (gpointer key)
-{
- struct rspamd_http_keypair *kp = (struct rspamd_http_keypair *)key;
-
- g_assert (key != NULL);
- REF_RETAIN (kp);
-
- return kp;
-}
-
-gpointer
-rspamd_http_connection_make_peer_key (const gchar *key)
-{
- guchar *pk_decoded;
- gsize dec_len;
- struct rspamd_http_keypair *kp = NULL;
- guchar kh[rspamd_cryptobox_HASHBYTES];
-
- pk_decoded = rspamd_decode_base32 (key, strlen (key), &dec_len);
-
- if (pk_decoded != NULL && dec_len == rspamd_cryptobox_pk_bytes ()) {
- kp = g_slice_alloc0 (sizeof (*kp));
- REF_INIT_RETAIN (kp, rspamd_http_keypair_dtor);
- memcpy (kp->pk, pk_decoded, rspamd_cryptobox_pk_bytes ());
- rspamd_cryptobox_hash (kh, kp->pk, rspamd_cryptobox_pk_bytes (),
- NULL, 0);
- memcpy (kp->id, kh, sizeof (kp->id));
- }
-
- g_free (pk_decoded);
-
- return kp;
-}
-
GHashTable *
rspamd_http_message_parse_query (struct rspamd_http_message *msg)
{