Remove libcore's dependency on bouncycastle

external/bouncycastle
- Change to be the primary build for bouncycastle sources (as opposed to part of libcore)
- Moved OpenSSLMessageDigest from libcore to OpenSSLDigest
  It uses NativeCrypto API from core, but implements a bouncycastle specific interface
- restored registration of bouncycastle MessageDigests for SHA-1, SHA-256, MD5
  OpenSSLProvider versions take precedence, but explicit provider of "BC" allows choice
- enabled native versions of SHA-384 and SHA-512
- pruned MD4 implementation

frameworks/base
- frameworks and CoreTests modules now depend on bouncycastle
- update preloades classes for NativeBN package change
- moved CryptoTest to libcore

libcore
- core now builds without bouncycastle sources
- core-tests, core-tests-support, core-tests-supportlib now depend on bouncycastle
- removed libcore/openssl directory, moving NativeBN to java/math
- minor cleanup of Provider, Security, Services style while working on ProviderTest
- added new OpenSSLProvider registered as first provider to have
  priority over the others to ensure our native implementations are used
- moved BouncyCastle to have priority as a provider over Harmony
- JarVerifier and JarUtils now implicitly use OpenSSLMessageDigest
- Cleanedup OpenSSLSignature, implementation needs to be finished to move to OpenSSLProvider
- To avoid using PEMWriter from BouncyCastle, NativeCrypto now takes binary encoded certs and keys
  This is more efficient as well avoiding the base64 decode/encode of the binary data
- removed SHA-224 to match the RI

packages/apps/CertInstaller
- CertificateInstaller module now depends on bouncycastle
  this is the only app to depend on bouncycastle

system/core
- updated BOOTCLASSPATH

Change-Id: I6205366b12baec4331b4a76e2c85d8324bf64b2c
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 64f99d8..a731aee 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -50,7 +50,7 @@
 endef
 
 # The Java files and their associated resources.
-core_src_files := $(call all-main-java-files-under,dalvik dom json luni openssl support xml ../external/bouncycastle)
+core_src_files := $(call all-main-java-files-under,dalvik dom json luni support xml)
 core_resource_dirs := $(call all-core-resource-dirs,main)
 test_resource_dirs := $(call all-core-resource-dirs,test)
 
@@ -151,6 +151,7 @@
 # libraries.
 # TODO: we should have a bogus module that just contains tests.AllTests for speed.
 LOCAL_JAVA_LIBRARIES := \
+        bouncycastle \
         core \
         core-junit \
         core-junitrunner \
@@ -172,7 +173,7 @@
 LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
 LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core core-junit core-junitrunner
+LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit core-junitrunner
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := core-tests-support
@@ -193,7 +194,7 @@
 LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
 LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core core-junit core-junitrunner
+LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit core-junitrunner
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := core-tests-supportlib
diff --git a/luni/src/main/java/java/math/BigInt.java b/luni/src/main/java/java/math/BigInt.java
index 70448ee..9f828d0 100644
--- a/luni/src/main/java/java/math/BigInt.java
+++ b/luni/src/main/java/java/math/BigInt.java
@@ -17,7 +17,6 @@
 package java.math;
 
 import java.util.Random;
-import org.openssl.NativeBN;
 
 /*
  * In contrast to BigIntegers this class doesn't fake two's complement representation.
diff --git a/openssl/src/main/java/org/openssl/NativeBN.java b/luni/src/main/java/java/math/NativeBN.java
similarity index 98%
rename from openssl/src/main/java/org/openssl/NativeBN.java
rename to luni/src/main/java/java/math/NativeBN.java
index 7653cba..1fc228b 100644
--- a/openssl/src/main/java/org/openssl/NativeBN.java
+++ b/luni/src/main/java/java/math/NativeBN.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package org.openssl;
+package java.math;
 
-public class NativeBN {
+final class NativeBN {
 
     public static native int ERR_get_error();
     // unsigned long ERR_get_error(void);
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
index 81137ad..d1d9c4d 100644
--- a/luni/src/main/java/java/security/Provider.java
+++ b/luni/src/main/java/java/security/Provider.java
@@ -549,8 +549,7 @@
         if (sm != null) {
             sm.checkSecurityAccess("putProviderProperty." + name);
         }
-        if ("Provider".equals(s.getType())) { // Provider service type cannot be
-                                              // added
+        if ("Provider".equals(s.getType())) { // Provider service type cannot be added
             return;
         }
         servicesChanged();
@@ -562,8 +561,8 @@
             if (aliasTable == null) {
                 aliasTable = new TwoKeyHashMap<String, String, Service>(256);
             }
-            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
-                aliasTable.put(s.type, Util.toUpperCase(it.next()), s);
+            for (String alias : s.getAliases()) {
+                aliasTable.put(s.type, Util.toUpperCase(alias), s);
             }
         }
         serviceInfoToProperties(s);
@@ -599,14 +598,16 @@
             serviceTable.remove(s.type, Util.toUpperCase(s.algorithm));
         }
         if (aliasTable != null && s.aliases != null) {
-            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
-                aliasTable.remove(s.type, Util.toUpperCase(it.next()));
+            for (String alias: s.getAliases()) {
+                aliasTable.remove(s.type, Util.toUpperCase(alias));
             }
         }
         serviceInfoFromProperties(s);
     }
 
-    // Add Service information to the provider's properties.
+    /**
+     * Add Service information to the provider's properties.
+     */
     private void serviceInfoToProperties(Provider.Service s) {
         super.put(s.type + "." + s.algorithm, s.className);
         if (s.aliases != null) {
@@ -615,8 +616,7 @@
             }
         }
         if (s.attributes != null) {
-            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
-                Map.Entry<String, String> entry = i.next();
+            for (Map.Entry<String, String> entry : s.attributes.entrySet()) {
                 super.put(s.type + "." + s.algorithm + " " + entry.getKey(),
                         entry.getValue());
             }
@@ -627,7 +627,9 @@
         }
     }
 
-    // Remove Service information from the provider's properties.
+    /**
+     * Remove Service information from the provider's properties.
+     */
     private void serviceInfoFromProperties(Provider.Service s) {
         super.remove(s.type + "." + s.algorithm);
         if (s.aliases != null) {
@@ -636,8 +638,7 @@
             }
         }
         if (s.attributes != null) {
-            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
-                Map.Entry<String, String> entry = i.next();
+            for (Map.Entry<String, String> entry : s.attributes.entrySet()) {
                 super.remove(s.type + "." + s.algorithm + " " + entry.getKey());
             }
         }
@@ -692,7 +693,8 @@
             serviceName = k.substring(0, j);
             algorithm = k.substring(j + 1);
             if (propertyServiceTable != null) {
-                Provider.Service ser = propertyServiceTable.remove(serviceName, Util.toUpperCase(algorithm));
+                Provider.Service ser = propertyServiceTable.remove(serviceName,
+                                                                   Util.toUpperCase(algorithm));
                 if (ser != null && propertyAliasTable != null
                         && ser.aliases != null) {
                     for (Iterator<String> it = ser.aliases.iterator(); it.hasNext();) {
@@ -701,8 +703,9 @@
                     }
                 }
             }
-        } else { // <crypto_service>.<algorithm_or_type>
-                 // <attribute_name>=<attrValue>
+        } else {
+            // <crypto_service>.<algorithm_or_type>
+            // <attribute_name>=<attrValue>
             attribute = k.substring(i + 1);
             serviceName = k.substring(0, j);
             algorithm = k.substring(j + 1, i);
@@ -737,11 +740,13 @@
             }
             String key = (String) _key;
             String value = (String) _value;
-            if (key.startsWith("Provider")) { // Provider service type is reserved
+            if (key.startsWith("Provider")) {
+                // Provider service type is reserved
                 continue;
             }
             int i;
-            if (key.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<standardName>
+            if (key.startsWith("Alg.Alias.")) {
+                // Alg.Alias.<crypto_service>.<aliasName>=<standardName>
                 String aliasName;
                 String service_alias = key.substring(10);
                 i = service_alias.indexOf('.');
@@ -811,8 +816,9 @@
                     propertyServiceTable.put(serviceName, alg, s);
 
                 }
-            } else { // <crypto_service>.<algorithm_or_type>
-                     // <attribute_name>=<attrValue>
+            } else {
+                // <crypto_service>.<algorithm_or_type>
+                // <attribute_name>=<attrValue>
                 serviceName = key.substring(0, j);
                 algorithm = key.substring(j + 1, i);
                 String attribute = key.substring(i + 1);
@@ -854,9 +860,11 @@
         lastServicesSet = null;
     }
 
-    // These attributes should be placed in each Provider object:
-    // Provider.id name, Provider.id version, Provider.id info,
-    // Provider.id className
+    /**
+     * These attributes should be placed in each Provider object:
+     * Provider.id name, Provider.id version, Provider.id info,
+     * Provider.id className
+     */
     @SuppressWarnings("nls")
     private void putProviderInfo() {
         super.put("Provider.id name", null != name ? name : "null");
@@ -865,11 +873,13 @@
         super.put("Provider.id className", this.getClass().getName());
     }
 
-    // Searches for the property with the specified key in the provider
-    // properties. Key is not case-sensitive.
-    //
-    // @param prop
-    // @return the property value with the specified key value.
+    /**
+     * Searches for the property with the specified key in the
+     * provider properties. Key is not case-sensitive.
+     *
+     * @param prop
+     * @return the property value with the specified key value.
+     */
     private String getPropertyIgnoreCase(String key) {
         String res = getProperty(key);
         if (res != null) {
@@ -1042,11 +1052,11 @@
             return attributes.get(name);
         }
 
-        Iterator<String> getAliases() {
-            if(aliases == null){
+        List<String> getAliases() {
+            if (aliases == null){
                 aliases = new ArrayList<String>(0);
             }
-            return aliases.iterator();
+            return aliases;
         }
 
         /**
@@ -1080,7 +1090,9 @@
                                     implementation = Class.forName(className,
                                             true, cl);
                                 } catch (Exception e) {
-                                    return new NoSuchAlgorithmException(type + " " + algorithm + " implementation not found: " + e);
+                                    return new NoSuchAlgorithmException(
+                                            type + " " + algorithm
+                                            + " implementation not found: " + e);
                                 }
                                 lastClassName = className;
                                 return null;
@@ -1094,7 +1106,8 @@
                 try {
                     return implementation.newInstance();
                 } catch (Exception e) {
-                    throw new NoSuchAlgorithmException(type + " " + algorithm + " implementation not found", e);
+                    throw new NoSuchAlgorithmException(
+                            type + " " + algorithm + " implementation not found", e);
                 }
             }
             if (!supportsParameter(constructorParameter)) {
@@ -1113,7 +1126,8 @@
                 return implementation.getConstructor(parameterTypes)
                         .newInstance(initargs);
             } catch (Exception e) {
-                throw new NoSuchAlgorithmException(type + " " + algorithm + " implementation not found", e);
+                throw new NoSuchAlgorithmException(type + " " + algorithm
+                        + " implementation not found", e);
             }
         }
 
@@ -1150,7 +1164,8 @@
         }
     }
 
-    private void readObject(java.io.ObjectInputStream in) throws NotActiveException, IOException, ClassNotFoundException {
+    private void readObject(java.io.ObjectInputStream in)
+            throws NotActiveException, IOException, ClassNotFoundException {
         in.defaultReadObject();
         versionString = String.valueOf(version);
         providerNumber = -1;
diff --git a/luni/src/main/java/java/security/Security.java b/luni/src/main/java/java/security/Security.java
index 6c94e79..af8e916 100644
--- a/luni/src/main/java/java/security/Security.java
+++ b/luni/src/main/java/java/security/Security.java
@@ -17,25 +17,24 @@
 
 package java.security;
 
+
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-// BEGIN android-added
-import java.util.logging.Level;
-import java.util.logging.Logger;
-// END android-added
-import java.util.Enumeration;
 import java.net.URL;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.Map.Entry;
-
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.apache.harmony.security.Util;
 import org.apache.harmony.security.fortress.Engine;
 import org.apache.harmony.security.fortress.PolicyUtils;
@@ -131,10 +130,11 @@
 
     // Register default providers
     private static void registerDefaultProviders() {
-        secprops.put("security.provider.1", "org.apache.harmony.security.provider.cert.DRLCertFactory");
-        secprops.put("security.provider.2", "org.apache.harmony.security.provider.crypto.CryptoProvider");
-        secprops.put("security.provider.3", "org.apache.harmony.xnet.provider.jsse.JSSEProvider");
-        secprops.put("security.provider.4", "org.bouncycastle.jce.provider.BouncyCastleProvider");
+        secprops.put("security.provider.1", "org.apache.harmony.xnet.provider.jsse.OpenSSLProvider");
+        secprops.put("security.provider.2", "org.bouncycastle.jce.provider.BouncyCastleProvider");
+        secprops.put("security.provider.3", "org.apache.harmony.security.provider.cert.DRLCertFactory");
+        secprops.put("security.provider.4", "org.apache.harmony.security.provider.crypto.CryptoProvider");
+        secprops.put("security.provider.5", "org.apache.harmony.xnet.provider.jsse.JSSEProvider");
     }
 
     /**
@@ -526,7 +526,7 @@
         }
 
         //  Access to Security.getAliases()
-        public Iterator<String> getAliases(Provider.Service s) {
+        public List<String> getAliases(Provider.Service s) {
             return s.getAliases();
         }
 
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
index cc16be7..9d333b5 100644
--- a/luni/src/main/java/java/security/security.properties
+++ b/luni/src/main/java/java/security/security.properties
@@ -21,12 +21,14 @@
 # Providers
 # See also: J2SE doc. "How to Implement a Provider for the JavaTM Cryptography Architecture"
 #
+# Android's provider of OpenSSL backed implementations
+security.provider.1=libcore.openssl.OpenSSLProvider
+# Android's stripped down BouncyCastle provider
+security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider
 # Harmony providers
-security.provider.1=org.apache.harmony.security.provider.cert.DRLCertFactory
-security.provider.2=org.apache.harmony.security.provider.crypto.CryptoProvider
-security.provider.3=org.apache.harmony.xnet.provider.jsse.JSSEProvider
-# Other Open Source providers
-security.provider.4=org.bouncycastle.jce.provider.BouncyCastleProvider
+security.provider.3=org.apache.harmony.security.provider.cert.DRLCertFactory
+security.provider.4=org.apache.harmony.security.provider.crypto.CryptoProvider
+security.provider.5=org.apache.harmony.xnet.provider.jsse.JSSEProvider
 
 #
 # Class to instantiate as a default Configuration implementation
@@ -85,9 +87,9 @@
 # javax/net/ssl/SSLSocketFactory.html#getDefault()
 # javax/net/ssl/SSLServerSocketFactory.html#getDefault()
 
-# BEGIN android-removed
+# BEGIN android-changed
 ssl.SocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
-# END android-removed
+# END android-changed
 
 # BEGIN android-added
 # Use the definition above to get the new, OpenSSL-based SSL implementation,
diff --git a/luni/src/main/java/java/util/jar/JarVerifier.java b/luni/src/main/java/java/util/jar/JarVerifier.java
index 2324992..88373a3 100644
--- a/luni/src/main/java/java/util/jar/JarVerifier.java
+++ b/luni/src/main/java/java/util/jar/JarVerifier.java
@@ -37,10 +37,6 @@
 
 import org.apache.harmony.luni.util.Util;
 
-// BEGIN android-added
-import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
-// END android-added
-
 /**
  * Non-public class used by {@link JarFile} and {@link JarInputStream} to manage
  * the verification of signed JARs. {@code JarFile} and {@code JarInputStream}
@@ -217,10 +213,8 @@
             byte[] hashBytes = hash.getBytes(Charsets.ISO_8859_1);
 
             try {
-                // BEGIN android-changed
-                return new VerifierEntry(name, OpenSSLMessageDigestJDK.getInstance(algorithm),
-                        hashBytes, certificatesArray);
-                // END android-changed
+                return new VerifierEntry(name, MessageDigest
+                        .getInstance(algorithm), hashBytes, certificatesArray);
             } catch (NoSuchAlgorithmException e) {
                 // ignored
             }
@@ -407,9 +401,7 @@
 
             MessageDigest md;
             try {
-                // BEGIN android-changed
-                md = OpenSSLMessageDigestJDK.getInstance(algorithm);
-                // END android-changed
+                md = MessageDigest.getInstance(algorithm);
             } catch (NoSuchAlgorithmException e) {
                 continue;
             }
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java b/luni/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java
index 6dd679f..be3e0cc 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java
@@ -22,8 +22,8 @@
 
 package org.apache.harmony.security.fortress;
 
-import java.util.Iterator;
 import java.security.Provider;
+import java.util.List;
 
 /**
  *
@@ -42,7 +42,7 @@
      * @param s
      * @return
      */
-    public Iterator<String> getAliases(Provider.Service s);
+    public List<String> getAliases(Provider.Service s);
 
     /**
      * Access to Provider.getService(String type)
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index 94c5667..7730fa6 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -49,7 +49,8 @@
     // BEGIN android-changed
     // set the initial size to 600 so we don't grow to 1024 by default because
     // initialization adds a few entries more than the growth threshold.
-    private static final Map<String, Provider.Service> services = new HashMap<String, Provider.Service>(600);
+    private static final Map<String, Provider.Service> services
+            = new HashMap<String, Provider.Service>(600);
     // END android-changed
 
     // Need refresh flag
@@ -93,8 +94,8 @@
                 initServiceInfo(p);
             } catch (ClassNotFoundException e) { // ignore Exceptions
             } catch (IllegalAccessException e) {
-			} catch (InstantiationException e) {
-			}
+            } catch (InstantiationException e) {
+            }
         }
         Engine.door.renumProviders();
     }
@@ -166,23 +167,17 @@
      * @param p
      */
     public static void initServiceInfo(Provider p) {
-        Provider.Service serv;
-        String key;
-        String type;
-        String alias;
         StringBuilder sb = new StringBuilder(128);
 
-        for (Iterator<Provider.Service> it1 = p.getServices().iterator(); it1.hasNext();) {
-            serv = it1.next();
-            type = serv.getType();
+        for (Provider.Service serv : p.getServices()) {
+            String type = serv.getType();
             sb.delete(0, sb.length());
-            key = sb.append(type).append(".").append(
+            String key = sb.append(type).append(".").append(
                     Util.toUpperCase(serv.getAlgorithm())).toString();
             if (!services.containsKey(key)) {
                 services.put(key, serv);
             }
-            for (Iterator<String> it2 = Engine.door.getAliases(serv); it2.hasNext();) {
-                alias = it2.next();
+            for (String alias : Engine.door.getAliases(serv)) {
                 sb.delete(0, sb.length());
                 key = sb.append(type).append(".").append(Util.toUpperCase(alias))
                         .toString();
@@ -200,8 +195,8 @@
      */
     public static void updateServiceInfo() {
         services.clear();
-        for (Iterator<Provider> it = providers.iterator(); it.hasNext();) {
-            initServiceInfo(it.next());
+        for (Provider p : providers) {
+            initServiceInfo(p);
         }
         needRefresh = false;
     }
@@ -227,19 +222,6 @@
     }
 
     /**
-     * Prints Services content
-     */
-    // FIXME remove debug function
-    public static void printServices() {
-        refresh();
-        Set<String> s = services.keySet();
-        for (Iterator<String> i = s.iterator(); i.hasNext();) {
-            String key = i.next();
-            System.out.println(key + "=" + services.get(key));
-        }
-    }
-
-    /**
      * Set flag needRefresh
      *
      */
@@ -257,4 +239,4 @@
             updateServiceInfo();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
index aeddd41..5870f60 100644
--- a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
+++ b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
@@ -38,23 +38,18 @@
 import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
-
 import javax.security.auth.x500.X500Principal;
-
 import org.apache.harmony.security.utils.AlgNameMapper;
 import org.apache.harmony.security.x509.Certificate;
 import org.apache.harmony.security.x509.Extension;
 import org.apache.harmony.security.x509.Extensions;
 import org.apache.harmony.security.x509.TBSCertificate;
-
-// BEGIN android-added
-import java.security.interfaces.RSAPublicKey;
 import org.apache.harmony.xnet.provider.jsse.NativeCrypto;
-// END android-added
 
 /**
  * This class is an implementation of X509Certificate. It wraps
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index 02f37dc..9013eba 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -36,20 +36,14 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-
 import javax.security.auth.x500.X500Principal;
-
 import org.apache.harmony.security.asn1.BerInputStream;
 import org.apache.harmony.security.pkcs7.ContentInfo;
 import org.apache.harmony.security.pkcs7.SignedData;
 import org.apache.harmony.security.pkcs7.SignerInfo;
 import org.apache.harmony.security.provider.cert.X509CertImpl;
 import org.apache.harmony.security.x501.AttributeTypeAndValue;
-
-// BEGIN android-added
-import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
 import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
-// END android-added
 
 public class JarUtils {
 
@@ -176,12 +170,7 @@
                 }
             }
             if (existingDigest != null) {
-                // BEGIN android-removed
-                // MessageDigest md = MessageDigest.getInstance(sigInfo.getDigestAlgorithm());
-                // END android-removed
-                // BEGIN android-added
-                MessageDigest md = OpenSSLMessageDigestJDK.getInstance(sigInfo.getDigestAlgorithm());
-                // END android-added
+                MessageDigest md = MessageDigest.getInstance(sigInfo.getDigestAlgorithm());
                 byte[] computedDigest = md.digest(sfBytes);
                 if (!Arrays.equals(existingDigest, computedDigest)) {
                     throw new SecurityException("Incorrect MD");
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java
index 0309838..a35fbac 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java
@@ -154,7 +154,7 @@
         }
     }
 
-    /** 
+    /**
      * Called when a session is removed. Used by ClientSessionContext
      * to update its host-and-port based cache.
      */
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
index cb7d6c9..35cac53 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
@@ -118,18 +118,6 @@
                 put("SSLContext.Default", DefaultSSLContextImpl.class.getName());
                 put("SSLContext.SSL", SSLContextImpl.class.getName());
                 put("Alg.Alias.SSLContext.SSLv3", "SSL");
-                put("MessageDigest.SHA-1", "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA1");
-                put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
-                put("Alg.Alias.MessageDigest.SHA", "SHA-1");
-                put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA-1");
-                put("MessageDigest.SHA-224", "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA224");
-                put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
-                put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.4", "SHA-224");
-                put("MessageDigest.SHA-256", "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA256");
-                put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
-                put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
-                put("MessageDigest.MD5", "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$MD5");
-                put("Alg.Alias.MessageDigest.1.2.840.113549.2.5", "MD5");
                 // END android-added
                 return null;
             }
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 7e6723e..63275f0 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -28,11 +28,9 @@
 import java.util.Map;
 
 /**
- * Provides the Java side of our JNI glue for OpenSSL. Currently only
- * hashing and verifying are covered. Is expected to grow over
- * time. Also needs to move into libcore/openssl at some point.
+ * Provides the Java side of our JNI glue for OpenSSL.
  */
-public class NativeCrypto {
+public final class NativeCrypto {
 
     // --- OpenSSL library initialization --------------------------------------
     static {
@@ -258,9 +256,9 @@
 
     public static final String[] KEY_TYPES = new String[] { "RSA", "DSA", "DH_RSA" , "DH_DSA" };
 
-    public static native void SSL_use_certificate(int ssl, byte[] pemEncodedCertificate);
+    public static native void SSL_use_certificate(int ssl, byte[][] asn1DerEncodedCertificate);
 
-    public static native void SSL_use_PrivateKey(int ssl, byte[] pemEncodedPrivateKey);
+    public static native void SSL_use_PrivateKey(int ssl, byte[] pkcs8EncodedPrivateKey);
 
     public static native void SSL_check_private_key(int ssl);
 
@@ -302,8 +300,8 @@
                 optionsToSet &= ~SSL_OP_NO_TLSv1;
                 optionsToClear |= SSL_OP_NO_TLSv1;
             } else {
-                throw new IllegalArgumentException("protocol " + protocol +
-                                                   " is not supported");
+                throw new IllegalArgumentException("protocol " + protocol
+                                                   + " is not supported");
             }
         }
 
@@ -322,8 +320,8 @@
             }
             if ((!protocol.equals(SUPPORTED_PROTOCOL_SSLV3))
                     && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1))) {
-                throw new IllegalArgumentException("protocol " + protocol +
-                                                   " is not supported");
+                throw new IllegalArgumentException("protocol " + protocol
+                                                   + " is not supported");
             }
         }
         return protocols;
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigest.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigest.java
deleted file mode 100644
index 0fd5879..0000000
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.harmony.xnet.provider.jsse;
-
-import org.bouncycastle.crypto.ExtendedDigest;
-
-import java.security.NoSuchAlgorithmException;
-
-/**
- * Implements the BouncyCastle Digest interface using OpenSSL's EVP API.
- */
-public class OpenSSLMessageDigest implements ExtendedDigest {
-
-    /**
-     * Holds the name of the hashing algorithm, e.g. "SHA-1";
-     */
-    private String algorithm;
-
-    /**
-     * Holds a pointer to the native message digest context.
-     */
-    private int ctx;
-
-    /**
-     * Holds a dummy buffer for writing single bytes to the digest.
-     */
-    private byte[] singleByte = new byte[1];
-
-    /**
-     * Creates a new OpenSSLMessageDigest instance for the given algorithm
-     * name.
-     *
-     * @param algorithm The name of the algorithm, e.g. "SHA1".
-     *
-     * @return The new OpenSSLMessageDigest instance.
-     *
-     * @throws RuntimeException In case of problems.
-     */
-    public static OpenSSLMessageDigest getInstance(String algorithm) {
-        return new OpenSSLMessageDigest(algorithm);
-    }
-
-    /**
-     * Creates a new OpenSSLMessageDigest instance for the given algorithm
-     * name.
-     *
-     * @param algorithm The name of the algorithm, e.g. "SHA1".
-     */
-    private OpenSSLMessageDigest(String algorithm) {
-        this.algorithm = algorithm;
-
-        // We don't support MD2 anymore. This needs to also check for aliases
-        // and OIDs.
-        if ("MD2".equalsIgnoreCase(algorithm) || "1.2.840.113549.2.2"
-                .equals(algorithm)) {
-            throw new RuntimeException(algorithm + " not supported");
-        }
-
-        ctx = NativeCrypto.EVP_new();
-        try {
-            NativeCrypto.EVP_DigestInit(ctx, algorithm.replace("-", "").toLowerCase());
-        } catch (Exception ex) {
-            throw new RuntimeException(ex.getMessage() + " (" + algorithm + ")");
-        }
-    }
-
-    public int doFinal(byte[] out, int outOff) {
-        int i = NativeCrypto.EVP_DigestFinal(ctx, out, outOff);
-        reset();
-        return i;
-    }
-
-    public String getAlgorithmName() {
-        return algorithm;
-    }
-
-    public int getDigestSize() {
-        return NativeCrypto.EVP_DigestSize(ctx);
-    }
-
-    public int getByteLength() {
-        return NativeCrypto.EVP_DigestBlockSize(ctx);
-    }
-
-    public void reset() {
-        NativeCrypto.EVP_DigestInit(ctx, algorithm.replace("-", "").toLowerCase());
-    }
-
-    public void update(byte in) {
-        singleByte[0] = in;
-        NativeCrypto.EVP_DigestUpdate(ctx, singleByte, 0, 1);
-    }
-
-    public void update(byte[] in, int inOff, int len) {
-        NativeCrypto.EVP_DigestUpdate(ctx, in, inOff, len);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        super.finalize();
-        NativeCrypto.EVP_free(ctx);
-    }
-
-}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
new file mode 100644
index 0000000..01681f1
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xnet.provider.jsse;
+
+import java.security.Provider;
+
+public final class OpenSSLProvider extends Provider {
+
+    public OpenSSLProvider() {
+        super("AndroidOpenSSL", 1.0, "Android's OpenSSL-backed security provider");
+
+        put("MessageDigest.SHA-1",
+            "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA1");
+        put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+        put("Alg.Alias.MessageDigest.SHA", "SHA-1");
+        put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA-1");
+
+        put("MessageDigest.SHA-256",
+            "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA256");
+        put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+        put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
+
+        put("MessageDigest.SHA-384",
+            "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA384");
+        put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+        put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
+
+        put("MessageDigest.SHA-512",
+            "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA512");
+        put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+        put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
+
+        put("MessageDigest.MD5",
+            "org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$MD5");
+        put("Alg.Alias.MessageDigest.1.2.840.113549.2.5", "MD5");
+
+        // TODO Flush out implementation of OpenSSLSignature so it can be registered here
+    }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
index c651213..5ea288f 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
@@ -16,6 +16,8 @@
 
 package org.apache.harmony.xnet.provider.jsse;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.security.InvalidKeyException;
 import java.security.InvalidParameterException;
 import java.security.NoSuchAlgorithmException;
@@ -28,14 +30,57 @@
 import java.security.interfaces.RSAPublicKey;
 
 /**
- * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
+ * Implements the subset of the JDK Signature interface needed for
+ * signature verification using OpenSSL.
  */
 public class OpenSSLSignature extends Signature {
 
+    private static Map<String,Class<? extends OpenSSLSignature>> jdkToOpenSsl
+            = new HashMap<String,Class<? extends OpenSSLSignature>>();
+
+    static {
+        // TODO Finish OpenSSLSignature implementation and move
+        // registration information to the OpenSSLProvider
+        jdkToOpenSsl.put("MD5WithRSAEncryption", MD5RSA.class);
+        jdkToOpenSsl.put("MD5WithRSA", MD5RSA.class);
+        jdkToOpenSsl.put("MD5/RSA", MD5RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.1.1.4", MD5RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.2.5with1.2.840.113549.1.1.1", MD5RSA.class);
+
+        jdkToOpenSsl.put("SHA1WithRSAEncryption", SHA1RSA.class);
+        jdkToOpenSsl.put("SHA1WithRSA", SHA1RSA.class);
+        jdkToOpenSsl.put("SHA1/RSA", SHA1RSA.class);
+        jdkToOpenSsl.put("SHA-1/RSA", SHA1RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.1.1.5", SHA1RSA.class);
+        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.1", SHA1RSA.class);
+        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.5", SHA1RSA.class);
+        jdkToOpenSsl.put("1.3.14.3.2.29", SHA1RSA.class);
+
+        jdkToOpenSsl.put("SHA256WithRSAEncryption", SHA256RSA.class);
+        jdkToOpenSsl.put("SHA256WithRSA", SHA256RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.1.1.11", SHA256RSA.class);
+
+        jdkToOpenSsl.put("SHA384WithRSAEncryption", SHA384RSA.class);
+        jdkToOpenSsl.put("SHA384WithRSA", SHA384RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.1.1.12", SHA384RSA.class);
+
+        jdkToOpenSsl.put("SHA512WithRSAEncryption", SHA512RSA.class);
+        jdkToOpenSsl.put("SHA512WithRSA", SHA512RSA.class);
+        jdkToOpenSsl.put("1.2.840.113549.1.1.13", SHA512RSA.class);
+
+        jdkToOpenSsl.put("SHA1withDSA", SHA1DSA.class);
+        jdkToOpenSsl.put("SHA/DSA", SHA1DSA.class);
+        jdkToOpenSsl.put("DSA", SHA1DSA.class);
+        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.1", SHA1DSA.class);
+        jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.3", SHA1DSA.class);
+        jdkToOpenSsl.put("DSAWithSHA1", SHA1DSA.class);
+        jdkToOpenSsl.put("1.2.840.10040.4.3", SHA1DSA.class);
+    }
+
     /**
      * Holds a pointer to the native message digest context.
      */
-    private int ctx;
+    private final int ctx;
 
     /**
      * Holds a pointer to the native DSA key.
@@ -50,63 +95,53 @@
     /**
      * Holds the OpenSSL name of the algorithm (lower case, no dashes).
      */
-    private String evpAlgorithm;
+    private final String evpAlgorithm;
 
     /**
      * Holds a dummy buffer for writing single bytes to the digest.
      */
-    private byte[] singleByte = new byte[1];
+    private final byte[] singleByte = new byte[1];
 
     /**
      * Creates a new OpenSSLSignature instance for the given algorithm name.
      *
-     * @param algorithm The name of the algorithm, e.g. "SHA1".
+     * @param algorithm The name of the algorithm, e.g. "SHA1WithRSA".
      *
      * @return The new OpenSSLSignature instance.
      *
      * @throws RuntimeException In case of problems.
      */
     public static OpenSSLSignature getInstance(String algorithm) throws NoSuchAlgorithmException {
-        //log("OpenSSLSignature", "getInstance() invoked with " + algorithm);
-        return new OpenSSLSignature(algorithm);
+        // System.out.println("getInstance() invoked with " + algorithm);
+
+        Class <? extends OpenSSLSignature> clazz = jdkToOpenSsl.get(algorithm);
+        if (clazz == null) {
+            throw new NoSuchAlgorithmException(algorithm);
+        }
+        try {
+            return clazz.newInstance();
+        } catch (InstantiationException e) {
+            throw new NoSuchAlgorithmException(algorithm, e);
+        } catch (IllegalAccessException e) {
+            throw new NoSuchAlgorithmException(algorithm, e);
+        }
     }
 
     /**
      * Creates a new OpenSSLSignature instance for the given algorithm name.
      *
-     * @param algorithm The name of the algorithm, e.g. "SHA1".
+     * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1".
      */
     private OpenSSLSignature(String algorithm) throws NoSuchAlgorithmException {
         super(algorithm);
 
-        int i = algorithm.indexOf("with");
-        if (i == -1) {
+        // We don't support MD2
+        if ("RSA-MD2".equals(algorithm)) {
             throw new NoSuchAlgorithmException(algorithm);
         }
 
-        // We don't support MD2 anymore. This needs to also check for aliases
-        // and OIDs.
-        if ("MD2withRSA".equalsIgnoreCase(algorithm) ||
-                "MD2withRSAEncryption".equalsIgnoreCase(algorithm) ||
-                "1.2.840.113549.1.1.2".equalsIgnoreCase(algorithm) ||
-                "MD2/RSA".equalsIgnoreCase(algorithm)) {
-            throw new NoSuchAlgorithmException("MD2withRSA");
-        }
-
-        // For the special combination of DSA and SHA1, we need to pass the
-        // algorithm name as a pair consisting of crypto algorithm and hash
-        // algorithm. For all other (RSA) cases, passing the hash algorithm
-        // alone is not only sufficient, but actually necessary. OpenSSL
-        // doesn't accept something like RSA-SHA1.
-        if ("1.3.14.3.2.26with1.2.840.10040.4.1".equals(algorithm)
-                || "SHA1withDSA".equals(algorithm)
-                || "SHAwithDSA".equals(algorithm)) {
-            evpAlgorithm = "DSA-SHA";
-        } else {
-            evpAlgorithm = algorithm.substring(0, i).replace("-", "").toUpperCase();
-        }
-
-        ctx = NativeCrypto.EVP_new();
+        this.evpAlgorithm = algorithm;
+        this.ctx = NativeCrypto.EVP_new();
     }
 
     @Override
@@ -136,7 +171,8 @@
 
     @Override
     protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
-        //log("OpenSSLSignature", "engineInitVerify() invoked with " + publicKey.getClass().getCanonicalName());
+        // System.out.println("engineInitVerify() invoked with "
+        //                    + publicKey.getClass().getCanonicalName());
 
         if (publicKey instanceof DSAPublicKey) {
             try {
@@ -212,4 +248,36 @@
             NativeCrypto.EVP_free(ctx);
         }
     }
+
+    public static final class MD5RSA extends OpenSSLSignature {
+        public MD5RSA() throws NoSuchAlgorithmException {
+            super("RSA-MD5");
+        }
+    }
+    public static final class SHA1RSA extends OpenSSLSignature {
+        public SHA1RSA() throws NoSuchAlgorithmException {
+            super("RSA-SHA1");
+        }
+    }
+    public static final class SHA256RSA extends OpenSSLSignature {
+        public SHA256RSA() throws NoSuchAlgorithmException {
+            super("RSA-SHA256");
+        }
+    }
+    public static final class SHA384RSA extends OpenSSLSignature {
+        public SHA384RSA() throws NoSuchAlgorithmException {
+            super("RSA-SHA384");
+        }
+    }
+    public static final class SHA512RSA extends OpenSSLSignature {
+        public SHA512RSA() throws NoSuchAlgorithmException {
+            super("RSA-SHA512");
+        }
+    }
+    public static final class SHA1DSA extends OpenSSLSignature {
+        public SHA1DSA() throws NoSuchAlgorithmException {
+            super("DSA-SHA1");
+        }
+    }
 }
+
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketFactoryImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketFactoryImpl.java
index ed8861c..17ac99a 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketFactoryImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketFactoryImpl.java
@@ -21,7 +21,6 @@
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.security.KeyManagementException;
-
 import org.apache.harmony.xnet.provider.jsse.SSLParameters;
 
 public class OpenSSLSocketFactoryImpl extends javax.net.ssl.SSLSocketFactory {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index b23f50e..0435717 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -16,16 +16,15 @@
 
 package org.apache.harmony.xnet.provider.jsse;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketException;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
@@ -37,7 +36,6 @@
 import javax.net.ssl.SSLPeerUnverifiedException;
 import javax.net.ssl.SSLSession;
 import org.apache.harmony.security.provider.cert.X509CertImpl;
-import org.bouncycastle.openssl.PEMWriter;
 
 /**
  * Implementation of the class OpenSSLSocketImpl
@@ -449,21 +447,18 @@
         }
 
         PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
-        ByteArrayOutputStream privateKeyOS = new ByteArrayOutputStream();
-        PEMWriter privateKeyPEMWriter = new PEMWriter(new OutputStreamWriter(privateKeyOS));
-        privateKeyPEMWriter.writeObject(privateKey);
-        privateKeyPEMWriter.close();
-        byte[] privateKeyBytes = privateKeyOS.toByteArray();
+        byte[] privateKeyBytes = privateKey.getEncoded();
         NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
 
         X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
-        ByteArrayOutputStream certificateOS = new ByteArrayOutputStream();
-        PEMWriter certificateWriter = new PEMWriter(new OutputStreamWriter(certificateOS));
-        for (X509Certificate certificate : certificates) {
-            certificateWriter.writeObject(certificate);
+        byte[][] certificateBytes = new byte[certificates.length][];
+        for (int i = 0; i < certificates.length; i++) {
+            try {
+                certificateBytes[i] = certificates[i].getEncoded();
+            } catch (CertificateEncodingException e) {
+                throw new IOException("Problem encoding certificate " + certificates[i], e);
+            }
         }
-        certificateWriter.close();
-        byte[] certificateBytes = certificateOS.toByteArray();
         // TODO SSL_use_certificate only looks at the first certificate in the chain.
         // It would be better to use a custom version of SSL_CTX_use_certificate_chain_file
         // to set the whole chain. Note there is no SSL_ equivalent of this SSL_CTX_ function.
diff --git a/openssl/src/main/native/NativeBN.cpp b/luni/src/main/native/NativeBN.cpp
similarity index 98%
rename from openssl/src/main/native/NativeBN.cpp
rename to luni/src/main/native/NativeBN.cpp
index 3d129c8..ac9cd90 100644
--- a/openssl/src/main/native/NativeBN.cpp
+++ b/luni/src/main/native/NativeBN.cpp
@@ -546,6 +546,6 @@
    { "sign", "(I)I", (void*)NativeBN_sign },
    { "twosComp2bn", "([BII)Z", (void*)NativeBN_twosComp2bn },
 };
-int register_org_openssl_NativeBN(JNIEnv* env) {
-    return jniRegisterNativeMethods(env, "org/openssl/NativeBN", gMethods, NELEM(gMethods));
+int register_java_math_NativeBN(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
 }
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/NativeCrypto.cpp
similarity index 96%
rename from luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
rename to luni/src/main/native/NativeCrypto.cpp
index 96ef89c..2a1b431 100644
--- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
+++ b/luni/src/main/native/NativeCrypto.cpp
@@ -89,6 +89,13 @@
 };
 typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
 
+struct PKCS8_PRIV_KEY_INFO_Delete {
+    void operator()(PKCS8_PRIV_KEY_INFO* p) const {
+        PKCS8_PRIV_KEY_INFO_free(p);
+    }
+};
+typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
+
 struct RSA_Delete {
     void operator()(RSA* p) const {
         RSA_free(p);
@@ -600,7 +607,7 @@
         return;
     }
 
-    const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
+    const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
 
     if (digest == NULL) {
         jniThrowRuntimeException(env, "Hash algorithm not found");
@@ -682,7 +689,7 @@
         return;
     }
 
-    const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
+    const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
 
     if (digest == NULL) {
         jniThrowRuntimeException(env, "Hash algorithm not found");
@@ -785,7 +792,7 @@
     }
     EVP_PKEY_set1_RSA(pkey.get(), rsa);
 
-    const EVP_MD *type = EVP_get_digestbyname(algorithm);
+    const EVP_MD* type = EVP_get_digestbyname(algorithm);
     if (type == NULL) {
         return -1;
     }
@@ -1676,20 +1683,6 @@
     return (jint)ssl.release();
 }
 
-/**
- * Gets the bytes from a jbyteArray and stores them in a freshly-allocated BIO memory buffer.
- */
-static BIO* jbyteArrayToMemBuf(JNIEnv* env, jbyteArray byteArray) {
-    ScopedByteArrayRO buf(env, byteArray);
-    Unique_BIO bio(BIO_new(BIO_s_mem()));
-    if (bio.get() == NULL) {
-        jniThrowRuntimeException(env, "BIO_new failed");
-        return NULL;
-    }
-    BIO_write(bio.get(), buf.get(), buf.size());
-    return bio.release();
-}
-
 static void NativeCrypto_SSL_use_PrivateKey(JNIEnv* env, jclass,
                                             jint ssl_address, jbyteArray privatekey)
 {
@@ -1701,17 +1694,29 @@
 
     if (privatekey == NULL) {
         jniThrowNullPointerException(env, "privatekey == null");
-        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => privatekey error", ssl);
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => privatekey == null", ssl);
         return;
     }
 
-    Unique_BIO privatekeybio(jbyteArrayToMemBuf(env, privatekey));
-    Unique_EVP_PKEY privatekeyevp(PEM_read_bio_PrivateKey(privatekeybio.get(), NULL, 0, NULL));
+    ScopedByteArrayRO buf(env, privatekey);
+    const unsigned char* tmp = (const unsigned char*) buf.get();
+    Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, buf.size()));
+    if (pkcs8.get() == NULL) {
+        LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE,
+                                       "Error parsing private key from DER to PKCS8");
+        SSL_clear(ssl);
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => error from DER to PKCS8", ssl);
+        return;
+    }
+
+    Unique_EVP_PKEY privatekeyevp(EVP_PKCS82PKEY(pkcs8.get()));
     if (privatekeyevp.get() == NULL) {
         LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
-        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing the private key");
+        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, 
+                                       "Error creating private key from PKCS8");
         SSL_clear(ssl);
-        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => privatekeyevp error", ssl);
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => error from PKCS8 to key", ssl);
         return;
     }
 
@@ -1720,7 +1725,7 @@
         privatekeyevp.release();
     } else {
         LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
-        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting the private key");
+        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key");
         SSL_clear(ssl);
         JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => error", ssl);
         return;
@@ -1730,7 +1735,7 @@
 }
 
 static void NativeCrypto_SSL_use_certificate(JNIEnv* env, jclass,
-                                             jint ssl_address, jbyteArray certificates)
+                                             jint ssl_address, jobjectArray certificates)
 {
     SSL* ssl = to_SSL(env, ssl_address, true);
     JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate certificates=%p", ssl, certificates);
@@ -1739,30 +1744,49 @@
     }
 
     if (certificates == NULL) {
-        jniThrowNullPointerException(env, "privatekey == null");
-        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates error", ssl);
+        jniThrowNullPointerException(env, "certificates == null");
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl);
         return;
     }
 
-    Unique_BIO certificatesbio(jbyteArrayToMemBuf(env, certificates));
-    Unique_X509 certificatesx509(PEM_read_bio_X509(certificatesbio.get(), NULL, 0, NULL));
-
-    if (certificatesx509.get() == NULL) {
-        LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
-        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing the certificates");
-        SSL_clear(ssl);
-        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificatesx509 error", ssl);
+    int length = env->GetArrayLength(certificates);
+    if (length == 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "certificates.length == 0");
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates.length == 0", ssl);
         return;
     }
 
-    int ret = SSL_use_certificate(ssl, certificatesx509.get());
+    Unique_X509 certificatesX509[length];
+    for (int i = 0; i < length; i++) {
+        ScopedLocalRef<jbyteArray> certificate(env,
+                reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(certificates, i)));
+        if (certificate.get() == NULL) {
+            jniThrowNullPointerException(env, "certificates element == null");
+            JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates element null", ssl);
+            return;
+        }
+
+        ScopedByteArrayRO buf(env, certificate.get());
+        const unsigned char* tmp = (const unsigned char*) buf.get();
+        certificatesX509[i].reset(d2i_X509(NULL, &tmp, buf.size()));
+
+        if (certificatesX509[i].get() == NULL) {
+            LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+            throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate");
+            SSL_clear(ssl);
+            JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl);
+            return;
+        }
+    }
+
+    int ret = SSL_use_certificate(ssl, certificatesX509[0].get());
     if (ret == 1) {
-        certificatesx509.release();
+        certificatesX509[0].release();
     } else {
         LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
-        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting the certificates");
+        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate");
         SSL_clear(ssl);
-        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => error", ssl);
+        JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate error", ssl);
         return;
     }
 
@@ -1778,7 +1802,7 @@
     }
     int ret = SSL_check_private_key(ssl);
     if (ret != 1) {
-        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error checking the private key");
+        throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error checking private key");
         SSL_clear(ssl);
         JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => error", ssl);
         return;
@@ -2878,7 +2902,7 @@
     { "SSL_CTX_free",         "(I)V",          (void*)NativeCrypto_SSL_CTX_free },
     { "SSL_new",              "(I)I",          (void*)NativeCrypto_SSL_new},
     { "SSL_use_PrivateKey",   "(I[B)V",        (void*)NativeCrypto_SSL_use_PrivateKey},
-    { "SSL_use_certificate",  "(I[B)V",        (void*)NativeCrypto_SSL_use_certificate},
+    { "SSL_use_certificate",  "(I[[B)V",       (void*)NativeCrypto_SSL_use_certificate},
     { "SSL_check_private_key","(I)V",          (void*)NativeCrypto_SSL_check_private_key},
     { "SSL_get_mode",         "(I)J",          (void*)NativeCrypto_SSL_get_mode },
     { "SSL_set_mode",         "(IJ)J",         (void*)NativeCrypto_SSL_set_mode },
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 0e94531..01cf1c2 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -39,6 +39,7 @@
 extern int register_java_lang_ProcessManager(JNIEnv* env);
 extern int register_java_lang_StrictMath(JNIEnv* env);
 extern int register_java_lang_System(JNIEnv* env);
+extern int register_java_math_NativeBN(JNIEnv* env);
 extern int register_java_net_InetAddress(JNIEnv* env);
 extern int register_java_net_NetworkInterface(JNIEnv* env);
 extern int register_java_util_regex_Matcher(JNIEnv* env);
@@ -60,7 +61,6 @@
 extern int register_org_apache_harmony_text_NativeBidi(JNIEnv* env);
 extern int register_org_apache_harmony_xml_ExpatParser(JNIEnv* env);
 extern int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env);
-extern int register_org_openssl_NativeBN(JNIEnv* env);
 
 // DalvikVM calls this on startup, so we can statically register all our native methods.
 extern "C" int registerCoreLibrariesJni(JNIEnv* env) {
@@ -87,6 +87,7 @@
             register_java_lang_ProcessManager(env) != -1 &&
             register_java_lang_StrictMath(env) != -1 &&
             register_java_lang_System(env) != -1 &&
+            register_java_math_NativeBN(env) != -1 &&
             register_java_net_InetAddress(env) != -1 &&
             register_java_net_NetworkInterface(env) != -1 &&
             register_java_util_regex_Matcher(env) != -1 &&
@@ -106,7 +107,6 @@
             register_org_apache_harmony_luni_util_fltparse(env) != -1 &&
             register_org_apache_harmony_text_NativeBidi(env) != -1 &&
             register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(env) != -1 &&
-            register_org_openssl_NativeBN(env) != -1 &&
             // Initialize the Android classes last, as they have dependencies on the "corer" core classes.
             android::register_dalvik_system_TouchDex(env) != -1 &&
             register_org_apache_harmony_dalvik_NativeTestTarget(env) != -1 &&
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index d204d56..73ceedb 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -6,10 +6,12 @@
 	ErrorCode.cpp \
 	ICU.cpp \
 	JniConstants.cpp \
+	NativeBN.cpp \
 	NativeBidi.cpp \
 	NativeBreakIterator.cpp \
 	NativeCollation.cpp \
 	NativeConverter.cpp \
+	NativeCrypto.cpp \
 	NativeDecimalFormat.cpp \
 	NativeIDN.cpp \
 	NativeNormalizer.cpp \
@@ -46,7 +48,6 @@
 	org_apache_harmony_luni_util_NumberConvert.cpp \
 	org_apache_harmony_luni_util_fltparse.cpp \
 	org_apache_harmony_xml_ExpatParser.cpp \
-	org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp \
 	valueOf.cpp
 
 
diff --git a/luni/src/test/java/org/bouncycastle/crypto/digests/DigestTest.java b/luni/src/test/java/org/bouncycastle/crypto/digests/DigestTest.java
new file mode 100644
index 0000000..7ad6254
--- /dev/null
+++ b/luni/src/test/java/org/bouncycastle/crypto/digests/DigestTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bouncycastle.crypto.digests;
+
+import junit.framework.TestCase;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * Implements unit tests for our JNI wrapper around OpenSSL. We use the
+ * existing Bouncy Castle implementation as our test oracle.
+ */
+public class DigestTest extends TestCase {
+
+    /**
+     * Processes the two given message digests for the same data and checks
+     * the results. Requirement is that the results must be equal, the digest
+     * implementations must have the same properties, and the new implementation
+     * must be faster than the old one.
+     *
+     * @param oldDigest The old digest implementation, provided by Bouncy Castle
+     * @param newDigest The new digest implementation, provided by OpenSSL
+     */
+    public void doTestMessageDigest(Digest oldDigest, Digest newDigest) {
+        final int ITERATIONS = 10;
+
+        byte[] data = new byte[1024];
+
+        byte[] oldHash = new byte[oldDigest.getDigestSize()];
+        byte[] newHash = new byte[newDigest.getDigestSize()];
+
+        assertEquals("Hash names must be equal",
+                     oldDigest.getAlgorithmName(), newDigest.getAlgorithmName());
+        assertEquals("Hash sizes must be equal",
+                     oldHash.length, newHash.length);
+        assertEquals("Hash block sizes must be equal",
+                     ((ExtendedDigest)oldDigest).getByteLength(),
+                     ((ExtendedDigest)newDigest).getByteLength());
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte)i;
+        }
+
+        long oldTime = 0;
+        long newTime = 0;
+
+        for (int j = 0; j < ITERATIONS; j++) {
+            long t0 = System.currentTimeMillis();
+            for (int i = 0; i < 4; i++) {
+                oldDigest.update(data, 0, data.length);
+            }
+            int oldLength = oldDigest.doFinal(oldHash, 0);
+            long t1 = System.currentTimeMillis();
+
+            oldTime = oldTime + (t1 - t0);
+
+            long t2 = System.currentTimeMillis();
+            for (int i = 0; i < 4; i++) {
+                newDigest.update(data, 0, data.length);
+            }
+            int newLength = newDigest.doFinal(newHash, 0);
+            long t3 = System.currentTimeMillis();
+
+            newTime = newTime + (t3 - t2);
+
+            assertEquals("Hash sizes must be equal", oldLength, newLength);
+
+            for (int i = 0; i < oldLength; i++) {
+                assertEquals("Hashes[" + i + "] must be equal", oldHash[i], newHash[i]);
+            }
+        }
+
+        System.out.println("Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms");
+        System.out.println("Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms");
+
+        assertTrue("New hash should be faster", newTime < oldTime);
+    }
+
+    /**
+     * Tests the MD5 implementation.
+     */
+    public void testMD5() {
+        Digest oldDigest = new MD5Digest();
+        Digest newDigest = new OpenSSLDigest.MD5();
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+
+    /**
+     * Tests the SHA-1 implementation.
+     */
+    public void testSHA1() {
+        Digest oldDigest = new SHA1Digest();
+        Digest newDigest = new OpenSSLDigest.SHA1();
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+
+    /**
+     * Tests the SHA-256 implementation.
+     */
+    public void testSHA256() {
+        Digest oldDigest = new SHA256Digest();
+        Digest newDigest = new OpenSSLDigest.SHA256();
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+
+    /**
+     * Tests the SHA-384 implementation.
+     */
+    public void testSHA384() {
+        Digest oldDigest = new SHA384Digest();
+        Digest newDigest = new OpenSSLDigest.SHA384();
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+
+    /**
+     * Tests the SHA-512 implementation.
+     */
+    public void testSHA512() {
+        Digest oldDigest = new SHA512Digest();
+        Digest newDigest = new OpenSSLDigest.SHA512();
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+}
diff --git a/openssl/src/main/native/sub.mk b/openssl/src/main/native/sub.mk
deleted file mode 100644
index ce4d4d4..0000000
--- a/openssl/src/main/native/sub.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file is included by the top-level libcore Makefile.
-# It's not a normal makefile, so we don't include CLEAR_VARS
-# or BUILD_*_LIBRARY.
-
-LOCAL_SRC_FILES := \
-	NativeBN.cpp
-
-LOCAL_C_INCLUDES += \
-	external/openssl/include
-
-# Any shared/static libs that are listed here must also
-# be listed in libs/nativehelper/Makefile.
-# TODO: fix this requirement
-
-LOCAL_SHARED_LIBRARIES += \
-	libcrypto
-
-LOCAL_STATIC_LIBRARIES +=
diff --git a/support/src/test/java/java/security/StandardNames.java b/support/src/test/java/java/security/StandardNames.java
index 316b46e..ec34eda 100644
--- a/support/src/test/java/java/security/StandardNames.java
+++ b/support/src/test/java/java/security/StandardNames.java
@@ -263,7 +263,7 @@
             unprovide("KeyManagerFactory", "SunX509");
             provide("KeyManagerFactory", "X509");
 
-            // different names SHA vs SHA-1
+            // different names: BouncyCastle actually uses the Standard name of SHA-1 vs SHA
             unprovide("MessageDigest", "SHA");
             provide("MessageDigest", "SHA-1");
 
@@ -287,10 +287,6 @@
             // TODO remove one, probably Harmony's
             provide("CertificateFactory", "X509");
 
-            // The Harmony JSSEProvider registers an OpenSSL based MessageDigest SHA-224
-            // TODO remove it since the RI does not provide this variant
-            provide("MessageDigest", "SHA-224");
-
             // Harmony JSSEProvider is missing these
             // TODO add them
             unprovide("SSLContext", "SSLv3");