/*
 * X.509v3 certificate parsing and processing
 * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
 *
 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
 */

#ifndef X509V3_H
#define X509V3_H

#include "asn1.h"


/*typedef long os_time_t;*/

struct x509_parser_time {
	unsigned short year;       /* Year  - 1900.  */
	unsigned char  mon;        /* Month.   [0-11] */
	unsigned char  mday;       /* Day.     [1-31] */
	unsigned char  hour;       /* Hours.   [0-23] */
	unsigned char  min;        /* Minutes. [0-59] */
	unsigned char  sec;        /* Seconds. [0-60] (1 leap second) */
	unsigned char  dummy;      /* Not used*/
	unsigned char *start;
	unsigned char *end;
};

struct x509_algorithm_identifier {
	struct asn1_oid oid;
	struct asn1_oid oid_custom_1;
};

struct x509_name_attr {
	enum x509_name_attr_type {
		X509_NAME_ATTR_NOT_USED,
		X509_NAME_ATTR_DC,
		X509_NAME_ATTR_CN,
		X509_NAME_ATTR_C,
		X509_NAME_ATTR_L,
		X509_NAME_ATTR_ST,
		X509_NAME_ATTR_O,
		X509_NAME_ATTR_OU,
		X509_NAME_ATTR_UID
	} type;
	char const *value;
	size_t value_size; /* used only for string types */
};

struct x509_extensions {
	unsigned int extensions_present;
#	define X509_EXT_BASIC_CONSTRAINTS		    (1 << 0)
#	define X509_EXT_PATH_LEN_CONSTRAINT		    (1 << 1)
#	define X509_EXT_KEY_USAGE			        (1 << 2)
#	define X509_EXT_SUBJECT_ALT_NAME		    (1 << 3)
#	define X509_EXT_ISSUER_ALT_NAME		        (1 << 4)
#	define X509_EXT_SUBJECT_KEY_IDENTIFIER	    (1 << 5)
#	define X509_EXT_AUTHORITY_KEY_IDENTIFIER	(1 << 6)
#	define X509_EXT_AUTHORITY_INFORMATION_ACCESS (1 << 7)
#	define X509_EXT_CRL_DISTRIBUTION_POINTS	    (1 << 8)
	/* BasicConstraints */
	int ca; /* cA */
	unsigned long path_len_constraint; /* pathLenConstraint */

	struct {
		int length;
		const u8 *data;
	} subjectKeyIdentifier;

	struct {
		int length;
		const u8 *data;
	} authorityKeyIdentifier;

	struct {
		int length;
		const u8 *data;
	} authorityInformationAccess;

	struct {
		int length;
		const u8 *data;
	} CRLDistributionPoints;

	/* KeyUsage */
	unsigned long key_usage;
#	define X509_KEY_USAGE_DIGITAL_SIGNATURE	(1 << 0)
#	define X509_KEY_USAGE_NON_REPUDIATION		(1 << 1)
#	define X509_KEY_USAGE_KEY_ENCIPHERMENT		(1 << 2)
#	define X509_KEY_USAGE_DATA_ENCIPHERMENT	(1 << 3)
#	define X509_KEY_USAGE_KEY_AGREEMENT		(1 << 4)
#	define X509_KEY_USAGE_KEY_CERT_SIGN		(1 << 5)
#	define X509_KEY_USAGE_CRL_SIGN			(1 << 6)
#	define X509_KEY_USAGE_ENCIPHER_ONLY		(1 << 7)
#	define X509_KEY_USAGE_DECIPHER_ONLY		(1 << 8)
};

#define X509_MAX_NAME_ATTRIBUTES 20

struct x509_name {
	struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];
	size_t num_attr;
	char const *email; /* emailAddress */
	size_t email_len;

	/* from alternative name extension */
	char const *alt_email; /* rfc822Name */
	size_t alt_email_len;
	char const *dns; /* dNSName */
	size_t dns_len;
	char const *uri; /* uniformResourceIdentifier */
	size_t uri_len;
	u8 const *ip; /* iPAddress */
	size_t ip_len; /* IPv4: 4, IPv6: 16 */
	struct asn1_oid rid; /* registeredID */
};

typedef enum {
	X509_CERT_V1 = 0,
	X509_CERT_V2 = 1,
	X509_CERT_V3 = 2
} cert_version_t;

struct x509_certificate {
	struct x509_certificate *next;
	//enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
	cert_version_t version;
	unsigned long serial_number;
	struct x509_algorithm_identifier signature;
	struct x509_name issuer;
	struct x509_name subject;
	/*
	 * remove dependency from libc mktime
	os_time_t not_before;
	os_time_t not_after;
	*/
	struct x509_parser_time not_before;
	struct x509_parser_time not_after;
	struct x509_algorithm_identifier public_key_alg;
	u8 const *public_key;
	size_t public_key_len;
	struct x509_algorithm_identifier signature_alg;
	u8 const *sign_value;
	size_t sign_value_len;

	/* Extensions */
	struct x509_extensions exts;

	/*
	 * The DER format certificate follows struct x509_certificate. These
	 * pointers point to that buffer.
	 */
	const u8 *cert_start;
	size_t cert_len;
	const u8 *tbs_cert_start;
	size_t tbs_cert_len;
};

enum {
	X509_VALIDATE_OK,
	X509_VALIDATE_BAD_CERTIFICATE,
	X509_VALIDATE_UNSUPPORTED_CERTIFICATE,
	X509_VALIDATE_CERTIFICATE_REVOKED,
	X509_VALIDATE_CERTIFICATE_EXPIRED,
	X509_VALIDATE_CERTIFICATE_UNKNOWN,
	X509_VALIDATE_UNKNOWN_CA
};

/* Parser return Error codes*/
typedef enum {
	X509_PARSE_OK = 0,
	X509_PARSE_ERROR_UNDEFINED = -1,
	X509_PARSE_ERROR_INVALID_ARGUMENTS = -2,
	X509_PARSE_ERROR_INVALID_SEQUENCE = -3,
	X509_PARSE_ERROR_EXPECTED_BITSTRING = -4,
	X509_PARSE_ERROR_INVALID_HEADER = -5,
	X509_PARSE_ERROR_SIGNATURE_LENGTH = -6,
	X509_PARSE_ERROR_INVALID_SET = -7,
	X509_PARSE_ERROR_INVALID_OID = -8,
	X509_PARSE_ERROR_VERSION_TAG = -9,
	X509_PARSE_ERROR_INVALID_TAG = -10,
	X509_PARSE_ERROR_ALGORITHM_IDENTIFIER = -11,
	X509_PARSE_ERROR_NAME = -12,
	X509_PARSE_ERROR_VALIDITY = -13,
	X509_PARSE_ERROR_PUBLIC_KEY = -14,
	X509_PARSE_ERROR_EXTENSIONS = -15,
} x509_parser_error_t;

void x509_certificate_reset(struct x509_certificate *cert);
x509_parser_error_t x509_certificate_parse(const u8 *buf, size_t len, struct x509_certificate * px509_certificate);
void x509_name_string(struct x509_name *name, char *buf, size_t len);
int x509_name_compare(struct x509_name *a, struct x509_name *b);
void x509_certificate_chain_free(struct x509_certificate *cert);
struct x509_certificate *x509_certificate_get_by_subject(struct x509_certificate *chain, struct x509_name *name);
int x509_certificate_self_signed(struct x509_certificate *cert);

#endif /* X509V3_H */
