/*-
 * Copyright (c) 2012 Alistair Crooks <agc@NetBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef NETPGP_VERIFY_H_
#define NETPGP_VERIFY_H_	20140304

#define NETPGPVERIFY_VERSION	"netpgpverify portable 20140304"

#include <sys/types.h>

#include <inttypes.h>

#ifndef PGPV_ARRAY
/* creates 2 unsigned vars called "name"c and "name"size in current scope */
/* also creates an array called "name"s in current scope */
#define PGPV_ARRAY(type, name)						\
	unsigned name##c; unsigned name##vsize; type *name##s
#endif

/* 64bit key ids */
#define PGPV_KEYID_LEN		8
#define PGPV_STR_KEYID_LEN	(PGPV_KEYID_LEN + PGPV_KEYID_LEN + 1)

/* bignum structure */
typedef struct pgpv_bignum_t {
	void			*bn;	/* hide the implementation details */
	uint16_t		 bits;	/* cached number of bits */
} pgpv_bignum_t;

/* right now, our max binary digest length is 20 bytes */
#define PGPV_MAX_HASH_LEN	64

/* fingerprint */
typedef struct pgpv_fingerprint_t {
	uint8_t			hashalg;	/* algorithm for digest */
	uint8_t			v[PGPV_MAX_HASH_LEN];	/* the digest */
	uint32_t		len;		/* its length */
} pgpv_fingerprint_t;

/* specify size for array of bignums */
#define PGPV_MAX_PUBKEY_BN	4

/* public key */
typedef struct pgpv_pubkey_t {
	pgpv_fingerprint_t	 fingerprint;	/* key fingerprint i.e. digest */
	uint8_t			 keyid[PGPV_KEYID_LEN];	/* last 8 bytes of v4 keys */
	int64_t		 	 birth;		/* creation time */
	int64_t			 expiry;	/* expiry time */
	pgpv_bignum_t		 bn[PGPV_MAX_PUBKEY_BN];	/* bignums */
	uint8_t			 keyalg;	/* key algorithm */
	uint8_t			 hashalg;	/* hash algorithm */
	uint8_t			 version;	/* key version */
} pgpv_pubkey_t;

#define PGPV_MAX_SESSKEY_BN	2

/* a (size, byte array) string */
typedef struct pgpv_string_t {
	size_t			 size;
	uint8_t			*data;
} pgpv_string_t;

typedef struct pgpv_ref_t {
	void			*vp;
	size_t			 offset;
	unsigned		 mem;
} pgpv_ref_t;

#define PGPV_MAX_SECKEY_BN	4

typedef struct pgpv_compress_t {
	pgpv_string_t		 s;
	uint8_t			 compalg;
} pgpv_compress_t;

/* a packet dealing with trust */
typedef struct pgpv_trust_t {
	uint8_t			level;
	uint8_t			amount;
} pgpv_trust_t;

/* a signature sub packet */
typedef struct pgpv_sigsubpkt_t {
	pgpv_string_t		 s;
	uint8_t			 tag;
	uint8_t			 critical;
} pgpv_sigsubpkt_t;

#define PGPV_MAX_SIG_BN		2

typedef struct pgpv_signature_t {
	uint8_t			*signer;		/* key id of signer */
	pgpv_ref_t		 hashstart;
	uint8_t			*hash2;
	uint8_t			*mpi;
	int64_t			 birth;
	int64_t			 keyexpiry;
	int64_t			 expiry;
	uint32_t		 hashlen;
	uint8_t			 version;
	uint8_t			 type;
	uint8_t			 keyalg;
	uint8_t			 hashalg;
	uint8_t			 trustlevel;
	uint8_t			 trustamount;
	pgpv_bignum_t		 bn[PGPV_MAX_SIG_BN];
	char			*regexp;
	char			*pref_key_server;
	char			*policy;
	char			*features;
	char			*why_revoked;
	uint8_t			*revoke_fingerprint;
	uint8_t			 revoke_alg;
	uint8_t			 revoke_sensitive;
	uint8_t			 trustsig;
	uint8_t			 revocable;
	uint8_t			 pref_symm_alg;
	uint8_t			 pref_hash_alg;
	uint8_t			 pref_compress_alg;
	uint8_t			 key_server_modify;
	uint8_t			 notation;
	uint8_t			 type_key;
	uint8_t			 primary_userid;
	uint8_t			 revoked;	/* subtract 1 to get real reason, 0 == not revoked */
} pgpv_signature_t;

/* a signature packet */
typedef struct pgpv_sigpkt_t {
	pgpv_signature_t	 sig;
	uint16_t		 subslen;
	uint16_t		 unhashlen;
	PGPV_ARRAY(pgpv_sigsubpkt_t, subpkts);
} pgpv_sigpkt_t;

/* a one-pass signature packet */
typedef struct pgpv_onepass_t {
	uint8_t			 keyid[PGPV_KEYID_LEN];
	uint8_t			 version;
	uint8_t			 type;
	uint8_t			 hashalg;
	uint8_t			 keyalg;
	uint8_t			 nested;
} pgpv_onepass_t;

/* a literal data packet */
typedef struct pgpv_litdata_t {
	uint8_t			*filename;
	pgpv_string_t		 s;
	uint32_t		 secs;
	uint8_t			 namelen;
	char			 format;
	unsigned		 mem;
	size_t			 offset;
	size_t			 len;
} pgpv_litdata_t;

/* user attributes - images */
typedef struct pgpv_userattr_t {
	size_t 			 len;
	PGPV_ARRAY(pgpv_string_t, subattrs);
} pgpv_userattr_t;

/* a general PGP packet */
typedef struct pgpv_pkt_t {
	uint8_t			 tag;
	uint8_t			 newfmt;
	uint8_t			 allocated;
	uint8_t			 mement;
	size_t			 offset;
	pgpv_string_t		 s;
	union {
		pgpv_sigpkt_t	sigpkt;
		pgpv_onepass_t	onepass;
		pgpv_litdata_t	litdata;
		pgpv_compress_t	compressed;
		pgpv_trust_t	trust;
		pgpv_pubkey_t	pubkey;
		pgpv_string_t	userid;
		pgpv_userattr_t	userattr;
	} u;
} pgpv_pkt_t;

/* a memory structure */
typedef struct pgpv_mem_t {
	size_t			 size;
	size_t			 cc;
	uint8_t			*mem;
	FILE			*fp;
	uint8_t			 dealloc;
	const char		*allowed;	/* the types of packet that are allowed */
} pgpv_mem_t;

/* packet parser */

typedef struct pgpv_signed_userid_t {
	pgpv_string_t	 	 userid;
	PGPV_ARRAY(pgpv_signature_t, sigs);
	uint8_t			 primary_userid;
	uint8_t			 revoked;
} pgpv_signed_userid_t;

typedef struct pgpv_signed_userattr_t {
	pgpv_userattr_t	 	 userattr;
	PGPV_ARRAY(pgpv_signature_t, sigs);
	uint8_t			 revoked;
} pgpv_signed_userattr_t;

typedef struct pgpv_signed_subkey_t {
	pgpv_pubkey_t	 	 subkey;
	pgpv_signature_t 	 revoc_self_sig;
	PGPV_ARRAY(pgpv_signature_t, sigs);
} pgpv_signed_subkey_t;

typedef struct pgpv_primarykey_t {
	pgpv_pubkey_t 		 primary;
	pgpv_signature_t 	 revoc_self_sig;
	PGPV_ARRAY(pgpv_signature_t, direct_sigs);
	PGPV_ARRAY(pgpv_signed_userid_t, signed_userids);
	PGPV_ARRAY(pgpv_signed_userattr_t, signed_userattrs);
	PGPV_ARRAY(pgpv_signed_subkey_t, signed_subkeys);
	size_t			 fmtsize;
	uint8_t			 primary_userid;
} pgpv_primarykey_t;

/* everything stems from this structure */
typedef struct pgpv_t {
	PGPV_ARRAY(pgpv_pkt_t, 	 pkts);		/* packet array */
	PGPV_ARRAY(pgpv_primarykey_t,	 primaries);	/* array of primary keys */
	PGPV_ARRAY(pgpv_mem_t,	 areas);	/* areas we read packets from */
	PGPV_ARRAY(size_t,	 datastarts);	/* starts of data packets */
	size_t		 	 pkt;		/* when parsing, current pkt number */
	const char		*op;		/* the operation we're doing */
	unsigned		 ssh;		/* using ssh keys */
} pgpv_t;

#define PGPV_REASON_LEN		128

/* when searching, we define a cursor, and fill in an array of subscripts */
typedef struct pgpv_cursor_t {
	pgpv_t			*pgp;			/* pointer to pgp tree */
	char			*field;			/* field we're searching on */
	char			*op;			/* operation we're doing */
	char			*value;			/* value we're searching for */
	void			*ptr;			/* for regexps etc */
	PGPV_ARRAY(uint32_t,	 found);		/* array of matched subscripts */
	PGPV_ARRAY(size_t,	 datacookies);		/* cookies to retrieve matched data */
	int64_t			 sigtime;		/* time of signature */
	char			 why[PGPV_REASON_LEN];	/* reason for bad signature */
} pgpv_cursor_t;

#ifndef __BEGIN_DECLS
#  if defined(__cplusplus)
#  define __BEGIN_DECLS           extern "C" {
#  define __END_DECLS             }
#  else
#  define __BEGIN_DECLS
#  define __END_DECLS
#  endif
#endif

__BEGIN_DECLS

int pgpv_read_pubring(pgpv_t */*pgp*/, const void */*keyringfile/mem*/, ssize_t /*size*/);
int pgpv_read_ssh_pubkeys(pgpv_t */*pgp*/, const void */*keyring*/, ssize_t /*size*/);

size_t pgpv_verify(pgpv_cursor_t */*cursor*/, pgpv_t */*pgp*/, const void */*mem/file*/, ssize_t /*size*/);
size_t pgpv_get_verified(pgpv_cursor_t */*cursor*/, size_t /*cookie*/, char **/*ret*/);
int pgpv_get_cursor_element(pgpv_cursor_t */*cursor*/, size_t /*element*/);

size_t pgpv_get_entry(pgpv_t */*pgp*/, unsigned /*ent*/, char **/*ret*/, const char */*modifiers*/);

int pgpv_close(pgpv_t */*pgp*/);

__END_DECLS

#endif
