Index: typemap
===================================================================
--- typemap	(revision 293)
+++ typemap	(working copy)
@@ -16,6 +16,8 @@
 EVP_PKEY *      T_PTR
 const EVP_MD *  T_PTR
 EVP_MD *        T_PTR
+EVP_MD_CTX *    T_PTR
+const EVP_MD_CTX *      T_PTR
 CERT *          T_PTR
 LHASH *         T_PTR
 struct lhash_st_SSL_SESSION *	T_PTR
Index: SSLeay.xs
===================================================================
--- SSLeay.xs	(revision 293)
+++ SSLeay.xs	(working copy)
@@ -273,6 +273,22 @@
 
 typedef int perl_filehandle_t;
 
+/* ======= special handler used by EVP_MD_do_all_sorted ======= */
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+static void handler_list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
+{  
+  /* taken from apps/dgst.c */
+  const char *mname;  
+  if (!m) return;                                           /* Skip aliases */
+  mname = OBJ_nid2ln(EVP_MD_type(m));
+  if (strcmp(from, mname)) return;                          /* Skip shortnames */       
+  if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST) return;    /* Skip clones */
+  if (strchr(mname, ' ')) mname= EVP_MD_name(m);
+  av_push(arg, newSVpv(mname,0));
+}
+#endif
+
 /* ============= callback stuff ============== */
 
 static int
@@ -2224,12 +2240,10 @@
 	PREINIT:
 	STRLEN len;
 	unsigned char md[MD4_DIGEST_LENGTH];
-	unsigned char * ret;
 	INPUT:
 	unsigned char* data = (unsigned char *) SvPV( ST(0), len );
 	CODE:
-	ret = MD4(data,len,md);
-	if (ret!=NULL) {
+	if (MD4(data,len,md)) {
 		XSRETURN_PVN((char *) md, MD4_DIGEST_LENGTH);
 	} else {
 		XSRETURN_UNDEF;
@@ -2240,12 +2254,10 @@
      PREINIT:
      STRLEN len;
      unsigned char md[MD5_DIGEST_LENGTH];
-     unsigned char * ret;
      INPUT:
      unsigned char *  data = (unsigned char *) SvPV( ST(0), len);
      CODE:
-     ret = MD5(data,len,md);
-     if (ret!=NULL) {
+     if (MD5(data,len,md)) {
 	  XSRETURN_PVN((char *) md, MD5_DIGEST_LENGTH);
      } else {
 	  XSRETURN_UNDEF;
@@ -2258,12 +2270,10 @@
      PREINIT:
      STRLEN len;
      unsigned char md[RIPEMD160_DIGEST_LENGTH];
-     unsigned char * ret;
      INPUT:
      unsigned char *  data = (unsigned char *) SvPV( ST(0), len);
      CODE:
-     ret = RIPEMD160(data,len,md);
-     if (ret!=NULL) {
+     if (RIPEMD160(data,len,md)) {
 	  XSRETURN_PVN((char *) md, RIPEMD160_DIGEST_LENGTH);
      } else {
 	  XSRETURN_UNDEF;
@@ -2271,6 +2281,58 @@
 
 #endif
 
+#if !defined(OPENSSL_NO_SHA)
+
+void 
+SHA1(data)
+     PREINIT:
+     STRLEN len;
+     unsigned char md[SHA_DIGEST_LENGTH];
+     INPUT:
+     unsigned char *  data = (unsigned char *) SvPV( ST(0), len);
+     CODE:
+     if (SHA1(data,len,md)) {
+	  XSRETURN_PVN((char *) md, SHA_DIGEST_LENGTH);
+     } else {
+	  XSRETURN_UNDEF;
+     }
+
+#endif
+#if !defined(OPENSSL_NO_SHA256) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
+
+void 
+SHA256(data)
+     PREINIT:
+     STRLEN len;
+     unsigned char md[SHA256_DIGEST_LENGTH];
+     INPUT:
+     unsigned char *  data = (unsigned char *) SvPV( ST(0), len);
+     CODE:
+     if (SHA256(data,len,md)) {
+	  XSRETURN_PVN((char *) md, SHA256_DIGEST_LENGTH);
+     } else {
+	  XSRETURN_UNDEF;
+     }
+
+#endif
+#if !defined(OPENSSL_NO_SHA512) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
+
+void 
+SHA512(data)
+     PREINIT:
+     STRLEN len;
+     unsigned char md[SHA512_DIGEST_LENGTH];
+     INPUT:
+     unsigned char *  data = (unsigned char *) SvPV( ST(0), len);
+     CODE:
+     if (SHA512(data,len,md)) {
+	  XSRETURN_PVN((char *) md, SHA512_DIGEST_LENGTH);
+     } else {
+	  XSRETURN_UNDEF;
+     }
+
+#endif
+
 #ifndef OPENSSL_NO_SSL2 
 #if OPENSSL_VERSION_NUMBER < 0x10000000L
 
@@ -3262,16 +3324,109 @@
 
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_SHA
 
-#ifndef OPENSSL_NO_SHA256
+const EVP_MD *EVP_sha1()
 
+#endif
+#if !defined(OPENSSL_NO_SHA256) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
+
 const EVP_MD *EVP_sha256()
 
 #endif
+#if !defined(OPENSSL_NO_SHA512) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
 
+const EVP_MD *EVP_sha512()
+
 #endif
+void OpenSSL_add_all_digests()
 
+const EVP_MD * EVP_get_digestbyname(const char *name)
+
+int EVP_MD_type(const EVP_MD *md)
+
+int EVP_MD_size(const EVP_MD *md)
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+
+SV*
+P_EVP_MD_list_all()
+    INIT:        
+        AV * results;
+    CODE:
+        results = (AV *)sv_2mortal((SV *)newAV());
+        EVP_MD_do_all_sorted(handler_list_md_fn, results);
+        RETVAL = newRV((SV *)results);
+    OUTPUT:
+        RETVAL
+
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
+#define REM16 "NOTE: requires 0.9.7+"
+
+const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx)
+
+EVP_MD_CTX *EVP_MD_CTX_create()
+
+int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
+
+int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
+
+void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
+
+void
+EVP_DigestUpdate(ctx,data)
+     PREINIT:
+     STRLEN len;
+     INPUT:
+     EVP_MD_CTX *ctx = INT2PTR(EVP_MD_CTX *, SvIV(ST(0)));
+     unsigned char *data = (unsigned char *) SvPV(ST(1), len);
+     CODE:
+     XSRETURN_IV(EVP_DigestUpdate(ctx,data,len));
+     
+void
+EVP_DigestFinal(ctx)
+     EVP_MD_CTX *ctx
+     INIT:
+     unsigned char md[EVP_MAX_MD_SIZE];
+     unsigned int md_size;
+     CODE:
+     if (EVP_DigestFinal(ctx,md,&md_size))
+         XSRETURN_PVN((char *)md, md_size);
+     else
+         XSRETURN_UNDEF;
+
+void
+EVP_DigestFinal_ex(ctx)
+     EVP_MD_CTX *ctx
+     INIT:
+     unsigned char md[EVP_MAX_MD_SIZE];
+     unsigned int md_size;
+     CODE:
+     if (EVP_DigestFinal_ex(ctx,md,&md_size))
+         XSRETURN_PVN((char *)md, md_size);
+     else
+         XSRETURN_UNDEF;
+
+void
+EVP_Digest(...)
+     PREINIT:
+     STRLEN len;
+     unsigned char md[EVP_MAX_MD_SIZE];
+     unsigned int md_size;
+     INPUT:
+     unsigned char *data = (unsigned char *) SvPV(ST(0), len);
+     EVP_MD *type = INT2PTR(EVP_MD *, SvIV(ST(1)));
+     ENGINE *impl = (items>2 && SvOK(ST(2))) ? INT2PTR(ENGINE *, SvIV(ST(2))) : NULL;
+     CODE:
+     if (EVP_Digest(data,len,md,&md_size,type,impl))
+         XSRETURN_PVN((char *)md, md_size);
+     else
+         XSRETURN_UNDEF;
+
+#endif
+
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
 
 int
Index: t/local/50_digest.t
===================================================================
--- t/local/50_digest.t	(revision 293)
+++ t/local/50_digest.t	(working copy)
@@ -2,70 +2,293 @@
 
 use strict;
 use warnings;
-use Test::More;
-use Net::SSLeay;
+use Test::More tests => 230;
+use File::Spec;
+use Net::SSleay;
 
-my $have_md2 = exists &Net::SSLeay::MD2;
-my $have_ripemd160 = exists &Net::SSLeay::RIPEMD160;
+sub digest_chunked_f1 {
+  my ($file, $digest) = @_;
+  
+  my $md = Net::SSLeay::EVP_get_digestbyname($digest) or BAIL_OUT "digest '$digest' not available";
+  my $ctx = Net::SSLeay::EVP_MD_CTX_create();
+  Net::SSLeay::EVP_DigestInit($ctx, $md);
 
+  open my $fh, "<", $file or BAIL_OUT "cannot open file '$file'";
+  binmode $fh;
+  while(my $len = sysread($fh, my $chunk, 500)) {
+    Net::SSLeay::EVP_DigestUpdate($ctx,$chunk);
+  }
+  close $fh;
+
+  my $result = Net::SSLeay::EVP_DigestFinal($ctx);
+  Net::SSLeay::EVP_MD_CTX_destroy($ctx);
+  
+  return $result;
+}
+
+sub digest_chunked_f2 {
+  my ($file, $digest) = @_;
+  
+  my $md = Net::SSLeay::EVP_get_digestbyname($digest) or BAIL_OUT "digest '$digest' not available";
+  my $ctx = Net::SSLeay::EVP_MD_CTX_create();
+  Net::SSLeay::EVP_DigestInit_ex($ctx, $md, 0); #NULL ENGINE just to test whether the function exists
+
+  open my $fh, "<", $file or BAIL_OUT "cannot open file '$file'";
+  binmode $fh;
+  while(my $len = sysread($fh, my $chunk, 5)) {
+    Net::SSLeay::EVP_DigestUpdate($ctx,$chunk);
+  }
+  close $fh;
+
+  my $result = Net::SSLeay::EVP_DigestFinal_ex($ctx);
+  Net::SSLeay::EVP_MD_CTX_destroy($ctx);
+  
+  return $result;
+}
+
+sub digest_file {
+  my ($file, $expected_results, $available_digests) = @_;
+
+  for my $d (sort keys %$expected_results) {
+    SKIP: {
+      skip "digest '$d' not available (or pre-1.0.0)", 2 unless $available_digests->{$d};
+      is( unpack("H*", digest_chunked_f1($file, $d)), $expected_results->{$d}, "$d chunked.1 [$file]");
+      is( unpack("H*", digest_chunked_f2($file, $d)), $expected_results->{$d}, "$d chunked.2 [$file]");
+    }
+  }
+
+  open my $f, "<", $file or BAIL_OUT "cannot open file '$file'";
+  binmode $f;
+  sysread($f, my $data, -s $file) or BAIL_OUT "sysread failed";  
+  close $f;
+  
+  is(length($data), -s $file, 'got the whole file');
+
+  SKIP: {
+    skip "Net::SSLeay::MD2 not available", 1 unless exists &Net::SSLeay::MD2;
+    is( unpack("H*", Net::SSLeay::MD2($data)), $expected_results->{md2}, "MD2 all-in-one-go [$file]");
+  }
+  SKIP: {
+    skip "Net::SSLeay::MD4 not available", 1 unless exists &Net::SSLeay::MD4;
+    is( unpack("H*", Net::SSLeay::MD4($data)), $expected_results->{md4}, "MD4 all-in-one-go [$file]");
+  }
+  SKIP: {
+    skip "Net::SSLeay::MD5 not available", 1 unless exists &Net::SSLeay::MD5;
+    is( unpack("H*", Net::SSLeay::MD5($data)), $expected_results->{md5}, "MD5 all-in-one-go [$file]");
+  }
+  SKIP: {
+    skip "Net::SSLeay::RIPEMD160 not available", 1 unless exists &Net::SSLeay::RIPEMD160;
+    is( unpack("H*", Net::SSLeay::RIPEMD160($data)), $expected_results->{ripemd160}, "RIPEMD160 all-in-one-go [$file]");
+  }  
+}
+
+sub digest_strings {
+  my ($fps, $available_digests) = @_;
+  
+  for my $data (sort keys %$fps) {
+  
+    for my $d (sort keys %{$fps->{$data}}) {
+      SKIP: {
+        skip "digest '$d' not available (or pre-1.0.0)", 2 unless $available_digests->{$d};
+        my $md = Net::SSLeay::EVP_get_digestbyname($d) or BAIL_OUT "digest '$d' not available";
+        my $ctx = Net::SSLeay::EVP_MD_CTX_create();
+        Net::SSLeay::EVP_DigestInit($ctx, $md);
+        Net::SSLeay::EVP_DigestUpdate($ctx, $data);
+        my $result1 = Net::SSLeay::EVP_DigestFinal($ctx);
+        Net::SSLeay::EVP_MD_CTX_destroy($ctx);
+        is(unpack('H*', $result1), $fps->{$data}->{$d}, "$d for '$data'");        
+        # test EVP_Digest
+        my $result2 = Net::SSLeay::EVP_Digest($data, Net::SSLeay::EVP_get_digestbyname($d));
+        is(unpack('H*', $result2), $fps->{$data}->{$d}, "EVP_Digest($d)");
+      }
+    }
+  
+      
+  
+    SKIP: {
+      skip "Net::SSLeay::MD2 not available", 1 unless exists &Net::SSLeay::MD2;
+      is(unpack('H*', Net::SSLeay::MD2($data)), $fps->{$data}->{md2}, "MD2 hash for '$data'");
+    }
+    SKIP: {
+      skip "Net::SSLeay::MD4 not available", 1 unless exists &Net::SSLeay::MD4;
+      is(unpack('H*', Net::SSLeay::MD4($data)), $fps->{$data}->{md4}, "MD4 hash for '$data'");
+    }
+    SKIP: {
+      skip "Net::SSLeay::MD5 not available", 1 unless exists &Net::SSLeay::MD5;
+      is(unpack('H*', Net::SSLeay::MD5($data)), $fps->{$data}->{md5}, "MD5 hash for '$data'");
+    }
+    SKIP: {
+      skip "Net::SSLeay::RIPEMD160 not available", 1 unless exists &Net::SSLeay::RIPEMD160;
+      is(unpack('H*', Net::SSLeay::RIPEMD160($data)), $fps->{$data}->{ripemd160}, "RIPEMD160 hash for '$data'");
+    }
+
+    SKIP: {
+      skip "Net::SSLeay::SHA1 not available", 1 unless exists &Net::SSLeay::SHA1;
+      is(unpack('H*', Net::SSLeay::SHA1($data)), $fps->{$data}->{sha1}, "SHA1 hash for '$data'");
+    }
+    SKIP: {
+      skip "Net::SSLeay::SHA256 not available", 1 unless exists &Net::SSLeay::SHA256;
+      is(unpack('H*', Net::SSLeay::SHA256($data)), $fps->{$data}->{sha256}, "SHA256 hash for '$data'");
+    }
+    SKIP: {
+      skip "Net::SSLeay::SHA512 not available", 1 unless exists &Net::SSLeay::SHA512;
+      is(unpack('H*', Net::SSLeay::SHA512($data)), $fps->{$data}->{sha512}, "SHA512 hash for '$data'");
+    }
+  }
+}
+
+my %all_digests;
+
+eval {
+  Net::SSLeay::initialize();
+  Net::SSLeay::OpenSSL_add_all_digests();
+  if (Net::SSLeay::SSLeay >= 0x1000000f) {
+    %all_digests = map { $_=>1 } @{Net::SSLeay::P_EVP_MD_list_all()};
+  }
+  else {
+    %all_digests = ();
+  }
+};
+
+is($@, '', 'digest init OK');
+SKIP: {
+  skip "pre-1.0.0", 1 unless Net::SSLeay::SSLeay >= 0x1000000f;
+  isnt(scalar(keys %all_digests), 0, 'non-empty digest list');
+}
+
+my $file1 = File::Spec->catfile('t', 'data', 'cert.pem'); 
+my $results1 = {
+        md2       => '6d89cda9599a54d03652f9464e8b6e51',
+        md4       => 'ada352f40f1ca64f4168a8aae7c1a281',
+        md5       => 'e060f11c6afa9e1f59a8e7c873aa3423',
+        mdc2      => 'e9ca1fd1cfccfb450b402a0dd446db28',
+        ripemd160 => 'cbd50056558b01b5e9ec67901b518462b5393e5b',
+        sha       => '79de0d0cc736d98b65f5d6b3ac89e65ca8d3b2a7',
+        sha1      => '0267dd25bbd8930c537716d972dd9ba128846428',
+        sha224    => '5b42d5a3b16a6cee821b03c41f0428b09b70695becb0aaafbc7d6419',
+        sha256    => '764633a51af4ef374cabb1ea859cc324680cfeff694797e90562e19ffb71ab26',
+        sha512    => '37e3a2e84aec822922c51d4d8d37bf003e1d85f55a4bf2fae2940a5aab5b32f7601c2a9cde5b9c6391aaa4ffef1e845f11d2f0b6a37a9b2f48fb7f6469f0a51c',
+        whirlpool => 'b2dc90dbbc60e5e2dc28de3bdeab45fb2fa6d13d86ff14908130624a242e38ecc195b3b11a7ef137b77a24e9a0ba5be061ac1baa11892369286d613569199458',
+};
+
+my $file2 = File::Spec->catfile('t', 'data', 'binary-test.file'); 
+my $results2 = {
+        md2       => '67ae6d821be6898101414c56b1fb4f46',
+        md4       => '480438696e7d9a6ab3ecc1e2a3419f78',
+        md5       => 'cc89b43c171818c347639fa5170aee16',
+        mdc2      => 'ee605fe3fc966a7b17185ebdbcd13ada',
+        ripemd160 => 'cb70ba43fc6d263f6d7816170c1a33f28c2000fe',
+        sha       => 'c151c6f408cb94bc5c53b17852efbe8bfbeec2b9',
+        sha1      => '059404d1d0e952d0457a6c99b6e68b3b44c8ef13',
+        sha224    => '161c65efa1b9762f7e0448b5b369a3e2c236876b0b57a35add5106bb',
+        sha256    => 'e416730ddaa34729adb32ec6ddad4e50fca1fe97de313e800196b1f8cd5032bd',
+        sha512    => '8b5e7181fc76d49e1cb7971a6980b5d8db6b23c3b0553cf42f559156fd08e64567d17c4147c864efd4d3a5e22fb6602d613a055f7f14faad22744dbc3df89d59',
+        whirlpool => '31079767aa2dd9b8ab01caadd954a88aaaf6001941c38d17ba43c0ef80a074c3eedf35b73c3941929dea281805c6c5ffc0a619abef4c6a3365d6cb31412d0e0c',
+};
+
 my %fps = (
         '' => {
             md2 => '8350e5a3e24c153df2275c9f80692773',
             md4 => '31d6cfe0d16ae931b73c59d7e0c089c0',
             md5 => 'd41d8cd98f00b204e9800998ecf8427e',
 	    ripemd160 => '9c1185a5c5e9fc54612808977ee8f548b2258d31',
+            sha1      => 'da39a3ee5e6b4b0d3255bfef95601890afd80709',
+            sha256    => 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
+            sha512    => 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
         },
         'a' => {
             md2 => '32ec01ec4a6dac72c0ab96fb34c0b5d1',
             md4 => 'bde52cb31de33e46245e05fbdbd6fb24',
             md5 => '0cc175b9c0f1b6a831c399e269772661',
 	    ripemd160 => '0bdc9d2d256b3ee9daae347be6f4dc835a467ffe',
+            sha1=>'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8',
+            sha256=>'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb',
+            sha512=>'1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75',
         },
         '38' => {
             md2 => '4b85c826321a5ce87db408c908d0709e',
             md4 => 'ae9c7ebfb68ea795483d270f5934b71d',
             md5 => 'a5771bce93e200c36f7cd9dfd0e5deaa',
-	    ripemd160 => '6b2d075b1cd34cd1c3e43a995f110c55649dad0e', # guessed at this, since it wasn't present in the tables at http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+	    ripemd160 => '6b2d075b1cd34cd1c3e43a995f110c55649dad0e',
+            sha1=>'5b384ce32d8cdef02bc3a139d4cac0a22bb029e8',
+            sha256=>'aea92132c4cbeb263e6ac2bf6c183b5d81737f179f21efdc5863739672f0f470',
+            sha512=>'caae34a5e81031268bcdaf6f1d8c04d37b7f2c349afb705b575966f63e2ebf0fd910c3b05160ba087ab7af35d40b7c719c53cd8b947c96111f64105fd45cc1b2',
         },
         'abc' => {
             md2 => 'da853b0d3f88d99b30283a69e6ded6bb',
             md4 => 'a448017aaf21d8525fc10ae87aa6729d',
             md5 => '900150983cd24fb0d6963f7d28e17f72',
 	    ripemd160 => '8eb208f7e05d987a9b044a8e98c6b087f15a0bfc',
+            sha1=>'a9993e364706816aba3e25717850c26c9cd0d89d',
+            sha256=>'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad',
+            sha512=>'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f',
         },
         'message digest' => {
             md2 => 'ab4f496bfb2a530b219ff33031fe06b0',
             md4 => 'd9130a8164549fe818874806e1c7014b',
             md5 => 'f96b697d7cb7938d525a2f31aaf161d0',
 	    ripemd160 => '5d0689ef49d2fae572b881b123a85ffa21595f36',
+            sha1=>'c12252ceda8be8994d5fa0290a47231c1d16aae3',
+            sha256=>'f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650',
+            sha512=>'107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c',
         },
         'abcdefghijklmnopqrstuvwxyz' => {
             md2 => '4e8ddff3650292ab5a4108c3aa47940b',
             md4 => 'd79e1c308aa5bbcdeea8ed63df412da9',
             md5 => 'c3fcd3d76192e4007dfb496cca67e13b',
 	    ripemd160 => 'f71c27109c692c1b56bbdceb5b9d2865b3708dbc',
+            sha1=>'32d10c7b8cf96570ca04ce37f2a19d84240d3a89',
+            sha256=>'71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73',
+            sha512=>'4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1',
         },
         'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' => {
             md2 => 'da33def2a42df13975352846c30338cd',
             md4 => '043f8582f241db351ce627e153e7f0e4',
             md5 => 'd174ab98d277d9f5a5611c2c9f419d9f',
 	    ripemd160 => 'b0e20b6e3116640286ed3a87a5713079b21f5189',
+            sha1=>'761c457bf73b14d27e9e9265c46f4b4dda11f940',
+            sha256=>'db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0',
+            sha512=>'1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894',
         },
         '12345678901234567890123456789012345678901234567890123456789012345678901234567890' => {
             md2 => 'd5976f79d83d3a0dc9806c3c66f3efd8',
             md4 => 'e33b4ddc9c38f2199c3e7b164fcc0536',
             md5 => '57edf4a22be3c955ac49da2e2107b67a',
 	    ripemd160 => '9b752e45573d4b39f4dbd3323cab82bf63326bfb',
+            sha1=>'50abf5706a150990a08b2c5ea40fa0e585554732',
+            sha256=>'f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e',
+            sha512=>'72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843',
         },
 );
 
-plan tests => (keys %fps) * (2 + ($have_md2 ? 1 : 0) + ($have_ripemd160 ? 1 : 0));
+SKIP: {
+  skip "MD5 not available", 3 unless exists &Net::SSLeay::MD5;
+  is(Net::SSLeay::EVP_MD_type(Net::SSLeay::EVP_get_digestbyname("MD5")), 4, 'EVP_MD_type md5');
+  is(Net::SSLeay::EVP_MD_size(Net::SSLeay::EVP_get_digestbyname("MD5")), 16, 'EVP_MD_size md5');
+  
+  SKIP: {
+    skip "pre-0.9.7", 1 unless Net::SSLeay::SSLeay >= 0x0090700f;
+    my $md = Net::SSLeay::EVP_get_digestbyname("md5");
+    my $ctx = Net::SSLeay::EVP_MD_CTX_create();
+    Net::SSLeay::EVP_DigestInit($ctx, $md);
+    my $md2 = Net::SSLeay::EVP_MD_CTX_md($ctx);
+    is(Net::SSLeay::EVP_MD_size($md2), 16, 'EVP_MD_size via EVP_MD_CTX_md md5');
+  }
+}
 
-for my $data (sort keys %fps) {
-    is(unpack('H32', Net::SSLeay::MD2($data)), $fps{$data}->{md2}, "MD2 hash for '$data'")
-	if $have_md2;
-    is(unpack('H32', Net::SSLeay::MD4($data)), $fps{$data}->{md4}, "MD4 hash for '$data'");
-    is(unpack('H32', Net::SSLeay::MD5($data)), $fps{$data}->{md5}, "MD5 hash for '$data'");
-    is(unpack('H40', Net::SSLeay::RIPEMD160($data)), $fps{$data}->{ripemd160}, "RIPEMD160 hash for '$data'")
-	if $have_ripemd160;
+SKIP: {
+  skip "Net::SSLeay::EVP_sha512 not available", 1 unless exists &Net::SSLeay::EVP_sha512;
+  is(Net::SSLeay::EVP_MD_size(Net::SSLeay::EVP_sha512()), 64, 'EVP_MD_size sha512');
 }
+SKIP: {
+  skip "Net::SSLeay::EVP_sha256 not available", 1 unless exists &Net::SSLeay::EVP_sha256;
+  is(Net::SSLeay::EVP_MD_size(Net::SSLeay::EVP_sha256()), 32, 'EVP_MD_size sha256');
+}
+SKIP: {
+  skip "Net::SSLeay::EVP_sha1 not available", 1 unless exists &Net::SSLeay::EVP_sha1;
+  is(Net::SSLeay::EVP_MD_size(Net::SSLeay::EVP_sha1()), 20, 'EVP_MD_size sha1');
+}
+
+digest_file($file1, $results1, \%all_digests);
+digest_file($file2, $results2, \%all_digests);
+digest_strings(\%fps, \%all_digests);
Index: lib/Net/SSLeay.pm
===================================================================
--- lib/Net/SSLeay.pm	(revision 293)
+++ lib/Net/SSLeay.pm	(working copy)
@@ -1590,6 +1590,292 @@
     print Net::SSLeay::dump_peer_certificate($ssl);
     Net::SSLeay::randomize();
 
+=head2 Low level API: Digest related functions
+
+=over
+
+=item * OpenSSL_add_all_digests
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+ Net::SSLeay::OpenSSL_add_all_digests();
+ # no args, no return value
+
+http://www.openssl.org/docs/crypto/OpenSSL_add_all_algorithms.html
+
+=item * P_EVP_MD_list_all
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-1.0.0
+
+B<NOTE:> Does not exactly correspond to any low level API function
+
+ my $rv = Net::SSLeay::P_EVP_MD_list_all();
+ #
+ # returns: arrayref - list of available digest names
+
+The returned digest names correspond to values expected by L</EVP_get_digestbyname>.
+
+Note that some of the digets are available by default and some only after calling L</OpenSSL_add_all_digests>.
+
+=item * EVP_get_digestbyname
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+ my $rv = Net::SSLeay::EVP_get_digestbyname($name);
+ # $name - string with digest name
+ #
+ # returns: value of type coresponding to openssl's EVP_MD structure
+
+The $name param can be: 
+ 
+ md2
+ md4
+ md5
+ mdc2
+ ripemd160
+ sha
+ sha1
+ sha224
+ sha256
+ sha512
+ whirlpool
+
+Or better check the supported digests by calling L</P_EVP_MD_list_all>.
+
+=item * EVP_MD_type
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+ my $rv = Net::SSLeay::EVP_MD_type($md);
+ # $md - value of type coresponding to openssl's EVP_MD structure
+ #
+ # returns: the NID (integer) of the OBJECT IDENTIFIER representing the given message digest
+
+=item * EVP_MD_size
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+ my $rv = Net::SSLeay::EVP_MD_size($md);
+ # $md - value of type coresponding to openssl's EVP_MD structure
+ #
+ # returns: the size of the message digest in bytes (e.g. 20 for SHA1)
+
+=item * EVP_MD_CTX_md
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+ Net::SSLeay::EVP_MD_CTX_md($ctx);
+ # $ctx - value of type coresponding to openssl's EVP_MD_CTX structure
+ #
+ # returns: value of type coresponding to openssl's EVP_MD structure
+
+=item * EVP_MD_CTX_create
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Allocates, initializes and returns a digest context.
+
+ my $rv = Net::SSLeay::EVP_MD_CTX_create();
+ #
+ # returns: value of type coresponding to openssl's EVP_MD_CTX structure
+
+The complete idea behind EVP_MD_CTX looks like this example:
+
+  Net::SSLeay::OpenSSL_add_all_digests();
+  
+  my $md = Net::SSLeay::EVP_get_digestbyname("sha1");
+  my $ctx = Net::SSLeay::EVP_MD_CTX_create();
+  Net::SSLeay::EVP_DigestInit($ctx, $md);
+  
+  while(my $chunk = get_piece_of_data()) {
+    Net::SSLeay::EVP_DigestUpdate($ctx,$chunk);
+  }
+  
+  my $result = Net::SSLeay::EVP_DigestFinal($ctx);
+  Net::SSLeay::EVP_MD_CTX_destroy($ctx); 
+  
+  print "digest=", unpack('H*', $result), "\n"; #print hex value
+
+=item * EVP_DigestInit_ex
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Sets up digest context $ctx to use a digest $type from ENGINE $impl, $ctx must be
+initialized before calling this function, type will typically be supplied by a function
+such as L</EVP_get_digestbyname>. If $impl is 0 then the default implementation of digest $type is used. 
+
+ my $rv = Net::SSLeay::EVP_DigestInit_ex($ctx, $type, $impl);
+ # $ctx  - value of type coresponding to openssl's EVP_MD_CTX structure
+ # $type - value of type coresponding to openssl's EVP_MD structure
+ # $impl - value of type coresponding to openssl's ENGINE structure
+ #
+ # returns: 1 for success and 0 for failure
+
+=item * EVP_DigestInit
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Behaves in the same way as L</EVP_DigestInit_ex> except the passed context $ctx does not have
+to be initialized, and it always uses the default digest implementation. 
+
+ my $rv = Net::SSLeay::EVP_DigestInit($ctx, $type);
+ # $ctx - value of type coresponding to openssl's EVP_MD_CTX structure
+ # $type - value of type coresponding to openssl's EVP_MD structure
+ #
+ # returns: 1 for success and 0 for failure
+
+=item * EVP_MD_CTX_destroy
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Cleans up digest context $ctx and frees up the space allocated to it, it should be
+called only on a context created using L</EVP_MD_CTX_create>.
+
+ Net::SSLeay::EVP_MD_CTX_destroy($ctx);
+ # $ctx - value of type coresponding to openssl's EVP_MD_CTX structure
+ #
+ # returns: no return value
+
+=item * EVP_DigestUpdate
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+ my $rv = Net::SSLeay::EVP_DigestUpdate($ctx, $data);
+ # $ctx  - value of type coresponding to openssl's EVP_MD_CTX structure
+ # $data - data to be hashed
+ #
+ # returns: 1 for success and 0 for failure
+
+=item * EVP_DigestFinal_ex
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Retrieves the digest value from $ctx. After calling L</EVP_DigestFinal_ex> no
+additional calls to L</EVP_DigestUpdate> can be made, but 
+L</EVP_DigestInit_ex> can be called to initialize a new digest operation. 
+
+ my $digest_value = Net::SSLeay::EVP_DigestFinal_ex($ctx);
+ # $ctx - value of type coresponding to openssl's EVP_MD_CTX structure
+ #
+ # returns: hash value (binary)
+ 
+ #to get printable (hex) value of digest use:
+ print unpack('H*', $digest_value);
+
+=item * EVP_DigestFinal
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Similar to L</EVP_DigestFinal_ex> except the digest context ctx is automatically cleaned up.
+
+ my $rv = Net::SSLeay::EVP_DigestFinal($ctx);
+ # $ctx - value of type coresponding to openssl's EVP_MD_CTX structure
+ #
+ # returns: hash value (binary)
+
+ #to get printable (hex) value of digest use:
+ print unpack('H*', $digest_value);
+
+=item * MD2
+
+B<COMPATIBILITY:> no supported by default in openssl-1.0.0
+
+Computes MD2 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::MD2($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * MD4
+
+Computes MD4 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::MD4($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * MD5
+
+Computes MD5 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::MD5($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * RIPEMD160
+
+Computes RIPEMD160 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::RIPEMD160($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * SHA1
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+Computes SHA1 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::SHA1($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * SHA256
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.8
+
+Computes SHA256 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::SHA256($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * SHA512
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.8
+
+Computes SHA512 from given $data (all data needs to be loaded into memory)
+
+ my $digest = Net::SSLeay::SHA512($data);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * EVP_Digest
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.7
+
+Computes "any" digest from given $data (all data needs to be loaded into memory)
+
+ my $md = Net::SSLeay::EVP_get_digestbyname("sha1"); #or any other algorithm
+ my $digest = Net::SSLeay::EVP_Digest($data, $md);
+ print "digest(hexadecimal)=", unpack('H*', $digest);
+
+=item * EVP_sha1
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before
+
+ my $md = Net::SSLeay::EVP_sha1();
+ #
+ # returns: value of type coresponding to openssl's EVP_MD structure
+
+=item * EVP_sha256
+
+B<COMPATIBILITY:> requires at least openssl-0.9.8
+
+ my $md = Net::SSLeay::EVP_sha256();
+ #
+ # returns: value of type coresponding to openssl's EVP_MD structure
+
+=item * EVP_sha512
+
+B<COMPATIBILITY:> not available in Net-SSLeay-1.42 and before; requires at least openssl-0.9.8
+
+ my $md = Net::SSLeay::EVP_sha512();
+ #
+ # returns: value of type coresponding to openssl's EVP_MD structure
+
+=item * EVP_add_digest
+
+ my $rv = Net::SSLeay::EVP_add_digest($digest);
+ # $digest - value of type coresponding to openssl's EVP_MD structure
+ #
+ # returns: 1 on success, 0 otherwise
+
+=back
+
 =head2 Low level API: RSA_* related functions
 
 Some RSA functions are available:
Index: Changes
===================================================================
--- Changes	(revision 293)
+++ Changes	(working copy)
@@ -31,6 +31,25 @@
     - Net::SSLeay::P_ASN1_TIME_get_isotime
     - Net::SSLeay::P_ASN1_TIME_set_isotime
     - Net::SSLeay::P_ASN1_TIME_put2string
+    - Net::SSLeay::OpenSSL_add_all_digests
+    - Net::SSLeay::P_EVP_MD_list_all
+    - Net::SSLeay::EVP_get_digestbyname
+    - Net::SSLeay::EVP_MD_type
+    - Net::SSLeay::EVP_MD_size
+    - Net::SSLeay::EVP_MD_CTX_md
+    - Net::SSLeay::EVP_MD_CTX_create
+    - Net::SSLeay::EVP_MD_CTX_destroy
+    - Net::SSLeay::EVP_DigestInit
+    - Net::SSLeay::EVP_DigestInit_ex
+    - Net::SSLeay::EVP_DigestUpdate
+    - Net::SSLeay::EVP_DigestFinal
+    - Net::SSLeay::EVP_DigestFinal_ex
+    - Net::SSLeay::EVP_Digest
+    - Net::SSLeay::SHA1
+    - Net::SSLeay::SHA256
+    - Net::SSLeay::SHA512
+    - Net::SSLeay::EVP_sha1
+    - Net::SSLeay::EVP_sha512
     Fixed a problem with set_proxy where the password was not properly
     set. The code to do this went missing at some stage. Reported by Ulrich
     Weber via RT.
