/*
 * libekmfweb - EKMFWeb client library
 *
 * Copyright IBM Corp. 2020
 *
 * s390-tools is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */

#ifndef LIB_EKMFWEB_H
#define LIB_EKMFWEB_H

#include <stddef.h>
#include <stdbool.h>

typedef void CURL;

struct ekmf_config {
	/** The base URL of the server. Should use https:// ! */
	const char *base_url;
	/** Optional: File name of the CA bundle PEM file, or a name of a
	 *  directory the multiple CA certificates. If this is NULL, then the
	 *  default system path for CA certificates is used */
	const char *tls_ca;
	/** Optional: File name of the client certificate PEM file */
	const char *tls_client_cert;
	/** Optional: File name of the clients key PEM file */
	const char *tls_client_key;
	/** Optional: Passphrase to read the clients key PEM file */
	const char *tls_client_key_passphrase;
	/** Optional: File name of a PEM file holding a CA certificate of the
	 *  issuer */
	const char *tls_issuer_cert;
	/** Optional: File name of a PEM file containing the servers pinned
	 *  public key. Public key pinning requires that verify_peer or
	 *  verify_host (or both) is true. */
	const char *tls_pinned_pubkey;
	/** Optional: File name of a PEM file containing the server's
	 *  certificate. This can be used to allow peer verification with
	 *  self-signed server certificates */
	const char *tls_server_cert;
	/** If true, the peer certificate is verified */
	bool tls_verify_peer;
	/** If true, that the server certificate is for the server it is known
	 *  as (i.e. the hostname in the url) */
	bool tls_verify_host;
	/** Maximum number of redirects to follow. Zero means that redirects are
	 *  not followed. -1 means to infinitely follow redirects. */
	long max_redirs;
	/** File name of the login token (JSON Web Token) used for the last
	 *  login. */
	const char *login_token;
	/** File name of a file containing the client identity secure key blob.
	 *  This key represents the client identity against EKMFWeb. Some
	 *  requests sent to EKMFWeb are signed with this (secure) key */
	const char *identity_secure_key;
	/** File name of a PEM file containing the EKMFWeb servers public key
	 *  used to sign key export responses. */
	const char *ekmf_server_pubkey;
};

struct ekmf_cca_lib {
	void *cca_lib; /* Handle of CCA host library loaded via dlopen */
};

enum ekmf_ext_lib_type {
	EKMF_EXT_LIB_CCA = 1,
};

struct ekmf_ext_lib {
	enum ekmf_ext_lib_type type;
	union {
		struct ekmf_cca_lib *cca; /* Used if type = EKMF_EXT_LIB_CCA */
	};
};

/**
 * Connects to the specified server url and obtains the servers certificate
 * and its chain of signing certificates and stores them in the specified
 * PEM files.
 *
 * @param config            the configuration structure. Only the base_url must
 *                          be specified, all others are optional.
 * @param server_cert_pem   Optional: name of a PEM file to store the servers
 *                          certificate
 * @param server_pubkey_pem Optional: name of a PEM file to store the servers
 *                          public key (can be used for public key pinning)
 * @param ca_bundle_pem     Optional: name of a PEM file to store the CA
 *                          certificate chain as a bundle
 * @param verified          On return: If the server 's certificate has been
 *                          verified using the CA specification from the config
 *                          (if ca = NULL: default system CAs, otherwise path
 *                          or file to CAs).
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 */
int ekmf_get_server_cert_chain(const struct ekmf_config *config,
			       const char *server_cert_pem,
			       const char *server_pubkey_pem,
			       const char *ca_bundle_pem,
			       bool *verified, char **error_msg, bool verbose);

/**
 * Print the certificate(s) contained in the specified PEM file.
 *
 * @param cert_pem          the file name of the PEM file to print
 * @param verbose           if true, verbose messages are printed
 *
 * @returns -EIO if the file could not be opened. -ENOENT if the PEM file
 *          does not contain any certificates. 0 if success.
 */
int ekmf_print_certificates(const char *cert_pem, bool verbose);

/**
 * Checks if the login token stored in the file denoted by field login_token
 * of the config structure is valid or not. The file (if existent) contains a
 * JSON Web Token (JWT, see RFC7519). It is valid if the current date and time
 * is before its expiration time ("exp" claim), and after or equal its
 * not-before time ("nbf" claim).
 * Note: The signature (if any) of the JWT is not checked, nor any other JWT
 * fields.
 *
 * @param config            the configuration structure
 * @param valid             On return: true if the token is valid, false if not
 * @param login_token       On return: If not NULL: the login token, if the
 *                          token is still valid. The returned string must
 *                          be freed by the caller when no longer needed.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success.
 */
int ekmf_check_login_token(const struct ekmf_config *config, bool *valid,
			   char **login_token, bool verbose);

/**
 * Performs a login of the specified user with a passcode. On success the
 * returned login token is stored in the file denoted by field login_token
 * of the config structure, so that it can be used by subsequent requests.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param user_id           the user-ID to log-in.
 * @param passcode          the passcode to log-in the user.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if the passcode is no longer valid.
 */
int ekmf_login(const struct ekmf_config *config, CURL **curl_handle,
	       const char *user_id, const char *passcode, char **error_msg,
	       bool verbose);

enum ekmf_key_type {
	EKMF_KEY_TYPE_ECC = 1,
	EKMF_KEY_TYPE_RSA = 2,
};

struct ekmf_key_gen_info {
	enum ekmf_key_type type;
	union {
		struct {
			int curve_nid;
		} ecc;
		struct {
			size_t modulus_bits;
			unsigned int pub_exp;
		} rsa;
	} params;
};

/**
 * Generate a secure identity key used to identify the client to EKMFWeb.
 * The secure key blob is stored in a file specified in field
 * identity_secure_key of the config structure. If an secure key already exists
 * at that location, it is overwritten.
 *
 * @param config            the configuration structure. Only field
 *                          identity_secure_key must be specified, all others
 *                          are optional.
 * @param info              key generation info, such as key type (ECC or RSA)
 *                          and key parameters.
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success.
 */
int ekmf_generate_identity_key(const struct ekmf_config *config,
			       const struct ekmf_key_gen_info *info,
			       const struct ekmf_ext_lib *ext_lib,
			       bool verbose);

/**
 * Re-encipher the secure identity key (form field identity_secure_key in
 * config) used to identify the client to EKMFWeb.
 * The secure key blob is encrypted using the HSM master key. Whenever the HSM
 * master key is being changed, the secure identity key must be re-enciphered.
 * You can either pro-actively re-encipher a secure key once the new master key
 * has been prepared (but not yet made active): to_new = true; or you can
 * re-encipher a secure key when the HSM master key has already been changed:
 * to_new = false. This requires that the HSM still has the old master key.
 * Not all HSMs support this.
 *
 * For pro-active re-encipherment it is suggested to store the re-enciphered
 * secure key on a separate place, until the new HSM master key has been made
 * active. Specify a file name in reenc_secure_key to do so. For an in-place
 * re-encipherment, set reenc_secure_key = NULL.
 *
 * @param config            the configuration structure. Only field
 *                          identity_secure_key must be specified, all others
 *                          are optional.
 * @param to_new            If true: the identity key is re-enciphered from the
 *                          current to the new master key.
 *                          If false: the identity key is re-enciphered from the
 *                          old to the current master key.
 * @param reenc_secure_key  if not NULL, then the re-enciphered secure key is
 *                          stored into the filename specified here. Otherwise
 *                          the re-enciphered secure key replaces the original
 *                          secure identity key.
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success.
 * A -ENODEV indicates that the master keys are not loaded.
 */
int ekmf_reencipher_identity_key(const struct ekmf_config *config,
				 bool to_new, const char *reenc_secure_key,
				 const struct ekmf_ext_lib *ext_lib,
				 bool verbose);

struct ekmf_rsa_pss_params {
	int salt_len;        /* salt length in bytes, or OpenSSL constants
				RSA_PSS_SALTLEN_DIGEST (-1),
				RSA_PSS_SALTLEN_AUTO (-2), or
				RSA_PSS_SALTLEN_MAX(-3) */
	int mgf_digest_nid;  /* OpenSSl digest nid, or zero to use the same
				digest algorithm as the signature algorithm */
};

/**
 * Generate a certificate signing request using the secure identity key (field
 * identity_secure_key in config structure) with the specified subject name,
 * certificate extensions (if any), and writes the CSR to the specified file
 * in PEM format.
 *
 * To renew an existing certificate, specify renew_cert = true. In this case
 * the existing certificate (field sign_certificate in config struct) is read,
 * and the subject name is extracted from it. Any specified subject name RDNs
 * are added to the CSR. Also, the extensions are taken from the existing
 * certificate, and any specified extensions are added to the CSR.
 *
 * The CSR is signed using the secure identity key (field identity_secure_key in
 * config structure) with an signing algorithm matching the identity key (ECDSA,
 * RSA-PKCS, or RSA-PSS if rsa_pss is true), and the specified digest. If the
 * digest nid is zero, then a default digest is used.
 *
 * @param config            the configuration structure. Only field
 *                          identity_secure_key must be specified, all others
 *                          are optional.
 * @param subject_rdns      an array of strings, each string representing an
 *                          RDN in the form '[+]type=value'. If the type is
 *                          prepended with a '+', then this RDN is added to the
 *                          previous one.
 * @param num_subject_rdns  number of RDN elements in the array.
 * @param subject_utf8      if true, RDNs of type MBSTRING_UTF8 are created,
 *                          otherwise type is MBSTRING_ASC is used.
 * @param renew_cert_filename if not NULL, specifies the file name of a PEM file
 *                          containing an existing certificate that is renewed
 * @param extensions        an array of strings, each string representing an
 *                          certificate extension in the form 'type=value'.
 * @param num_extensions    number of extension elements in the array.
 * @param digest_nid        the OpenSSL digest nid to use with the signature
 *                          algorithm, or 0 to use the default
 * @param rsa_pss_params    if not NULL and the identity key is an RSA key, then
 *                          the CSR is signed with RSA-PSS using the specified
 *                          PSS parameters. Ignored if the identity key is an EC
 *                          key
 * @param csr_pem_filename  the name of the PEM file to which the CSR is written
 * @param new_hdr           if true, output "NEW" in the PEM header lines
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success:
 *          -EINVAL: invalid parameter
 *          -ENOMEM: Failed to allocate memory
 *          -EBADMSG: an RDN or extension is not formatted correctly
 *          -EIO: OpenSSL failed to create the CSR
 *          -EEXIST: if one of the RDN name entries or extensions to add is a
 *                   duplicate
 *          -ENOTSUP: the specified digest is not supported
 *          any other errno from file I/O routines
 */
int ekmf_generate_csr(const struct ekmf_config *config,
		      const char *subject_rdns[], size_t num_subject_rdns,
		      bool subject_utf8, const char *renew_cert_filename,
		      const char *extensions[], size_t num_extensions,
		      int digest_nid,
		      struct ekmf_rsa_pss_params *rsa_pss_params,
		      const char *csr_pem_filename, bool new_hdr,
		      const struct ekmf_ext_lib *ext_lib, bool verbose);

/**
 * Generate a self signed certificate using the secure identity key (field
 * identity_secure_key in config structure) with the specified subject name,
 * certificate extensions (if any), and writes the certificate the specified
 * file in PEM format.
 *
 * To renew an existing certificate, specify renew_cert = true. In this case
 * the existing certificate (field sign_certificate in config struct) is read,
 * and the subject name is extracted from it. Any specified subject name RDNs
 * are added to the certificate. Also, the extensions are taken from the
 * existing certificate, and any specified extensions are added to the new
 * certificate.
 *
 * The certificate is signed using the secure identity key (field
 * identity_secure_key in config structure) with an signing algorithm matching
 * the identity key (ECDSA, RSA-PKCS, or RSA-PSS if rsa_pss is true), and the
 * specified digest. If the digest nid is zero, then a default digest is used.
 *
 * @param config            the configuration structure. Only field
 *                          identity_secure_key must be specified, all others
 *                          are optional.
 * @param subject_rdns      an array of strings, each string representing an
 *                          RDN in the form '[+]type=value'. If the type is
 *                          prepended with a '+', then this RDN is added to the
 *                          previous one.
 * @param num_subject_rdns  number of RDN elements in the array.
 * @param subject_utf8      if true, RDNs of type MBSTRING_UTF8 are created,
 *                          otherwise type is MBSTRING_ASC is used.
 * @param renew_cert_filename if not NULL, specifies the file name of a PEM file
 *                          containing an existing certificate that is renewed
 * @param extensions        an array of strings, each string representing an
 *                          certificate extension in the form 'type=value'.
 * @param num_extensions    number of extension elements in the array.
 * @param validity_days     number if day from the current date how long the
 *                          certificate is valid.
 * @param digest_nid        the OpenSSL digest nid to use with the signature
 *                          algorithm, or 0 to use the default
 * @param rsa_pss_params    if not NULL and the identity key is an RSA key, then
 *                          the certificate is signed with RSA-PSS using the
 *                          specified PSS parameters. Ignored if the identity
 *                          key is an EC key
 * @param cert_pem_filename the name of the PEM file to which the Certificate
 *                          is written
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success.
 *          -EINVAL: invalid parameter
 *          -ENOMEM: Failed to allocate memory
 *          -EBADMSG: an RDN or extension is not formatted correctly
 *          -EIO: OpenSSL failed to create the certificate
 *          -EEXIST: if one of the RDN name entries or extensions to add is a
 *                   duplicate
 *          -ENOTSUP: the specified digest is not supported
 *          any other errno from file I/O routines
 */
int ekmf_generate_ss_cert(const struct ekmf_config *config,
			  const char *subject_rdns[], size_t num_subject_rdns,
			  bool subject_utf8, const char *renew_cert_filename,
			  const char *extensions[], size_t num_extensions,
			  int validity_days, int digest_nid,
			  struct ekmf_rsa_pss_params *rsa_pss_params,
			  const char *cert_pem_filename,
			  const struct ekmf_ext_lib *ext_lib, bool verbose);

/**
 * Validates that a certificate has the same public key as the secure identity
 * key (field identity_secure_key in config structure) .
 *
 * @param config            the configuration structure. Only field
 *                          identity_secure_key must be specified, all others
 *                          are optional.
 * @param x509_cert         the X509 certificate object to validate
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns a negative errno in case of an error, 0 if success.
 *          -EINVAL: invalid parameter, or certificate is not valid
 *          -ENOMEM: Failed to allocate memory
 *          any other errno from file I/O routines
 */
int ekmf_validate_cert(const struct ekmf_config *config, const X509 *x509_cert,
		       const struct ekmf_ext_lib *ext_lib, bool verbose);

/**
 * Retrieves settings from the EKMFWeb server, such as the template names for
 * generating keys in EKMFWeb.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param identity_template on return: If not NULL, the name of the template
 *                          used to generate identity keys with. The caller
 *                          must free the error string when it is not NULL.
 * @param xts_key1_template on return: If not NULL, the name of the template
 *                          used to generate the first XTS key with. The caller
 *                          must free the error string when it is not NULL.
 * @param xts_key1_template on return: If not NULL, the name of the template
 *                          used to generate the second XTS key with. The caller
 *                          must free the error string when it is not NULL.
 * @param xts_key1_template on return: If not NULL, the name of the template
 *                          used to generate a non-XTS key with. The caller
 *                          must free the error string when it is not NULL.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 */
int ekmf_get_settings(const struct ekmf_config *config, CURL **curl_handle,
		      char **identity_template, char **xts_key1_template,
		      char **xts_key2_template, char **non_xts_template,
		      char **error_msg, bool verbose);

/**
 * Checks if the EKMFWeb server has the required Pervasive Encryption feature
 * installed
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -ENOTSUP is returned, if the feature is not installed.
 */
int ekmf_check_feature(const struct ekmf_config *config, CURL **curl_handle,
		       char **error_msg, bool verbose);

/**
 * Request the EKMFWeb server's public signing key and store it into PEM file
 * specified in field server_pubkey of the config structure.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 */
int ekmf_get_public_key(const struct ekmf_config *config, CURL **curl_handle,
			char **error_msg, bool verbose);

/**
 * Requests a key to be retrieved from EKMFweb and imported under the current
 * HSM's master key.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_uuid          the UUID of the key to retrieve
 * @param sess_ec_curve_nid The OpenSSL nid of the EC curve used for the session
 *                          ECC key. If 0, then the default curve is used.
 * @param sign_rsa_digest_nid The OpenSSL nid of a digest used to sign the
 *                          request with if the identity key is an RSA-type key.
 *                          If 0, then the default digest is used.
 *                          Ignored for ECC-type identity keys.
 * @param use_rsa_pss       If true, and the identity key is an RSA-type key,
 *                          use RSA-PSS to sign the request.
 * @param signature_kid     the Key ID for the signature of the request
 * @param key_blob          a buffer to store the retrieved key blob to
 * @param key_blob_length   On entry: the size ofthe buffer
 *                          On return: the size of the key blob retrieved
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param ext_lib           External secure key crypto library to use
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          retrieve the key
 */
int ekmf_retrieve_key(const struct ekmf_config *config, CURL **curl_handle,
		      const char *key_uuid, int sess_ec_curve_nid,
		      int sign_rsa_digest_nid, bool use_rsa_pss,
		      const char *signature_kid, unsigned char *key_blob,
		      size_t *key_blob_length, char **error_msg,
		      const struct ekmf_ext_lib *ext_lib, bool verbose);

struct ekmf_tag_definition {
	/** name of the tag */
	const char *name;
	/** Optional: description of the tag (can be NULL) */
	const char *description;
};

struct ekmf_tag_def_list {
	/** array of tag definitions */
	struct ekmf_tag_definition *tag_defs;
	/** number of tag definitions in array above */
	size_t num_tag_defs;
};

struct ekmf_template_info {
	/** name of the template */
	const char *name;
	/** UUID of the template */
	const char *uuid;
	/** type of the keys generated with this template , e.g. CIPHER */
	const char *key_type;
	/** algorithm of the keys generated with this template, e.g. AES */
	const char *algorithm;
	/** bit size of the keys generated with this template */
	size_t key_size;
	/** state of the template , e.g. ACTIVE */
	const char *state;
	/** state of the keys generated with this template , e.g. ACTIVE */
	const char *key_state;
	/** label template when generating keys with this template */
	const char *label_template;
	/** label tag definition list */
	struct ekmf_tag_def_list label_tags;
	/** true if keys generated with this template can be exported */
	bool export_allowed;
	/** the keystore type of the keys generated with this template */
	const char *keystore_type;
	/** Type of ECC curve, e.g. PRIME_CURVE (for algorithm = ECC) */
	const char *curve;
	/** timestamp when the template was created */
	const char *created_on;
	/** timestamp when the template was updated */
	const char *updated_on;
};

struct ekmf_tag {
	/** name of the tag */
	const char *name;
	/** value of the tag */
	const char *value;
};

struct ekmf_tag_list {
	/** array of tags */
	struct ekmf_tag *tags;
	/** number of tags in array above */
	size_t num_tags;
};

struct ekmf_exporting_key {
	/** name of the exporting key */
	const char *name;
	/** uuid of the exporting key */
	const char *uuid;
};

struct ekmf_export_control {
	/** If true, export is allowed using the exporting keys below */
	bool export_allowed;
	/** array of erporting keys */
	struct ekmf_exporting_key *exporting_keys;
	/** number of keys in array above */
	size_t num_exporting_keys;
};

struct ekmf_key_info {
	/** label (name) of the key */
	const char *label;
	/** Optional: description of the key (can be NULL) */
	const char *description;
	/** UUID of the key */
	const char *uuid;
	/** type of the key, e.g. CIPHER */
	const char *key_type;
	/** algorithm of the key, e.g. AES */
	const char *algorithm;
	/** bit size of the key */
	size_t key_size;
	/** state of the key, e.g. ACTIVE */
	const char *state;
	/** type of the keystore, e.g. PERVASIVE_ENCRYPTION */
	const char *keystore_type;
	/** name of the template used to generate the key */
	const char *template;
	/** UUID of the template used to generate the key */
	const char *template_uuid;
	/** label tag list */
	struct ekmf_tag_list label_tags;
	/** custom tag list */
	struct ekmf_tag_list custom_tags;
	/** export control information */
	struct ekmf_export_control export_control;
	/** timestamp when the key was activated */
	const char *activate_on;
	/** timestamp when the key expires */
	const char *expires_on;
	/** timestamp when the key was created */
	const char *created_on;
	/** timestamp when the key was updated */
	const char *updated_on;
};

#define EKMF_KEY_STATE_PRE_ACTIVATION		"PRE-ACTIVATION"
#define EKMF_KEY_STATE_ACTIVE			"ACTIVE"
#define EKMF_KEY_STATE_DEACTIVATED		"DEACTIVATED"
#define EKMF_KEY_STATE_COMPROMISED		"COMPROMISED"
#define EKMF_KEY_STATE_DESTROYED		"DESTROYED"
#define EKMF_KEY_STATE_DESTROYED_COMPROMISED	"DESTROYED-COMPROMISED"

/**
 * Callback function used with the ekmf_list_templates function. This
 * callback is called for each template found.
 *
 * @param curl_handle      a CURL handle that can be used to perform further
 *                         EKMFWeb functions within the callback.
 * @param template_info    a struct containing information about the template.
 *                         If any of the information needs to be kept, then the
 *                         callback function must make a copy of the
 *                         information. The memory holding the information
 *                         passed to the callback is no longer valid after the
 *                         callback has returned.
 * @param private          the private pointer that was specified with the
 *                         ekmf_list_templates invocation.
 *
 * @returns zero for success, a negative errno in case of an error.
 * When a nonzero return code is returned, the template listing process stops,
 * and ekmf_list_templates returns the return code from the callback.
 */
typedef int (*ekmf_template_cb_t)(CURL *curl_handle,
				  struct ekmf_template_info *template_info,
				  void *private);

/**
 * List available key templates. Only templates in state ACTIVE, with key
 * algorithm AES and keystore type PERVASIVE_ENCRYPTION are listed. The
 * templates are ordered by name in ascending order.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param template_cb       a callback function that is called for each template
 *                          found
 * @param private           a pointer that is passed as-is to the callback
 * @param name_pattern      a pattern to filter by name, or NULL to list all.
 * @param state             the state of the templates to list. If NULL then
 *                          templates in state 'ACTIVE' are listed
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          list the templates
 */
int ekmf_list_templates(const struct ekmf_config *config, CURL **curl_handle,
			ekmf_template_cb_t template_cb, void *private,
			const char *name_pattern, const char *state,
			char **error_msg, bool verbose);

/**
 * Get a template by its UUID.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param template_uuid     the UUID of the template to get
 * @param template          an address of a template info pointer. On return
 *                          the pointer is updated to point to a newly allocated
 *                          template info struct. It must be freed by the caller
 *                          using ekmf_free_template_info when no longer needed.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          get the template
 */
int ekmf_get_template(const struct ekmf_config *config, CURL **curl_handle,
		      const char *template_uuid,
		      struct ekmf_template_info **template, char **error_msg,
		      bool verbose);

/**
 * Get the last used sequence number of a template by its UUID.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param template_uuid     the UUID of the template to get
 * @param seqNumber         On return: the last used sequence number of this
 *                          template.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          get the template
 */
int ekmf_get_last_seq_no(const struct ekmf_config *config, CURL **curl_handle,
			 const char *template_uuid, unsigned int *seqNumber,
			 char **error_msg, bool verbose);

/**
 * Clones a template info structure by making a deep copy of all strings and
 * arrays.
 * The copied template info must be freed using ekmf_free_template_info() by
 * the caller.
 *
 * @param src               the source template info structure
 * @param dest              the destination template info structure
 *
 * @returns zero for success, a negative errno in case of an error
 */
int ekmf_clone_template_info(const struct ekmf_template_info *src,
			     struct ekmf_template_info **dest);

/**
 * Free a template info structure.
 *
 * @param template          the template to free
 */
void ekmf_free_template_info(struct ekmf_template_info *template);

/**
 * Callback function used with the ekmf_list_keys function. This
 * callback is called for each ky found.
 *
 * @param curl_handle      a CURL handle that can be used to perform further
 *                         EKMFWeb functions within the callback.
 * @param template_info    a struct containing information about the key.
 *                         If any of the information needs to be kept, then the
 *                         callback function must make a copy of the
 *                         information. The memory holding the information
 *                         passed to the callback is no longer valid after the
 *                         callback has returned.
 * @param private          the private pointer that was specified with the
 *                         ekmf_list_keys invocation.
 *
 * @returns zero for success, a negative errno in case of an error.
 * When a nonzero return code is returned, the key listing process stops,
 * and ekmf_list_keys returns the return code from the callback.
 */
typedef int (*ekmf_key_cb_t)(CURL *curl_handle,
			     struct ekmf_key_info *key_info,
			     void *private);

/**
 * List available keys. The keys are ordered by name in ascending order.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_cb            a callback function that is called for each key
 *                          found
 * @param private           a pointer that is passed as-is to the callback
 * @param name_pattern      a pattern to filter by name, or NULL to list all.
 * @param states            the states of the keys to list, or NULL to list keys
 *                          in ACTIVE state only. Multiple states can be
 *                          specified separated by comma.*
 * @param tags              a list of custom tags to use as filter, or NULL
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          list the keys
 */
int ekmf_list_keys(const struct ekmf_config *config, CURL **curl_handle,
		   ekmf_key_cb_t key_cb, void *private,
		   const char *name_pattern, const char *states,
		   const struct ekmf_tag_list *tags,
		   char **error_msg, bool verbose);

/**
 * Get information about a key by its UUID.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_uuid          the UUID of the key to get info for
 * @param key               an address of a key info pointer. On return
 *                          the pointer is updated to point to a newly allocated
 *                          key info struct. It must be freed by the caller
 *                          using ekmf_free_key_info when no longer needed.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          get the key info
 */
int ekmf_get_key_info(const struct ekmf_config *config, CURL **curl_handle,
		      const char *key_uuid, struct ekmf_key_info **key,
		      char **error_msg, bool verbose);

/**
 * Changes the state of a key identified by its UUID. To update a key,
 * the timestamp from the last update is required. This can be found in
 * the key info struct in field update_on.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_uuid          the UUID of the key to get info for
 * @param new_state         the new state of the key
 * @param updated_on        the timestamp of the last update (must match)
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          update the key.
 *          -EAGAIN is returned if the timestamp does not match, indicating that
 *          the key has been updated in the meantime.
 */
int ekmf_set_key_state(const struct ekmf_config *config, CURL **curl_handle,
		       const char *key_uuid, const char *new_state,
		       const char *updated_on, char **error_msg, bool verbose);

/**
 * Sets (changed/adds) custom tags of a key identified by its UUID. To update a
 * key, the timestamp from the last update is required. This can be found in
 * the key info struct in field update_on.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_uuid          the UUID of the key to get info for
 * @param tags              a list of tags to set
 * @param updated_on        the timestamp of the last update (must match)
 * @param new_updated_on    on return: if not NULL, the new timestamp of the
 *                          current update. Can be used for subsequent updates
 *                          on the key.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          update the key.
 *          -EAGAIN is returned if the timestamp does not match, indicating that
 *          the key has been updated in the meantime.
 */
int ekmf_set_key_tags(const struct ekmf_config *config, CURL **curl_handle,
		       const char *key_uuid, const struct ekmf_tag_list *tags,
		       const char *updated_on, char **new_updated_on,
		       char **error_msg, bool verbose);

/**
 * Deletes custom tags of a key identified by its UUID. To update a
 * key, the timestamp from the last update is required. This can be found in
 * the key info struct in field update_on.
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param key_uuid          the UUID of the key to get info for
 * @param tags              a list of tags to delete. Only the name of the tags
 *                          must be present in the tag structs of the list, the
 *                          values are ignored.
 * @param updated_on        the timestamp of the last update (must match)
 * @param new_updated_on    on return: if not NULL, the new timestamp of the
 *                          current update. Can be used for subsequent updates
 *                          on the key.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          update the key.
 *          -EAGAIN is returned if the timestamp does not match, indicating that
 *          the key has been updated in the meantime.
 */
int ekmf_delete_key_tags(const struct ekmf_config *config, CURL **curl_handle,
			 const char *key_uuid, const struct ekmf_tag_list *tags,
			 const char *updated_on, char **new_updated_on,
			 char **error_msg, bool verbose);

/**
 * Clones a key info structure by making a deep copy of all strings and
 * arrays.
 * The copied key info must be freed using ekmf_free_key_info() by
 * the caller.
 *
 * @param src               the source key info structure
 * @param dest              the destination key info structure
 *
 * @returns zero for success, a negative errno in case of an error
 */
int ekmf_clone_key_info(const struct ekmf_key_info *src,
			struct ekmf_key_info **dest);

/**
 * Free a key info structure.
 *
 * @param key               the key info to free
 */
void ekmf_free_key_info(struct ekmf_key_info *key);

/**
 * Generates a new key in EKMFWeb
 *
 * To perform a single request, set curl_handle to NULL. This will cause the
 * function to initialize a new CURL handle, use it, and destroy it.
 * If you plan to perform multiple requests to the same host, supply the address
 * of a CURL pointer that is initially NULL. This function will then initialize
 * a new CURL handle on the first call. On subsequent calls, pass in the address
 * of the same CURL pointer so that the CURL handle is reused. After the last
 * request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
 *
 * @param config            the configuration structure
 * @param curl_handle       address of a CURL handle used for reusing the same
 *                          CURL handle with multiple requests.
 * @param template          the name of the template to generate the key with
 * @param description       Optional: a textual description of the key (can be
 *                          NULL)
 * @param label_tags        list of label tags. The label tags are required as
 *                          defined in the template
 * @param custom_tags       Optional: list of custom tags (can be NULL)
 * @param exporting_key     Optional: The uuid of the key that is allowed to
 *                          export the newly generated key (can be NULL).
 * @param certificate       Optional: The certificate to generate an identity
 *                          key from. Should be NULL for generating AES keys.
 * @param certificate_size  Optional: the size of the certificate. Required if
 *                          certificate is not NULL.
 * @param key_info          Optional: On return: If not NULL, a key info struct
 *                          is returned here containing key information. This
 *                          must be freed by the caller with ekmf_free_key_info
 *                          when no longer needed.
 * @param error_msg         on return: If not NULL, then a textual error message
 *                          is returned in case of a failing request. The caller
 *                          must free the error string when it is not NULL.
 * @param verbose           if true, verbose messages are printed
 *
 * @returns zero for success, a negative errno in case of an error.
 *          -EACCES is returned, if no or no valid login token is available.
 *          -EPERM is returned if the login token does not have permission to
 *          generate keys
 */
int ekmf_generate_key(const struct ekmf_config *config, CURL **curl_handle,
		      const char *template, const char *description,
		      const struct ekmf_tag_list *label_tags,
		      const struct ekmf_tag_list *custom_tags,
		      const char *exporting_key,
		      const unsigned char *certificate, size_t certificate_size,
		      struct ekmf_key_info **key_info,
		      char **error_msg, bool verbose);

/**
 * Close the connection to the EKMFWeb server by destroying the CURL handle.
 *
 * @param curl_handle       the CURL handle to destroy
 */
void ekmf_curl_destroy(CURL *curl_handle);

#endif
