diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-02-05 23:20:10 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-02-05 23:20:10 +0000 |
commit | c13d594abf0c2c1f75b7b55573a047b757e2c2ec (patch) | |
tree | 786cb607a6601eda9b30812927cfac9f6be48521 /src/libutil/http.c | |
parent | c712ffe5b94f3087e53c637352584d120ebc8452 (diff) | |
download | rspamd-c13d594abf0c2c1f75b7b55573a047b757e2c2ec.tar.gz rspamd-c13d594abf0c2c1f75b7b55573a047b757e2c2ec.zip |
Rework HTTP encryption
Diffstat (limited to 'src/libutil/http.c')
-rw-r--r-- | src/libutil/http.c | 320 |
1 files changed, 78 insertions, 242 deletions
diff --git a/src/libutil/http.c b/src/libutil/http.c index c72031bca..4640fbffe 100644 --- a/src/libutil/http.c +++ b/src/libutil/http.c @@ -36,8 +36,8 @@ struct rspamd_http_connection_private { 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; @@ -94,14 +94,6 @@ http_error_quark (void) } 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) { struct _rspamd_http_privbuf *p = (struct _rspamd_http_privbuf *)ud; @@ -408,10 +400,10 @@ static void 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 */ @@ -423,17 +415,17 @@ rspamd_http_parse_key (rspamd_ftok_t *data, struct rspamd_http_connection *conn, 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, @@ -442,8 +434,8 @@ rspamd_http_parse_key (rspamd_ftok_t *data, struct rspamd_http_connection *conn, } } } + priv->encrypted = TRUE; - g_free (decoded_key); g_free (decoded_id); } } @@ -688,29 +680,30 @@ rspamd_http_on_headers_complete_decrypted (http_parser *parser) 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; } @@ -761,21 +754,22 @@ rspamd_http_on_message_complete (http_parser * parser) (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; @@ -1163,7 +1157,6 @@ void rspamd_http_connection_free (struct rspamd_http_connection *conn) { struct rspamd_http_connection_private *priv; - struct rspamd_http_keypair *peer_key; priv = conn->priv; @@ -1171,11 +1164,10 @@ rspamd_http_connection_free (struct rspamd_http_connection *conn) 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); @@ -1241,13 +1233,18 @@ rspamd_http_connection_encrypt_message ( 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; /* @@ -1294,15 +1291,11 @@ rspamd_http_connection_encrypt_message ( 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 @@ -1312,11 +1305,12 @@ rspamd_http_connection_encrypt_message ( * 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; @@ -1342,11 +1336,11 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, 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; @@ -1381,6 +1375,8 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, } if (encrypted) { + mode = rspamd_keypair_alg (priv->local_key); + if (msg->body == NULL || msg->body->len == 0) { pbody = NULL; bodylen = 0; @@ -1405,8 +1401,8 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, * [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; } @@ -1434,8 +1430,8 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, 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; } @@ -1470,7 +1466,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, } } - peer_key = (struct rspamd_http_keypair *)msg->peer_key; + peer_key = msg->peer_key; priv->wr_total = bodylen + buf->len + 2; hdrcount = 0; @@ -1625,10 +1621,13 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, } 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); @@ -1643,9 +1642,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, /* 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) { @@ -1659,9 +1659,11 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn, } 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) { @@ -1829,7 +1831,7 @@ rspamd_http_message_free (struct rspamd_http_message *msg) 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); @@ -2213,14 +2215,11 @@ rspamd_http_router_new (rspamd_http_router_error_handler_t eh, 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 @@ -2273,7 +2272,6 @@ 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) @@ -2282,8 +2280,7 @@ rspamd_http_router_free (struct rspamd_http_connection_router *router) } if (router->key) { - kp = (struct rspamd_http_keypair *)router->key; - REF_RELEASE (kp); + rspamd_keypair_unref (router->key); } if (router->cache) { @@ -2298,131 +2295,14 @@ rspamd_http_router_free (struct rspamd_http_connection_router *router) } } -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 @@ -2440,50 +2320,6 @@ rspamd_http_connection_is_encrypted (struct rspamd_http_connection *conn) 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) { |