return TRUE;
}
-struct rspamd_dkim_sign_chunk {
- const gchar *begin;
- gsize len;
- gboolean append_crlf;
-};
static gboolean
-rspamd_dkim_canonize_header_simple (struct rspamd_dkim_common_ctx *ctx,
- const gchar *headers,
- gsize headers_length,
+rspamd_dkim_canonize_header (struct rspamd_dkim_common_ctx *ctx,
+ struct rspamd_task *task,
const gchar *header_name,
guint count,
- gboolean is_sign,
+ const gchar *dkim_header,
const gchar *dkim_domain)
{
- const gchar *p, *c, *end;
- gint state = 0, hlen;
- gboolean found = FALSE;
- GArray *to_sign;
- struct rspamd_dkim_sign_chunk chunk, *elt = NULL;
- gint i;
-
- /* This process is very similar to raw headers processing */
- to_sign =
- g_array_sized_new (FALSE,
- FALSE,
- sizeof (struct rspamd_dkim_sign_chunk),
- count);
- p = headers;
- end = p + headers_length;
- c = p;
- hlen = strlen (header_name);
+ struct raw_header *rh, *rh_iter;
+ guint rh_num = 0;
+ guint i;
+ GPtrArray *sign_headers;
- while (p < end) {
- switch (state) {
- case 0:
- /* Compare state */
- if (*p == ':') {
- /* Compare header's name with desired one */
- if (p - c == hlen) {
- if (g_ascii_strncasecmp (c, header_name, hlen) == 0) {
- /* Get value */
- state = 2;
- }
- else {
- /* Skip the whole header */
- state = 1;
- }
- }
- else {
- /* Skip the whole header */
- state = 1;
- }
+ if (dkim_header == NULL) {
+ rh = g_hash_table_lookup (task->raw_headers, header_name);
+
+ if (rh) {
+ LL_FOREACH (rh, rh_iter) {
+ rh_num++;
}
- p++;
- break;
- case 1:
- /* Skip header state */
- if (*p == '\n' && !g_ascii_isspace (p[1])) {
- /* Header is skipped */
- state = 0;
- c = p + 1;
+
+ if (rh_num > count) {
+ /* Set skip count */
+ rh_num -= count;
}
- p++;
- break;
- case 2:
- /* c contains the beginning of header */
- if (*p == '\n' && (!g_ascii_isspace (p[1]) || p[1] == '\0')) {
- chunk.begin = c;
- if (*(p - 1) == '\r') {
- chunk.len = p - c + 1;
- chunk.append_crlf = FALSE;
- }
- else {
- /* Need append CRLF as linefeed is not proper */
- chunk.len = p - c;
- chunk.append_crlf = TRUE;
- }
- g_array_append_val (to_sign, chunk);
- c = p + 1;
- state = 0;
- found = TRUE;
+ else {
+ rh_num = 0;
}
- p++;
- break;
- }
- }
- if (found) {
- if (!is_sign) {
+ sign_headers = g_ptr_array_sized_new (rh_num);
+ /* Skip number of headers */
+ rh_iter = rh;
+ while (rh_num) {
+ rh_iter = rh_iter->next;
+ rh_num--;
+ }
+
+ /* Now insert required headers */
+ while (rh_iter) {
+ g_ptr_array_add (sign_headers, rh_iter);
+ rh_iter = rh_iter->next;
+ }
- for (i = to_sign->len - 1; i >= 0 && count > 0; i--, count--) {
- elt =
- &g_array_index (to_sign, struct rspamd_dkim_sign_chunk, i);
+ for (i = 0; i < sign_headers->len; i ++) {
+ rh = g_ptr_array_index (sign_headers, i);
- if (!chunk.append_crlf) {
+ if (ctx->header_canon_type == DKIM_CANON_SIMPLE) {
+ rspamd_dkim_hash_update (ctx->headers_hash, rh->raw_value,
+ rh->raw_len);
msg_debug_dkim ("update signature with header: %*s",
- elt->len,
- elt->begin);
- rspamd_dkim_hash_update (ctx->headers_hash,
- elt->begin,
- elt->len);
+ (gint)rh->raw_len, rh->raw_value);
}
else {
- msg_debug_dkim ("update signature with header: %*s",
- elt->len + 1,
- elt->begin);
- rspamd_dkim_hash_update (ctx->headers_hash,
- elt->begin,
- elt->len + 1);
- }
- }
- }
- else {
- /* Try to find the proper header by domain */
- for (i = to_sign->len - 1; i >= 0; i--) {
- elt = &g_array_index (to_sign,
- struct rspamd_dkim_sign_chunk,
- i);
- if (rspamd_substring_search (elt->begin, elt->len,
- dkim_domain, strlen (dkim_domain)) != -1) {
- break;
+ if (!rspamd_dkim_canonize_header_relaxed (ctx, rh->value,
+ header_name, FALSE)) {
+
+ g_ptr_array_free (sign_headers, TRUE);
+ return FALSE;
+ }
}
}
- if (elt && elt->append_crlf) {
- rspamd_dkim_signature_update (ctx, elt->begin, elt->len + 1);
- }
- else if (elt) {
- rspamd_dkim_signature_update (ctx, elt->begin, elt->len);
- }
+ g_ptr_array_free (sign_headers, TRUE);
}
}
-
- g_array_free (to_sign, TRUE);
-
- return found;
-}
-
-static gboolean
-rspamd_dkim_canonize_header (struct rspamd_dkim_common_ctx *ctx,
- struct rspamd_task *task,
- const gchar *header_name,
- guint count,
- const gchar *dkim_header,
- const gchar *dkim_domain)
-{
- struct raw_header *rh, *rh_iter;
- guint rh_num = 0;
- GList *nh = NULL, *cur;
-
- if (ctx->header_canon_type == DKIM_CANON_SIMPLE) {
- return rspamd_dkim_canonize_header_simple (ctx,
- task->raw_headers_content.begin,
- task->raw_headers_content.len,
- header_name,
- count,
- dkim_header != NULL,
- dkim_domain);
- }
else {
- rh = g_hash_table_lookup (task->raw_headers, header_name);
- if (rh) {
- if (dkim_header == NULL) {
- rh_iter = rh;
- while (rh_iter) {
- rh_num++;
- rh_iter = rh_iter->next;
+ /* For signature check just use the saved dkim header */
+ if (ctx->header_canon_type == DKIM_CANON_SIMPLE) {
+ /* We need to find our own signature and use it */
+ rh = g_hash_table_lookup (task->raw_headers, DKIM_SIGNHEADER);
+
+ if (rh) {
+ /* We need to find our own signature */
+ if (!dkim_domain) {
+ return FALSE;
}
- if (rh_num > count) {
- /* Set skip count */
- rh_num -= count;
- }
- else {
- rh_num = 0;
- }
- rh_iter = rh;
- while (rh_num) {
- rh_iter = rh_iter->next;
- rh_num--;
- }
- /* Now insert required headers */
- while (rh_iter) {
- nh = g_list_prepend (nh, rh_iter);
- rh_iter = rh_iter->next;
- }
- cur = nh;
- while (cur) {
- rh = cur->data;
- if (!rspamd_dkim_canonize_header_relaxed (ctx, rh->value,
- header_name, FALSE)) {
- g_list_free (nh);
- return FALSE;
+ LL_FOREACH (rh, rh_iter) {
+ if (rspamd_substring_search_twoway (rh->raw_value,
+ rh->raw_len, dkim_domain,
+ strlen (dkim_domain)) != -1) {
+ rspamd_dkim_signature_update (ctx, rh->raw_value,
+ rh->raw_len);
+ break;
}
- cur = g_list_next (cur);
- }
- if (nh != NULL) {
- g_list_free (nh);
}
}
else {
- /* For signature check just use the saved dkim header */
- rspamd_dkim_canonize_header_relaxed (ctx,
+ return FALSE;
+ }
+ }
+ else {
+ if (!rspamd_dkim_canonize_header_relaxed (ctx,
dkim_header,
header_name,
- TRUE);
+ TRUE)) {
+ return FALSE;
}
-
- return TRUE;
}
}
- /* TODO: Implement relaxed algorithm */
- return FALSE;
-}
-
-static inline const gchar *
-rspamd_dkim_body_start (const gchar *headers_end, const gchar *body_end)
-{
- const gchar *p = headers_end;
- enum {
- st_start = 0,
- st_cr,
- st_lf,
- } state = st_start;
-
- if (headers_end + 1 >= body_end) {
- return headers_end;
- }
-
- switch (state) {
- case st_start:
- if (*p == '\r') {
- p ++;
- state = st_cr;
- }
- else if (*p == '\n') {
- p ++;
- state = st_lf;
- }
- break;
- case st_cr:
- if (*p == '\n' && p < body_end) {
- /* CRLF */
- p ++;
- }
- break;
- case st_lf:
- break;
- }
-
- return p;
+ return TRUE;
}
/**
rspamd_dkim_key_t *key,
struct rspamd_task *task)
{
- const gchar *p, *headers_end = NULL, *body_end, *body_start;
+ const gchar *p, *body_end, *body_start;
guchar raw_digest[EVP_MAX_MD_SIZE];
gsize dlen;
gint res = DKIM_CONTINUE;
/* First of all find place of body */
p = task->msg.begin;
body_end = task->msg.begin + task->msg.len;
- headers_end = task->msg.begin + task->raw_headers_content.len;
-
- body_start = rspamd_dkim_body_start (headers_end, body_end);
+ body_start = task->msg.begin + task->raw_headers_content.len;
/* Start canonization of body part */
if (!rspamd_dkim_canonize_body (&ctx->common, body_start, body_end)) {
{
GString *hdr;
struct rspamd_dkim_header *dh;
- const gchar *p, *headers_end = NULL, *body_end, *body_start;
+ const gchar *p, *body_end, *body_start;
guchar raw_digest[EVP_MAX_MD_SIZE];
gsize dlen;
guint i, j;
/* First of all find place of body */
p = task->msg.begin;
body_end = task->msg.begin + task->msg.len;
- headers_end = task->msg.begin + task->raw_headers_content.len;
- body_start = rspamd_dkim_body_start (headers_end, body_end);
+ body_start = task->msg.begin + task->raw_headers_content.len;
if (len > 0) {
ctx->common.len = len;