Revert "Merge Conscrypt upstream master." am: 77f9eef2d5 am: 8fc56a4d14

Original change: https://android-review.googlesource.com/c/platform/external/conscrypt/+/2821976

Change-Id: I4e93e99cc773fb1f8494bceb6f08295e945737a8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java
index d3965c7..3a7dbe7 100644
--- a/android/src/main/java/org/conscrypt/Platform.java
+++ b/android/src/main/java/org/conscrypt/Platform.java
@@ -459,6 +459,116 @@
         }
     }
 
+    /**
+     * Wraps an old AndroidOpenSSL key instance. This is not needed on platform
+     * builds since we didn't backport, so return null. This code is from
+     * Chromium's net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
+     */
+    @SuppressWarnings("LiteralClassName")
+    public static OpenSSLKey wrapRsaKey(PrivateKey javaKey) {
+        // This fixup only applies to pre-JB-MR1
+        if (Build.VERSION.SDK_INT >= 17) {
+            return null;
+        }
+
+        // First, check that this is a proper instance of OpenSSLRSAPrivateKey
+        // or one of its sub-classes.
+        Class<?> superClass;
+        try {
+            superClass =
+                    Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey");
+        } catch (Exception e) {
+            // This may happen if the target device has a completely different
+            // implementation of the java.security APIs, compared to vanilla
+            // Android. Highly unlikely, but still possible.
+            Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e);
+            return null;
+        }
+        if (!superClass.isInstance(javaKey)) {
+            // This may happen if the PrivateKey was not created by the
+            // Conscrypt provider, which should be the default. That could happen if an
+            // OEM decided to implement a different default provider. Also highly unlikely.
+            Log.e(TAG,
+                    "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:"
+                            + javaKey.getClass().getCanonicalName());
+            return null;
+        }
+
+        try {
+            // Use reflection to invoke the 'getOpenSSLKey()' method on
+            // the private key. This returns another Java object that wraps
+            // a native EVP_PKEY. Note that the method is final, so calling
+            // the superclass implementation is ok.
+            Method getKey = superClass.getDeclaredMethod("getOpenSSLKey");
+            getKey.setAccessible(true);
+            Object opensslKey = null;
+            try {
+                opensslKey = getKey.invoke(javaKey);
+            } finally {
+                getKey.setAccessible(false);
+            }
+            if (opensslKey == null) {
+                // Bail when detecting OEM "enhancement".
+                Log.e(TAG, "Could not getOpenSSLKey on instance: " + javaKey.toString());
+                return null;
+            }
+
+            // Use reflection to invoke the 'getPkeyContext' method on the
+            // result of the getOpenSSLKey(). This is an 32-bit integer
+            // which is the address of an EVP_PKEY object. Note that this
+            // method these days returns a 64-bit long, but since this code
+            // path is used for older Android versions, it may still return
+            // a 32-bit int here. To be on the safe side, we cast the return
+            // value via Number rather than directly to Integer or Long.
+            Method getPkeyContext;
+            try {
+                getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext");
+            } catch (Exception e) {
+                // Bail here too, something really not working as expected.
+                Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e);
+                return null;
+            }
+            getPkeyContext.setAccessible(true);
+            long evp_pkey = 0;
+            try {
+                evp_pkey = ((Number) getPkeyContext.invoke(opensslKey)).longValue();
+            } finally {
+                getPkeyContext.setAccessible(false);
+            }
+            if (evp_pkey == 0) {
+                // The PrivateKey is probably rotten for some reason.
+                Log.e(TAG, "getPkeyContext() returned null");
+                return null;
+            }
+            return new OpenSSLKey(evp_pkey);
+        } catch (Exception e) {
+            Log.e(TAG, "Error during conversion of privatekey instance: " + javaKey.toString(), e);
+            return null;
+        }
+    }
+
+    /**
+     * Logs to the system EventLog system.
+     */
+    @SuppressWarnings("LiteralClassName")
+    public static void logEvent(String message) {
+        try {
+            Class<?> processClass = Class.forName("android.os.Process");
+            Object processInstance = processClass.getDeclaredConstructor().newInstance();
+            Method myUidMethod = processClass.getMethod("myUid", (Class[]) null);
+            int uid = (Integer) myUidMethod.invoke(processInstance);
+
+            Class<?> eventLogClass = Class.forName("android.util.EventLog");
+            Object eventLogInstance = eventLogClass.getDeclaredConstructor().newInstance();
+            Method writeEventMethod =
+                    eventLogClass.getMethod("writeEvent", Integer.TYPE, Object[].class);
+            writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */,
+                    new Object[] {"conscrypt", uid, message});
+        } catch (Exception e) {
+            // Fail silently
+        }
+    }
+
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         // For now, don't wrap on Android.
         return engine;
diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
index d28a7d7..6d831d0 100644
--- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
@@ -4396,31 +4396,16 @@
     return resultArray.release();
 }
 
-static void NativeCrypto_CMAC_Reset(JNIEnv* env, jclass, jobject cmacCtxRef) {
-    CHECK_ERROR_QUEUE_ON_RETURN;
-    CMAC_CTX* cmacCtx = fromContextObject<CMAC_CTX>(env, cmacCtxRef);
-    JNI_TRACE("CMAC_Reset(%p)", cmacCtx);
-
-    if (cmacCtx == nullptr) {
-        return;
-    }
-
-    if (!CMAC_Reset(cmacCtx)) {
-        JNI_TRACE("CMAC_Reset(%p) => threw exception", cmacCtx);
-        conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CMAC_Reset");
-        return;
-    }
-}
-
 static jlong NativeCrypto_HMAC_CTX_new(JNIEnv* env, jclass) {
     CHECK_ERROR_QUEUE_ON_RETURN;
     JNI_TRACE("HMAC_CTX_new");
-    auto hmacCtx = HMAC_CTX_new();
+    auto hmacCtx = new HMAC_CTX;
     if (hmacCtx == nullptr) {
         conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate HMAC_CTX");
         return 0;
     }
 
+    HMAC_CTX_init(hmacCtx);
     return reinterpret_cast<jlong>(hmacCtx);
 }
 
@@ -4432,7 +4417,8 @@
         conscrypt::jniutil::throwNullPointerException(env, "hmacCtx == null");
         return;
     }
-    HMAC_CTX_free(hmacCtx);
+    HMAC_CTX_cleanup(hmacCtx);
+    delete hmacCtx;
 }
 
 static void NativeCrypto_HMAC_Init_ex(JNIEnv* env, jclass, jobject hmacCtxRef, jbyteArray keyArray,
@@ -4539,24 +4525,6 @@
     return resultArray.release();
 }
 
-static void NativeCrypto_HMAC_Reset(JNIEnv* env, jclass, jobject hmacCtxRef) {
-    CHECK_ERROR_QUEUE_ON_RETURN;
-    HMAC_CTX* hmacCtx = fromContextObject<HMAC_CTX>(env, hmacCtxRef);
-    JNI_TRACE("HMAC_Reset(%p)", hmacCtx);
-
-    if (hmacCtx == nullptr) {
-        return;
-    }
-
-    // HMAC_Init_ex with all nulls will reuse the existing key. This is slightly
-    // more efficient than re-initializing the context with the key again.
-    if (!HMAC_Init_ex(hmacCtx, /*key=*/nullptr, /*key_len=*/0, /*md=*/nullptr, /*impl=*/nullptr)) {
-        JNI_TRACE("HMAC_Reset(%p) => threw exception", hmacCtx);
-        conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "HMAC_Init_ex");
-        return;
-    }
-}
-
 static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) {
     CHECK_ERROR_QUEUE_ON_RETURN;
     JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output);
@@ -4860,20 +4828,6 @@
     return joa.release();
 }
 
-/*
- * Converts an ASN1_TIME to epoch time in milliseconds.
- */
-static jlong ASN1_TIME_convert_to_posix(JNIEnv* env, const ASN1_TIME* time) {
-    int64_t retval;
-    if (!ASN1_TIME_to_posix(time, &retval)) {
-        JNI_TRACE("ASN1_TIME_convert_to_posix(%p) => Invalid date value", time);
-        conscrypt::jniutil::throwParsingException(env, "Invalid date value");
-        return 0;
-    }
-    // ASN1_TIME_to_posix can only return years from 0000 to 9999, so this won't overflow.
-    return static_cast<jlong>(retval * 1000);
-}
-
 static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref,
                                              CONSCRYPT_UNUSED jobject holder) {
     CHECK_ERROR_QUEUE_ON_RETURN;
@@ -4888,7 +4842,7 @@
 
     ASN1_TIME* notBefore = X509_get_notBefore(x509);
     JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore);
-    return ASN1_TIME_convert_to_posix(env, notBefore);
+    return reinterpret_cast<uintptr_t>(notBefore);
 }
 
 static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref,
@@ -4905,7 +4859,7 @@
 
     ASN1_TIME* notAfter = X509_get_notAfter(x509);
     JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter);
-    return ASN1_TIME_convert_to_posix(env, notAfter);
+    return reinterpret_cast<uintptr_t>(notAfter);
 }
 
 // NOLINTNEXTLINE(runtime/int)
@@ -5541,7 +5495,7 @@
 
     JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked,
               X509_REVOKED_get0_revocationDate(revoked));
-    return ASN1_TIME_convert_to_posix(env, X509_REVOKED_get0_revocationDate(revoked));
+    return reinterpret_cast<uintptr_t>(X509_REVOKED_get0_revocationDate(revoked));
 }
 
 #ifdef __GNUC__
@@ -5635,7 +5589,7 @@
 
     ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl);
     JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate);
-    return ASN1_TIME_convert_to_posix(env, lastUpdate);
+    return reinterpret_cast<uintptr_t>(lastUpdate);
 }
 
 static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef,
@@ -5652,7 +5606,7 @@
 
     ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl);
     JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate);
-    return ASN1_TIME_convert_to_posix(env, nextUpdate);
+    return reinterpret_cast<uintptr_t>(nextUpdate);
 }
 
 static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) {
@@ -5676,6 +5630,63 @@
     return X509_supported_extension(ext);
 }
 
+static inline bool decimal_to_integer(const char* data, size_t len, int* out) {
+    int ret = 0;
+    for (size_t i = 0; i < len; i++) {
+        ret *= 10;
+        if (data[i] < '0' || data[i] > '9') {
+            return false;
+        }
+        ret += data[i] - '0';
+    }
+    *out = ret;
+    return true;
+}
+
+static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef,
+                                               jobject calendar) {
+    CHECK_ERROR_QUEUE_ON_RETURN;
+    ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef));
+    JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar);
+
+    if (asn1Time == nullptr) {
+        conscrypt::jniutil::throwNullPointerException(env, "asn1Time == null");
+        return;
+    }
+
+    if (!ASN1_TIME_check(asn1Time)) {
+        conscrypt::jniutil::throwParsingException(env, "Invalid date format");
+        return;
+    }
+
+    bssl::UniquePtr<ASN1_GENERALIZEDTIME> gen(ASN1_TIME_to_generalizedtime(asn1Time, nullptr));
+    if (gen.get() == nullptr) {
+        conscrypt::jniutil::throwParsingException(env,
+                                                  "ASN1_TIME_to_generalizedtime returned null");
+        return;
+    }
+
+    if (ASN1_STRING_length(gen.get()) < 14 || ASN1_STRING_get0_data(gen.get()) == nullptr) {
+        conscrypt::jniutil::throwNullPointerException(env, "gen->length < 14 || gen->data == null");
+        return;
+    }
+
+    int year, mon, mday, hour, min, sec;
+    const char* data = reinterpret_cast<const char*>(ASN1_STRING_get0_data(gen.get()));
+    if (!decimal_to_integer(data, 4, &year) ||
+        !decimal_to_integer(data + 4, 2, &mon) ||
+        !decimal_to_integer(data + 6, 2, &mday) ||
+        !decimal_to_integer(data + 8, 2, &hour) ||
+        !decimal_to_integer(data + 10, 2, &min) ||
+        !decimal_to_integer(data + 12, 2, &sec)) {
+        conscrypt::jniutil::throwParsingException(env, "Invalid date format");
+        return;
+    }
+
+    env->CallVoidMethod(calendar, conscrypt::jniutil::calendar_setMethod, year, mon - 1, mday, hour,
+                        min, sec);
+}
+
 // A CbsHandle is a structure used to manage resources allocated by asn1_read-*
 // functions so that they can be freed properly when finished.  This struct owns
 // all objects pointed to by its members.
@@ -10937,7 +10948,6 @@
         CONSCRYPT_NATIVE_METHOD(CMAC_Update, "(" REF_CMAC_CTX "[BII)V"),
         CONSCRYPT_NATIVE_METHOD(CMAC_UpdateDirect, "(" REF_CMAC_CTX "JI)V"),
         CONSCRYPT_NATIVE_METHOD(CMAC_Final, "(" REF_CMAC_CTX ")[B"),
-        CONSCRYPT_NATIVE_METHOD(CMAC_Reset, "(" REF_CMAC_CTX ")V"),
         CONSCRYPT_NATIVE_METHOD(EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)J"),
         CONSCRYPT_NATIVE_METHOD(EVP_PKEY_new_EC_KEY, "(" REF_EC_GROUP REF_EC_POINT "[B)J"),
         CONSCRYPT_NATIVE_METHOD(EVP_PKEY_type, "(" REF_EVP_PKEY ")I"),
@@ -11057,7 +11067,6 @@
         CONSCRYPT_NATIVE_METHOD(HMAC_Update, "(" REF_HMAC_CTX "[BII)V"),
         CONSCRYPT_NATIVE_METHOD(HMAC_UpdateDirect, "(" REF_HMAC_CTX "JI)V"),
         CONSCRYPT_NATIVE_METHOD(HMAC_Final, "(" REF_HMAC_CTX ")[B"),
-        CONSCRYPT_NATIVE_METHOD(HMAC_Reset, "(" REF_HMAC_CTX ")V"),
         CONSCRYPT_NATIVE_METHOD(RAND_bytes, "([B)V"),
         CONSCRYPT_NATIVE_METHOD(create_BIO_InputStream, ("(" REF_BIO_IN_STREAM "Z)J")),
         CONSCRYPT_NATIVE_METHOD(create_BIO_OutputStream, "(Ljava/io/OutputStream;)J"),
@@ -11130,6 +11139,7 @@
         CONSCRYPT_NATIVE_METHOD(X509_REVOKED_dup, "(J)J"),
         CONSCRYPT_NATIVE_METHOD(i2d_X509_REVOKED, "(J)[B"),
         CONSCRYPT_NATIVE_METHOD(X509_supported_extension, "(J)I"),
+        CONSCRYPT_NATIVE_METHOD(ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"),
         CONSCRYPT_NATIVE_METHOD(asn1_read_init, "([B)J"),
         CONSCRYPT_NATIVE_METHOD(asn1_read_sequence, "(J)J"),
         CONSCRYPT_NATIVE_METHOD(asn1_read_next_tag_is, "(JI)Z"),
diff --git a/common/src/main/java/org/conscrypt/ConscryptEngine.java b/common/src/main/java/org/conscrypt/ConscryptEngine.java
index a58aa73..bf3d1c8 100644
--- a/common/src/main/java/org/conscrypt/ConscryptEngine.java
+++ b/common/src/main/java/org/conscrypt/ConscryptEngine.java
@@ -441,6 +441,13 @@
             handshake();
             releaseResources = false;
         } catch (IOException e) {
+            // Write CCS errors to EventLog
+            String message = e.getMessage();
+            // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c)
+            if (message.contains("unexpected CCS")) {
+                String logMessage = String.format("ssl_unexpected_ccs: host=%s", getPeerHost());
+                Platform.logEvent(logMessage);
+            }
             closeAll();
             throw SSLUtils.toSSLHandshakeException(e);
         } finally {
diff --git a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
index eeba2bb..be0ec97 100644
--- a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
+++ b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -246,6 +246,16 @@
                         return;
                     }
                 }
+
+                // Write CCS errors to EventLog
+                String message = e.getMessage();
+                // Must match error string of SSL_R_UNEXPECTED_CCS
+                if (message.contains("unexpected CCS")) {
+                    String logMessage =
+                            String.format("ssl_unexpected_ccs: host=%s", getHostnameOrIP());
+                    Platform.logEvent(logMessage);
+                }
+
                 throw e;
             }
 
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index be48902..bd1239f 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -367,8 +367,6 @@
 
     static native byte[] CMAC_Final(NativeRef.CMAC_CTX ctx);
 
-    static native void CMAC_Reset(NativeRef.CMAC_CTX ctx);
-
     // --- HMAC functions ------------------------------------------------------
 
     static native long HMAC_CTX_new();
@@ -383,8 +381,6 @@
 
     static native byte[] HMAC_Final(NativeRef.HMAC_CTX ctx);
 
-    static native void HMAC_Reset(NativeRef.HMAC_CTX ctx);
-
     // --- HPKE functions ------------------------------------------------------
     static native byte[] EVP_HPKE_CTX_export(
             NativeRef.EVP_HPKE_CTX ctx, byte[] exporterCtx, int length);
@@ -632,6 +628,10 @@
 
     static native int X509_supported_extension(long x509ExtensionRef);
 
+    // --- ASN1_TIME -----------------------------------------------------------
+
+    static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) throws ParsingException;
+
     // --- ASN1 Encoding -------------------------------------------------------
 
     /**
diff --git a/common/src/main/java/org/conscrypt/OpenSSLKey.java b/common/src/main/java/org/conscrypt/OpenSSLKey.java
index e5e81f7..6eb94f4 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLKey.java
@@ -178,6 +178,11 @@
         if (key instanceof OpenSSLKeyHolder) {
             return ((OpenSSLKeyHolder) key).getOpenSSLKey();
         }
+
+        if ("RSA".equals(key.getAlgorithm())) {
+            return Platform.wrapRsaKey(key);
+        }
+
         return null;
     }
 
diff --git a/common/src/main/java/org/conscrypt/OpenSSLMac.java b/common/src/main/java/org/conscrypt/OpenSSLMac.java
index b8f5296..1bef88f 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLMac.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLMac.java
@@ -20,6 +20,7 @@
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
+import java.security.NoSuchAlgorithmException;
 import java.security.spec.AlgorithmParameterSpec;
 import javax.crypto.MacSpi;
 import javax.crypto.SecretKey;
@@ -30,6 +31,11 @@
 @Internal
 public abstract class OpenSSLMac extends MacSpi {
     /**
+     * The secret key used in this keyed MAC.
+     */
+    protected byte[] keyBytes;
+
+    /**
      * Holds the output size of the message digest.
      */
     private final int size;
@@ -47,11 +53,6 @@
     /**
      * Creates and initializes the relevant BoringSSL *MAC context.
      */
-    protected abstract void initContext(byte[] keyBytes);
-
-    /**
-     * Resets the context for a new operation with the same key.
-     */
     protected abstract void resetContext();
 
     /**
@@ -75,13 +76,13 @@
             throw new InvalidAlgorithmParameterException("unknown parameter type");
         }
 
-        byte[] keyBytes = key.getEncoded();
+        keyBytes = key.getEncoded();
         if (keyBytes == null) {
             throw new InvalidKeyException("key cannot be encoded");
         }
 
         try {
-            initContext(keyBytes);
+            resetContext();
         } catch (RuntimeException e) {
             throw new InvalidKeyException("invalid key", e);
         }
@@ -163,16 +164,12 @@
         }
 
         @Override
-        protected void initContext(byte[] keyBytes) {
-            NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
-            NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evpMd);
-            this.ctx = ctxLocal;
-        }
-
-        @Override
         protected void resetContext() {
-            final NativeRef.HMAC_CTX ctxLocal = ctx;
-            NativeCrypto.HMAC_Reset(ctxLocal);
+            NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
+            if (keyBytes != null) {
+                NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evpMd);
+            }
+            this.ctx = ctxLocal;
         }
 
         @Override
@@ -239,16 +236,12 @@
         }
 
         @Override
-        protected void initContext(byte[] keyBytes) {
-            NativeRef.CMAC_CTX ctxLocal = new NativeRef.CMAC_CTX(NativeCrypto.CMAC_CTX_new());
-            NativeCrypto.CMAC_Init(ctxLocal, keyBytes);
-            this.ctx = ctxLocal;
-        }
-
-        @Override
         protected void resetContext() {
-            final NativeRef.CMAC_CTX ctxLocal = ctx;
-            NativeCrypto.CMAC_Reset(ctxLocal);
+            NativeRef.CMAC_CTX ctxLocal = new NativeRef.CMAC_CTX(NativeCrypto.CMAC_CTX_new());
+            if (keyBytes != null) {
+                NativeCrypto.CMAC_Init(ctxLocal, keyBytes);
+            }
+            this.ctx = ctxLocal;
         }
 
         @Override
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
index c7e09fe..6371bbb 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -96,7 +96,12 @@
         return new OpenSSLRSAPrivateKey(key, params);
     }
 
-    static OpenSSLKey wrapPlatformKey(RSAPrivateKey rsaPrivateKey) {
+    static OpenSSLKey wrapPlatformKey(RSAPrivateKey rsaPrivateKey)
+            throws InvalidKeyException {
+        OpenSSLKey wrapper = Platform.wrapRsaKey(rsaPrivateKey);
+        if (wrapper != null) {
+            return wrapper;
+        }
         return new OpenSSLKey(NativeCrypto.getRSAPrivateKeyWrapper(rsaPrivateKey, rsaPrivateKey
                 .getModulus().toByteArray()), true);
     }
diff --git a/common/src/main/java/org/conscrypt/OpenSSLX509CRL.java b/common/src/main/java/org/conscrypt/OpenSSLX509CRL.java
index 9461faa..d3983cd 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLX509CRL.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLX509CRL.java
@@ -50,15 +50,23 @@
  */
 final class OpenSSLX509CRL extends X509CRL {
     private volatile long mContext;
-    private final long thisUpdate;
-    private final long nextUpdate;
+    private final Date thisUpdate;
+    private final Date nextUpdate;
 
     private OpenSSLX509CRL(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        thisUpdate = NativeCrypto.X509_CRL_get_lastUpdate(mContext, this);
-        nextUpdate = NativeCrypto.X509_CRL_get_nextUpdate(mContext, this);
+        thisUpdate = toDate(NativeCrypto.X509_CRL_get_lastUpdate(mContext, this));
+        nextUpdate = toDate(NativeCrypto.X509_CRL_get_nextUpdate(mContext, this));
+    }
+
+    // Package-visible because it's also used by OpenSSLX509CRLEntry
+    static Date toDate(long asn1time) throws ParsingException {
+        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+        calendar.set(Calendar.MILLISECOND, 0);
+        NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+        return calendar.getTime();
     }
 
     static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException {
@@ -270,12 +278,12 @@
 
     @Override
     public Date getThisUpdate() {
-        return new Date(thisUpdate);
+        return (Date) thisUpdate.clone();
     }
 
     @Override
     public Date getNextUpdate() {
-        return new Date(nextUpdate);
+        return (Date) nextUpdate.clone();
     }
 
     @Override
diff --git a/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java b/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java
index 2d4846c..9a3db62 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java
@@ -31,13 +31,13 @@
  */
 final class OpenSSLX509CRLEntry extends X509CRLEntry {
     private final long mContext;
-    private final long revocationDate;
+    private final Date revocationDate;
 
     OpenSSLX509CRLEntry(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        revocationDate = NativeCrypto.get_X509_REVOKED_revocationDate(mContext);
+        revocationDate = OpenSSLX509CRL.toDate(NativeCrypto.get_X509_REVOKED_revocationDate(mContext));
     }
 
     @Override
@@ -112,7 +112,7 @@
 
     @Override
     public Date getRevocationDate() {
-        return new Date(revocationDate);
+        return (Date) revocationDate.clone();
     }
 
     @Override
diff --git a/common/src/main/java/org/conscrypt/OpenSSLX509Certificate.java b/common/src/main/java/org/conscrypt/OpenSSLX509Certificate.java
index 925d60d..f5e5c5f 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLX509Certificate.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLX509Certificate.java
@@ -61,15 +61,29 @@
     private transient volatile long mContext;
     private transient Integer mHashCode;
 
-    private final long notBefore;
-    private final long notAfter;
+    private final Date notBefore;
+    private final Date notAfter;
 
     OpenSSLX509Certificate(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        notBefore = NativeCrypto.X509_get_notBefore(mContext, this);
-        notAfter = NativeCrypto.X509_get_notAfter(mContext, this);
+        notBefore = toDate(NativeCrypto.X509_get_notBefore(mContext, this));
+        notAfter = toDate(NativeCrypto.X509_get_notAfter(mContext, this));
+    }
+
+    // A non-throwing constructor used when we have already parsed the dates
+    private OpenSSLX509Certificate(long ctx, Date notBefore, Date notAfter) {
+        mContext = ctx;
+        this.notBefore = notBefore;
+        this.notAfter = notAfter;
+    }
+
+    private static Date toDate(long asn1time) throws ParsingException {
+        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+        calendar.set(Calendar.MILLISECOND, 0);
+        NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+        return calendar.getTime();
     }
 
     public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
@@ -246,12 +260,12 @@
             CertificateNotYetValidException {
         if (getNotBefore().compareTo(date) > 0) {
             throw new CertificateNotYetValidException("Certificate not valid until "
-                    + getNotBefore() + " (compared to " + date + ")");
+                    + getNotBefore().toString() + " (compared to " + date.toString() + ")");
         }
 
         if (getNotAfter().compareTo(date) < 0) {
             throw new CertificateExpiredException("Certificate expired at "
-                    + getNotAfter() + " (compared to " + date + ")");
+                    + getNotAfter().toString() + " (compared to " + date.toString() + ")");
         }
     }
 
@@ -277,12 +291,12 @@
 
     @Override
     public Date getNotBefore() {
-        return new Date(notBefore);
+        return (Date) notBefore.clone();
     }
 
     @Override
     public Date getNotAfter() {
-        return new Date(notAfter);
+        return (Date) notAfter.clone();
     }
 
     @Override
diff --git a/common/src/test/java/org/conscrypt/ConscryptJava7Suite.java b/common/src/test/java/org/conscrypt/ConscryptJava7Suite.java
new file mode 100644
index 0000000..a400599
--- /dev/null
+++ b/common/src/test/java/org/conscrypt/ConscryptJava7Suite.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 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.conscrypt;
+
+import static org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
+
+import org.conscrypt.ct.CTVerifierTest;
+import org.conscrypt.ct.SerializationTest;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersPSSTest;
+import org.conscrypt.java.security.AlgorithmParametersTestAES;
+import org.conscrypt.java.security.AlgorithmParametersTestDES;
+import org.conscrypt.java.security.AlgorithmParametersTestDESede;
+import org.conscrypt.java.security.AlgorithmParametersTestDH;
+import org.conscrypt.java.security.AlgorithmParametersTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersTestEC;
+import org.conscrypt.java.security.AlgorithmParametersTestGCM;
+import org.conscrypt.java.security.AlgorithmParametersTestOAEP;
+import org.conscrypt.java.security.KeyFactoryTestDH;
+import org.conscrypt.java.security.KeyFactoryTestDSA;
+import org.conscrypt.java.security.KeyFactoryTestEC;
+import org.conscrypt.java.security.KeyFactoryTestRSA;
+import org.conscrypt.java.security.KeyPairGeneratorTest;
+import org.conscrypt.java.security.KeyPairGeneratorTestDH;
+import org.conscrypt.java.security.KeyPairGeneratorTestDSA;
+import org.conscrypt.java.security.KeyPairGeneratorTestRSA;
+import org.conscrypt.java.security.MessageDigestTest;
+import org.conscrypt.java.security.SignatureTest;
+import org.conscrypt.java.security.cert.CertificateFactoryTest;
+import org.conscrypt.java.security.cert.X509CRLTest;
+import org.conscrypt.java.security.cert.X509CertificateTest;
+import org.conscrypt.javax.crypto.AeadCipherTest;
+import org.conscrypt.javax.crypto.CipherBasicsTest;
+import org.conscrypt.javax.crypto.KeyGeneratorTest;
+import org.conscrypt.javax.net.ssl.HttpsURLConnectionTest;
+import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
+import org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
+import org.conscrypt.javax.net.ssl.SNIHostNameTest;
+import org.conscrypt.javax.net.ssl.SSLContextTest;
+import org.conscrypt.javax.net.ssl.SSLEngineTest;
+import org.conscrypt.javax.net.ssl.SSLEngineVersionCompatibilityTest;
+import org.conscrypt.javax.net.ssl.SSLParametersTest;
+import org.conscrypt.javax.net.ssl.SSLServerSocketFactoryTest;
+import org.conscrypt.javax.net.ssl.SSLServerSocketTest;
+import org.conscrypt.javax.net.ssl.SSLSessionContextTest;
+import org.conscrypt.javax.net.ssl.SSLSessionTest;
+import org.conscrypt.javax.net.ssl.SSLSocketFactoryTest;
+import org.conscrypt.javax.net.ssl.SSLSocketTest;
+import org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest;
+import org.conscrypt.javax.net.ssl.TrustManagerFactoryTest;
+import org.conscrypt.javax.net.ssl.X509KeyManagerTest;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+        // org.conscrypt tests
+        CertPinManagerTest.class,
+        ChainStrengthAnalyzerTest.class,
+        TrustManagerImplTest.class,
+        // org.conscrypt.ct tests
+        CTVerifierTest.class,
+        SerializationTest.class,
+        // java.security tests
+        CertificateFactoryTest.class,
+        X509CertificateTest.class,
+        X509CRLTest.class,
+        AlgorithmParameterGeneratorTestDH.class,
+        AlgorithmParameterGeneratorTestDSA.class,
+        AlgorithmParametersPSSTest.class,
+        AlgorithmParametersTestAES.class,
+        AlgorithmParametersTestDES.class,
+        AlgorithmParametersTestDESede.class,
+        AlgorithmParametersTestDH.class,
+        AlgorithmParametersTestDSA.class,
+        AlgorithmParametersTestEC.class,
+        AlgorithmParametersTestGCM.class,
+        AlgorithmParametersTestOAEP.class,
+        KeyFactoryTestDH.class,
+        KeyFactoryTestDSA.class,
+        KeyFactoryTestEC.class,
+        KeyFactoryTestRSA.class,
+        KeyPairGeneratorTest.class,
+        KeyPairGeneratorTestDH.class,
+        KeyPairGeneratorTestDSA.class,
+        KeyPairGeneratorTestRSA.class,
+        MessageDigestTest.class,
+        SignatureTest.class,
+        // javax.crypto tests
+        AeadCipherTest.class,
+        CipherBasicsTest.class,
+        // CipherTest.class,  // Lots of weird, broken behaviors in Sun* providers on OpenJDK 7
+        // ECDHKeyAgreementTest.class,  // EC keys are broken on OpenJDK 7
+        KeyGeneratorTest.class,
+        // javax.net.ssl tests
+        HttpsURLConnectionTest.class,
+        KeyManagerFactoryTest.class,
+        KeyStoreBuilderParametersTest.class,
+        SNIHostNameTest.class,
+        SSLContextTest.class,
+        SSLEngineTest.class,
+        SSLEngineVersionCompatibilityTest.class,
+        SSLParametersTest.class,
+        SSLServerSocketFactoryTest.class,
+        SSLServerSocketTest.class,
+        SSLSessionContextTest.class,
+        SSLSessionTest.class,
+        SSLSocketFactoryTest.class,
+        SSLSocketTest.class,
+        SSLSocketVersionCompatibilityTest.class,
+        TrustManagerFactoryTest.class,
+        X509KeyManagerTest.class,
+})
+public class ConscryptJava7Suite {
+
+    @BeforeClass
+    public static void setupStatic() {
+        installConscryptAsDefaultProvider();
+    }
+
+}
diff --git a/common/src/test/java/org/conscrypt/ConscryptSuite.java b/common/src/test/java/org/conscrypt/ConscryptSuite.java
new file mode 100644
index 0000000..c0950f2
--- /dev/null
+++ b/common/src/test/java/org/conscrypt/ConscryptSuite.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 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.conscrypt;
+
+import static org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
+
+import org.conscrypt.ct.CTVerifierTest;
+import org.conscrypt.ct.SerializationTest;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersPSSTest;
+import org.conscrypt.java.security.AlgorithmParametersTestAES;
+import org.conscrypt.java.security.AlgorithmParametersTestDES;
+import org.conscrypt.java.security.AlgorithmParametersTestDESede;
+import org.conscrypt.java.security.AlgorithmParametersTestDH;
+import org.conscrypt.java.security.AlgorithmParametersTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersTestEC;
+import org.conscrypt.java.security.AlgorithmParametersTestGCM;
+import org.conscrypt.java.security.AlgorithmParametersTestOAEP;
+import org.conscrypt.java.security.KeyFactoryTestDH;
+import org.conscrypt.java.security.KeyFactoryTestDSA;
+import org.conscrypt.java.security.KeyFactoryTestEC;
+import org.conscrypt.java.security.KeyFactoryTestRSA;
+import org.conscrypt.java.security.KeyFactoryTestRSACrt;
+import org.conscrypt.java.security.KeyFactoryTestRSACustom;
+import org.conscrypt.java.security.KeyFactoryTestXDH;
+import org.conscrypt.java.security.KeyPairGeneratorTest;
+import org.conscrypt.java.security.KeyPairGeneratorTestDH;
+import org.conscrypt.java.security.KeyPairGeneratorTestDSA;
+import org.conscrypt.java.security.KeyPairGeneratorTestRSA;
+import org.conscrypt.java.security.KeyPairGeneratorTestXDH;
+import org.conscrypt.java.security.MessageDigestTest;
+import org.conscrypt.java.security.SignatureTest;
+import org.conscrypt.java.security.cert.CertificateFactoryTest;
+import org.conscrypt.java.security.cert.X509CRLTest;
+import org.conscrypt.java.security.cert.X509CertificateTest;
+import org.conscrypt.javax.crypto.AeadCipherTest;
+import org.conscrypt.javax.crypto.CipherBasicsTest;
+import org.conscrypt.javax.crypto.CipherTest;
+import org.conscrypt.javax.crypto.ECDHKeyAgreementTest;
+import org.conscrypt.javax.crypto.KeyGeneratorTest;
+import org.conscrypt.javax.crypto.XDHKeyAgreementTest;
+import org.conscrypt.javax.net.ssl.HttpsURLConnectionTest;
+import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
+import org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
+import org.conscrypt.javax.net.ssl.SNIHostNameTest;
+import org.conscrypt.javax.net.ssl.SSLContextTest;
+import org.conscrypt.javax.net.ssl.SSLEngineTest;
+import org.conscrypt.javax.net.ssl.SSLEngineVersionCompatibilityTest;
+import org.conscrypt.javax.net.ssl.SSLParametersTest;
+import org.conscrypt.javax.net.ssl.SSLServerSocketFactoryTest;
+import org.conscrypt.javax.net.ssl.SSLServerSocketTest;
+import org.conscrypt.javax.net.ssl.SSLSessionContextTest;
+import org.conscrypt.javax.net.ssl.SSLSessionTest;
+import org.conscrypt.javax.net.ssl.SSLSocketFactoryTest;
+import org.conscrypt.javax.net.ssl.SSLSocketTest;
+import org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest;
+import org.conscrypt.javax.net.ssl.TrustManagerFactoryTest;
+import org.conscrypt.javax.net.ssl.X509KeyManagerTest;
+import org.conscrypt.metrics.CipherSuiteTest;
+import org.conscrypt.metrics.OptionalMethodTest;
+import org.conscrypt.metrics.ProtocolTest;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+        // org.conscrypt tests
+        CertPinManagerTest.class,
+        ChainStrengthAnalyzerTest.class,
+        HostnameVerifierTest.class,
+        HpkeContextRecipientTest.class,
+        HpkeContextSenderTest.class,
+        HpkeContextTest.class,
+        HpkeSuiteTest.class,
+        HpkeTestVectorsTest.class,
+        NativeCryptoArgTest.class,
+        TrustManagerImplTest.class,
+        // org.conscrypt.ct tests
+        CTVerifierTest.class,
+        SerializationTest.class,
+        // java.security tests
+        CertificateFactoryTest.class,
+        X509CertificateTest.class,
+        X509CRLTest.class,
+        AlgorithmParameterGeneratorTestDH.class,
+        AlgorithmParameterGeneratorTestDSA.class,
+        AlgorithmParametersPSSTest.class,
+        AlgorithmParametersTestAES.class,
+        AlgorithmParametersTestDES.class,
+        AlgorithmParametersTestDESede.class,
+        AlgorithmParametersTestDH.class,
+        AlgorithmParametersTestDSA.class,
+        AlgorithmParametersTestEC.class,
+        AlgorithmParametersTestGCM.class,
+        AlgorithmParametersTestOAEP.class,
+        BufferUtilsTest.class,
+        CipherSuiteTest.class,
+        KeyFactoryTestDH.class,
+        KeyFactoryTestDSA.class,
+        KeyFactoryTestEC.class,
+        KeyFactoryTestRSA.class,
+        KeyFactoryTestRSACrt.class,
+        KeyFactoryTestRSACustom.class,
+        KeyFactoryTestXDH.class,
+        KeyPairGeneratorTest.class,
+        KeyPairGeneratorTestDH.class,
+        KeyPairGeneratorTestDSA.class,
+        KeyPairGeneratorTestRSA.class,
+        KeyPairGeneratorTestXDH.class,
+        MessageDigestTest.class,
+        SignatureTest.class,
+        // javax.crypto tests
+        AeadCipherTest.class,
+        CipherBasicsTest.class,
+        CipherTest.class,
+        MacTest.class,
+        ECDHKeyAgreementTest.class,
+        KeyGeneratorTest.class,
+        XDHKeyAgreementTest.class,
+        // javax.net.ssl tests
+        HttpsURLConnectionTest.class,
+        KeyManagerFactoryTest.class,
+        KeyStoreBuilderParametersTest.class,
+        OptionalMethodTest.class,
+        ProtocolTest.class,
+        SNIHostNameTest.class,
+        SSLContextTest.class,
+        SSLEngineTest.class,
+        SSLEngineVersionCompatibilityTest.class,
+        SSLParametersTest.class,
+        SSLServerSocketFactoryTest.class,
+        SSLServerSocketTest.class,
+        SSLSessionContextTest.class,
+        SSLSessionTest.class,
+        SSLSocketFactoryTest.class,
+        SSLSocketTest.class,
+        SSLSocketVersionCompatibilityTest.class,
+        TrustManagerFactoryTest.class,
+        VeryBasicHttpServerTest.class,
+        X509KeyManagerTest.class,
+})
+public class ConscryptSuite {
+
+    @BeforeClass
+    public static void setupStatic() {
+        installConscryptAsDefaultProvider();
+    }
+
+}
diff --git a/common/src/test/java/org/conscrypt/HostnameVerifierTest.java b/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
index 969518b..253ca34 100644
--- a/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
+++ b/common/src/test/java/org/conscrypt/HostnameVerifierTest.java
@@ -598,7 +598,7 @@
         //
         // Certificate generated using:-
         //     openssl req -x509 -nodes -days 36500 -subj "/CN=Google Inc" \
-        //         -addext "subjectAltName=DNS:*.com" -
+        //         -addext "subjectAltName=DNS:*.com" -newkey rsa:512
         SSLSession session = session(""
                 + "-----BEGIN CERTIFICATE-----\n"
                 + "MIIBlTCCAT+gAwIBAgIUe1RB6C61ZW/SEQpKiywSEJOEOUMwDQYJKoZIhvcNAQEL\n"
diff --git a/common/src/test/java/org/conscrypt/MacTest.java b/common/src/test/java/org/conscrypt/MacTest.java
index b258563..1fadbd6 100644
--- a/common/src/test/java/org/conscrypt/MacTest.java
+++ b/common/src/test/java/org/conscrypt/MacTest.java
@@ -127,11 +127,6 @@
             macBytes = generateReusingMac(algorithm, keyBytes, msgBytes);
             assertArrayEquals(failMessage("Re-use Mac", baseFailMsg, macBytes),
                     expectedBytes, macBytes);
-
-            // Calculated using a pre-loved Mac with the same key
-            macBytes = generateReusingMacSameKey(algorithm, secretKey, msgBytes);
-            assertArrayEquals(failMessage("Re-use Mac same key", baseFailMsg, macBytes),
-                    expectedBytes, macBytes);
         }
     }
 
@@ -387,19 +382,6 @@
         return mac.doFinal();
     }
 
-    private byte[] generateReusingMacSameKey(String algorithm, SecretKeySpec key, byte[] message)
-            throws Exception {
-        Mac mac = getConscryptMac(algorithm, key);
-
-        // Calculate a MAC over some other message.
-        byte[] otherMessage = new byte[message.length];
-        mac.doFinal(otherMessage);
-
-        // The MAC should now have been reset to compute a new MAC with the same
-        // key.
-        return mac.doFinal(message);
-    }
-
     private Mac getConscryptMac(String algorithm) throws Exception {
         return getConscryptMac(algorithm, null);
     }
diff --git a/openjdk/build.gradle b/openjdk/build.gradle
index cda93c3..2c0adb1 100644
--- a/openjdk/build.gradle
+++ b/openjdk/build.gradle
@@ -315,12 +315,28 @@
     publishing.publications.maven.artifact jarTask.get()
 }
 
+
+// TODO(prb) Still provide a mechanism for testing on Java 7?
+// Check which version
+//def javaError = new ByteArrayOutputStream()
+//exec {
+//    executable test.executable
+//    System.out.println("Running tests with java executable: " + test.executable + ".")
+//    args = ['-version']
+//    ignoreExitValue true
+//    errorOutput = javaError
+//}
+//
+//def suiteClass = (javaError.toString() =~ /"1[.]7[.].*"/) ?
+//        "org/conscrypt/ConscryptJava7Suite.class" : "org/conscrypt/ConscryptSuite.class";
+def suiteClass = "org/conscrypt/ConscryptSuite.class";
+
 test {
-    include "org/conscrypt/ConscryptOpenJdkSuite.class"
+    include suiteClass, "org/conscrypt/ConscryptOpenJdkSuite.class"
 }
 
 def testFdSocket = tasks.register("testFdSocket", Test) {
-    include "org/conscrypt/ConscryptOpenJdkSuite.class"
+    include suiteClass, "org/conscrypt/ConscryptOpenJdkSuite.class"
     InvokerHelper.setProperties(testLogging, test.testLogging.properties)
     systemProperties = test.systemProperties
     systemProperty "org.conscrypt.useEngineSocketByDefault", false
@@ -391,7 +407,6 @@
 
                     if (toolChain in Clang || toolChain in Gcc) {
                         cppCompiler.args "-Wall",
-                                "-Werror",
                                 "-fPIC",
                                 "-O3",
                                 "-std=c++17",
diff --git a/openjdk/src/main/java/org/conscrypt/Platform.java b/openjdk/src/main/java/org/conscrypt/Platform.java
index 24ade2c..4211c31 100644
--- a/openjdk/src/main/java/org/conscrypt/Platform.java
+++ b/openjdk/src/main/java/org/conscrypt/Platform.java
@@ -344,6 +344,20 @@
     }
 
     /**
+     * Wraps an old AndroidOpenSSL key instance. This is not needed on RI.
+     */
+    @SuppressWarnings("unused")
+    static OpenSSLKey wrapRsaKey(@SuppressWarnings("unused") PrivateKey javaKey) {
+        return null;
+    }
+
+    /**
+     * Logs to the system EventLog system.
+     */
+    @SuppressWarnings("unused")
+    static void logEvent(@SuppressWarnings("unused") String message) {}
+
+    /**
      * For unbundled versions, SNI is always enabled by default.
      */
     @SuppressWarnings("unused")
diff --git a/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java b/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
index b55ca1b..813eaac 100644
--- a/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
+++ b/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
@@ -1,173 +1,35 @@
-/*
- * Copyright (C) 2023 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.conscrypt;
 
 import static org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
 
-import org.conscrypt.ct.CTVerifierTest;
-import org.conscrypt.ct.SerializationTest;
-import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
-import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
-import org.conscrypt.java.security.AlgorithmParametersPSSTest;
-import org.conscrypt.java.security.AlgorithmParametersTestAES;
-import org.conscrypt.java.security.AlgorithmParametersTestDES;
-import org.conscrypt.java.security.AlgorithmParametersTestDESede;
-import org.conscrypt.java.security.AlgorithmParametersTestDH;
-import org.conscrypt.java.security.AlgorithmParametersTestDSA;
-import org.conscrypt.java.security.AlgorithmParametersTestEC;
-import org.conscrypt.java.security.AlgorithmParametersTestGCM;
-import org.conscrypt.java.security.AlgorithmParametersTestOAEP;
-import org.conscrypt.java.security.KeyFactoryTestDH;
-import org.conscrypt.java.security.KeyFactoryTestDSA;
-import org.conscrypt.java.security.KeyFactoryTestEC;
-import org.conscrypt.java.security.KeyFactoryTestRSA;
-import org.conscrypt.java.security.KeyFactoryTestRSACrt;
-import org.conscrypt.java.security.KeyPairGeneratorTest;
-import org.conscrypt.java.security.KeyPairGeneratorTestDH;
-import org.conscrypt.java.security.KeyPairGeneratorTestDSA;
-import org.conscrypt.java.security.KeyPairGeneratorTestRSA;
-import org.conscrypt.java.security.KeyPairGeneratorTestXDH;
-import org.conscrypt.java.security.MessageDigestTest;
-import org.conscrypt.java.security.SignatureTest;
-import org.conscrypt.java.security.cert.CertificateFactoryTest;
-import org.conscrypt.java.security.cert.X509CRLTest;
-import org.conscrypt.java.security.cert.X509CertificateTest;
-import org.conscrypt.javax.crypto.AeadCipherTest;
-import org.conscrypt.javax.crypto.CipherBasicsTest;
-import org.conscrypt.javax.crypto.CipherTest;
-import org.conscrypt.javax.crypto.ECDHKeyAgreementTest;
-import org.conscrypt.javax.crypto.KeyGeneratorTest;
-import org.conscrypt.javax.crypto.ScryptTest;
-import org.conscrypt.javax.crypto.XDHKeyAgreementTest;
-import org.conscrypt.javax.net.ssl.HttpsURLConnectionTest;
-import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
-import org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
-import org.conscrypt.javax.net.ssl.SNIHostNameTest;
-import org.conscrypt.javax.net.ssl.SSLContextTest;
-import org.conscrypt.javax.net.ssl.SSLEngineTest;
-import org.conscrypt.javax.net.ssl.SSLEngineVersionCompatibilityTest;
-import org.conscrypt.javax.net.ssl.SSLParametersTest;
-import org.conscrypt.javax.net.ssl.SSLServerSocketFactoryTest;
-import org.conscrypt.javax.net.ssl.SSLServerSocketTest;
-import org.conscrypt.javax.net.ssl.SSLSessionContextTest;
-import org.conscrypt.javax.net.ssl.SSLSessionTest;
-import org.conscrypt.javax.net.ssl.SSLSocketFactoryTest;
-import org.conscrypt.javax.net.ssl.SSLSocketTest;
-import org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest;
-import org.conscrypt.javax.net.ssl.TrustManagerFactoryTest;
-import org.conscrypt.javax.net.ssl.X509KeyManagerTest;
-import org.conscrypt.metrics.CipherSuiteTest;
-import org.conscrypt.metrics.OptionalMethodTest;
-import org.conscrypt.metrics.ProtocolTest;
 import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        // org.conscrypt tests
-        AddressUtilsTest.class,
-        ApplicationProtocolSelectorAdapterTest.class,
-        CertPinManagerTest.class,
-        ChainStrengthAnalyzerTest.class,
-        ClientSessionContextTest.class,
-        ConscryptSocketTest.class,
-        ConscryptTest.class,
-        DuckTypedHpkeSpiTest.class,
-        DuckTypedPSKKeyManagerTest.class,
-        FileClientSessionCacheTest.class,
-        HostnameVerifierTest.class,
-        NativeCryptoArgTest.class,
-        NativeCryptoTest.class,
-        NativeRefTest.class,
-        NativeSslSessionTest.class,
-        OpenSSLKeyTest.class,
-        OpenSSLX509CertificateTest.class,
-        PlatformTest.class,
-        SSLUtilsTest.class,
-        ServerSessionContextTest.class,
-        TestSessionBuilderTest.class,
-        TrustManagerImplTest.class,
-        // org.conscrypt.ct tests
-        CTVerifierTest.class,
-        SerializationTest.class,
-        // java.security tests
-        CertificateFactoryTest.class,
-        X509CertificateTest.class,
-        X509CRLTest.class,
-        AlgorithmParameterGeneratorTestDH.class,
-        AlgorithmParameterGeneratorTestDSA.class,
-        AlgorithmParametersPSSTest.class,
-        AlgorithmParametersTestAES.class,
-        AlgorithmParametersTestDES.class,
-        AlgorithmParametersTestDESede.class,
-        AlgorithmParametersTestDH.class,
-        AlgorithmParametersTestDSA.class,
-        AlgorithmParametersTestEC.class,
-        AlgorithmParametersTestGCM.class,
-        AlgorithmParametersTestOAEP.class,
-        BufferUtilsTest.class,
-        CipherSuiteTest.class,
-        KeyFactoryTestDH.class,
-        KeyFactoryTestDSA.class,
-        KeyFactoryTestEC.class,
-        KeyFactoryTestRSA.class,
-        KeyFactoryTestRSACrt.class,
-        KeyPairGeneratorTest.class,
-        KeyPairGeneratorTestDH.class,
-        KeyPairGeneratorTestDSA.class,
-        KeyPairGeneratorTestRSA.class,
-        KeyPairGeneratorTestXDH.class,
-        MessageDigestTest.class,
-        SignatureTest.class,
-        // javax.crypto tests
-        AeadCipherTest.class,
-        CipherBasicsTest.class,
-        CipherTest.class,
-        MacTest.class,
-        ECDHKeyAgreementTest.class,
-        KeyGeneratorTest.class,
-        XDHKeyAgreementTest.class,
-        // javax.net.ssl tests
-        HttpsURLConnectionTest.class,
-        KeyManagerFactoryTest.class,
-        KeyStoreBuilderParametersTest.class,
-        OptionalMethodTest.class,
-        ProtocolTest.class,
-        ScryptTest.class,
-        SNIHostNameTest.class,
-        SSLContextTest.class,
-        SSLEngineTest.class,
-        SSLEngineVersionCompatibilityTest.class,
-        SSLParametersTest.class,
-        SSLServerSocketFactoryTest.class,
-        SSLServerSocketTest.class,
-        SSLSessionContextTest.class,
-        SSLSessionTest.class,
-        SSLSocketFactoryTest.class,
-        SSLSocketTest.class,
-        SSLSocketVersionCompatibilityTest.class,
-        TrustManagerFactoryTest.class,
-        VeryBasicHttpServerTest.class,
-        X509KeyManagerTest.class,
+  AddressUtilsTest.class,
+  ApplicationProtocolSelectorAdapterTest.class,
+  ClientSessionContextTest.class,
+  ConscryptSocketTest.class,
+  ConscryptTest.class,
+  DuckTypedPSKKeyManagerTest.class,
+  FileClientSessionCacheTest.class,
+  NativeCryptoTest.class,
+  NativeRefTest.class,
+  NativeSslSessionTest.class,
+  OpenSSLKeyTest.class,
+  OpenSSLX509CertificateTest.class,
+  PlatformTest.class,
+  ServerSessionContextTest.class,
+  SSLUtilsTest.class,
+  TestSessionBuilderTest.class,
 })
 public class ConscryptOpenJdkSuite {
-    @BeforeClass
-    public static void setupStatic() {
-        installConscryptAsDefaultProvider();
-    }
+
+  @BeforeClass
+  public static void setupStatic() {
+    installConscryptAsDefaultProvider();
+  }
+
 }
diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java
index 215f031..005d4e4 100644
--- a/platform/src/main/java/org/conscrypt/Platform.java
+++ b/platform/src/main/java/org/conscrypt/Platform.java
@@ -264,6 +264,35 @@
         }
     }
 
+    /**
+     * Wraps an old AndroidOpenSSL key instance. This is not needed on platform
+     * builds since we didn't backport, so return null.
+     */
+    static OpenSSLKey wrapRsaKey(PrivateKey key) {
+        return null;
+    }
+
+    /**
+     * Logs to the system EventLog system.
+     */
+    static void logEvent(String message) {
+        try {
+            Class processClass = Class.forName("android.os.Process");
+            Object processInstance = processClass.newInstance();
+            Method myUidMethod = processClass.getMethod("myUid", (Class[]) null);
+            int uid = (Integer) myUidMethod.invoke(processInstance);
+
+            Class eventLogClass = Class.forName("android.util.EventLog");
+            Object eventLogInstance = eventLogClass.newInstance();
+            Method writeEventMethod = eventLogClass.getMethod(
+                    "writeEvent", new Class[] {Integer.TYPE, Object[].class});
+            writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */,
+                    new Object[] {"conscrypt", uid, message});
+        } catch (Exception e) {
+            // Do not log and fail silently
+        }
+    }
+
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         return new Java8EngineWrapper(engine);
     }
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
index 46c03a9..d1152b2 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptEngine.java
@@ -441,6 +441,13 @@
             handshake();
             releaseResources = false;
         } catch (IOException e) {
+            // Write CCS errors to EventLog
+            String message = e.getMessage();
+            // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c)
+            if (message.contains("unexpected CCS")) {
+                String logMessage = String.format("ssl_unexpected_ccs: host=%s", getPeerHost());
+                Platform.logEvent(logMessage);
+            }
             closeAll();
             throw SSLUtils.toSSLHandshakeException(e);
         } finally {
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
index 72b98ef..1724e48 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/ConscryptFileDescriptorSocket.java
@@ -246,6 +246,16 @@
                         return;
                     }
                 }
+
+                // Write CCS errors to EventLog
+                String message = e.getMessage();
+                // Must match error string of SSL_R_UNEXPECTED_CCS
+                if (message.contains("unexpected CCS")) {
+                    String logMessage =
+                            String.format("ssl_unexpected_ccs: host=%s", getHostnameOrIP());
+                    Platform.logEvent(logMessage);
+                }
+
                 throw e;
             }
 
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
index fac5b69..f53c91d 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/NativeCrypto.java
@@ -378,8 +378,6 @@
 
     static native byte[] CMAC_Final(NativeRef.CMAC_CTX ctx);
 
-    static native void CMAC_Reset(NativeRef.CMAC_CTX ctx);
-
     // --- HMAC functions ------------------------------------------------------
 
     static native long HMAC_CTX_new();
@@ -394,8 +392,6 @@
 
     static native byte[] HMAC_Final(NativeRef.HMAC_CTX ctx);
 
-    static native void HMAC_Reset(NativeRef.HMAC_CTX ctx);
-
     // --- HPKE functions ------------------------------------------------------
     static native byte[] EVP_HPKE_CTX_export(
             NativeRef.EVP_HPKE_CTX ctx, byte[] exporterCtx, int length);
@@ -658,6 +654,12 @@
     @android.compat.annotation.UnsupportedAppUsage
     static native int X509_supported_extension(long x509ExtensionRef);
 
+    // --- ASN1_TIME -----------------------------------------------------------
+
+    @android.compat.annotation.UnsupportedAppUsage
+    static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal)
+            throws ParsingException;
+
     // --- ASN1 Encoding -------------------------------------------------------
 
     /**
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
index 9034c31..bc09c81 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLKey.java
@@ -182,6 +182,11 @@
         if (key instanceof OpenSSLKeyHolder) {
             return ((OpenSSLKeyHolder) key).getOpenSSLKey();
         }
+
+        if ("RSA".equals(key.getAlgorithm())) {
+            return Platform.wrapRsaKey(key);
+        }
+
         return null;
     }
 
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
index 974f08f..7b3ee3b 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLMac.java
@@ -21,6 +21,7 @@
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
+import java.security.NoSuchAlgorithmException;
 import java.security.spec.AlgorithmParameterSpec;
 import javax.crypto.MacSpi;
 import javax.crypto.SecretKey;
@@ -32,6 +33,11 @@
 @Internal
 public abstract class OpenSSLMac extends MacSpi {
     /**
+     * The secret key used in this keyed MAC.
+     */
+    protected byte[] keyBytes;
+
+    /**
      * Holds the output size of the message digest.
      */
     private final int size;
@@ -49,11 +55,6 @@
     /**
      * Creates and initializes the relevant BoringSSL *MAC context.
      */
-    protected abstract void initContext(byte[] keyBytes);
-
-    /**
-     * Resets the context for a new operation with the same key.
-     */
     protected abstract void resetContext();
 
     /**
@@ -77,13 +78,13 @@
             throw new InvalidAlgorithmParameterException("unknown parameter type");
         }
 
-        byte[] keyBytes = key.getEncoded();
+        keyBytes = key.getEncoded();
         if (keyBytes == null) {
             throw new InvalidKeyException("key cannot be encoded");
         }
 
         try {
-            initContext(keyBytes);
+            resetContext();
         } catch (RuntimeException e) {
             throw new InvalidKeyException("invalid key", e);
         }
@@ -168,16 +169,12 @@
         }
 
         @Override
-        protected void initContext(byte[] keyBytes) {
-            NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
-            NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evpMd);
-            this.ctx = ctxLocal;
-        }
-
-        @Override
         protected void resetContext() {
-            final NativeRef.HMAC_CTX ctxLocal = ctx;
-            NativeCrypto.HMAC_Reset(ctxLocal);
+            NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
+            if (keyBytes != null) {
+                NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evpMd);
+            }
+            this.ctx = ctxLocal;
         }
 
         @Override
@@ -264,16 +261,12 @@
         }
 
         @Override
-        protected void initContext(byte[] keyBytes) {
-            NativeRef.CMAC_CTX ctxLocal = new NativeRef.CMAC_CTX(NativeCrypto.CMAC_CTX_new());
-            NativeCrypto.CMAC_Init(ctxLocal, keyBytes);
-            this.ctx = ctxLocal;
-        }
-
-        @Override
         protected void resetContext() {
-            final NativeRef.CMAC_CTX ctxLocal = ctx;
-            NativeCrypto.CMAC_Reset(ctxLocal);
+            NativeRef.CMAC_CTX ctxLocal = new NativeRef.CMAC_CTX(NativeCrypto.CMAC_CTX_new());
+            if (keyBytes != null) {
+                NativeCrypto.CMAC_Init(ctxLocal, keyBytes);
+            }
+            this.ctx = ctxLocal;
         }
 
         @Override
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
index d74c0bd..0170d1b 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -97,7 +97,12 @@
         return new OpenSSLRSAPrivateKey(key, params);
     }
 
-    static OpenSSLKey wrapPlatformKey(RSAPrivateKey rsaPrivateKey) {
+    static OpenSSLKey wrapPlatformKey(RSAPrivateKey rsaPrivateKey)
+            throws InvalidKeyException {
+        OpenSSLKey wrapper = Platform.wrapRsaKey(rsaPrivateKey);
+        if (wrapper != null) {
+            return wrapper;
+        }
         return new OpenSSLKey(NativeCrypto.getRSAPrivateKeyWrapper(rsaPrivateKey, rsaPrivateKey
                 .getModulus().toByteArray()), true);
     }
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
index e870647..da20605 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRL.java
@@ -51,15 +51,23 @@
  */
 final class OpenSSLX509CRL extends X509CRL {
     private volatile long mContext;
-    private final long thisUpdate;
-    private final long nextUpdate;
+    private final Date thisUpdate;
+    private final Date nextUpdate;
 
     private OpenSSLX509CRL(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        thisUpdate = NativeCrypto.X509_CRL_get_lastUpdate(mContext, this);
-        nextUpdate = NativeCrypto.X509_CRL_get_nextUpdate(mContext, this);
+        thisUpdate = toDate(NativeCrypto.X509_CRL_get_lastUpdate(mContext, this));
+        nextUpdate = toDate(NativeCrypto.X509_CRL_get_nextUpdate(mContext, this));
+    }
+
+    // Package-visible because it's also used by OpenSSLX509CRLEntry
+    static Date toDate(long asn1time) throws ParsingException {
+        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+        calendar.set(Calendar.MILLISECOND, 0);
+        NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+        return calendar.getTime();
     }
 
     static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException {
@@ -272,12 +280,12 @@
 
     @Override
     public Date getThisUpdate() {
-        return new Date(thisUpdate);
+        return (Date) thisUpdate.clone();
     }
 
     @Override
     public Date getNextUpdate() {
-        return new Date(nextUpdate);
+        return (Date) nextUpdate.clone();
     }
 
     @Override
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java
index 2ba5f71..d8c5d9e 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509CRLEntry.java
@@ -32,13 +32,13 @@
  */
 final class OpenSSLX509CRLEntry extends X509CRLEntry {
     private final long mContext;
-    private final long revocationDate;
+    private final Date revocationDate;
 
     OpenSSLX509CRLEntry(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        revocationDate = NativeCrypto.get_X509_REVOKED_revocationDate(mContext);
+        revocationDate = OpenSSLX509CRL.toDate(NativeCrypto.get_X509_REVOKED_revocationDate(mContext));
     }
 
     @Override
@@ -113,7 +113,7 @@
 
     @Override
     public Date getRevocationDate() {
-        return new Date(revocationDate);
+        return (Date) revocationDate.clone();
     }
 
     @Override
diff --git a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
index e827b83..b007dbc 100644
--- a/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
+++ b/repackaged/common/src/main/java/com/android/org/conscrypt/OpenSSLX509Certificate.java
@@ -63,15 +63,29 @@
     @android.compat.annotation.UnsupportedAppUsage private transient volatile long mContext;
     private transient Integer mHashCode;
 
-    private final long notBefore;
-    private final long notAfter;
+    private final Date notBefore;
+    private final Date notAfter;
 
     OpenSSLX509Certificate(long ctx) throws ParsingException {
         mContext = ctx;
         // The legacy X509 OpenSSL APIs don't validate ASN1_TIME structures until access, so
         // parse them here because this is the only time we're allowed to throw ParsingException
-        notBefore = NativeCrypto.X509_get_notBefore(mContext, this);
-        notAfter = NativeCrypto.X509_get_notAfter(mContext, this);
+        notBefore = toDate(NativeCrypto.X509_get_notBefore(mContext, this));
+        notAfter = toDate(NativeCrypto.X509_get_notAfter(mContext, this));
+    }
+
+    // A non-throwing constructor used when we have already parsed the dates
+    private OpenSSLX509Certificate(long ctx, Date notBefore, Date notAfter) {
+        mContext = ctx;
+        this.notBefore = notBefore;
+        this.notAfter = notAfter;
+    }
+
+    private static Date toDate(long asn1time) throws ParsingException {
+        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+        calendar.set(Calendar.MILLISECOND, 0);
+        NativeCrypto.ASN1_TIME_to_Calendar(asn1time, calendar);
+        return calendar.getTime();
     }
 
     public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
@@ -247,12 +261,12 @@
             throws CertificateExpiredException, CertificateNotYetValidException {
         if (getNotBefore().compareTo(date) > 0) {
             throw new CertificateNotYetValidException("Certificate not valid until "
-                    + getNotBefore() + " (compared to " + date + ")");
+                    + getNotBefore().toString() + " (compared to " + date.toString() + ")");
         }
 
         if (getNotAfter().compareTo(date) < 0) {
-            throw new CertificateExpiredException(
-                    "Certificate expired at " + getNotAfter() + " (compared to " + date + ")");
+            throw new CertificateExpiredException("Certificate expired at "
+                    + getNotAfter().toString() + " (compared to " + date.toString() + ")");
         }
     }
 
@@ -278,12 +292,12 @@
 
     @Override
     public Date getNotBefore() {
-        return new Date(notBefore);
+        return (Date) notBefore.clone();
     }
 
     @Override
     public Date getNotAfter() {
-        return new Date(notAfter);
+        return (Date) notAfter.clone();
     }
 
     @Override
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java
index 280aefa..f3da396 100644
--- a/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/HostnameVerifierTest.java
@@ -603,7 +603,7 @@
         //
         // Certificate generated using:-
         //     openssl req -x509 -nodes -days 36500 -subj "/CN=Google Inc" \
-        //         -addext "subjectAltName=DNS:*.com" -
+        //         -addext "subjectAltName=DNS:*.com" -newkey rsa:512
         SSLSession session = session(""
                 + "-----BEGIN CERTIFICATE-----\n"
                 + "MIIBlTCCAT+gAwIBAgIUe1RB6C61ZW/SEQpKiywSEJOEOUMwDQYJKoZIhvcNAQEL\n"
diff --git a/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java b/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java
index 899343f..d0a1c64 100644
--- a/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java
+++ b/repackaged/common/src/test/java/com/android/org/conscrypt/MacTest.java
@@ -131,11 +131,6 @@
             macBytes = generateReusingMac(algorithm, keyBytes, msgBytes);
             assertArrayEquals(failMessage("Re-use Mac", baseFailMsg, macBytes),
                     expectedBytes, macBytes);
-
-            // Calculated using a pre-loved Mac with the same key
-            macBytes = generateReusingMacSameKey(algorithm, secretKey, msgBytes);
-            assertArrayEquals(failMessage("Re-use Mac same key", baseFailMsg, macBytes),
-                    expectedBytes, macBytes);
         }
     }
 
@@ -396,19 +391,6 @@
         return mac.doFinal();
     }
 
-    private byte[] generateReusingMacSameKey(String algorithm, SecretKeySpec key, byte[] message)
-            throws Exception {
-        Mac mac = getConscryptMac(algorithm, key);
-
-        // Calculate a MAC over some other message.
-        byte[] otherMessage = new byte[message.length];
-        mac.doFinal(otherMessage);
-
-        // The MAC should now have been reset to compute a new MAC with the same
-        // key.
-        return mac.doFinal(message);
-    }
-
     private Mac getConscryptMac(String algorithm) throws Exception {
         return getConscryptMac(algorithm, null);
     }
diff --git a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
index 079458c..8f45a24 100644
--- a/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
+++ b/repackaged/openjdk/src/main/java/com/android/org/conscrypt/Platform.java
@@ -345,6 +345,20 @@
     }
 
     /**
+     * Wraps an old AndroidOpenSSL key instance. This is not needed on RI.
+     */
+    @SuppressWarnings("unused")
+    static OpenSSLKey wrapRsaKey(@SuppressWarnings("unused") PrivateKey javaKey) {
+        return null;
+    }
+
+    /**
+     * Logs to the system EventLog system.
+     */
+    @SuppressWarnings("unused")
+    static void logEvent(@SuppressWarnings("unused") String message) {}
+
+    /**
      * For unbundled versions, SNI is always enabled by default.
      */
     @SuppressWarnings("unused")
diff --git a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java
index 3465e1b..42d9663 100644
--- a/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java
+++ b/repackaged/openjdk/src/test/java/com/android/org/conscrypt/ConscryptOpenJdkSuite.java
@@ -1,79 +1,8 @@
 /* GENERATED SOURCE. DO NOT MODIFY. */
-/*
- * Copyright (C) 2023 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 com.android.org.conscrypt;
 
 import static com.android.org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
 
-import com.android.org.conscrypt.ct.CTVerifierTest;
-import com.android.org.conscrypt.ct.SerializationTest;
-import com.android.org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
-import com.android.org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
-import com.android.org.conscrypt.java.security.AlgorithmParametersPSSTest;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestAES;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestDES;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestDESede;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestDH;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestDSA;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestEC;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestGCM;
-import com.android.org.conscrypt.java.security.AlgorithmParametersTestOAEP;
-import com.android.org.conscrypt.java.security.KeyFactoryTestDH;
-import com.android.org.conscrypt.java.security.KeyFactoryTestDSA;
-import com.android.org.conscrypt.java.security.KeyFactoryTestEC;
-import com.android.org.conscrypt.java.security.KeyFactoryTestRSA;
-import com.android.org.conscrypt.java.security.KeyFactoryTestRSACrt;
-import com.android.org.conscrypt.java.security.KeyPairGeneratorTest;
-import com.android.org.conscrypt.java.security.KeyPairGeneratorTestDH;
-import com.android.org.conscrypt.java.security.KeyPairGeneratorTestDSA;
-import com.android.org.conscrypt.java.security.KeyPairGeneratorTestRSA;
-import com.android.org.conscrypt.java.security.KeyPairGeneratorTestXDH;
-import com.android.org.conscrypt.java.security.MessageDigestTest;
-import com.android.org.conscrypt.java.security.SignatureTest;
-import com.android.org.conscrypt.java.security.cert.CertificateFactoryTest;
-import com.android.org.conscrypt.java.security.cert.X509CRLTest;
-import com.android.org.conscrypt.java.security.cert.X509CertificateTest;
-import com.android.org.conscrypt.javax.crypto.AeadCipherTest;
-import com.android.org.conscrypt.javax.crypto.CipherBasicsTest;
-import com.android.org.conscrypt.javax.crypto.CipherTest;
-import com.android.org.conscrypt.javax.crypto.ECDHKeyAgreementTest;
-import com.android.org.conscrypt.javax.crypto.KeyGeneratorTest;
-import com.android.org.conscrypt.javax.crypto.ScryptTest;
-import com.android.org.conscrypt.javax.crypto.XDHKeyAgreementTest;
-import com.android.org.conscrypt.javax.net.ssl.HttpsURLConnectionTest;
-import com.android.org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
-import com.android.org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
-import com.android.org.conscrypt.javax.net.ssl.SNIHostNameTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLContextTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLEngineTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLEngineVersionCompatibilityTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLParametersTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLServerSocketFactoryTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLServerSocketTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLSessionContextTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLSessionTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLSocketFactoryTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLSocketTest;
-import com.android.org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest;
-import com.android.org.conscrypt.javax.net.ssl.TrustManagerFactoryTest;
-import com.android.org.conscrypt.javax.net.ssl.X509KeyManagerTest;
-import com.android.org.conscrypt.metrics.CipherSuiteTest;
-import com.android.org.conscrypt.metrics.OptionalMethodTest;
-import com.android.org.conscrypt.metrics.ProtocolTest;
 import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -83,95 +12,28 @@
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        // org.conscrypt tests
-        AddressUtilsTest.class,
-        ApplicationProtocolSelectorAdapterTest.class,
-        CertPinManagerTest.class,
-        ChainStrengthAnalyzerTest.class,
-        ClientSessionContextTest.class,
-        ConscryptSocketTest.class,
-        ConscryptTest.class,
-        DuckTypedHpkeSpiTest.class,
-        DuckTypedPSKKeyManagerTest.class,
-        FileClientSessionCacheTest.class,
-        HostnameVerifierTest.class,
-        NativeCryptoArgTest.class,
-        NativeCryptoTest.class,
-        NativeRefTest.class,
-        NativeSslSessionTest.class,
-        OpenSSLKeyTest.class,
-        OpenSSLX509CertificateTest.class,
-        PlatformTest.class,
-        SSLUtilsTest.class,
-        ServerSessionContextTest.class,
-        TestSessionBuilderTest.class,
-        TrustManagerImplTest.class,
-        // org.conscrypt.ct tests
-        CTVerifierTest.class,
-        SerializationTest.class,
-        // java.security tests
-        CertificateFactoryTest.class,
-        X509CertificateTest.class,
-        X509CRLTest.class,
-        AlgorithmParameterGeneratorTestDH.class,
-        AlgorithmParameterGeneratorTestDSA.class,
-        AlgorithmParametersPSSTest.class,
-        AlgorithmParametersTestAES.class,
-        AlgorithmParametersTestDES.class,
-        AlgorithmParametersTestDESede.class,
-        AlgorithmParametersTestDH.class,
-        AlgorithmParametersTestDSA.class,
-        AlgorithmParametersTestEC.class,
-        AlgorithmParametersTestGCM.class,
-        AlgorithmParametersTestOAEP.class,
-        BufferUtilsTest.class,
-        CipherSuiteTest.class,
-        KeyFactoryTestDH.class,
-        KeyFactoryTestDSA.class,
-        KeyFactoryTestEC.class,
-        KeyFactoryTestRSA.class,
-        KeyFactoryTestRSACrt.class,
-        KeyPairGeneratorTest.class,
-        KeyPairGeneratorTestDH.class,
-        KeyPairGeneratorTestDSA.class,
-        KeyPairGeneratorTestRSA.class,
-        KeyPairGeneratorTestXDH.class,
-        MessageDigestTest.class,
-        SignatureTest.class,
-        // javax.crypto tests
-        AeadCipherTest.class,
-        CipherBasicsTest.class,
-        CipherTest.class,
-        MacTest.class,
-        ECDHKeyAgreementTest.class,
-        KeyGeneratorTest.class,
-        XDHKeyAgreementTest.class,
-        // javax.net.ssl tests
-        HttpsURLConnectionTest.class,
-        KeyManagerFactoryTest.class,
-        KeyStoreBuilderParametersTest.class,
-        OptionalMethodTest.class,
-        ProtocolTest.class,
-        ScryptTest.class,
-        SNIHostNameTest.class,
-        SSLContextTest.class,
-        SSLEngineTest.class,
-        SSLEngineVersionCompatibilityTest.class,
-        SSLParametersTest.class,
-        SSLServerSocketFactoryTest.class,
-        SSLServerSocketTest.class,
-        SSLSessionContextTest.class,
-        SSLSessionTest.class,
-        SSLSocketFactoryTest.class,
-        SSLSocketTest.class,
-        SSLSocketVersionCompatibilityTest.class,
-        TrustManagerFactoryTest.class,
-        VeryBasicHttpServerTest.class,
-        X509KeyManagerTest.class,
+  AddressUtilsTest.class,
+  ApplicationProtocolSelectorAdapterTest.class,
+  ClientSessionContextTest.class,
+  ConscryptSocketTest.class,
+  ConscryptTest.class,
+  DuckTypedPSKKeyManagerTest.class,
+  FileClientSessionCacheTest.class,
+  NativeCryptoTest.class,
+  NativeRefTest.class,
+  NativeSslSessionTest.class,
+  OpenSSLKeyTest.class,
+  OpenSSLX509CertificateTest.class,
+  PlatformTest.class,
+  ServerSessionContextTest.class,
+  SSLUtilsTest.class,
+  TestSessionBuilderTest.class,
 })
 public class ConscryptOpenJdkSuite {
-    @BeforeClass
-    public static void setupStatic() {
-        installConscryptAsDefaultProvider();
-    }
+
+  @BeforeClass
+  public static void setupStatic() {
+    installConscryptAsDefaultProvider();
+  }
+
 }
diff --git a/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
index 1a34afb..5eb8812 100644
--- a/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
+++ b/repackaged/platform/src/main/java/com/android/org/conscrypt/Platform.java
@@ -265,6 +265,35 @@
         }
     }
 
+    /**
+     * Wraps an old AndroidOpenSSL key instance. This is not needed on platform
+     * builds since we didn't backport, so return null.
+     */
+    static OpenSSLKey wrapRsaKey(PrivateKey key) {
+        return null;
+    }
+
+    /**
+     * Logs to the system EventLog system.
+     */
+    static void logEvent(String message) {
+        try {
+            Class processClass = Class.forName("android.os.Process");
+            Object processInstance = processClass.newInstance();
+            Method myUidMethod = processClass.getMethod("myUid", (Class[]) null);
+            int uid = (Integer) myUidMethod.invoke(processInstance);
+
+            Class eventLogClass = Class.forName("android.util.EventLog");
+            Object eventLogInstance = eventLogClass.newInstance();
+            Method writeEventMethod = eventLogClass.getMethod(
+                    "writeEvent", new Class[] {Integer.TYPE, Object[].class});
+            writeEventMethod.invoke(eventLogInstance, 0x534e4554 /* SNET */,
+                    new Object[] {"conscrypt", uid, message});
+        } catch (Exception e) {
+            // Do not log and fail silently
+        }
+    }
+
     static SSLEngine wrapEngine(ConscryptEngine engine) {
         return new Java8EngineWrapper(engine);
     }
diff --git a/srcgen/unsupported-app-usage.json b/srcgen/unsupported-app-usage.json
index a8233e1..12935e9 100644
--- a/srcgen/unsupported-app-usage.json
+++ b/srcgen/unsupported-app-usage.json
@@ -125,6 +125,9 @@
     "@location": "method:com.android.org.conscrypt.NativeCrypto#ASN1_seq_unpack_X509_bio(long)"
   },
   {
+    "@location": "method:com.android.org.conscrypt.NativeCrypto#ASN1_TIME_to_Calendar(long,Calendar)"
+  },
+  {
     "@location": "method:com.android.org.conscrypt.NativeCrypto#BIO_free_all(long)"
   },
   {