Some parsing and serializing fixes. (#219)

This fixes a memory leak in NativeCrypto_i2d_PKCS7. It never frees
derBytes. Also removing a dependency on the legacy ASN.1 stack.
diff --git a/common/src/jni/main/cpp/NativeCrypto.cpp b/common/src/jni/main/cpp/NativeCrypto.cpp
index e4256c2..7220acc 100644
--- a/common/src/jni/main/cpp/NativeCrypto.cpp
+++ b/common/src/jni/main/cpp/NativeCrypto.cpp
@@ -308,6 +308,35 @@
 }
 
 /**
+ * Finishes a pending CBB and returns a jbyteArray with the contents.
+ */
+jbyteArray CBBToByteArray(JNIEnv* env, CBB* cbb) {
+    uint8_t *data;
+    size_t len;
+    if (!CBB_finish(cbb, &data, &len)) {
+        Errors::jniThrowRuntimeException(env, "CBB_finish failed");
+        JNI_TRACE("creating byte array failed");
+        return nullptr;
+    }
+    bssl::UniquePtr<uint8_t> free_data(data);
+
+    ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(static_cast<jsize>(len)));
+    if (byteArray.get() == nullptr) {
+        JNI_TRACE("creating byte array failed");
+        return nullptr;
+    }
+
+    ScopedByteArrayRW bytes(env, byteArray.get());
+    if (bytes.get() == nullptr) {
+        JNI_TRACE("using byte array failed");
+        return nullptr;
+    }
+
+    memcpy(bytes.get(), data, len);
+    return byteArray.release();
+}
+
+/**
  * Converts ASN.1 BIT STRING to a jbooleanArray.
  */
 jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) {
@@ -1028,90 +1057,106 @@
 }
 
 /*
- * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[])
+ * static native byte[] EVP_marshal_private_key(long)
  */
-static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_marshal_private_key(JNIEnv* env, jclass, jobject pkeyRef) {
     EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
-    JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey);
+    JNI_TRACE("EVP_marshal_private_key(%p)", pkey);
 
     if (pkey == nullptr) {
         return nullptr;
     }
 
-    bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> pkcs8(EVP_PKEY2PKCS8(pkey));
-    if (pkcs8.get() == nullptr) {
-        Errors::throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO");
-        JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey);
+    bssl::ScopedCBB cbb;
+    if (!CBB_init(cbb.get(), 64)) {
+        Errors::jniThrowOutOfMemory(env, "CBB_init failed");
+        JNI_TRACE("CBB_init failed");
         return nullptr;
     }
 
-    return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO>(env, pkcs8.get(), i2d_PKCS8_PRIV_KEY_INFO);
+    if (!EVP_marshal_private_key(cbb.get(), pkey)) {
+        Errors::throwExceptionIfNecessary(env, "EVP_marshal_private_key");
+        JNI_TRACE("key=%p EVP_marshal_private_key => error", pkey);
+        return nullptr;
+    }
+
+    return CBBToByteArray(env, cbb.get());
 }
 
 /*
- * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[])
+ * static native long EVP_parse_private_key(byte[])
  */
-static jlong NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
-    JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes);
+static jlong NativeCrypto_EVP_parse_private_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+    JNI_TRACE("EVP_parse_private_key(%p)", keyJavaBytes);
 
     ScopedByteArrayRO bytes(env, keyJavaBytes);
     if (bytes.get() == nullptr) {
-        JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes);
+        JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
         return 0;
     }
 
-    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
-    bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> pkcs8(
-            d2i_PKCS8_PRIV_KEY_INFO(nullptr, &tmp, static_cast<long>(bytes.size())));
-    if (pkcs8.get() == nullptr) {
-        Errors::throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
-        JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes);
+    CBS cbs;
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(bytes.get()), bytes.size());
+    bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs));
+    if (!pkey || CBS_len(&cbs) != 0) {
+        Errors::throwParsingException(env, "Error parsing private key");
+        JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
         return 0;
     }
 
-    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKCS82PKEY(pkcs8.get()));
-    if (pkey.get() == nullptr) {
-        Errors::throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
-        JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes);
-        return 0;
-    }
-
-    JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get());
+    JNI_TRACE("bytes=%p EVP_parse_private_key => %p", keyJavaBytes, pkey.get());
     return reinterpret_cast<uintptr_t>(pkey.release());
 }
 
 /*
- * static native byte[] i2d_PUBKEY(int)
+ * static native byte[] EVP_marshal_public_key(long)
  */
-static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_marshal_public_key(JNIEnv* env, jclass, jobject pkeyRef) {
     EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
-    JNI_TRACE("i2d_PUBKEY(%p)", pkey);
+    JNI_TRACE("EVP_marshal_public_key(%p)", pkey);
+
     if (pkey == nullptr) {
         return nullptr;
     }
-    return ASN1ToByteArray<EVP_PKEY>(env, pkey, reinterpret_cast<int (*) (EVP_PKEY*, uint8_t **)>(i2d_PUBKEY));
+
+    bssl::ScopedCBB cbb;
+    if (!CBB_init(cbb.get(), 64)) {
+        Errors::jniThrowOutOfMemory(env, "CBB_init failed");
+        JNI_TRACE("CBB_init failed");
+        return nullptr;
+    }
+
+    if (!EVP_marshal_public_key(cbb.get(), pkey)) {
+        Errors::throwExceptionIfNecessary(env, "EVP_marshal_public_key");
+        JNI_TRACE("key=%p EVP_marshal_public_key => error", pkey);
+        return nullptr;
+    }
+
+    return CBBToByteArray(env, cbb.get());
 }
 
 /*
- * static native int d2i_PUBKEY(byte[])
+ * static native long EVP_parse_public_key(byte[])
  */
-static jlong NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) {
-    JNI_TRACE("d2i_PUBKEY(%p)", javaBytes);
+static jlong NativeCrypto_EVP_parse_public_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+    JNI_TRACE("EVP_parse_public_key(%p)", keyJavaBytes);
 
-    ScopedByteArrayRO bytes(env, javaBytes);
+    ScopedByteArrayRO bytes(env, keyJavaBytes);
     if (bytes.get() == nullptr) {
-        JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes);
+        JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
         return 0;
     }
 
-    const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
-    bssl::UniquePtr<EVP_PKEY> pkey(d2i_PUBKEY(nullptr, &tmp, static_cast<long>(bytes.size())));
-    if (pkey.get() == nullptr) {
-        JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes);
-        Errors::throwExceptionIfNecessary(env, "d2i_PUBKEY");
+    CBS cbs;
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(bytes.get()), bytes.size());
+    bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_public_key(&cbs));
+    if (!pkey || CBS_len(&cbs) != 0) {
+        Errors::throwParsingException(env, "Error parsing public key");
+        JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
         return 0;
     }
 
+    JNI_TRACE("bytes=%p EVP_parse_public_key => %p", keyJavaBytes, pkey.get());
     return reinterpret_cast<uintptr_t>(pkey.release());
 }
 
@@ -4437,29 +4482,7 @@
 
     sk_X509_free(stack);
 
-    uint8_t *derBytes;
-    size_t derLen;
-    if (!CBB_finish(out.get(), &derBytes, &derLen)) {
-        Errors::throwExceptionIfNecessary(env, "CBB_finish");
-        return nullptr;
-    }
-
-    ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(static_cast<jsize>(derLen)));
-    if (byteArray.get() == nullptr) {
-        JNI_TRACE("creating byte array failed");
-        return nullptr;
-    }
-
-    ScopedByteArrayRW bytes(env, byteArray.get());
-    if (bytes.get() == nullptr) {
-        JNI_TRACE("using byte array failed");
-        return nullptr;
-    }
-
-    uint8_t* p = reinterpret_cast<unsigned char*>(bytes.get());
-    memcpy(p, derBytes, derLen);
-
-    return byteArray.release();
+    return CBBToByteArray(env, out.get());
 }
 
 static jlongArray NativeCrypto_PEM_read_bio_PKCS7(JNIEnv* env, jclass, jlong bioRef, jint which) {
@@ -4638,29 +4661,7 @@
         }
     }
 
-    uint8_t *out;
-    size_t out_len;
-    if (!CBB_finish(result.get(), &out, &out_len)) {
-        return nullptr;
-    }
-    std::unique_ptr<uint8_t> out_storage(out);
-
-    ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(static_cast<jsize>(out_len)));
-    if (byteArray.get() == nullptr) {
-        JNI_TRACE("ASN1_seq_pack_X509(%p) => creating byte array failed", certs);
-        return nullptr;
-    }
-
-    ScopedByteArrayRW bytes(env, byteArray.get());
-    if (bytes.get() == nullptr) {
-        JNI_TRACE("ASN1_seq_pack_X509(%p) => using byte array failed", certs);
-        return nullptr;
-    }
-
-    uint8_t *p = reinterpret_cast<uint8_t*>(bytes.get());
-    memcpy(p, out, out_len);
-
-    return byteArray.release();
+    return CBBToByteArray(env, result.get());
 }
 
 static void NativeCrypto_X509_free(JNIEnv* env, jclass, jlong x509Ref) {
@@ -9162,10 +9163,10 @@
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_params, "(" REF_EVP_PKEY ")Ljava/lang/String;"),
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(J)V"),
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(" REF_EVP_PKEY REF_EVP_PKEY ")I"),
-        CONSCRYPT_NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(" REF_EVP_PKEY ")[B"),
-        CONSCRYPT_NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)J"),
-        CONSCRYPT_NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(" REF_EVP_PKEY ")[B"),
-        CONSCRYPT_NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)J"),
+        CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_marshal_private_key, "(" REF_EVP_PKEY ")[B"),
+        CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_parse_private_key, "([B)J"),
+        CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_marshal_public_key, "(" REF_EVP_PKEY ")[B"),
+        CONSCRYPT_NATIVE_METHOD(NativeCrypto, EVP_parse_public_key, "([B)J"),
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, PEM_read_bio_PUBKEY, "(J)J"),
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, PEM_read_bio_PrivateKey, "(J)J"),
         CONSCRYPT_NATIVE_METHOD(NativeCrypto, getRSAPrivateKeyWrapper, "(Ljava/security/PrivateKey;[B)J"),
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index b77805e..773c38c 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -80,13 +80,13 @@
 
     static native int EVP_PKEY_cmp(NativeRef.EVP_PKEY pkey1, NativeRef.EVP_PKEY pkey2);
 
-    static native byte[] i2d_PKCS8_PRIV_KEY_INFO(NativeRef.EVP_PKEY pkey);
+    static native byte[] EVP_marshal_private_key(NativeRef.EVP_PKEY pkey);
 
-    static native long d2i_PKCS8_PRIV_KEY_INFO(byte[] data);
+    static native long EVP_parse_private_key(byte[] data);
 
-    static native byte[] i2d_PUBKEY(NativeRef.EVP_PKEY pkey);
+    static native byte[] EVP_marshal_public_key(NativeRef.EVP_PKEY pkey);
 
-    static native long d2i_PUBKEY(byte[] data);
+    static native long EVP_parse_public_key(byte[] data);
 
     static native long PEM_read_bio_PUBKEY(long bioCtx);
 
diff --git a/common/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java b/common/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java
index c0e1654..a466812 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLECPrivateKey.java
@@ -161,7 +161,7 @@
 
     @Override
     public byte[] getEncoded() {
-        return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getNativeRef());
+        return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
     }
 
     @Override
@@ -214,7 +214,7 @@
 
     @Override
     public int hashCode() {
-        return Arrays.hashCode(NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getNativeRef()));
+        return Arrays.hashCode(NativeCrypto.EVP_marshal_private_key(key.getNativeRef()));
     }
 
     @Override
@@ -231,7 +231,7 @@
 
         byte[] encoded = (byte[]) stream.readObject();
 
-        key = new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(encoded));
+        key = new OpenSSLKey(NativeCrypto.EVP_parse_private_key(encoded));
         group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
                 NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
     }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLECPublicKey.java b/common/src/main/java/org/conscrypt/OpenSSLECPublicKey.java
index 6e32810..792a282 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLECPublicKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLECPublicKey.java
@@ -87,7 +87,7 @@
 
     @Override
     public byte[] getEncoded() {
-        return NativeCrypto.i2d_PUBKEY(key.getNativeRef());
+        return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
     }
 
     @Override
@@ -143,7 +143,7 @@
 
     @Override
     public int hashCode() {
-        return Arrays.hashCode(NativeCrypto.i2d_PUBKEY(key.getNativeRef()));
+        return Arrays.hashCode(NativeCrypto.EVP_marshal_public_key(key.getNativeRef()));
     }
 
     @Override
@@ -156,7 +156,7 @@
 
         byte[] encoded = (byte[]) stream.readObject();
 
-        key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(encoded));
+        key = new OpenSSLKey(NativeCrypto.EVP_parse_public_key(encoded));
         group = new OpenSSLECGroupContext(new NativeRef.EC_GROUP(
                 NativeCrypto.EC_KEY_get1_group(key.getNativeRef())));
     }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLKey.java b/common/src/main/java/org/conscrypt/OpenSSLKey.java
index 1ca0b2c..54af772 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLKey.java
@@ -73,7 +73,7 @@
             throw new InvalidKeyException("Key encoding is null");
         }
 
-        return new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(key.getEncoded()));
+        return new OpenSSLKey(NativeCrypto.EVP_parse_private_key(key.getEncoded()));
     }
 
     /**
@@ -177,7 +177,7 @@
         if (encoded == null) {
             return null;
         }
-        return new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(encoded));
+        return new OpenSSLKey(NativeCrypto.EVP_parse_private_key(encoded));
     }
 
     /**
@@ -222,7 +222,7 @@
         }
 
         try {
-            return new OpenSSLKey(NativeCrypto.d2i_PUBKEY(key.getEncoded()));
+            return new OpenSSLKey(NativeCrypto.EVP_parse_public_key(key.getEncoded()));
         } catch (Exception e) {
             throw new InvalidKeyException(e);
         }
@@ -267,7 +267,7 @@
 
         final OpenSSLKey key;
         try {
-            key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(x509KeySpec.getEncoded()));
+            key = new OpenSSLKey(NativeCrypto.EVP_parse_public_key(x509KeySpec.getEncoded()));
         } catch (Exception e) {
             throw new InvalidKeySpecException(e);
         }
@@ -300,7 +300,7 @@
 
         final OpenSSLKey key;
         try {
-            key = new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(pkcs8KeySpec.getEncoded()));
+            key = new OpenSSLKey(NativeCrypto.EVP_parse_private_key(pkcs8KeySpec.getEncoded()));
         } catch (Exception e) {
             throw new InvalidKeySpecException(e);
         }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
index 259e38e..8c2e4df 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -198,7 +198,7 @@
 
     @Override
     public final byte[] getEncoded() {
-        return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getNativeRef());
+        return NativeCrypto.EVP_marshal_private_key(key.getNativeRef());
     }
 
     @Override
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
index 40d878d..ffc672f 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPublicKey.java
@@ -96,7 +96,7 @@
 
     @Override
     public byte[] getEncoded() {
-        return NativeCrypto.i2d_PUBKEY(key.getNativeRef());
+        return NativeCrypto.EVP_marshal_public_key(key.getNativeRef());
     }
 
     private void ensureReadParams() {
diff --git a/platform/src/main/java/org/conscrypt/InternalUtil.java b/platform/src/main/java/org/conscrypt/InternalUtil.java
index 40937c8..dbc6137 100644
--- a/platform/src/main/java/org/conscrypt/InternalUtil.java
+++ b/platform/src/main/java/org/conscrypt/InternalUtil.java
@@ -30,7 +30,7 @@
 @Internal
 public final class InternalUtil {
     public static PublicKey logKeyToPublicKey(byte[] logKey) throws NoSuchAlgorithmException {
-        return new OpenSSLKey(NativeCrypto.d2i_PUBKEY(logKey)).getPublicKey();
+        return new OpenSSLKey(NativeCrypto.EVP_parse_public_key(logKey)).getPublicKey();
     }
 
     public static PublicKey readPublicKeyPem(InputStream pem) throws InvalidKeyException, NoSuchAlgorithmException {