/* This file is part of Mailfromd.
   Copyright (C) 2020-2025 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

/* DKIM implementation defines */

/* Verification result codes are defined in status.h */
#include <mflib/status.h>

/* Canonicalization types. */
enum {
	DKIM_CANON_ERR = -1,
	DKIM_CANON_SIMPLE,
	DKIM_CANON_RELAXED
};

#define DKIM_VERSION "1"
#define DKIM_KEYRECORD_VERSION "DKIM1"
#define DKIM_SIGNATURE_HEADER "DKIM-Signature"
#define DKIM_QUERY_METHOD "dns/txt"
#define DKIM_KEY_TYPE "rsa"

enum dkim_algorithm {
	DKIM_ALGO_RSA_SHA1,
	DKIM_ALGO_RSA_SHA256
};

#define DKIM_ALGO_DEFAULT DKIM_ALGO_RSA_SHA256

extern char const *dkim_algo_str[];
int dkim_algo(char const *a);

/* Special value for the signature "l" member */
#define DKIM_LENGTH_ALL ((size_t)~0)

/*
 * Structure governing creation and verification of a DKIM signature.
 * Most members are named after the DKIM-Signature tags.
 * See RFC 6376, 3.5.  "The DKIM-Signature Header Field" (page 17).
 */
struct dkim_signature {
	char *a;
	int algo;
	uint8_t *b;
	uint8_t *bh;
	int canon[2];
	char *d;
	char *s;
	char *h;
	char *i;
	size_t l;
	char *q;
	time_t t;
	time_t x;
	char *v;
};

/* Convert canonicalization type to a DKIM_CANON_ constant. */
int dkim_str_to_canon_type(char const *str, char **endp);

/*
 * Create canonicalizer filter for STREAM.  Use canonicalization types
 * supplied by CANON_HEADER and CANON_BODY.  FLAGS are mailutils stream
 * flags (normally MU_STREAM_READ).
 */
int dkim_canonicalizer_create(mu_stream_t *pstream,
			      mu_stream_t stream,
			      int canon_header,
			      int canon_body,
			      int flags);

/*
 * Sign the message MSG using the SIG and private key PRIV_KEY.
 * Return the created DKIM-Signature header in RET_SIGHDR.
 */
int mfd_dkim_sign(mu_message_t msg, struct dkim_signature *sig,
		  char *priv_key, char **ret_sighdr);

int dkim_header_list_match(char const *h_list, char const *h);

/* Explanatory error codes */
enum {
	DKIM_EXPL_OK                  = _MFL_DKIM_EXPL_OK,
	DKIM_EXPL_NO_SIG	      = _MFL_DKIM_EXPL_NO_SIG,
	DKIM_EXPL_INTERNAL_ERROR      = _MFL_DKIM_EXPL_INTERNAL_ERROR,
	DKIM_EXPL_SIG_SYNTAX	      = _MFL_DKIM_EXPL_SIG_SYNTAX,
	DKIM_EXPL_SIG_MISS	      = _MFL_DKIM_EXPL_SIG_MISS,
	DKIM_EXPL_DOMAIN_MISMATCH     = _MFL_DKIM_EXPL_DOMAIN_MISMATCH,
	DKIM_EXPL_BAD_VERSION	      = _MFL_DKIM_EXPL_BAD_VERSION,
	DKIM_EXPL_BAD_ALGORITHM	      = _MFL_DKIM_EXPL_BAD_ALGORITHM,
	DKIM_EXPL_BAD_QUERY	      = _MFL_DKIM_EXPL_BAD_QUERY,
	DKIM_EXPL_FROM		      = _MFL_DKIM_EXPL_FROM,
	DKIM_EXPL_EXPIRED	      = _MFL_DKIM_EXPL_EXPIRED,
	DKIM_EXPL_DNS_UNAVAIL	      = _MFL_DKIM_EXPL_DNS_UNAVAIL,
	DKIM_EXPL_DNS_NOTFOUND	      = _MFL_DKIM_EXPL_DNS_NOTFOUND,
	DKIM_EXPL_KEY_SYNTAX	      = _MFL_DKIM_EXPL_KEY_SYNTAX,
	DKIM_EXPL_KEY_REVOKED	      = _MFL_DKIM_EXPL_KEY_REVOKED,
	DKIM_EXPL_BAD_BODY	      = _MFL_DKIM_EXPL_BAD_BODY,
	DKIM_EXPL_BAD_BASE64	      = _MFL_DKIM_EXPL_BAD_BASE64,
	DKIM_EXPL_BAD_SIG             = _MFL_DKIM_EXPL_BAD_SIG,
	DKIM_EXPL_BAD_KEY_TYPE        = _MFL_DKIM_EXPL_BAD_KEY_TYPE,
};

/* Verification error codes */
enum {
	DKIM_VERIFY_OK = _MFL_DKIM_VERIFY_OK,
	DKIM_VERIFY_PERMFAIL = _MFL_DKIM_VERIFY_PERMFAIL,
	DKIM_VERIFY_TEMPFAIL = _MFL_DKIM_VERIFY_TEMPFAIL,
};

int mfd_dkim_verify(mu_message_t msg, char **sigstr, char const **algo);

extern char const *dkim_explanation_str[];
extern int dkim_result_trans[];
