From 8068d66db7914d304355705e95156ae5b4896dfb Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 6 Nov 2020 16:15:42 +0900
Subject: [PATCH 3/3] Add new implementation

---
 src/common/Makefile         |   8 +-
 src/common/md5_openssl.c    | 157 ++++++++++++++++++++++++++++++++++++
 src/tools/msvc/Mkvcbuild.pm |   4 +-
 3 files changed, 165 insertions(+), 4 deletions(-)
 create mode 100644 src/common/md5_openssl.c

diff --git a/src/common/Makefile b/src/common/Makefile
index 69de65fab5..4571a8ac23 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -63,7 +63,6 @@ OBJS_COMMON = \
 	keywords.o \
 	kwlookup.o \
 	link-canary.o \
-	md5.o \
 	md5_common.o \
 	pg_get_line.o \
 	pg_lzcompress.o \
@@ -83,9 +82,12 @@ OBJS_COMMON = \
 ifeq ($(with_openssl),yes)
 OBJS_COMMON += \
 	protocol_openssl.o \
-	sha2_openssl.o
+	sha2_openssl.o \
+	md5_openssl.o
 else
-OBJS_COMMON += sha2.o
+OBJS_COMMON += \
+	md5.o \
+	sha2.o
 endif
 
 # A few files are currently only built for frontend, not server
diff --git a/src/common/md5_openssl.c b/src/common/md5_openssl.c
new file mode 100644
index 0000000000..56bef35ee8
--- /dev/null
+++ b/src/common/md5_openssl.c
@@ -0,0 +1,157 @@
+/*-------------------------------------------------------------------------
+ *
+ * md5_openssl.c
+ *	  Set of wrapper routines on top of OpenSSL to support MD5.
+ *
+ * This should only be used if code is compiled with OpenSSL support.
+ *
+ * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		  src/common/md52_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <openssl/evp.h>
+
+#include "common/md5.h"
+#ifndef FRONTEND
+#include "utils/memutils.h"
+#include "utils/resowner.h"
+#include "utils/resowner_private.h"
+#endif
+
+/*
+ * In backend, use palloc/pfree to ease the error handling.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
+ */
+#ifndef FRONTEND
+#define ALLOC(size) palloc(size)
+#define FREE(ptr) pfree(ptr)
+#else
+#define ALLOC(size) malloc(size)
+#define FREE(ptr) free(ptr)
+#endif
+
+/*
+ * pg_md5_create
+ *
+ * Allocate a MD5 context.  Returns NULL on failure.
+ */
+void *
+pg_md5_create(void)
+{
+	void	   *ctx;
+
+#ifndef FRONTEND
+	ResourceOwnerEnlargeEVP(CurrentResourceOwner);
+#endif
+
+	ctx = EVP_MD_CTX_create();
+
+	if (ctx == NULL)
+	{
+#ifndef FRONTEND
+		elog(ERROR, "out of memory");
+#else
+		return NULL;
+#endif
+	}
+
+#ifndef FRONTEND
+	ResourceOwnerRememberEVP(CurrentResourceOwner,
+							 PointerGetDatum(ctx));
+#endif
+
+	return ctx;
+}
+
+/*
+ * pg_md5_init
+ *
+ * Initialize a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_init(void *ctx)
+{
+	int			status = 0;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestInit_ex((EVP_MD_CTX *) ctx,
+							   EVP_md5(), NULL);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_update
+ *
+ * Update a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_update(void *ctx, const uint8 *data, size_t len)
+{
+	int			status;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestUpdate((EVP_MD_CTX *) ctx, data, len);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_final
+ *
+ * Finalize a MD5 context.  Returns 0 on success, and -1 on failure.
+ */
+int
+pg_md5_final(void *ctx, uint8 *dest)
+{
+	int			status;
+
+	if (ctx == NULL)
+		return 0;
+
+	status = EVP_DigestFinal_ex((EVP_MD_CTX *) ctx, dest, 0);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_md5_free
+ *
+ * Free a MD5 context.
+ */
+void
+pg_md5_free(void *ctx)
+{
+	if (ctx == NULL)
+		return;
+
+	EVP_MD_CTX_destroy((EVP_MD_CTX *) ctx);
+
+#ifndef FRONTEND
+	ResourceOwnerForgetEVP(CurrentResourceOwner,
+						   PointerGetDatum(ctx));
+#endif
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 150e1493ef..3401557492 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -122,18 +122,20 @@ sub mkvcbuild
 	  archive.c base64.c checksum_helper.c
 	  config_info.c controldata_utils.c d2s.c encnames.c exec.c
 	  f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
-	  keywords.c kwlookup.c link-canary.c md5.c md5_common.c
+	  keywords.c kwlookup.c link-canary.c md5_common.c
 	  pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
 	  saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
 	  wait_error.c wchar.c);
 
 	if ($solution->{options}->{openssl})
 	{
+		push(@pgcommonallfiles, 'md5_openssl.c');
 		push(@pgcommonallfiles, 'sha2_openssl.c');
 		push(@pgcommonallfiles, 'protocol_openssl.c');
 	}
 	else
 	{
+		push(@pgcommonallfiles, 'md5.c');
 		push(@pgcommonallfiles, 'sha2.c');
 	}
 
-- 
2.29.1

