#ifndef _IPXE_TLS_H
#define _IPXE_TLS_H

/**
 * @file
 *
 * Transport Layer Security Protocol
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <stdint.h>
#include <ipxe/refcnt.h>
#include <ipxe/interface.h>
#include <ipxe/process.h>
#include <ipxe/crypto.h>
#include <ipxe/md5.h>
#include <ipxe/sha1.h>
#include <ipxe/x509.h>
#include <ipxe/privkey.h>
#include <ipxe/pending.h>
#include <ipxe/iobuf.h>
#include <ipxe/tables.h>

struct tls_connection;

/** A TLS header */
struct tls_header {
	/** Content type
	 *
	 * This is a TLS_TYPE_XXX constant
	 */
	uint8_t type;
	/** Protocol version
	 *
	 * This is a TLS_VERSION_XXX constant
	 */
	uint16_t version;
	/** Length of payload */
	uint16_t length;
} __attribute__ (( packed ));

/** TLS version 1.1 */
#define TLS_VERSION_TLS_1_1 0x0302

/** TLS version 1.2 */
#define TLS_VERSION_TLS_1_2 0x0303

/** Maximum supported TLS version */
#define TLS_VERSION_MAX TLS_VERSION_TLS_1_2

/** Change cipher content type */
#define TLS_TYPE_CHANGE_CIPHER 20

/** Change cipher spec magic byte */
#define TLS_CHANGE_CIPHER_SPEC 1

/** Alert content type */
#define TLS_TYPE_ALERT 21

/** Handshake content type */
#define TLS_TYPE_HANDSHAKE 22

/** Application data content type */
#define TLS_TYPE_DATA 23

/* Handshake message types */
#define TLS_HELLO_REQUEST 0
#define TLS_CLIENT_HELLO 1
#define TLS_SERVER_HELLO 2
#define TLS_NEW_SESSION_TICKET 4
#define TLS_CERTIFICATE 11
#define TLS_SERVER_KEY_EXCHANGE 12
#define TLS_CERTIFICATE_REQUEST 13
#define TLS_SERVER_HELLO_DONE 14
#define TLS_CERTIFICATE_VERIFY 15
#define TLS_CLIENT_KEY_EXCHANGE 16
#define TLS_FINISHED 20

/* TLS alert levels */
#define TLS_ALERT_WARNING 1
#define TLS_ALERT_FATAL 2

/* TLS cipher specifications */
#define TLS_RSA_WITH_NULL_MD5 0x0001
#define TLS_RSA_WITH_NULL_SHA 0x0002
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003c
#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003d
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006b
#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009c
#define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009d
#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009e
#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009f

/* TLS hash algorithm identifiers */
#define TLS_MD5_ALGORITHM 1
#define TLS_SHA1_ALGORITHM 2
#define TLS_SHA224_ALGORITHM 3
#define TLS_SHA256_ALGORITHM 4
#define TLS_SHA384_ALGORITHM 5
#define TLS_SHA512_ALGORITHM 6

/* TLS signature algorithm identifiers */
#define TLS_RSA_ALGORITHM 1

/* TLS server name extension */
#define TLS_SERVER_NAME 0
#define TLS_SERVER_NAME_HOST_NAME 0

/* TLS maximum fragment length extension */
#define TLS_MAX_FRAGMENT_LENGTH 1
#define TLS_MAX_FRAGMENT_LENGTH_512 1
#define TLS_MAX_FRAGMENT_LENGTH_1024 2
#define TLS_MAX_FRAGMENT_LENGTH_2048 3
#define TLS_MAX_FRAGMENT_LENGTH_4096 4

/* TLS signature algorithms extension */
#define TLS_SIGNATURE_ALGORITHMS 13

/* TLS session ticket extension */
#define TLS_SESSION_TICKET 35

/* TLS renegotiation information extension */
#define TLS_RENEGOTIATION_INFO 0xff01

/** TLS authentication header */
struct tls_auth_header {
	/** Sequence number */
	uint64_t seq;
	/** TLS header */
	struct tls_header header;
} __attribute__ (( packed ));

/** TLS verification data */
struct tls_verify_data {
	/** Client verification data */
	uint8_t client[12];
	/** Server verification data */
	uint8_t server[12];
} __attribute__ (( packed ));

/** TLS RX state machine state */
enum tls_rx_state {
	TLS_RX_HEADER = 0,
	TLS_RX_DATA,
};

/** TLS TX pending flags */
enum tls_tx_pending {
	TLS_TX_CLIENT_HELLO = 0x0001,
	TLS_TX_CERTIFICATE = 0x0002,
	TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004,
	TLS_TX_CERTIFICATE_VERIFY = 0x0008,
	TLS_TX_CHANGE_CIPHER = 0x0010,
	TLS_TX_FINISHED = 0x0020,
};

/** A TLS key exchange algorithm */
struct tls_key_exchange_algorithm {
	/** Algorithm name */
	const char *name;
	/**
	 * Transmit Client Key Exchange record
	 *
	 * @v tls		TLS connection
	 * @ret rc		Return status code
	 */
	int ( * exchange ) ( struct tls_connection *tls );
};

/** A TLS cipher suite */
struct tls_cipher_suite {
	/** Key exchange algorithm */
	struct tls_key_exchange_algorithm *exchange;
	/** Public-key encryption algorithm */
	struct pubkey_algorithm *pubkey;
	/** Bulk encryption cipher algorithm */
	struct cipher_algorithm *cipher;
	/** MAC digest algorithm */
	struct digest_algorithm *digest;
	/** Handshake digest algorithm (for TLSv1.2 and above) */
	struct digest_algorithm *handshake;
	/** Numeric code (in network-endian order) */
	uint16_t code;
	/** Key length */
	uint8_t key_len;
	/** Fixed initialisation vector length */
	uint8_t fixed_iv_len;
	/** Record initialisation vector length */
	uint8_t record_iv_len;
	/** MAC length */
	uint8_t mac_len;
};

/** TLS cipher suite table */
#define TLS_CIPHER_SUITES						\
	__table ( struct tls_cipher_suite, "tls_cipher_suites" )

/** Declare a TLS cipher suite */
#define __tls_cipher_suite( pref )					\
	__table_entry ( TLS_CIPHER_SUITES, pref )

/** A TLS cipher specification */
struct tls_cipherspec {
	/** Cipher suite */
	struct tls_cipher_suite *suite;
	/** Dynamically-allocated storage */
	void *dynamic;
	/** Public key encryption context */
	void *pubkey_ctx;
	/** Bulk encryption cipher context */
	void *cipher_ctx;
	/** MAC secret */
	void *mac_secret;
	/** Fixed initialisation vector */
	void *fixed_iv;
};

/** A TLS signature and hash algorithm identifier */
struct tls_signature_hash_id {
	/** Hash algorithm */
	uint8_t hash;
	/** Signature algorithm */
	uint8_t signature;
} __attribute__ (( packed ));

/** A TLS signature algorithm */
struct tls_signature_hash_algorithm {
	/** Digest algorithm */
	struct digest_algorithm *digest;
	/** Public-key algorithm */
	struct pubkey_algorithm *pubkey;
	/** Numeric code */
	struct tls_signature_hash_id code;
};

/** TLS signature hash algorithm table
 *
 * Note that the default (TLSv1.1 and earlier) algorithm using
 * MD5+SHA1 is never explicitly specified.
 */
#define TLS_SIG_HASH_ALGORITHMS						\
	__table ( struct tls_signature_hash_algorithm,			\
		  "tls_sig_hash_algorithms" )

/** Declare a TLS signature hash algorithm */
#define __tls_sig_hash_algorithm					\
	__table_entry ( TLS_SIG_HASH_ALGORITHMS, 01 )

/** TLS client random data */
struct tls_client_random {
	/** GMT Unix time */
	uint32_t gmt_unix_time;
	/** Random data */
	uint8_t random[28];
} __attribute__ (( packed ));

/** An MD5+SHA1 context */
struct md5_sha1_context {
	/** MD5 context */
	uint8_t md5[MD5_CTX_SIZE];
	/** SHA-1 context */
	uint8_t sha1[SHA1_CTX_SIZE];
} __attribute__ (( packed ));

/** MD5+SHA1 context size */
#define MD5_SHA1_CTX_SIZE sizeof ( struct md5_sha1_context )

/** An MD5+SHA1 digest */
struct md5_sha1_digest {
	/** MD5 digest */
	uint8_t md5[MD5_DIGEST_SIZE];
	/** SHA-1 digest */
	uint8_t sha1[SHA1_DIGEST_SIZE];
} __attribute__ (( packed ));

/** MD5+SHA1 digest size */
#define MD5_SHA1_DIGEST_SIZE sizeof ( struct md5_sha1_digest )

/** A TLS session */
struct tls_session {
	/** Reference counter */
	struct refcnt refcnt;
	/** List of sessions */
	struct list_head list;

	/** Server name */
	const char *name;
	/** Root of trust */
	struct x509_root *root;
	/** Private key */
	struct private_key *key;

	/** Session ID */
	uint8_t id[32];
	/** Length of session ID */
	size_t id_len;
	/** Session ticket */
	void *ticket;
	/** Length of session ticket */
	size_t ticket_len;
	/** Master secret */
	uint8_t master_secret[48];

	/** List of connections */
	struct list_head conn;
};

/** A TLS connection */
struct tls_connection {
	/** Reference counter */
	struct refcnt refcnt;

	/** Session */
	struct tls_session *session;
	/** List of connections within the same session */
	struct list_head list;
	/** Session ID */
	uint8_t session_id[32];
	/** Length of session ID */
	size_t session_id_len;
	/** New session ticket */
	void *new_session_ticket;
	/** Length of new session ticket */
	size_t new_session_ticket_len;

	/** Plaintext stream */
	struct interface plainstream;
	/** Ciphertext stream */
	struct interface cipherstream;

	/** Protocol version */
	uint16_t version;
	/** Current TX cipher specification */
	struct tls_cipherspec tx_cipherspec;
	/** Next TX cipher specification */
	struct tls_cipherspec tx_cipherspec_pending;
	/** Current RX cipher specification */
	struct tls_cipherspec rx_cipherspec;
	/** Next RX cipher specification */
	struct tls_cipherspec rx_cipherspec_pending;
	/** Master secret */
	uint8_t master_secret[48];
	/** Server random bytes */
	uint8_t server_random[32];
	/** Client random bytes */
	struct tls_client_random client_random;
	/** Server Key Exchange record (if any) */
	void *server_key;
	/** Server Key Exchange record length */
	size_t server_key_len;
	/** Digest algorithm used for handshake verification */
	struct digest_algorithm *handshake_digest;
	/** Digest algorithm context used for handshake verification */
	uint8_t *handshake_ctx;
	/** Private key */
	struct private_key *key;
	/** Client certificate chain (if used) */
	struct x509_chain *certs;
	/** Secure renegotiation flag */
	int secure_renegotiation;
	/** Verification data */
	struct tls_verify_data verify;

	/** Root of trust */
	struct x509_root *root;
	/** Server certificate chain */
	struct x509_chain *chain;
	/** Certificate validator */
	struct interface validator;

	/** Client security negotiation pending operation */
	struct pending_operation client_negotiation;
	/** Server security negotiation pending operation */
	struct pending_operation server_negotiation;
	/** Certificate validation pending operation */
	struct pending_operation validation;

	/** TX sequence number */
	uint64_t tx_seq;
	/** TX pending transmissions */
	unsigned int tx_pending;
	/** TX process */
	struct process process;

	/** RX sequence number */
	uint64_t rx_seq;
	/** RX state */
	enum tls_rx_state rx_state;
	/** Current received record header */
	struct tls_header rx_header;
	/** Current received record header (static I/O buffer) */
	struct io_buffer rx_header_iobuf;
	/** List of received data buffers */
	struct list_head rx_data;
	/** Received handshake fragment */
	struct io_buffer *rx_handshake;
};

/** RX I/O buffer size
 *
 * The maximum fragment length extension is optional, and many common
 * implementations (including OpenSSL) do not support it.  We must
 * therefore be prepared to receive records of up to 16kB in length.
 * The chance of an allocation of this size failing is non-negligible,
 * so we must split received data into smaller allocations.
 */
#define TLS_RX_BUFSIZE 4096

/** Minimum RX I/O buffer size
 *
 * To simplify manipulations, we ensure that no RX I/O buffer is
 * smaller than this size.  This allows us to assume that the MAC and
 * padding are entirely contained within the final I/O buffer.
 */
#define TLS_RX_MIN_BUFSIZE 512

/** RX I/O buffer alignment */
#define TLS_RX_ALIGN 16

extern struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm;
extern struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm;

extern int add_tls ( struct interface *xfer, const char *name,
		     struct x509_root *root, struct private_key *key );

#endif /* _IPXE_TLS_H */
