/*
**  Copyright (c) 2005-2008 Sendmail, Inc. and its suppliers.
**    All rights reserved.
**
**  Copyright (c) 2009-2014, The Trusted Domain Project.  All rights reserved.
*/

#ifndef _DKIM_TYPES_H_
#define _DKIM_TYPES_H_

#include "build-config.h"

/* system includes */
#include <sys/types.h>
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#endif /* HAVE_STDBOOL_H */
#ifdef USE_TRE
# ifdef TRE_PRE_080
#  include <tre/regex.h>
# else /* TRE_PRE_080 */
#  include <tre/tre.h>
# endif /* TRE_PRE_080 */
#else /* USE_TRE */
# include <regex.h>
#endif /* USE_TRE */

#ifdef USE_GNUTLS
# include <gnutls/gnutls.h>
# include <gnutls/crypto.h>
# include <gnutls/abstract.h>
#else /* USE_GNUTLS */
/* OpenSSL includes */
# include <openssl/pem.h>
# include <openssl/rsa.h>
# include <openssl/bio.h>
# include <openssl/err.h>
# include <openssl/sha.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/decoder.h>
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
#endif /* USE_GNUTLS */

#ifdef QUERY_CACHE
/* libdb includes */
# include <db.h>
#endif /* QUERY_CACHE */

/* libopendkim includes */
#include "dkim.h"
#include "dkim-internal.h"

/* struct dkim_qmethod -- signature query method */
struct dkim_qmethod
{
	char *			qm_type;
	char *			qm_options;
	struct dkim_qmethod *	qm_next;
};

/* struct dkim_xtag -- signature extension tag */
struct dkim_xtag
{
	char *			xt_tag;
	char *			xt_value;
	struct dkim_xtag *	xt_next;
};

/* struct dkim_queryinfo -- DNS query information */
struct dkim_queryinfo
{
	int			dq_type;
	const char		dq_name[DKIM_MAXHOSTNAMELEN + 1];
};

/* struct dkim_dstring -- a dynamically-sized string */
struct dkim_dstring
{
	int			ds_alloc;
	int			ds_max;
	int			ds_len;
	DKIM *		ds_dkim;
	char *		ds_buf;
};


/* hdr_flags bits */
#define	DKIM_HDR_SIGNED		0x01
#define	DKIM_HDR_TO_BE_SIGNED	0x02

/* struct dkim_plist -- a parameter/value pair */
struct dkim_plist
{
	char *              plist_param;
	char *              plist_value;
	struct dkim_plist * plist_next;
};

/* struct dkim_header -- an RFC2822 header of some kind */
struct dkim_header
{
	int         hdr_flags;
	size_t      hdr_textlen;
	size_t      hdr_namelen;
	char *      hdr_text;
	char *      hdr_colon;
	struct dkim_header *hdr_next;
};

/* struct dkim_set -- a set of parameter/value pairs */
struct dkim_set
{
	_Bool               set_bad;
	dkim_set_t          set_type;
	char *              set_data;
	const char *        set_name;
	struct dkim_header* set_udata;
	struct dkim_plist * set_plist[NPRINTABLE];
	struct dkim_set *   set_next;
};

/* struct dkim_siginfo -- signature information for use by the caller */
struct dkim_siginfo
{
	int			sig_dnssec_key;
	u_int			sig_flags;
	int			sig_error;
	int			sig_bh;
	u_int			sig_version;
	u_int			sig_hashtype;
	u_int			sig_keytype;
	u_int			sig_keybits;
	size_t			sig_siglen;
	size_t			sig_keylen;
	// size_t			sig_b64keylen; not used
	dkim_query_t		sig_query;
	dkim_alg_t		sig_signalg;
	dkim_canon_t		sig_hdrcanonalg;
	dkim_canon_t		sig_bodycanonalg;
	uint64_t		sig_timestamp;
	char *		sig_domain;
	char *		sig_selector;
	char *		sig_sig;
	char *		sig_key;
	// char *		sig_b64key; not used
	void *			sig_context;
	void *			sig_signature;
	struct dkim_canon *	sig_hdrcanon;
	struct dkim_canon *	sig_bodycanon;
	struct dkim_set *	sig_taglist;
	struct dkim_set *	sig_keytaglist;
	struct dkim_dstring *	sig_sslerrbuf;
};

/* struct arc_set -- a complete single set of ARC header fields */
struct arc_set
{
	struct dkim_set *	arcset_aar;
	struct dkim_siginfo *	arcsig_ams;
	struct dkim_siginfo *	arcsig_as;
};


#ifdef USE_GNUTLS
/* struct dkim_sha -- stuff needed to do a sha hash */
struct dkim_sha
{
	int              sha_tmpfd;
	u_int            sha_outlen;
	gnutls_hash_hd_t sha_hd;
	char *           sha_out;
};
#else /* USE_GNUTLS */

/* convert to unsigned char*, making sure it's a char* */
static inline unsigned char *char2unsigned_char(char *p)
{return (unsigned char*)p;}

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
struct dkim_sha
{
	EVP_MD_CTX       *ctx;
	char *           sha_out;
	int              sha_tmpfd;
	u_int            sha_outlen;
	_Bool            failed;
};
#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */

/* struct dkim_sha1 -- stuff needed to do a sha1 hash */
struct dkim_sha1
{
	int             sha1_tmpfd;
	BIO *           sha1_tmpbio;
	SHA_CTX         sha1_ctx;
	char            sha1_out[SHA_DIGEST_LENGTH];
};

# ifdef HAVE_SHA256
/* struct dkim_sha256 -- stuff needed to do a sha256 hash */
struct dkim_sha256
{
	int             sha256_tmpfd;
	BIO *           sha256_tmpbio;
	SHA256_CTX      sha256_ctx;
	char            sha256_out[SHA256_DIGEST_LENGTH];
};
# endif /* HAVE_SHA256 */
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
#endif /* USE_GNUTLS */

/* struct dkim_canon -- a canonicalization status handle */
struct dkim_canon
{
	_Bool                   canon_done;
	_Bool                   canon_hdr;
	_Bool                   canon_blankline;
	_Bool                   n_u; // 32bit alignment
	int                     canon_lastchar;
	int                     canon_bodystate;
	int                     canon_hashtype;
	u_int                   canon_blanks;
	dkim_canon_t            canon_canon;
	size_t                  canon_hashbuflen;
	size_t                  canon_hashbufsize;
	ssize_t                 canon_remain;
	ssize_t                 canon_wrote;
	ssize_t                 canon_length;
	char *                  canon_hashbuf;
	char *                  canon_hdrlist;
	void *                  canon_hash;
	struct dkim_dstring *   canon_buf;
	struct dkim_header *    canon_sigheader;
	struct dkim_canon *     canon_next;
};

/* struct dkim_crypto (was dkim_rsa) -- stuff needed to do sign/verify */
struct dkim_crypto
{
#ifdef USE_GNUTLS
	size_t                crypto_rsaoutlen;
	unsigned int          crypto_keysize;
	gnutls_x509_privkey_t crypto_key;
	gnutls_privkey_t      crypto_privkey;
	gnutls_pubkey_t       crypto_pubkey;
	gnutls_datum_t        crypto_sig;
	gnutls_datum_t        crypto_digest;
	gnutls_datum_t        crypto_out;
	gnutls_datum_t        crypto_keydata;
#else /* USE_GNUTLS */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
	EVP_PKEY *            crypto_pkey;
	BIO *                 crypto_keydata;
	char *                crypto_out;
	size_t                crypto_outlen;
	int                   crypto_keysize;
#else /* OPENSSL_VERSION_NUMBER >= 0x30000000L */

	u_char                crypto_pad;
	int                   crypto_keysize;
	size_t                crypto_inlen;
	size_t                crypto_outlen;
	EVP_PKEY *            crypto_pkey;
	void *                crypto_key;
	BIO *                 crypto_keydata;
	char *                crypto_in;
	char *                crypto_out;
#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
#endif /* USE_GNUTLS */
};

/* struct dkim_test_dns_data -- simulated DNS replies */
struct dkim_test_dns_data
{
	int			dns_class;
	int			dns_type;
	int			dns_prec;
	char *		dns_query;
	u_char *		dns_reply;
	struct dkim_test_dns_data * dns_next;
};

/* struct dkim_unbound_cb_data -- libunbound callback data */
struct dkim_unbound_cb_data
{
	int			ubd_done;
	int			ubd_rcode;
	int			ubd_id;
	int			ubd_type;
	u_int			ubd_result;
	DKIM_STAT		ubd_stat;
	size_t			ubd_buflen;
	u_char *		ubd_buf;
	const char *		ubd_jobid;
};

/* struct dkim -- a complete DKIM transaction context */
struct dkim
{
  	struct dkim_qmethod *	dkim_querymethods;
	ssize_t			dkim_bodylen;
	ssize_t			dkim_signlen;
	const char *		dkim_id;
	char *		dkim_domain;
	char *		dkim_user;
	char *		dkim_selector;
	char *		dkim_b64key;
	char *		dkim_b64sig;
	char *		dkim_key;
	char *		dkim_reportaddr;
	char *		dkim_sender; // this is useless
	char *		dkim_signer;
	char *		dkim_error;
//	char *		dkim_hdrlist; only used by dkim_canon_selecthdrs
	char *		dkim_zdecode;
	char *		dkim_tmpdir;
	DKIM_SIGINFO *		dkim_signature;
	void *			dkim_keydata;
	void *			dkim_closure;
	const void *		dkim_user_context;
#ifdef _FFR_RESIGN
	DKIM *			dkim_resign;
#endif /* _FFR_RESIGN */
	struct dkim_xtag *	dkim_xtags;
	struct dkim_siginfo **	dkim_siglist;
	struct dkim_set *	dkim_sethead;
	struct dkim_set *	dkim_settail;
	struct dkim_set *	dkim_sigset;
	struct dkim_header *	dkim_hhead;
	struct dkim_header *	dkim_htail;
	struct dkim_header *	dkim_senderhdr;
	struct dkim_canon *	dkim_canonhead;
	struct dkim_canon *	dkim_canontail;
	struct dkim_dstring *	dkim_hdrbuf;
	struct dkim_dstring *	dkim_canonbuf;
	struct dkim_dstring *	dkim_sslerrbuf;
	struct dkim_test_dns_data * dkim_dnstesth;
	struct dkim_test_dns_data * dkim_dnstestt;
	struct arc_set *arc_sets;
	regex_t *		dkim_hdrre;
	DKIM_LIB *		dkim_libhandle;

	size_t			dkim_margin;
	size_t			dkim_b64siglen;
	size_t			dkim_keylen;
	uint64_t		dkim_timestamp;

	int			dkim_mode;
	int			dkim_state;
	int			dkim_chunkstate;
	int			dkim_chunksm;
	int			dkim_chunkcrlf;
	int			dkim_timeout;
	int			dkim_presult;
	int			dkim_hdrcnt;
	u_int		dkim_minsiglen;

	// should be size_t, but adapt to return value of the printf family of functions.
	int			dkim_errlen;
#ifdef _FFR_RESIGN
	u_int			dkim_refcnt;
#endif /* _FFR_RESIGN */
#ifdef QUERY_CACHE
	u_int			dkim_cache_queries;
	u_int			dkim_cache_hits;
#endif /* QUERY_CACHE */
	u_int			dkim_version;
	u_int			dkim_sigcount;
	unsigned int    dkim_arccount; // multiple of 3 until eoh, elements in arc_sets when set
	unsigned int    dkim_arcmax;   // top value seen
	int             arc_seal_failed;
	arc_chain_state arc_state; // ARC_CHAIN_ UNKNOWN/ NONE/ FAIL/ PASS
	unsigned int    oldest_pass; // if arc_state == ARC_CHAIN_PASS
	_Bool           arc_set_inconsistent;

	dkim_canon_t		dkim_hdrcanonalg;
	dkim_canon_t		dkim_bodycanonalg;
	dkim_alg_t		dkim_signalg;
#ifdef _FFR_ATPS
	_Bool			dkim_atps;
#endif /* _FFR_ATPS */

	_Bool			dkim_partial;
	_Bool			dkim_bodydone;
	_Bool			dkim_subdomain;
	_Bool			dkim_skipbody;
#ifdef _FFR_RESIGN
	_Bool			dkim_hdrbind;
#endif /* _FFR_RESIGN */
	_Bool			dkim_eoh_reentry;
	_Bool			memory_fault;
};

/* struct dkim_lib -- a DKIM library context */
struct dkim_lib
{
	DKIM            *dkiml_dkim; // for dkim_error
	_Bool           dkiml_signre;
	_Bool           dkiml_skipre;
	_Bool           dkiml_dnsinit_done;
	u_int           dkiml_timeout;
	u_int           dkiml_version;
	u_int           dkiml_callback_int;
	u_int           dkiml_flsize;
	u_int           dkiml_minkeybits;
	uint32_t        dkiml_flags;
	uint64_t        dkiml_fixedtime;
	uint64_t        dkiml_sigttl;
	uint64_t        dkiml_clockdrift;
	dkim_query_t    dkiml_querymethod;
	u_int *         dkiml_flist;
	void *          (*dkiml_malloc) (void *closure, size_t nbytes);
	void            (*dkiml_free) (void *closure, void *p);
	char **         dkiml_requiredhdrs;
	char **         dkiml_oversignhdrs;
	char **         dkiml_mbs;
#ifdef QUERY_CACHE
	DB *            dkiml_cache;
#endif /* QUERY_CACHE */
	regex_t         dkiml_hdrre;
	regex_t         dkiml_skiphdrre;
	DKIM_CBSTAT     (*dkiml_key_lookup)
		(DKIM *dkim, DKIM_SIGINFO *sig, char *buf, size_t buflen);
	void            (*dkiml_key_retrieved)
		(DKIM *dkim, DKIM_STAT status, DKIM_SIGINFO *sig);
//	void *          (*dkiml_sig_handle) (void *closure);
//	void            (*dkiml_sig_handle_free) (void *closure, void *user);
//	void            (*dkiml_sig_tagvalues)
//		(void *user, dkim_param_t pcode, const char *param, const char *value);
	DKIM_CBSTAT     (*dkiml_prescreen)
		(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs);
	DKIM_CBSTAT     (*dkiml_final)
		(DKIM *dkim, DKIM_SIGINFO **sigs, int nsigs);
	void            (*dkiml_dns_callback) (const void *context);
	void            *dkiml_dns_service;
	int             (*dkiml_dns_init) (void **srv);
	void            (*dkiml_dns_close) (void *srv);
	int             (*dkiml_dns_start)
		(void *srv, int type, char *query,
			unsigned char *buf, size_t buflen, void **qh);
	int             (*dkiml_dns_cancel) (void *srv, void *qh);
	int             (*dkiml_dns_setns) (void *srv, const char *ns);
	int             (*dkiml_dns_config) (void *srv, const char *conf);
	int             (*dkiml_dns_trustanchor) (void *srv, const char *ta);
	int             (*dkiml_dns_waitreply)
		(void *srv, void *qh, struct timeval *to, size_t *bytes,
			int *error, int *dnssec);
	char            dkiml_tmpdir[MAXPATHLEN + 1];
	char            dkiml_queryinfo[MAXPATHLEN + 1];
};

#endif /* _DKIM_TYPES_H_ */
