diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index a4840227ad1c0fb0cfd28d329f87de5c8c4919b3..8fc60eba420b5ff3459f3a72ec25f19a88f0f040 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.26 2005/10/15 02:49:06 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.27 2006/02/18 20:48:51 neilc Exp $
  */
 
 #include "postgres.h"
@@ -47,17 +47,24 @@
 #define MAX_IV		(128/8)
 
 /*
- * Does OpenSSL support AES?
+ * Compatibility with OpenSSL 0.9.6
+ *
+ * It needs AES and newer DES and digest API.
  */
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
 
-/* Yes, it does. */
+/*
+ * Nothing needed for OpenSSL 0.9.7+
+ */
+
 #include <openssl/aes.h>
+
 #else							/* old OPENSSL */
 
 /*
- * No, it does not.  So use included rijndael code to emulate it.
+ * Emulate OpenSSL AES.
  */
+
 #include "rijndael.c"
 
 #define AES_ENCRYPT 1
@@ -90,12 +97,11 @@
 			memcpy(iv, (src) + (len) - 16, 16); \
 		} \
 	} while (0)
-#endif   /* old OPENSSL */
 
 /*
- * Compatibility with older OpenSSL API for DES.
+ * Emulate DES_* API
  */
-#if OPENSSL_VERSION_NUMBER < 0x00907000L
+
 #define DES_key_schedule des_key_schedule
 #define DES_cblock des_cblock
 #define DES_set_key(k, ks) \
@@ -110,63 +116,91 @@
 #define DES_ede3_cbc_encrypt(i, o, l, k1, k2, k3, iv, e) \
 		des_ede3_cbc_encrypt((i), (o), \
 				(l), *(k1), *(k2), *(k3), (iv), (e))
-#endif
+
+/*
+ * Emulate newer digest API.
+ */
+
+static void EVP_MD_CTX_init(EVP_MD_CTX *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+static int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	return 1;
+}
+
+static int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
+{
+	EVP_DigestInit(ctx, md);
+	return 1;
+}
+
+static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len)
+{
+	EVP_DigestFinal(ctx, res, len);
+	return 1;
+}
+
+#endif   /* old OpenSSL */
 
 /*
  * Hashes
  */
+
+typedef struct OSSLDigest {
+	const EVP_MD *algo;
+	EVP_MD_CTX ctx;
+} OSSLDigest;
+
 static unsigned
 digest_result_size(PX_MD * h)
 {
-	return EVP_MD_CTX_size((EVP_MD_CTX *) h->p.ptr);
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
+	return EVP_MD_CTX_size(&digest->ctx);
 }
 
 static unsigned
 digest_block_size(PX_MD * h)
 {
-	return EVP_MD_CTX_block_size((EVP_MD_CTX *) h->p.ptr);
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
+	return EVP_MD_CTX_block_size(&digest->ctx);
 }
 
 static void
 digest_reset(PX_MD * h)
 {
-	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
-	const EVP_MD *md;
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
 
-	md = EVP_MD_CTX_md(ctx);
-
-	EVP_DigestInit(ctx, md);
+	EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL);
 }
 
 static void
 digest_update(PX_MD * h, const uint8 *data, unsigned dlen)
 {
-	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
 
-	EVP_DigestUpdate(ctx, data, dlen);
+	EVP_DigestUpdate(&digest->ctx, data, dlen);
 }
 
 static void
 digest_finish(PX_MD * h, uint8 *dst)
 {
-	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
-	const EVP_MD *md = EVP_MD_CTX_md(ctx);
-
-	EVP_DigestFinal(ctx, dst, NULL);
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
 
-	/*
-	 * Some builds of 0.9.7x clear all of ctx in EVP_DigestFinal. Fix it by
-	 * reinitializing ctx.
-	 */
-	EVP_DigestInit(ctx, md);
+	EVP_DigestFinal_ex(&digest->ctx, dst, NULL);
 }
 
 static void
 digest_free(PX_MD * h)
 {
-	EVP_MD_CTX *ctx = (EVP_MD_CTX *) h->p.ptr;
+	OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
+
+	EVP_MD_CTX_cleanup(&digest->ctx);
 
-	px_free(ctx);
+	px_free(digest);
 	px_free(h);
 }
 
@@ -178,8 +212,8 @@ int
 px_find_digest(const char *name, PX_MD ** res)
 {
 	const EVP_MD *md;
-	EVP_MD_CTX *ctx;
 	PX_MD	   *h;
+	OSSLDigest *digest;
 
 	if (!px_openssl_initialized)
 	{
@@ -191,8 +225,12 @@ px_find_digest(const char *name, PX_MD ** res)
 	if (md == NULL)
 		return PXE_NO_HASH;
 
-	ctx = px_alloc(sizeof(*ctx));
-	EVP_DigestInit(ctx, md);
+	digest = px_alloc(sizeof(*digest));
+	digest->algo = md;
+
+	EVP_MD_CTX_init(&digest->ctx);
+	if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0)
+		return -1;
 
 	h = px_alloc(sizeof(*h));
 	h->result_size = digest_result_size;
@@ -201,7 +239,7 @@ px_find_digest(const char *name, PX_MD ** res)
 	h->update = digest_update;
 	h->finish = digest_finish;
 	h->free = digest_free;
-	h->p.ptr = (void *) ctx;
+	h->p.ptr = (void *) digest;
 
 	*res = h;
 	return 0;