/**
 * @file
 * Implements the PKI security layer.
 *
 * @defgroup brp_lib BRP Communication Library
 * @{
 */

#ifndef __PKI_PROTOCOL_H__
#define __PKI_PROTOCOL_H__


#include "protocol.h"


/**
 * Creates a new PKI protocol layer.
 *
 * This protocol layer will manage all PKI-relevant authentication and
 * encryption on top of another BRP protocol layer.
 *
 * @return A BRP protocol on success or NULL on failure. All commands executed
 * via the returned protocol are transferred encrypted.
 */
BRP_LIB brp_protocol brp_create_pki
(
	int security_level,          ///< security level that shall be authenticated
	brp_buf host_cert_chain,     ///< host certificate chain in ASN.1 DER format
	size_t host_cert_chain_len,  ///< length of 'host_cert_chain' in bytes
	brp_buf dev_ca_cert_chain,   ///< device's certificate authority's
	                             ///  certificate chain in ASN.1 DER format
	size_t dev_ca_cert_chain_len,///< length of 'dev_ca_cert_chain' in bytes
	brp_buf private_key,         ///< private key of host in ASN.1 DER format
	size_t private_key_len,      ///< length of 'private_key' in bytes
	brp_time session_timeout     ///< timeout in ms how long session shall be
	                             ///  valid. If 0, the session is valid until
	                             ///  reboot or a new session is started.
);


/**
 * Adds certificate(s) to the host certificate chain.
 *
 * This is a convenience function if the certificate cannot be set at once
 * by the host_cert_chain parameter of the brp_create_pki() function.
 *
 * If @em protocol is NULL, this function is a no-operation.
 */
BRP_LIB brp_errcode brp_append_host_certs
(
	brp_protocol protocol,     ///< PKI protocol that shall be extended
	brp_buf host_cert_chain,   ///< pointer to ASN.1 DER-encoded certificate(s)
	                           ///  Multiple certificates can be added by simply
	                           ///  joining them
	size_t host_cert_chain_len ///  length of host_cert_chain
);


/**
 * Adds certificate(s) to the devices CA certificate chain.
 *
 * This is a convenience function if the certificate cannot be set at once
 * by the dev_ca_cert_chain parameter of brp_create_pki() function.
 *
 * If @em protocol is NULL, this function is a no-operation.
 */
BRP_LIB brp_errcode brp_append_dev_ca_certs
(
	brp_protocol protocol,       ///< PKI protocol that shall be extended
	brp_buf dev_ca_cert_chain,   ///< pointer to ASN.1 DER-enc. certificate(s)
	                             ///  Multiple certificates can be added by
	                             /// simply /  joining them
	size_t dev_ca_cert_chain_len ///  length of dev_ca_cert_chain
);


/**
 * @cond INTERNAL
 */


/**
 * Generates a common shared secret that is shared to the device via ECDH.
 *
 * This function is only required for lowlevel PKI operations.
 * Usually brp_create_pki() will be appropriate.
 *
 * @return The errorcode on failure or #BRP_OK on success.
 */
BRP_LIB brp_errcode brp_pki_pfs_gen_key
(
	brp_protocol protocol,  ///< the protocol that shall be used to run the
	                        ///  brp_pki_pfs_gen_key() command
	brp_buf shared_secret   ///< the shared secret used for further ops
);


/**
 * Exchanges and verifies the certificates
 * (secured via shared_secret from brp_pki_pfs_gen_key()) and creates a
 * session key
 *
 * This function is only required for lowlevel PKI operations.
 * Usually brp_create_pki() will be appropriate.
 *
 * @return The errorcode on failure or #BRP_OK on success.
 */
BRP_LIB brp_errcode brp_pki_init_pfs_session
(
	brp_protocol protocol,      ///< the protocol that shall be used to run the
	                            ///  brp_pki_pfs_gen_key() command
	brp_buf session_key,        ///< returns the session key generated by this
	                            ///  command sequence is stored here and has
	                            ///  to be passed to brp_pki_send_frame()
	brp_buf shared_secret,      ///< the shared secret from brp_pfs_gen_key()
	int security_level,         ///< security level that shall be authenticated
	brp_buf private_key_derfmt, ///< private key of host in ASN.1 DER format
	brp_frame dev_cert_chain,   ///< all certificates (including the root
	                            ///  certificate) of the device except the
	                            ///  end certifcate concatenated
	brp_frame host_cert_chain,  ///< all certificates of the host
	                            ///  concatenated.
	brp_frame dev_cert,         ///< returns the certificate provided by the
	                            ///  device into the provided frame
	                            ///  (will be appended).
	                            ///  ATTENTION: has to be initialized
	                            ///  (see BRP_FRAME_INIT())
	brp_time session_timeout    ///< timeout how long session shall be valid
);


/**
 * This command is identical to brp_send_frame() with the exception, that the
 * data is encrypted by session_key.
 *
 * This function is only required for lowlevel PKI operations.
 * Usually brp_create_pki() will be appropriate.
 *
 * @return The errorcode on failure or #BRP_OK on success.
 */
BRP_LIB brp_errcode brp_pki_tunnel_send_frame
(
	brp_protocol protocol, ///< a protocol handle, where the
	                       ///  connected reader shall run the passed command.
	brp_buf session_key,   ///< the session key that shall be used for
	                       ///  encryption
	unsigned long seq_ctr, ///< a counter that has to be incremented on every
	                       ///  command.
	brp_frame plain_cmd    ///< plain command
);


/**
 * This command is identical to brp_recv_any_frame() with the exception, that
 * the data is decrypted by session_key
 *
 * This function is only required for lowlevel PKI operations.
 * Usually brp_create_pki() will be appropriate.
 *
 * @return The errorcode on failure or #BRP_OK on success.
 */
BRP_LIB brp_errcode brp_pki_tunnel_recv_any_frame
(
	brp_protocol protocol, ///< a protocol handle, where the
	                       ///  connected reader shall run the passed command.
	brp_buf session_key,   ///< the session key that shall be used for
	                       ///  encryption
	unsigned long seq_ctr, ///< a counter that has to be incremented on every
	                       ///  command.
	int cmd_code,          ///< calling command code
	brp_frame plain_rsp,   ///< plain response
	brp_time timeout       ///< maximum time to wait for receiving frame.
	                       ///  If set to BRP_INFINITE (or alternatively 0)
	                       ///  the session will never time out.
);



/**
 * @endcond
 */


/**
 * This command stores the current PKI session state in a persistent storage
 * for being continued later using brp_pki_restore_session().
 *
 * This command freezes the current session, e.g. in a database,
 * and finishes the current process. When the device is reconnected later,
 * you can use brp_pki_restore_session() to restore the session without having
 * to re-authenticate (which requires about 30 secs).
 *
 * ATTENTION:
 * - The protocol must be in idle state (no command must be executed).
 * - If you run a BRP command after brp_pki_save_session(), you have to save the
 *   session again (by running brp_pki_save_session()). Otherwise, restoring the
 *   session will fail.
 *
 * @returns
 * BRP_OK on success or BRP_ERR_BUFFER_OVERFLOW if persistent_session_size is
 * smaller than persistent_session_len.
 */
BRP_LIB brp_errcode brp_pki_save_session
(
	brp_protocol protocol,        ///< a PKI protocol handle that shall be
                                  ///  saved
	brp_buf persistent_buf,       ///< a pointer to a buffer where to store the
	                              ///  session. If NULL, persistent_buf_size has
	                              ///  to be 0, too (persistent_buf_len will be
	                              ///  set anyway)
	size_t peristent_buf_size,    ///< size of persistent_session in bytes
	size_t * persistent_buf_actlen///< actual length of persistent_session in
	                              ///  bytes. If NULL, this parameter will be
	                              ///  ignored.
);


/**
 * Returns the size of the buffer required to store the session state using
 * brp_pki_save_session().
 *
 * @returns
 * Size of persistent state in bytes or 0 on error.
 */
BRP_LIB size_t brp_pki_get_session_buf_size
(
	brp_protocol protocol         ///< the PKI protocol handle which shall
	                              ///  be made persistent
);


/**
 * This command reloads the current PKI session that was stored by
 * brp_pki_save_session().
 *
 * This command must be run between brp_create_pki() and brp_open(), as
 * otherwise opening a PKI protocol runs a complete authentication sequence.
 *
 * @code
 * dev = brp_create(...);
 * brp_set_io(dev, ...);
 * brp_set_crypto(dev, brp_create_pki(...));
 * brp_restore_session(dev, ...);
 * brp_open(dev);
 * @endcode
 *
 * @returns
 * BRP_OK on success or BRP_ERR_INVALID_API_CALL if persistent_buf is invalid.
 */
BRP_LIB brp_errcode brp_pki_restore_session
(
	brp_protocol protocol,       ///< a PKI protocol handle that shall be saved
	brp_buf persistent_buf,      ///< a pointer to a buffer from where to load
	                             ///  the session
	size_t persistent_buf_size   ///< size of persistent_session in bytes
);


/**
 * This command retrieves the certificate of the device which it created a
 * PKI connection to.
 *
 * @returns
 * BRP_OK on success or BRP_ERR_BUFFER_OVERFLOW if dev_cert_buf_size is
 * smaller than the device certificates actual size.
 */
BRP_LIB brp_errcode brp_pki_get_dev_cert
(
	brp_protocol protocol,       ///< an opened pki protocol handle
	brp_buf dev_cert_buf,        ///< a pointer to a buffer, where the device's
	                             ///  certificate shall be returned.
	                             ///  Will *only* be written if BRP_OK is
	                             ///  returned.
	                             ///  May be NULL if dev_cert_buf_size is 0.
	size_t dev_cert_buf_size,    ///< the size of 'dev_cert_buf'
	size_t * dev_cert_len        ///< returns the actual size of the
	                             ///  certificate. Will be even set to the
	                             ///  actual size of the certificate,
	                             ///  if dev_cert_buf_size is smaller.
);


#endif //__BRP_H__

/** @} */ // end of defgroup brp_lib
