#include <stddef.h>
#include <string.h>
#include "xp_ca.h"
#include "xp_cipher.h"
#include "xp_digest.h"
#include "xp_kdf.h"
#include "xp_keyset.h"
#include "xp_sign.h"
#include "xp_tls.h"

static unsigned tls_log_count;

static void
capture_tls_log(const struct xp_tls_log_record *record, void *arg)
{
	unsigned *count = arg;
	if (record != NULL && record->level == XP_TLS_LOG_ERROR
	    && record->source == XP_TLS_LOG_SOURCE_LIBRARY
	    && record->backend != NULL && strcmp(record->backend, "none") == 0
	    && record->message != NULL && record->message_len != 0)
		(*count)++;
}

int main(void)
{
	xp_key_t key = (xp_key_t)1;
	const struct xp_key_spec spec = { XP_KEY_ED25519, 0, XP_KEY_CURVE_NONE };
	if (xp_key_generate(&key, &spec) != XP_CA_ERR_DISABLED || key != NULL)
		return 1;
	if (xp_key_import_private_pem(&key, "x", 1, NULL, NULL) != XP_CA_ERR_DISABLED || key != NULL)
		return 1;
	struct xp_key_store_config key_store = {
		.policy = XP_KEY_STORAGE_NAMED,
		.store = "pkcs11",
		.store_uri = "pkcs11:?module-path=missing",
	};
	struct xp_key_store_capabilities capabilities;
	if (xp_key_store_query(&key_store, &spec, &capabilities)
		!= XP_CRYPTO_ERR_DISABLED
		|| capabilities.available
		|| capabilities.availability_status != XP_CRYPTO_ERR_DISABLED)
		return 1;
	if (xp_key_generate_stored(&key, &key_store, &spec)
		!= XP_CRYPTO_ERR_DISABLED || key != NULL)
		return 1;
	if (xp_sign(NULL, XP_SIGN_ED25519, XP_SIGNATURE_ENCODING_STANDARD,
		"x", 1, NULL, NULL) != XP_CA_ERR_DISABLED)
		return 1;
	if (xp_verify(NULL, XP_SIGN_ED25519, XP_SIGNATURE_ENCODING_STANDARD,
		"x", 1, "x", 1) != XP_CA_ERR_DISABLED)
		return 1;
	if (xp_digest_size(XP_DIGEST_SHA256) != 0
	    || xp_digest_create(XP_DIGEST_SHA256) != NULL)
		return 1;
	struct xp_tls_client_config client = {
		.log_cb = capture_tls_log,
		.log_cb_arg = &tls_log_count,
		.log_level = XP_TLS_LOG_ERROR,
	};
	struct xp_tls_server_config server = {
		.log_cb = capture_tls_log,
		.log_cb_arg = &tls_log_count,
		.log_level = XP_TLS_LOG_ERROR,
	};
	if (xp_tls_client_open_config(INVALID_SOCKET, &client) != NULL
	    || xp_tls_server_open(INVALID_SOCKET, NULL, &server) != NULL
	    || strstr(xp_tls_last_err(), "disabled") == NULL
	    || tls_log_count != 2)
		return 1;
	unsigned char output[32];
	if (xp_kdf_pbkdf2(XP_DIGEST_SHA256, "x", 1, "y", 1, 1,
	    output, sizeof(output)) != XP_CRYPTO_ERR_DISABLED
	    || xp_kdf_scrypt("x", 1, "y", 1, 2, 1, 1,
	    output, sizeof(output)) != XP_CRYPTO_ERR_DISABLED
	    || xp_cipher_supported(XP_CIPHER_AES, XP_CIPHER_MODE_CBC,
	    XP_CIPHER_ENCRYPT))
		return 1;
	xp_tls_server_credentials_t credentials = (xp_tls_server_credentials_t)1;
	struct xp_tls_server_credentials_config credential_config = {
		.certificate_chain_file = "disabled.pem",
		.private_key = (xp_key_t)1,
	};
	if (xp_tls_server_credentials_load(&credentials, &credential_config)
	    != XP_CRYPTO_ERR_DISABLED || credentials != NULL)
		return 1;
	xp_keyset_t keyset = (xp_keyset_t)1;
	const struct xp_keyset_config keyset_config = {
		.path = "disabled.manifest",
		.mode = XP_KEYSET_CREATE,
		.format = XP_KEYSET_FORMAT_MANIFEST,
	};
	if (xp_keyset_open(&keyset, &keyset_config) != XP_CRYPTO_ERR_DISABLED
	    || keyset != NULL)
		return 1;
	return 0;
}
