OpenDKIM icon indicating copy to clipboard operation
OpenDKIM copied to clipboard

libopendkim might segfault (assert) with empty reuired header option

Open countsudoku opened this issue 2 years ago • 0 comments

Hello,

I've noticed, that the libopendkim might segfault because of a assertion if I try to sign a message with newlines instead of CRLF via the chunk API with some options set:

  • the required headers (DKIM_OPTS_REQUIREDHDRS) set empty, and
  • the headers to skip (DKIM_OPTS_SKIPHDRS) set to the constant dkim_should_not_signhdrs.

I've noticed that during the a test of the DKIM_LIBFLAGS_FIXCRLF flag. The assertion that is triggered is:

dkim: dkim-canon.c:974: dkim_canon_selecthdrs: Assertion `nptrs != 0' failed.

I admit that this is a rare combination of problematig settings and a problematic mail. But nevertheless should this not happen.

The OpenDkim library version, that was used is (from dkim_libversion): 2.11.0.0

A minimal example to trigger the assertion is:

#include <stdio.h>
#include <string.h>

#include <opendkim/dkim.h>

const char* message =
    "Return-Path: [email protected]\n"
    "\n"
    "This is a test mailing\n";

const char* privateKey = "not needed";

const char* empty[1] = {NULL};

int main()
{
    DKIM_LIB* lib = dkim_init(NULL, NULL);
    DKIM_STAT stat;

    stat = dkim_options(
        lib,
        DKIM_OP_SETOPT,
        DKIM_OPTS_SKIPHDRS,
        &dkim_should_not_signhdrs,
        sizeof(char **));
    if (stat != DKIM_STAT_OK) {
        return 1;
    }

    stat = dkim_options(
        lib,
        DKIM_OP_SETOPT,
        DKIM_OPTS_REQUIREDHDRS,
        empty,
        sizeof(empty));
    if (stat != DKIM_STAT_OK) {
        return 1;
    }

    DKIM* dkim = dkim_sign(
        lib,
        (unsigned char*) "id",
        NULL,
        (unsigned char*) privateKey,
        (unsigned char*) "selector",
        (unsigned char*) "dkim.test",
        DKIM_CANON_SIMPLE,
        DKIM_CANON_SIMPLE,
        DKIM_SIGN_RSASHA256,
        -1,
        &stat);
    if (stat != DKIM_STAT_OK) {
        return 1;
    }

    stat = dkim_signhdrs(dkim, (const char**) dkim_should_signhdrs);
    if (stat != DKIM_STAT_OK) {
        return 1;
    }

    // feed the whole message via the chunk interface
    stat = dkim_chunk(dkim, (unsigned char*) message, strlen(message));
    if (stat != DKIM_STAT_OK) {
        return 1;
    }
    stat = dkim_chunk(dkim, NULL, 0);
    if (stat != DKIM_STAT_OK) {
        return 1;
    }

    dkim_free(dkim);
    dkim_close(lib);
    return 0;
}

countsudoku avatar Mar 23 '23 12:03 countsudoku