/*-
 * Copyright (c) 2009 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Alistair Crooks (agc@NetBSD.org)
 *
 * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */
/*
 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
 * All rights reserved.
 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
 * their moral rights under the UK Copyright Design and Patents Act 1988 to
 * be recorded as the authors of this copyright work.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** \file
 * packet related headers.
 */

#ifndef PACKET_H_
#define PACKET_H_

#include <time.h>

#ifdef HAVE_OPENSSL_BN_H
#include <openssl/bn.h>
#endif

#include "types.h"
#include "errors.h"

/* structure to keep track of printing state variables */
typedef struct pgp_printstate_t {
	unsigned	unarmoured;
	unsigned	skipping;
	int		indent;
} pgp_printstate_t;

/** General-use structure for variable-length data
 */

typedef struct {
	size_t           len;
	uint8_t		*contents;
	uint8_t		 mmapped;	/* contents need an munmap(2) */
} pgp_data_t;

/************************************/
/* Packet Tags - RFC4880, 4.2 */
/************************************/

/** Packet Tag - Bit 7 Mask (this bit is always set).
 * The first byte of a packet is the "Packet Tag".  It always
 * has bit 7 set.  This is the mask for it.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_ALWAYS_SET		0x80

/** Packet Tag - New Format Flag.
 * Bit 6 of the Packet Tag is the packet format indicator.
 * If it is set, the new format is used, if cleared the
 * old format is used.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_NEW_FORMAT		0x40


/** Old Packet Format: Mask for content tag.
 * In the old packet format bits 5 to 2 (including)
 * are the content tag.  This is the mask to apply
 * to the packet tag.  Note that you need to
 * shift by #PGP_PTAG_OF_CONTENT_TAG_SHIFT bits.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_OF_CONTENT_TAG_MASK	0x3c
/** Old Packet Format: Offset for the content tag.
 * As described at #PGP_PTAG_OF_CONTENT_TAG_MASK the
 * content tag needs to be shifted after being masked
 * out from the Packet Tag.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_OF_CONTENT_TAG_SHIFT	2
/** Old Packet Format: Mask for length type.
 * Bits 1 and 0 of the packet tag are the length type
 * in the old packet format.
 *
 * See #pgp_ptag_of_lt_t for the meaning of the values.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_OF_LENGTH_TYPE_MASK	0x03


/** Old Packet Format Lengths.
 * Defines the meanings of the 2 bits for length type in the
 * old packet format.
 *
 * \see RFC4880 4.2.1
 */
typedef enum {
	PGP_PTAG_OLD_LEN_1 = 0x00,	/* Packet has a 1 byte length -
					 * header is 2 bytes long. */
	PGP_PTAG_OLD_LEN_2 = 0x01,	/* Packet has a 2 byte length -
					 * header is 3 bytes long. */
	PGP_PTAG_OLD_LEN_4 = 0x02,	/* Packet has a 4 byte
						 * length - header is 5 bytes
						 * long. */
	PGP_PTAG_OLD_LEN_INDETERMINATE = 0x03	/* Packet has a
						 * indeterminate length. */
} pgp_ptag_of_lt_t;


/** New Packet Format: Mask for content tag.
 * In the new packet format the 6 rightmost bits
 * are the content tag.  This is the mask to apply
 * to the packet tag.  Note that you need to
 * shift by #PGP_PTAG_NF_CONTENT_TAG_SHIFT bits.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_NF_CONTENT_TAG_MASK	0x3f
/** New Packet Format: Offset for the content tag.
 * As described at #PGP_PTAG_NF_CONTENT_TAG_MASK the
 * content tag needs to be shifted after being masked
 * out from the Packet Tag.
 *
 * \see RFC4880 4.2
 */
#define PGP_PTAG_NF_CONTENT_TAG_SHIFT	0

/* PTag Content Tags */
/***************************/

/** Package Tags (aka Content Tags) and signature subpacket types.
 * This enumerates all rfc-defined packet tag values and the
 * signature subpacket type values that we understand.
 *
 * \see RFC4880 4.3
 * \see RFC4880 5.2.3.1
 */
typedef enum {
	PGP_PTAG_CT_RESERVED = 0,	/* Reserved - a packet tag must
					 * not have this value */
	PGP_PTAG_CT_PK_SESSION_KEY = 1,	/* Public-Key Encrypted Session
					 * Key Packet */
	PGP_PTAG_CT_SIGNATURE = 2,	/* Signature Packet */
	PGP_PTAG_CT_SK_SESSION_KEY = 3,	/* Symmetric-Key Encrypted Session
					 * Key Packet */
	PGP_PTAG_CT_1_PASS_SIG = 4,	/* One-Pass Signature
						 * Packet */
	PGP_PTAG_CT_SECRET_KEY = 5,	/* Secret Key Packet */
	PGP_PTAG_CT_PUBLIC_KEY = 6,	/* Public Key Packet */
	PGP_PTAG_CT_SECRET_SUBKEY = 7,	/* Secret Subkey Packet */
	PGP_PTAG_CT_COMPRESSED = 8,	/* Compressed Data Packet */
	PGP_PTAG_CT_SE_DATA = 9,/* Symmetrically Encrypted Data Packet */
	PGP_PTAG_CT_MARKER = 10,/* Marker Packet */
	PGP_PTAG_CT_LITDATA = 11,	/* Literal Data Packet */
	PGP_PTAG_CT_TRUST = 12,	/* Trust Packet */
	PGP_PTAG_CT_USER_ID = 13,	/* User ID Packet */
	PGP_PTAG_CT_PUBLIC_SUBKEY = 14,	/* Public Subkey Packet */
	PGP_PTAG_CT_RESERVED2 = 15,	/* reserved */
	PGP_PTAG_CT_RESERVED3 = 16,	/* reserved */
	PGP_PTAG_CT_USER_ATTR = 17,	/* User Attribute Packet */
	PGP_PTAG_CT_SE_IP_DATA = 18,	/* Sym. Encrypted and Integrity
					 * Protected Data Packet */
	PGP_PTAG_CT_MDC = 19,	/* Modification Detection Code Packet */

	PGP_PARSER_PTAG = 0x100,/* Internal Use: The packet is the "Packet
				 * Tag" itself - used when callback sends
				 * back the PTag. */
	PGP_PTAG_RAW_SS = 0x101,/* Internal Use: content is raw sig subtag */
	PGP_PTAG_SS_ALL = 0x102,/* Internal Use: select all subtags */
	PGP_PARSER_PACKET_END = 0x103,

	/* signature subpackets (0x200-2ff) (type+0x200) */
	/* only those we can parse are listed here */
	PGP_PTAG_SIG_SUBPKT_BASE = 0x200,	/* Base for signature
							 * subpacket types - All
							 * signature type values
							 * are relative to this
							 * value. */
	PGP_PTAG_SS_CREATION_TIME = 0x200 + 2,	/* signature creation time */
	PGP_PTAG_SS_EXPIRATION_TIME = 0x200 + 3,	/* signature
							 * expiration time */

	PGP_PTAG_SS_EXPORT_CERT = 0x200 + 4,	/* exportable certification */
	PGP_PTAG_SS_TRUST = 0x200 + 5,	/* trust signature */
	PGP_PTAG_SS_REGEXP = 0x200 + 6,	/* regular expression */
	PGP_PTAG_SS_REVOCABLE = 0x200 + 7,	/* revocable */
	PGP_PTAG_SS_KEY_EXPIRY = 0x200 + 9,	/* key expiration
							 * time */
	PGP_PTAG_SS_RESERVED = 0x200 + 10,	/* reserved */
	PGP_PTAG_SS_PREFERRED_SKA = 0x200 + 11,	/* preferred symmetric
						 * algs */
	PGP_PTAG_SS_REVOCATION_KEY = 0x200 + 12,	/* revocation key */
	PGP_PTAG_SS_ISSUER_KEY_ID = 0x200 + 16,	/* issuer key ID */
	PGP_PTAG_SS_NOTATION_DATA = 0x200 + 20,	/* notation data */
	PGP_PTAG_SS_PREFERRED_HASH = 0x200 + 21,	/* preferred hash
							 * algs */
	PGP_PTAG_SS_PREF_COMPRESS = 0x200 + 22,	/* preferred
							 * compression
							 * algorithms */
	PGP_PTAG_SS_KEYSERV_PREFS = 0x200 + 23,	/* key server
							 * preferences */
	PGP_PTAG_SS_PREF_KEYSERV = 0x200 + 24,	/* Preferred Key
							 * Server */
	PGP_PTAG_SS_PRIMARY_USER_ID = 0x200 + 25,	/* primary User ID */
	PGP_PTAG_SS_POLICY_URI = 0x200 + 26,	/* Policy URI */
	PGP_PTAG_SS_KEY_FLAGS = 0x200 + 27,	/* key flags */
	PGP_PTAG_SS_SIGNERS_USER_ID = 0x200 + 28,	/* Signer's User ID */
	PGP_PTAG_SS_REVOCATION_REASON = 0x200 + 29,	/* reason for
							 * revocation */
	PGP_PTAG_SS_FEATURES = 0x200 + 30,	/* features */
	PGP_PTAG_SS_SIGNATURE_TARGET = 0x200 + 31,	/* signature target */
	PGP_PTAG_SS_EMBEDDED_SIGNATURE = 0x200 + 32,	/* embedded signature */
	PGP_PTAG_SS_ISSUER_FINGERPRINT = 0x200 + 33,	/* issuer fingerprint */
	PGP_PTAG_SS_USERDEFINED00 = 0x200 + 100,	/* internal or
							 * user-defined */
	PGP_PTAG_SS_USERDEFINED01 = 0x200 + 101,
	PGP_PTAG_SS_USERDEFINED02 = 0x200 + 102,
	PGP_PTAG_SS_USERDEFINED03 = 0x200 + 103,
	PGP_PTAG_SS_USERDEFINED04 = 0x200 + 104,
	PGP_PTAG_SS_USERDEFINED05 = 0x200 + 105,
	PGP_PTAG_SS_USERDEFINED06 = 0x200 + 106,
	PGP_PTAG_SS_USERDEFINED07 = 0x200 + 107,
	PGP_PTAG_SS_USERDEFINED08 = 0x200 + 108,
	PGP_PTAG_SS_USERDEFINED09 = 0x200 + 109,
	PGP_PTAG_SS_USERDEFINED10 = 0x200 + 110,

	/* pseudo content types */
	PGP_PTAG_CT_LITDATA_HEADER = 0x300,
	PGP_PTAG_CT_LITDATA_BODY = 0x300 + 1,
	PGP_PTAG_CT_SIGNATURE_HEADER = 0x300 + 2,
	PGP_PTAG_CT_SIGNATURE_FOOTER = 0x300 + 3,
	PGP_PTAG_CT_ARMOUR_HEADER = 0x300 + 4,
	PGP_PTAG_CT_ARMOUR_TRAILER = 0x300 + 5,
	PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER = 0x300 + 6,
	PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY = 0x300 + 7,
	PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER = 0x300 + 8,
	PGP_PTAG_CT_UNARMOURED_TEXT = 0x300 + 9,
	PGP_PTAG_CT_ENCRYPTED_SECRET_KEY = 0x300 + 10,	/* In this case the
							 * algorithm specific
							 * fields will not be
							 * initialised */
	PGP_PTAG_CT_SE_DATA_HEADER = 0x300 + 11,
	PGP_PTAG_CT_SE_DATA_BODY = 0x300 + 12,
	PGP_PTAG_CT_SE_IP_DATA_HEADER = 0x300 + 13,
	PGP_PTAG_CT_SE_IP_DATA_BODY = 0x300 + 14,
	PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY = 0x300 + 15,

	/* commands to the callback */
	PGP_GET_PASSPHRASE = 0x400,
	PGP_GET_SECKEY = 0x400 + 1,

	/* Errors */
	PGP_PARSER_ERROR = 0x500,	/* Internal Use: Parser Error */
	PGP_PARSER_ERRCODE = 0x500 + 1	/* Internal Use: Parser Error
					 * with errcode returned */
} pgp_content_enum;

enum {
	PGP_REVOCATION_NO_REASON	= 0,
	PGP_REVOCATION_SUPERSEDED	= 1,
	PGP_REVOCATION_COMPROMISED	= 2,
	PGP_REVOCATION_RETIRED		= 3,
	PGP_REVOCATION_NO_LONGER_VALID	= 0x20
};

/** Structure to hold one error code */
typedef struct {
	pgp_errcode_t   errcode;
} pgp_parser_errcode_t;

/** Structure to hold one packet tag.
 * \see RFC4880 4.2
 */
typedef struct {
	unsigned        new_format;	/* Whether this packet tag is new
					 * (1) or old format (0) */
	unsigned        type;	/* content_tag value - See
					 * #pgp_content_enum for meanings */
	pgp_ptag_of_lt_t length_type;	/* Length type (#pgp_ptag_of_lt_t)
					 * - only if this packet tag is old
					 * format.  Set to 0 if new format. */
	unsigned        length;	/* The length of the packet.  This value
				 * is set when we read and compute the length
				 * information, not at the same moment we
				 * create the packet tag structure. Only
	 * defined if #readc is set. *//* XXX: Ben, is this correct? */
	unsigned        position;	/* The position (within the
					 * current reader) of the packet */
	unsigned	size;	/* number of bits */
} pgp_ptag_t;

/** Public Key Algorithm Numbers.
 * OpenPGP assigns a unique Algorithm Number to each algorithm that is part of OpenPGP.
 *
 * This lists algorithm numbers for public key algorithms.
 *
 * \see RFC4880 9.1
 */
typedef enum {
	PGP_PKA_NOTHING	= 0,	/* No PKA */
	PGP_PKA_RSA = 1,	/* RSA (Encrypt or Sign) */
	PGP_PKA_RSA_ENCRYPT_ONLY = 2,	/* RSA Encrypt-Only (deprecated -
					 * \see RFC4880 13.5) */
	PGP_PKA_RSA_SIGN_ONLY = 3,	/* RSA Sign-Only (deprecated -
					 * \see RFC4880 13.5) */
	PGP_PKA_ELGAMAL = 16,	/* Elgamal (Encrypt-Only) */
	PGP_PKA_DSA = 17,	/* DSA (Digital Signature Algorithm) */
	PGP_PKA_RESERVED_ELLIPTIC_CURVE = 18,	/* Reserved for Elliptic
						 * Curve */
	PGP_PKA_ECDSA = 19,			/* ECDSA */
	PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN = 20,	/* Deprecated. */
	PGP_PKA_RESERVED_DH = 21,	/* Reserved for Diffie-Hellman
					 * (X9.42, as defined for
					 * IETF-S/MIME) */
	PGP_PKA_PRIVATE00 = 100,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE01 = 101,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE02 = 102,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE03 = 103,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE04 = 104,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE05 = 105,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE06 = 106,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE07 = 107,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE08 = 108,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE09 = 109,/* Private/Experimental Algorithm */
	PGP_PKA_PRIVATE10 = 110	/* Private/Experimental Algorithm */
} pgp_pubkey_alg_t;

/** Structure to hold one DSA public key params.
 *
 * \see RFC4880 5.5.2
 */
typedef struct {
	BIGNUM         *p;	/* DSA prime p */
	BIGNUM         *q;	/* DSA group order q */
	BIGNUM         *g;	/* DSA group generator g */
	BIGNUM         *y;	/* DSA public key value y (= g^x mod p
				 * with x being the secret) */
} pgp_dsa_pubkey_t;

/** Structure to hold one ECDSA public key params.
 *
 * \see RFC6637 9
 */
typedef struct {
	uint8_t		len;
	uint8_t		oid[8];
	BIGNUM		*p;
} pgp_ecdsa_pubkey_t;

/** Structure to hold an RSA public key.
 *
 * \see RFC4880 5.5.2
 */
typedef struct {
	BIGNUM         *n;	/* RSA public modulus n */
	BIGNUM         *e;	/* RSA public encryption exponent e */
} pgp_rsa_pubkey_t;

/** Structure to hold an ElGamal public key params.
 *
 * \see RFC4880 5.5.2
 */
typedef struct {
	BIGNUM         *p;	/* ElGamal prime p */
	BIGNUM         *g;	/* ElGamal group generator g */
	BIGNUM         *y;	/* ElGamal public key value y (= g^x mod p
				 * with x being the secret) */
} pgp_elgamal_pubkey_t;

/** Version.
 * OpenPGP has two different protocol versions: version 3 and version 4.
 *
 * \see RFC4880 5.2
 */
typedef enum {
	PGP_V2 = 2,		/* Version 2 (essentially the same as v3) */
	PGP_V3 = 3,		/* Version 3 */
	PGP_V4 = 4		/* Version 4 */
} pgp_version_t;

/** Structure to hold a pgp public key */
typedef struct {
	pgp_version_t		version;/* version of the key (v3, v4...) */
	time_t			birthtime;
	time_t			duration;
		/* validity period of the key in days since
		* creation.  A value of 0 has a special meaning
		* indicating this key does not expire.  Only used with
		* v3 keys.  */
	unsigned		days_valid;	/* v4 duration */
	pgp_pubkey_alg_t	alg;	/* Public Key Algorithm type */
	union {
		pgp_dsa_pubkey_t dsa;	/* A DSA public key */
		pgp_ecdsa_pubkey_t ecdsa; /* An ECDSA public key */
		pgp_rsa_pubkey_t rsa;	/* An RSA public key */
		pgp_elgamal_pubkey_t elgamal;	/* An ElGamal public key */
	}			key;	/* Public Key Parameters */
} pgp_pubkey_t;

/** Structure to hold data for one RSA secret key
 */
typedef struct {
	BIGNUM         *d;
	BIGNUM         *p;
	BIGNUM         *q;
	BIGNUM         *u;
} pgp_rsa_seckey_t;

/** pgp_dsa_seckey_t */
typedef struct {
	BIGNUM         *x;
} pgp_dsa_seckey_t;

/** pgp_ecdsa_seckey_t */
typedef struct {
	BIGNUM         *x;
} pgp_ecdsa_seckey_t;

/** pgp_elgamal_seckey_t */
typedef struct {
	BIGNUM         *x;
} pgp_elgamal_seckey_t;

/** s2k_usage_t
 */
typedef enum {
	PGP_S2KU_NONE = 0,
	PGP_S2KU_ENCRYPTED_AND_HASHED = 254,
	PGP_S2KU_ENCRYPTED = 255
} pgp_s2k_usage_t;

/** s2k_specifier_t
 */
typedef enum {
	PGP_S2KS_SIMPLE = 0,
	PGP_S2KS_SALTED = 1,
	PGP_S2KS_ITERATED_AND_SALTED = 3
} pgp_s2k_specifier_t;

/** Symmetric Key Algorithm Numbers.
 * OpenPGP assigns a unique Algorithm Number to each algorithm that is
 * part of OpenPGP.
 *
 * This lists algorithm numbers for symmetric key algorithms.
 *
 * \see RFC4880 9.2
 */
typedef enum {
	PGP_SA_PLAINTEXT = 0,	/* Plaintext or unencrypted data */
	PGP_SA_IDEA = 1,	/* IDEA */
	PGP_SA_TRIPLEDES = 2,	/* TripleDES */
	PGP_SA_CAST5 = 3,	/* CAST5 */
	PGP_SA_BLOWFISH = 4,	/* Blowfish */
	PGP_SA_AES_128 = 7,	/* AES with 128-bit key (AES) */
	PGP_SA_AES_192 = 8,	/* AES with 192-bit key */
	PGP_SA_AES_256 = 9,	/* AES with 256-bit key */
	PGP_SA_TWOFISH = 10,	/* Twofish with 256-bit key (TWOFISH) */
	PGP_SA_CAMELLIA_128 = 100,	/* Camellia with 128-bit key (CAMELLIA) */
	PGP_SA_CAMELLIA_192 = 101,	/* Camellia with 192-bit key */
	PGP_SA_CAMELLIA_256 = 102	/* Camellia with 256-bit key */
} pgp_symm_alg_t;

#define PGP_SA_DEFAULT_CIPHER	PGP_SA_CAST5

/** Hashing Algorithm Numbers.
 * OpenPGP assigns a unique Algorithm Number to each algorithm that is
 * part of OpenPGP.
 *
 * This lists algorithm numbers for hash algorithms.
 *
 * \see RFC4880 9.4
 */
typedef enum {
	PGP_HASH_UNKNOWN = -1,	/* used to indicate errors */
	PGP_HASH_MD5 = 1,	/* MD5 */
	PGP_HASH_SHA1 = 2,	/* SHA-1 */
	PGP_HASH_RIPEMD = 3,	/* RIPEMD160 */

	PGP_HASH_SHA256 = 8,	/* SHA256 */
	PGP_HASH_SHA384 = 9,	/* SHA384 */
	PGP_HASH_SHA512 = 10,	/* SHA512 */
	PGP_HASH_SHA224 = 11	/* SHA224 */
} pgp_hash_alg_t;

#define	PGP_DEFAULT_HASH_ALGORITHM	PGP_HASH_SHA256

void   pgp_calc_mdc_hash(const uint8_t *,
			const size_t,
			const uint8_t *,
			const unsigned,
			uint8_t *);
unsigned   pgp_is_hash_alg_supported(const pgp_hash_alg_t *);

/* Maximum block size for symmetric crypto */
#define PGP_MAX_BLOCK_SIZE	16

/* Maximum key size for symmetric crypto */
#define PGP_MAX_KEY_SIZE	32

/* Salt size for hashing */
#define PGP_SALT_SIZE		8

/* Max hash size */
#define PGP_MAX_HASH_SIZE	64

/** pgp_seckey_t
 */
typedef struct pgp_seckey_t {
	pgp_pubkey_t			pubkey;		/* public key */
	pgp_s2k_usage_t		s2k_usage;
	pgp_s2k_specifier_t		s2k_specifier;
	pgp_symm_alg_t		alg;		/* symmetric alg */
	pgp_hash_alg_t		hash_alg;	/* hash algorithm */
	uint8_t				salt[PGP_SALT_SIZE];
	unsigned			octetc;
	uint8_t				iv[PGP_MAX_BLOCK_SIZE];
	union {
		pgp_rsa_seckey_t		rsa;
		pgp_dsa_seckey_t		dsa;
		pgp_ecdsa_seckey_t		ecdsa;
		pgp_elgamal_seckey_t		elgamal;
	}				key;
	unsigned			checksum;
	uint8_t			       *checkhash;
} pgp_seckey_t;

/** Signature Type.
 * OpenPGP defines different signature types that allow giving
 * different meanings to signatures.  Signature types include 0x10 for
 * generitc User ID certifications (used when Ben signs Weasel's key),
 * Subkey binding signatures, document signatures, key revocations,
 * etc.
 *
 * Different types are used in different places, and most make only
 * sense in their intended location (for instance a subkey binding has
 * no place on a UserID).
 *
 * \see RFC4880 5.2.1
 */
typedef enum {
	PGP_SIG_BINARY = 0x00,	/* Signature of a binary document */
	PGP_SIG_TEXT = 0x01,	/* Signature of a canonical text document */
	PGP_SIG_STANDALONE = 0x02,	/* Standalone signature */

	PGP_CERT_GENERIC = 0x10,/* Generic certification of a User ID and
				 * Public Key packet */
	PGP_CERT_PERSONA = 0x11,/* Persona certification of a User ID and
				 * Public Key packet */
	PGP_CERT_CASUAL = 0x12,	/* Casual certification of a User ID and
				 * Public Key packet */
	PGP_CERT_POSITIVE = 0x13,	/* Positive certification of a
					 * User ID and Public Key packet */

	PGP_SIG_SUBKEY = 0x18,	/* Subkey Binding Signature */
	PGP_SIG_PRIMARY = 0x19,	/* Primary Key Binding Signature */
	PGP_SIG_DIRECT = 0x1f,	/* Signature directly on a key */

	PGP_SIG_REV_KEY = 0x20,	/* Key revocation signature */
	PGP_SIG_REV_SUBKEY = 0x28,	/* Subkey revocation signature */
	PGP_SIG_REV_CERT = 0x30,/* Certification revocation signature */

	PGP_SIG_TIMESTAMP = 0x40,	/* Timestamp signature */

	PGP_SIG_3RD_PARTY = 0x50/* Third-Party Confirmation signature */
} pgp_sig_type_t;

/** Struct to hold params of an RSA signature */
typedef struct pgp_rsa_sig_t {
	BIGNUM         *sig;	/* the signature value (m^d % n) */
} pgp_rsa_sig_t;

/** Struct to hold params of a DSA signature */
typedef struct pgp_dsa_sig_t {
	BIGNUM         *r;	/* DSA value r */
	BIGNUM         *s;	/* DSA value s */
} pgp_dsa_sig_t;

/** Struct to hold params of an ECDSA signature */
typedef struct pgp_ecdsa_sig_t {
	BIGNUM         *r;	/* ECDSA value r */
	BIGNUM         *s;	/* ECDSA value s */
} pgp_ecdsa_sig_t;

/** pgp_elgamal_signature_t */
typedef struct pgp_elgamal_sig_t {
	BIGNUM         *r;
	BIGNUM         *s;
} pgp_elgamal_sig_t;

#define PGP_KEY_ID_SIZE		8
#define PGP_FINGERPRINT_SIZE	20

/** Struct to hold a signature packet.
 *
 * \see RFC4880 5.2.2
 * \see RFC4880 5.2.3
 */
typedef struct pgp_sig_info_t {
	pgp_version_t   version;/* signature version number */
	pgp_sig_type_t  type;	/* signature type value */
	time_t          birthtime;	/* creation time of the signature */
	time_t          duration;	/* number of seconds it's valid for */
	uint8_t		signer_id[PGP_KEY_ID_SIZE];	/* Eight-octet key ID
							 * of signer */
	pgp_pubkey_alg_t key_alg;	/* public key algorithm number */
	pgp_hash_alg_t hash_alg;	/* hashing algorithm number */
	union {
		pgp_rsa_sig_t	rsa;	/* An RSA Signature */
		pgp_dsa_sig_t	dsa;	/* A DSA Signature */
		pgp_ecdsa_sig_t ecdsa; /* An ECDSA Signature */
		pgp_elgamal_sig_t	elgamal;	/* deprecated */
		pgp_data_t	unknown;	/* private or experimental */
	}			sig;	/* signature params */
	size_t          v4_hashlen;
	uint8_t		*v4_hashed;
	unsigned	 birthtime_set:1;
	unsigned	 signer_id_set:1;
	unsigned	 duration_set:1;
} pgp_sig_info_t;

/** Struct used when parsing a signature */
typedef struct pgp_sig_t {
	pgp_sig_info_t info;	/* The signature information */
	/* The following fields are only used while parsing the signature */
	uint8_t		 hash2[2];	/* high 2 bytes of hashed value */
	size_t		 v4_hashstart;	/* only valid if accumulate is set */
	pgp_hash_t     *hash;	/* the hash filled in for the data so far */
} pgp_sig_t;

/** The raw bytes of a signature subpacket */

typedef struct pgp_ss_raw_t {
	pgp_content_enum	 tag;
	size_t          	 length;
	uint8_t			*raw;
} pgp_ss_raw_t;

/** Signature Subpacket : Trust Level */

typedef struct pgp_ss_trust_t {
	uint8_t			 level;		/* Trust Level */
	uint8_t			 amount;	/* Amount */
} pgp_ss_trust_t;

typedef struct pgp_ss_issuer_fingerprint {
	uint8_t			len; /* 20 or 32 */
	uint8_t			fingerprint[32]; /* max 32 */
} pgp_ss_issuer_fingerprint;

/** Signature Subpacket : Notation Data */
typedef struct pgp_ss_notation_t {
	pgp_data_t		flags;
	pgp_data_t		name;
	pgp_data_t		value;
} pgp_ss_notation_t;

/** Signature Subpacket : Signature Target */
typedef struct pgp_ss_sig_target_t {
	pgp_pubkey_alg_t	pka_alg;
	pgp_hash_alg_t		hash_alg;
	pgp_data_t		hash;
} pgp_ss_sig_target_t;

/** pgp_subpacket_t */
typedef struct pgp_subpacket_t {
	pgp_content_enum	 tag;
	size_t          	 length;
	uint8_t			*raw;
} pgp_subpacket_t;

/** Types of Compression */
typedef enum {
	PGP_C_NONE = 0,
	PGP_C_ZIP = 1,
	PGP_C_ZLIB = 2,
	PGP_C_BZIP2 = 3
} pgp_compression_type_t;

/** pgp_one_pass_sig_t */
typedef struct {
	uint8_t			version;
	pgp_sig_type_t		sig_type;
	pgp_hash_alg_t		hash_alg;
	pgp_pubkey_alg_t	key_alg;
	uint8_t			keyid[PGP_KEY_ID_SIZE];
	unsigned		nested;
} pgp_one_pass_sig_t;

/** Signature Subpacket : Revocation Key */
typedef struct {
	uint8_t   		class;
	uint8_t   		algid;
	uint8_t   		fingerprint[PGP_FINGERPRINT_SIZE];
} pgp_ss_revocation_key_t;

/** Signature Subpacket : Revocation Reason */
typedef struct {
	uint8_t   		 code;
	char			*reason;
} pgp_ss_revocation_t;

/** litdata_type_t */
typedef enum {
	PGP_LDT_BINARY = 'b',
	PGP_LDT_TEXT = 't',
	PGP_LDT_UTF8 = 'u',
	PGP_LDT_LOCAL = 'l',
	PGP_LDT_LOCAL2 = '1'
} pgp_litdata_enum;

/** pgp_litdata_header_t */
typedef struct {
	pgp_litdata_enum	format;
	char			filename[256];
	time_t			mtime;
} pgp_litdata_header_t;

/** pgp_litdata_body_t */
typedef struct {
	unsigned         length;
	uint8_t		*data;
	void		*mem;		/* pgp_memory_t pointer */
} pgp_litdata_body_t;

/** pgp_header_var_t */
typedef struct {
	char           *key;
	char           *value;
} pgp_header_var_t;

/** pgp_headers_t */
typedef struct {
	pgp_header_var_t	*headers;
	unsigned	         headerc;
} pgp_headers_t;

/** pgp_armour_header_t */
typedef struct {
	const char	*type;
	pgp_headers_t	 headers;
} pgp_armour_header_t;

/** pgp_fixed_body_t */
typedef struct pgp_fixed_body_t {
	unsigned        length;
	uint8_t		data[8192];	/* \todo fix hard-coded value? */
} pgp_fixed_body_t;

/** pgp_dyn_body_t */
typedef struct pgp_dyn_body_t {
	unsigned         length;
	uint8_t		*data;
} pgp_dyn_body_t;

enum {
	PGP_SE_IP_DATA_VERSION = 1,
	PGP_PKSK_V3 = 3
};

/** pgp_pk_sesskey_params_rsa_t */
typedef struct {
	BIGNUM         *encrypted_m;
	BIGNUM         *m;
} pgp_pk_sesskey_params_rsa_t;

/** pgp_pk_sesskey_params_elgamal_t */
typedef struct {
	BIGNUM         *g_to_k;
	BIGNUM         *encrypted_m;
} pgp_pk_sesskey_params_elgamal_t;

/** pgp_pk_sesskey_params_t */
typedef union {
	pgp_pk_sesskey_params_rsa_t rsa;
	pgp_pk_sesskey_params_elgamal_t elgamal;
} pgp_pk_sesskey_params_t;

/** pgp_pk_sesskey_t */
typedef struct {
	unsigned			version;
	uint8_t				key_id[PGP_KEY_ID_SIZE];
	pgp_pubkey_alg_t		alg;
	pgp_pk_sesskey_params_t	params;
	pgp_symm_alg_t		symm_alg;
	uint8_t				key[PGP_MAX_KEY_SIZE];
	uint16_t			checksum;
} pgp_pk_sesskey_t;

/** pgp_seckey_passphrase_t */
typedef struct {
	const pgp_seckey_t *seckey;
	char          **passphrase;	/* point somewhere that gets filled
					 * in to work around constness of
					 * content */
} pgp_seckey_passphrase_t;

/** pgp_get_seckey_t */
typedef struct {
	const pgp_seckey_t **seckey;
	const pgp_pk_sesskey_t *pk_sesskey;
} pgp_get_seckey_t;

/** pgp_parser_union_content_t */
typedef union {
	const char 			*error;
	pgp_parser_errcode_t		errcode;
	pgp_ptag_t			ptag;
	pgp_pubkey_t			pubkey;
	pgp_data_t			trust;
	uint8_t				*userid;
	pgp_data_t			userattr;
	pgp_sig_t			sig;
	pgp_ss_raw_t			ss_raw;
	pgp_ss_trust_t			ss_trust;
	pgp_ss_issuer_fingerprint 	ss_issuer_fingerprint;
	unsigned			ss_revocable;
	time_t				ss_time;
	uint8_t				ss_issuer[PGP_KEY_ID_SIZE];
	pgp_ss_notation_t		ss_notation;
	pgp_subpacket_t			packet;
	pgp_compression_type_t		compressed;
	pgp_one_pass_sig_t		one_pass_sig;
	pgp_data_t			ss_skapref;
	pgp_data_t			ss_hashpref;
	pgp_data_t			ss_zpref;
	pgp_data_t			ss_key_flags;
	pgp_data_t			ss_key_server_prefs;
	unsigned			ss_primary_userid;
	char				*ss_regexp;
	char				*ss_policy;
	char				*ss_keyserv;
	pgp_ss_revocation_key_t		ss_revocation_key;
	pgp_data_t			ss_userdef;
	pgp_data_t			ss_unknown;
	pgp_litdata_header_t		litdata_header;
	pgp_litdata_body_t		litdata_body;
	pgp_dyn_body_t		mdc;
	pgp_data_t			ss_features;
	pgp_ss_sig_target_t		ss_sig_target;
	pgp_data_t			ss_embedded_sig;
	pgp_ss_revocation_t		ss_revocation;
	pgp_seckey_t			seckey;
	uint8_t				*ss_signer;
	pgp_armour_header_t		armour_header;
	const char 			*armour_trailer;
	pgp_headers_t			cleartext_head;
	pgp_fixed_body_t		cleartext_body;
	struct pgp_hash_t		*cleartext_trailer;
	pgp_dyn_body_t		unarmoured_text;
	pgp_pk_sesskey_t		pk_sesskey;
	pgp_seckey_passphrase_t	skey_passphrase;
	unsigned			se_ip_data_header;
	pgp_dyn_body_t		se_ip_data_body;
	pgp_fixed_body_t		se_data_body;
	pgp_get_seckey_t		get_seckey;
} pgp_contents_t;

/** pgp_packet_t */
struct pgp_packet_t {
	pgp_content_enum	tag;		/* type of contents */
	uint8_t			critical;	/* for sig subpackets */
	pgp_contents_t	u;		/* union for contents */
};

/** pgp_fingerprint_t */
typedef struct {
	uint8_t			fingerprint[PGP_FINGERPRINT_SIZE];
	unsigned        	length;
	pgp_hash_alg_t	hashtype;
} pgp_fingerprint_t;

int pgp_keyid(uint8_t *, const size_t, const pgp_pubkey_t *, pgp_hash_alg_t);
int pgp_fingerprint(pgp_fingerprint_t *, const pgp_pubkey_t *, pgp_hash_alg_t);

void pgp_finish(void);
void pgp_pubkey_free(pgp_pubkey_t *);
void pgp_userid_free(uint8_t **);
void pgp_data_free(pgp_data_t *);
void pgp_sig_free(pgp_sig_t *);
void pgp_ss_notation_free(pgp_ss_notation_t *);
void pgp_ss_revocation_free(pgp_ss_revocation_t *);
void pgp_ss_sig_target_free(pgp_ss_sig_target_t *);

void pgp_subpacket_free(pgp_subpacket_t *);
void pgp_parser_content_free(pgp_packet_t *);
void pgp_seckey_free(pgp_seckey_t *);
void pgp_pk_sesskey_free(pgp_pk_sesskey_t *);

int pgp_print_packet(pgp_printstate_t *, const pgp_packet_t *);

#define DYNARRAY(type, arr)	\
	unsigned arr##c; unsigned arr##vsize; type *arr##s

#define EXPAND_ARRAY(str, arr) do {					\
	if (str->arr##c == str->arr##vsize) {				\
		void	*__newarr;					\
		char	*__newarrc;					\
		unsigned	__newsize;				\
		__newsize = (str->arr##vsize * 2) + 10; 		\
		if ((__newarrc = __newarr = realloc(str->arr##s,	\
			__newsize * sizeof(*str->arr##s))) == NULL) {	\
			(void) fprintf(stderr, "EXPAND_ARRAY - bad realloc\n"); \
		} else {						\
			(void) memset(&__newarrc[str->arr##vsize * sizeof(*str->arr##s)], \
				0x0, (__newsize - str->arr##vsize) * sizeof(*str->arr##s)); \
			str->arr##s = __newarr;				\
			str->arr##vsize = __newsize;			\
		}							\
	}								\
} while(/*CONSTCOND*/0)

/** pgp_keydata_key_t
 */
typedef union {
	pgp_pubkey_t pubkey;
	pgp_seckey_t seckey;
} pgp_keydata_key_t;


/* sigpacket_t */
typedef struct {
	uint8_t			**userid;
	pgp_subpacket_t	*packet;
} sigpacket_t;

/* user revocation info */
typedef struct pgp_revoke_t {
	uint32_t		 uid;		/* index in uid array */
	uint8_t			 code;		/* revocation code */
	char			*reason;	/* c'mon, spill the beans */
} pgp_revoke_t;

/** signature subpackets */
typedef struct pgp_subsig_t {
	uint32_t		uid;		/* index in userid array in key */
	pgp_sig_t		sig;		/* trust signature */
	uint8_t			trustlevel;	/* level of trust */
	uint8_t			trustamount;	/* amount of trust */
} pgp_subsig_t;

/* describes a user's key */
struct pgp_key_t {
	DYNARRAY(uint8_t *, uid);		/* array of user ids */
	DYNARRAY(pgp_subpacket_t, packet);	/* array of raw subpackets */
	DYNARRAY(pgp_subsig_t, subsig);	/* array of signature subkeys */
	DYNARRAY(pgp_revoke_t, revoke);	/* array of signature revocations */
	pgp_content_enum	type;		/* type of key */
	pgp_keydata_key_t	key;		/* pubkey/seckey data */
	pgp_pubkey_t		sigkey;		/* signature key */
	uint8_t			sigid[PGP_KEY_ID_SIZE];
	pgp_fingerprint_t	sigfingerprint;	/* pgp signature fingerprint */
	pgp_pubkey_t		enckey;		/* encryption key */
	uint8_t			encid[PGP_KEY_ID_SIZE];
	pgp_fingerprint_t	encfingerprint;	/* pgp encryption id fingerprint */
	uint32_t		uid0;		/* primary uid index in uids array */
	uint8_t			revoked;	/* key has been revoked */
	pgp_revoke_t		revocation;	/* revocation reason */
};

#define MDC_PKT_TAG	0xd3

#endif /* PACKET_H_ */
