/*
 * 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;

#if 0 
    struct
    {
        int length;
        const u8 *data;
    } authorityInformationAccess;

    struct
    {
        int length;
        const u8 *data;
    } CRLDistributionPoints;
#endif

	/* 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);
/*int x509_certificate_check_signature(struct x509_certificate *issuer,
				     struct x509_certificate *cert);*/
/*int x509_certificate_chain_validate(struct x509_certificate *trusted,
				    struct x509_certificate *chain,
				    int *reason, int disable_time_checks);*/
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 */
