/*
 * Empirically determine whether PostgreSQL's EXISTING crypto code paths
 * dispatch through an OpenSSL 3 provider, versus the fetch-based paths the
 * patch switches to.  Uses OpenSSL provider introspection only; no assertions
 * about the outcome are baked in -- it prints whatever OpenSSL reports.
 */
#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/provider.h>
#include <openssl/core_names.h>
#include <openssl/params.h>

static const char *
pn(const OSSL_PROVIDER *p)
{
	return p ? OSSL_PROVIDER_get0_name(p) : "LEGACY BUILT-IN (no provider)";
}

int
main(void)
{
	printf("Runtime: %s\n\n", OpenSSL_version(OPENSSL_VERSION));

	/* ---------------- DIGEST ---------------- */

	/* Q1: is EVP_sha256() itself provider-backed? */
	printf("Q1  EVP_sha256() provider                         : %s\n",
		   pn(EVP_MD_get0_provider(EVP_sha256())));

	/* Q2: what does PG do today -- EVP_DigestInit_ex(ctx, EVP_sha256(), NULL).
	 *     Inspect the MD the context actually ends up using. */
	{
		EVP_MD_CTX *c = EVP_MD_CTX_new();

		EVP_DigestInit_ex(c, EVP_sha256(), NULL);
		printf("Q2  ctx MD after DigestInit_ex(EVP_sha256())      : %s\n",
			   pn(EVP_MD_get0_provider(EVP_MD_CTX_get0_md(c))));
		EVP_MD_CTX_free(c);
	}

	/* Q3: what the patch does -- explicit fetch, default libctx, NULL propq. */
	{
		EVP_MD	   *f = EVP_MD_fetch(NULL, "SHA256", NULL);

		printf("Q3  EVP_MD_fetch(NULL,\"SHA256\",NULL)              : %s\n",
			   pn(EVP_MD_get0_provider(f)));
		EVP_MD_free(f);
	}

	/* Q4: does fetch honor the library context / provider configuration?
	 *     Build a libctx with ONLY the legacy provider loaded (no default). */
	{
		OSSL_LIB_CTX *lc = OSSL_LIB_CTX_new();
		OSSL_PROVIDER *leg = OSSL_PROVIDER_load(lc, "legacy");
		EVP_MD	   *sha = EVP_MD_fetch(lc, "SHA256", NULL);
		EVP_MD	   *md5 = EVP_MD_fetch(lc, "MD5", NULL);

		printf("Q4a EVP_MD_fetch(legacy-only ctx,\"SHA256\")        : %s\n",
			   sha ? pn(EVP_MD_get0_provider(sha)) : "FETCH FAILED (SHA256 absent from legacy)");
		printf("Q4b EVP_MD_fetch(legacy-only ctx,\"MD5\")           : %s\n",
			   md5 ? pn(EVP_MD_get0_provider(md5)) : "FETCH FAILED");
		if (sha)
			EVP_MD_free(sha);
		if (md5)
			EVP_MD_free(md5);
		OSSL_PROVIDER_unload(leg);
		OSSL_LIB_CTX_free(lc);
	}

	/* ---------------- HMAC ---------------- */

	/* Q5: PG today uses HMAC_CTX/HMAC_Init_ex -- the low-level legacy HMAC,
	 *     deprecated since 3.0.  It has no provider introspection at all. */
	printf("Q5  legacy HMAC_CTX/HMAC_Init_ex                  : legacy low-level API (deprecated 3.0; not provider-dispatched)\n");

	/* Q6: the patch uses EVP_MAC_fetch("HMAC") -- provider-backed. */
	{
		EVP_MAC    *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);

		printf("Q6  EVP_MAC_fetch(NULL,\"HMAC\",NULL)               : %s\n",
			   pn(EVP_MAC_get0_provider(mac)));
		EVP_MAC_free(mac);
	}

	return 0;
}
