Snap for 7652338 from a6d06322f44b1e750d07bafbc2f1a7f436c2c8ac to mainline-wifi-release

Change-Id: I17f4708881839d0c5364071170723e4797a04e4c
diff --git a/suspend/1.0/default/SystemSuspend.cpp b/suspend/1.0/default/SystemSuspend.cpp
index 81f3d45..e9bb646 100644
--- a/suspend/1.0/default/SystemSuspend.cpp
+++ b/suspend/1.0/default/SystemSuspend.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <fcntl.h>
 #include <hidl/Status.h>
@@ -70,8 +71,8 @@
     std::string reasonlines;
 
     lseek(fd, 0, SEEK_SET);
-    if (!ReadFdToString(fd, &reasonlines)) {
-        LOG(ERROR) << "failed to read wakeup reasons";
+    if (!ReadFdToString(fd, &reasonlines) || reasonlines.empty()) {
+        PLOG(ERROR) << "failed to read wakeup reasons";
         // Return unknown wakeup reason if we fail to read
         return {kUnknownWakeup};
     }
@@ -236,6 +237,17 @@
     }
 }
 
+unique_fd SystemSuspend::reopenFileUsingFd(const int fd, const int permission) {
+    string filePath = android::base::StringPrintf("/proc/self/fd/%d", fd);
+
+    unique_fd tempFd{TEMP_FAILURE_RETRY(open(filePath.c_str(), permission))};
+    if (tempFd < 0) {
+        PLOG(ERROR) << "SystemSuspend: Error opening file, using path: " << filePath;
+        return unique_fd(-1);
+    }
+    return tempFd;
+}
+
 void SystemSuspend::initAutosuspend() {
     std::thread autosuspendThread([this] {
         while (true) {
@@ -268,6 +280,12 @@
             updateSleepTime(success, suspendTime);
 
             std::vector<std::string> wakeupReasons = readWakeupReasons(mWakeupReasonsFd);
+            if (wakeupReasons == std::vector<std::string>({kUnknownWakeup})) {
+                LOG(INFO) << "Unknown/empty wakeup reason. Re-opening wakeup_reason file.";
+
+                mWakeupReasonsFd =
+                    std::move(reopenFileUsingFd(mWakeupReasonsFd.get(), O_CLOEXEC | O_RDONLY));
+            }
             mWakeupList.update(wakeupReasons);
 
             mControlService->notifyWakeup(success, wakeupReasons);
diff --git a/suspend/1.0/default/SystemSuspend.h b/suspend/1.0/default/SystemSuspend.h
index 5632325..b84b1c9 100644
--- a/suspend/1.0/default/SystemSuspend.h
+++ b/suspend/1.0/default/SystemSuspend.h
@@ -114,6 +114,7 @@
     Result<SuspendStats> getSuspendStats();
     void getSuspendInfo(SuspendInfo* info);
     std::chrono::milliseconds getSleepTime() const;
+    unique_fd reopenFileUsingFd(const int fd, int permission);
 
    private:
     void initAutosuspend();
diff --git a/wifi/keystore/1.0/default/keystore.cpp b/wifi/keystore/1.0/default/keystore.cpp
index a8faa10..69bac18 100644
--- a/wifi/keystore/1.0/default/keystore.cpp
+++ b/wifi/keystore/1.0/default/keystore.cpp
@@ -7,19 +7,17 @@
 #include <android-base/strings.h>
 #include <android/binder_manager.h>
 #include <binder/IServiceManager.h>
-#include <ctype.h>
 #include <openssl/base.h>
 #include <openssl/bio.h>
 #include <openssl/pem.h>
 #include <openssl/x509.h>
 #include <private/android_filesystem_config.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
-#include <future>
 #include <vector>
 
+#include "wifikeystorehal_utils.h"
+
 #define AT __func__ << ":" << __LINE__ << " "
 
 namespace ks2 = ::aidl::android::system::keystore2;
@@ -35,43 +33,6 @@
 
 const std::string keystore2_grant_id_prefix("ks2_keystore-engine_grant_id:");
 
-// Helper method to extract public key from the certificate.
-std::vector<uint8_t> extractPubKey(const std::vector<uint8_t>& cert_bytes) {
-    bssl::UniquePtr<BIO> cert_bio(BIO_new_mem_buf(cert_bytes.data(), cert_bytes.size()));
-    if (!cert_bio) {
-        LOG(ERROR) << AT << "Failed to create BIO";
-        return {};
-    }
-    bssl::UniquePtr<X509> decoded_cert(d2i_X509_bio(cert_bio.get(), nullptr));
-    if (!decoded_cert) {
-        LOG(INFO) << AT << "Could not decode the cert, trying decoding as PEM";
-        decoded_cert =
-            bssl::UniquePtr<X509>(PEM_read_bio_X509(cert_bio.get(), nullptr, nullptr, nullptr));
-    }
-    if (!decoded_cert) {
-        LOG(ERROR) << AT << "Could not decode the cert.";
-        return {};
-    }
-    bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(decoded_cert.get()));
-    if (!pub_key) {
-        LOG(ERROR) << AT << "Could not extract public key.";
-        return {};
-    }
-    bssl::UniquePtr<BIO> pub_key_bio(BIO_new(BIO_s_mem()));
-    if (!pub_key_bio || i2d_PUBKEY_bio(pub_key_bio.get(), pub_key.get()) <= 0) {
-        LOG(ERROR) << AT << "Could not serialize public key.";
-        return {};
-    }
-    const uint8_t* pub_key_bytes;
-    size_t pub_key_len;
-    if (!BIO_mem_contents(pub_key_bio.get(), &pub_key_bytes, &pub_key_len)) {
-        LOG(ERROR) << AT << "Could not get bytes from BIO.";
-        return {};
-    }
-
-    return {pub_key_bytes, pub_key_bytes + pub_key_len};
-}
-
 ks2::KeyDescriptor mkKeyDescriptor(const std::string& alias) {
     // If the key_id starts with the grant id prefix, we parse the following string as numeric
     // grant id. We can then use the grant domain without alias to load the designated key.
@@ -101,6 +62,46 @@
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 
+// Helper method to convert certs in DER format to PEM format required by
+// openssl library used by supplicant. If boringssl cannot parse the input as one or more
+// X509 certificates in DER encoding, this function returns the input as-is. The assumption in
+// that case is that either the `cert_bytes` is already PEM encoded, or `cert_bytes` is something
+// completely different that was intentionally installed by the Wi-Fi subsystem and it must not
+// be changed here.
+// If any error occurs during PEM encoding, this function returns std::nullopt and logs an error.
+std::optional<hidl_vec<uint8_t>> convertDerCertToPemOrPassthrough(
+    const std::vector<uint8_t>& cert_bytes) {
+    // If cert_bytes is a DER encoded X509 certificate, it must be reencoded as PEM, because
+    // wpa_supplicant only understand PEM. Otherwise the cert_bytes are returned as is.
+    const uint8_t* cert_current = cert_bytes.data();
+    const uint8_t* cert_end = cert_current + cert_bytes.size();
+    bssl::UniquePtr<BIO> pem_bio(BIO_new(BIO_s_mem()));
+    while (cert_current < cert_end) {
+        auto cert =
+            bssl::UniquePtr<X509>(d2i_X509(nullptr, &cert_current, cert_end - cert_current));
+        // If part of the bytes cannot be parsed as X509 DER certificate, the original blob
+        // shall be returned as-is.
+        if (!cert) {
+            LOG(WARNING) << AT
+                         << "Could not parse DER X509 cert from buffer. Returning blob as is.";
+            return cert_bytes;
+        }
+
+        if (!PEM_write_bio_X509(pem_bio.get(), cert.get())) {
+            LOG(ERROR) << AT << "Could not convert cert to PEM format.";
+            return std::nullopt;
+        }
+    }
+
+    const uint8_t* pem_bytes;
+    size_t pem_len;
+    if (!BIO_mem_contents(pem_bio.get(), &pem_bytes, &pem_len)) {
+        LOG(ERROR) << AT << "Could not extract pem_bytes from BIO.";
+        return std::nullopt;
+    }
+    return {{pem_bytes, pem_bytes + pem_len}};
+}
+
 std::optional<std::vector<uint8_t>> keyStore2GetCert(const hidl_string& key) {
     ::ndk::SpAIBinder keystoreBinder(AServiceManager_checkService(kKeystore2ServiceName));
     auto keystore2 = ks2::IKeystoreService::fromBinder(keystoreBinder);
@@ -326,13 +327,22 @@
 namespace implementation {
 // Methods from ::android::hardware::wifi::keystore::V1_0::IKeystore follow.
 Return<void> Keystore::getBlob(const hidl_string& key, getBlob_cb _hidl_cb) {
+    std::vector<uint8_t> result_cert;
     if (auto ks2_cert = keyStore2GetCert(key)) {
-        _hidl_cb(KeystoreStatusCode::SUCCESS, std::move(*ks2_cert));
+        result_cert = std::move(*ks2_cert);
     } else if (auto blob = getLegacyKeystoreBlob(key)) {
-        _hidl_cb(KeystoreStatusCode::SUCCESS, *blob);
+        result_cert = std::move(*blob);
     } else {
         LOG(ERROR) << AT << "Failed to get certificate.";
         _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
+        return Void();
+    }
+
+    if (auto result_cert_hidl = convertDerCertToPemOrPassthrough(result_cert)) {
+        _hidl_cb(KeystoreStatusCode::SUCCESS, *result_cert_hidl);
+    } else {
+        LOG(ERROR) << AT << "Conversion to PEM failed.";
+        _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
     }
     return Void();
 }
diff --git a/wifi/keystore/1.0/default/test/Android.bp b/wifi/keystore/1.0/default/test/Android.bp
index e16155b..eef58e9 100644
--- a/wifi/keystore/1.0/default/test/Android.bp
+++ b/wifi/keystore/1.0/default/test/Android.bp
@@ -23,6 +23,7 @@
     shared_libs: [
         "libbase",
         "liblog",
+        "libcrypto",
         "libcutils",
         "libhidlbase",
         "libnativehelper",
diff --git a/wifi/keystore/1.0/default/test/WifiLegacyKeystoreIntegrationTest.cpp b/wifi/keystore/1.0/default/test/WifiLegacyKeystoreIntegrationTest.cpp
index b6dcf01..ac801e5 100644
--- a/wifi/keystore/1.0/default/test/WifiLegacyKeystoreIntegrationTest.cpp
+++ b/wifi/keystore/1.0/default/test/WifiLegacyKeystoreIntegrationTest.cpp
@@ -15,19 +15,16 @@
  */
 
 #include <aidl/android/security/legacykeystore/ILegacyKeystore.h>
-#include <aidl/android/system/keystore2/IKeystoreOperation.h>
-#include <aidl/android/system/keystore2/IKeystoreSecurityLevel.h>
-#include <aidl/android/system/keystore2/IKeystoreService.h>
 #include <aidl/android/system/keystore2/ResponseCode.h>
 #include <android/binder_manager.h>
 #include <android/system/wifi/keystore/1.0/IKeystore.h>
-#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 #include <private/android_filesystem_config.h>
-#include <utils/String16.h>
+
+#include "../wifikeystorehal_utils.h"
 
 using namespace std;
 using namespace ::testing;
@@ -50,6 +47,65 @@
     SIGNING,
 };
 
+// Some test certificate in PEM encoding.
+static const char kPemTestCert[] = R"(-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIUMpH52TRcL1gTknsm5eR+wvCGxNMwDQYJKoZIhvcNAQEL
+BQAwPjELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxGjAYBgNVBAoM
+EUFuZHJvaWQgVGVzdCBDZXJ0MB4XDTIxMDczMDAwMzY1OVoXDTIyMDczMDAwMzY1
+OVowPjELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxGjAYBgNVBAoM
+EUFuZHJvaWQgVGVzdCBDZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL
+q7JTXvL3ErVX2ZU9hQ0PLnkyw984qweNhQw8xIvwzTs3hXtV0K4hmWJiPKxOv3H7
+Q//TOcxI6+Qp4qOa79UUYDvmObjOCW1jQvZ9UQQfvdMO1WSa3BQoPJYQXiuyiuPs
++XM58Yl8TPV+IQ+Znx5axn5PxEmoqCUmeBv/wbJlDwIDAQABo1MwUTAdBgNVHQ4E
+FgQUEbhF5fYkUPchj+GdWX1aoOHkH3owHwYDVR0jBBgwFoAUEbhF5fYkUPchj+Gd
+WX1aoOHkH3owDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQChejph
+iYWFBeQEQtPYGGwSNO1HgzRhvsdGKDJUtRDAvDPxlRO8jkGmrSaD3QJUY4bCkx5c
+S9W7oRxyiUaxJFtw9Lbxkc4G3v0hpxYqfX4R4lzM8oU/50cPEpZGVaIZNrqBiXbd
+wFzPSv/UTXFBKlR5grYTmsiHCBbEv0apNJNI0g==
+-----END CERTIFICATE-----
+)";
+
+// Some test certificate in DER encoding.
+static const std::vector<uint8_t> kDerTestCert{
+    0x30, 0x82, 0x02, 0x58, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x32,
+    0x91, 0xf9, 0xd9, 0x34, 0x5c, 0x2f, 0x58, 0x13, 0x92, 0x7b, 0x26, 0xe5, 0xe4, 0x7e, 0xc2, 0xf0,
+    0x86, 0xc4, 0xd3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+    0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+    0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+    0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+    0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36,
+    0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35,
+    0x39, 0x5a, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+    0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+    0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+    0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65,
+    0x72, 0x74, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+    0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcb,
+    0xab, 0xb2, 0x53, 0x5e, 0xf2, 0xf7, 0x12, 0xb5, 0x57, 0xd9, 0x95, 0x3d, 0x85, 0x0d, 0x0f, 0x2e,
+    0x79, 0x32, 0xc3, 0xdf, 0x38, 0xab, 0x07, 0x8d, 0x85, 0x0c, 0x3c, 0xc4, 0x8b, 0xf0, 0xcd, 0x3b,
+    0x37, 0x85, 0x7b, 0x55, 0xd0, 0xae, 0x21, 0x99, 0x62, 0x62, 0x3c, 0xac, 0x4e, 0xbf, 0x71, 0xfb,
+    0x43, 0xff, 0xd3, 0x39, 0xcc, 0x48, 0xeb, 0xe4, 0x29, 0xe2, 0xa3, 0x9a, 0xef, 0xd5, 0x14, 0x60,
+    0x3b, 0xe6, 0x39, 0xb8, 0xce, 0x09, 0x6d, 0x63, 0x42, 0xf6, 0x7d, 0x51, 0x04, 0x1f, 0xbd, 0xd3,
+    0x0e, 0xd5, 0x64, 0x9a, 0xdc, 0x14, 0x28, 0x3c, 0x96, 0x10, 0x5e, 0x2b, 0xb2, 0x8a, 0xe3, 0xec,
+    0xf9, 0x73, 0x39, 0xf1, 0x89, 0x7c, 0x4c, 0xf5, 0x7e, 0x21, 0x0f, 0x99, 0x9f, 0x1e, 0x5a, 0xc6,
+    0x7e, 0x4f, 0xc4, 0x49, 0xa8, 0xa8, 0x25, 0x26, 0x78, 0x1b, 0xff, 0xc1, 0xb2, 0x65, 0x0f, 0x02,
+    0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+    0x16, 0x04, 0x14, 0x11, 0xb8, 0x45, 0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59,
+    0x7d, 0x5a, 0xa0, 0xe1, 0xe4, 0x1f, 0x7a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+    0x30, 0x16, 0x80, 0x14, 0x11, 0xb8, 0x45, 0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d,
+    0x59, 0x7d, 0x5a, 0xa0, 0xe1, 0xe4, 0x1f, 0x7a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+    0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xa1, 0x7a, 0x3a, 0x61,
+    0x89, 0x85, 0x85, 0x05, 0xe4, 0x04, 0x42, 0xd3, 0xd8, 0x18, 0x6c, 0x12, 0x34, 0xed, 0x47, 0x83,
+    0x34, 0x61, 0xbe, 0xc7, 0x46, 0x28, 0x32, 0x54, 0xb5, 0x10, 0xc0, 0xbc, 0x33, 0xf1, 0x95, 0x13,
+    0xbc, 0x8e, 0x41, 0xa6, 0xad, 0x26, 0x83, 0xdd, 0x02, 0x54, 0x63, 0x86, 0xc2, 0x93, 0x1e, 0x5c,
+    0x4b, 0xd5, 0xbb, 0xa1, 0x1c, 0x72, 0x89, 0x46, 0xb1, 0x24, 0x5b, 0x70, 0xf4, 0xb6, 0xf1, 0x91,
+    0xce, 0x06, 0xde, 0xfd, 0x21, 0xa7, 0x16, 0x2a, 0x7d, 0x7e, 0x11, 0xe2, 0x5c, 0xcc, 0xf2, 0x85,
+    0x3f, 0xe7, 0x47, 0x0f, 0x12, 0x96, 0x46, 0x55, 0xa2, 0x19, 0x36, 0xba, 0x81, 0x89, 0x76, 0xdd,
+    0xc0, 0x5c, 0xcf, 0x4a, 0xff, 0xd4, 0x4d, 0x71, 0x41, 0x2a, 0x54, 0x79, 0x82, 0xb6, 0x13, 0x9a,
+    0xc8, 0x87, 0x08, 0x16, 0xc4, 0xbf, 0x46, 0xa9, 0x34, 0x93, 0x48, 0xd2};
+
 // The fixture for testing the Wifi Keystore HAL legacy keystore integration.
 class WifiLegacyKeystoreTest : public TestWithParam<std::string> {
    protected:
@@ -163,10 +219,10 @@
                      << "Cannot transition to AID_SYSTEM.";
     }
 
-    // Only AID_SYSTEM (and AID_WIFI) is allowed to manipulate
+    // Only AID_SYSTEM (and AID_WIFI) is allowed to manipulate the wifi namespace.
     ASSERT_EQ(0, seteuid(AID_SYSTEM)) << "Failed to set uid to AID_SYSTEM: " << strerror(errno);
 
-    const std::vector<uint8_t> TESTBLOB{1, 2, 3, 5};
+    const std::vector<uint8_t> TESTBLOB(std::begin(kPemTestCert), std::end(kPemTestCert));
     const std::string TESTALIAS = "LegacyKeystoreWifiTestAlias";
 
     ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
@@ -188,4 +244,222 @@
     ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
 }
 
+/*
+ * This tests checks that a DER encoded certificate is always returned in PEM encoding by getBlob.
+ */
+TEST_P(WifiLegacyKeystoreTest, IKeystoreGetAlwaysReturnsPem) {
+    if (!isDebuggableBuild() || getuid() != 0) {
+        GTEST_SKIP() << "Device not running a debuggable build or not running as root. "
+                     << "Cannot transition to AID_SYSTEM.";
+    }
+
+    // Only AID_SYSTEM (and AID_WIFI) is allowed to manipulate
+    ASSERT_EQ(0, seteuid(AID_SYSTEM)) << "Failed to set uid to AID_SYSTEM: " << strerror(errno);
+
+    const std::string TESTALIAS = "LegacyKeystoreWifiTestAlias";
+
+    ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
+    ASSERT_TRUE(LegacyKeystorePut(TESTALIAS, kDerTestCert, AID_WIFI));
+
+    IKeystore::KeystoreStatusCode statusCode;
+    std::vector<uint8_t> blob;
+    auto rc = wifiKeystoreHal->getBlob(TESTALIAS,
+                                       [&](IKeystore::KeystoreStatusCode status,
+                                           const ::android::hardware::hidl_vec<uint8_t>& value) {
+                                           statusCode = status;
+                                           blob = value;
+                                       });
+
+    ASSERT_TRUE(rc.isOk()) << "Description: " << rc.description();
+    ASSERT_EQ(IKeystore::KeystoreStatusCode::SUCCESS, statusCode);
+
+    std::string blob_str(reinterpret_cast<const char*>(blob.data()),
+                         reinterpret_cast<const char*>(blob.data()) + blob.size());
+    ASSERT_EQ(blob_str.rfind("-----BEGIN CERTIFICATE-----", 0), 0);
+    ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
+}
+
+/*
+ * This tests checks that a DER encoded certificate is always returned in PEM encoding by getBlob.
+ */
+TEST_P(WifiLegacyKeystoreTest, IKeystoreGetAlwaysReturnsPemWithChain) {
+    if (!isDebuggableBuild() || getuid() != 0) {
+        GTEST_SKIP() << "Device not running a debuggable build or not running as root. "
+                     << "Cannot transition to AID_SYSTEM.";
+    }
+
+    // Only AID_SYSTEM (and AID_WIFI) is allowed to manipulate
+    ASSERT_EQ(0, seteuid(AID_SYSTEM)) << "Failed to set uid to AID_SYSTEM: " << strerror(errno);
+
+    // Some test certificate in DER encoding, this is three times the same cert.
+    const std::vector<uint8_t> TESTBLOB_DER_3CERT{
+        0x30, 0x82, 0x02, 0x58, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+        0x32, 0x91, 0xf9, 0xd9, 0x34, 0x5c, 0x2f, 0x58, 0x13, 0x92, 0x7b, 0x26, 0xe5, 0xe4, 0x7e,
+        0xc2, 0xf0, 0x86, 0xc4, 0xd3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+        0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+        0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+        0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x1a, 0x30, 0x18,
+        0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20,
+        0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x32,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x30, 0x3e, 0x31, 0x0b,
+        0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
+        0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+        0x74, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e,
+        0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+        0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+        0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcb,
+        0xab, 0xb2, 0x53, 0x5e, 0xf2, 0xf7, 0x12, 0xb5, 0x57, 0xd9, 0x95, 0x3d, 0x85, 0x0d, 0x0f,
+        0x2e, 0x79, 0x32, 0xc3, 0xdf, 0x38, 0xab, 0x07, 0x8d, 0x85, 0x0c, 0x3c, 0xc4, 0x8b, 0xf0,
+        0xcd, 0x3b, 0x37, 0x85, 0x7b, 0x55, 0xd0, 0xae, 0x21, 0x99, 0x62, 0x62, 0x3c, 0xac, 0x4e,
+        0xbf, 0x71, 0xfb, 0x43, 0xff, 0xd3, 0x39, 0xcc, 0x48, 0xeb, 0xe4, 0x29, 0xe2, 0xa3, 0x9a,
+        0xef, 0xd5, 0x14, 0x60, 0x3b, 0xe6, 0x39, 0xb8, 0xce, 0x09, 0x6d, 0x63, 0x42, 0xf6, 0x7d,
+        0x51, 0x04, 0x1f, 0xbd, 0xd3, 0x0e, 0xd5, 0x64, 0x9a, 0xdc, 0x14, 0x28, 0x3c, 0x96, 0x10,
+        0x5e, 0x2b, 0xb2, 0x8a, 0xe3, 0xec, 0xf9, 0x73, 0x39, 0xf1, 0x89, 0x7c, 0x4c, 0xf5, 0x7e,
+        0x21, 0x0f, 0x99, 0x9f, 0x1e, 0x5a, 0xc6, 0x7e, 0x4f, 0xc4, 0x49, 0xa8, 0xa8, 0x25, 0x26,
+        0x78, 0x1b, 0xff, 0xc1, 0xb2, 0x65, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30,
+        0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0xb8, 0x45,
+        0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a, 0xa0, 0xe1, 0xe4,
+        0x1f, 0x7a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+        0x11, 0xb8, 0x45, 0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a,
+        0xa0, 0xe1, 0xe4, 0x1f, 0x7a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+        0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+        0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xa1, 0x7a, 0x3a, 0x61,
+        0x89, 0x85, 0x85, 0x05, 0xe4, 0x04, 0x42, 0xd3, 0xd8, 0x18, 0x6c, 0x12, 0x34, 0xed, 0x47,
+        0x83, 0x34, 0x61, 0xbe, 0xc7, 0x46, 0x28, 0x32, 0x54, 0xb5, 0x10, 0xc0, 0xbc, 0x33, 0xf1,
+        0x95, 0x13, 0xbc, 0x8e, 0x41, 0xa6, 0xad, 0x26, 0x83, 0xdd, 0x02, 0x54, 0x63, 0x86, 0xc2,
+        0x93, 0x1e, 0x5c, 0x4b, 0xd5, 0xbb, 0xa1, 0x1c, 0x72, 0x89, 0x46, 0xb1, 0x24, 0x5b, 0x70,
+        0xf4, 0xb6, 0xf1, 0x91, 0xce, 0x06, 0xde, 0xfd, 0x21, 0xa7, 0x16, 0x2a, 0x7d, 0x7e, 0x11,
+        0xe2, 0x5c, 0xcc, 0xf2, 0x85, 0x3f, 0xe7, 0x47, 0x0f, 0x12, 0x96, 0x46, 0x55, 0xa2, 0x19,
+        0x36, 0xba, 0x81, 0x89, 0x76, 0xdd, 0xc0, 0x5c, 0xcf, 0x4a, 0xff, 0xd4, 0x4d, 0x71, 0x41,
+        0x2a, 0x54, 0x79, 0x82, 0xb6, 0x13, 0x9a, 0xc8, 0x87, 0x08, 0x16, 0xc4, 0xbf, 0x46, 0xa9,
+        0x34, 0x93, 0x48, 0xd2,  // End of first cert.
+        0x30, 0x82, 0x02, 0x58, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+        0x32, 0x91, 0xf9, 0xd9, 0x34, 0x5c, 0x2f, 0x58, 0x13, 0x92, 0x7b, 0x26, 0xe5, 0xe4, 0x7e,
+        0xc2, 0xf0, 0x86, 0xc4, 0xd3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+        0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+        0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+        0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x1a, 0x30, 0x18,
+        0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20,
+        0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x32,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x30, 0x3e, 0x31, 0x0b,
+        0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
+        0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+        0x74, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e,
+        0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+        0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+        0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcb,
+        0xab, 0xb2, 0x53, 0x5e, 0xf2, 0xf7, 0x12, 0xb5, 0x57, 0xd9, 0x95, 0x3d, 0x85, 0x0d, 0x0f,
+        0x2e, 0x79, 0x32, 0xc3, 0xdf, 0x38, 0xab, 0x07, 0x8d, 0x85, 0x0c, 0x3c, 0xc4, 0x8b, 0xf0,
+        0xcd, 0x3b, 0x37, 0x85, 0x7b, 0x55, 0xd0, 0xae, 0x21, 0x99, 0x62, 0x62, 0x3c, 0xac, 0x4e,
+        0xbf, 0x71, 0xfb, 0x43, 0xff, 0xd3, 0x39, 0xcc, 0x48, 0xeb, 0xe4, 0x29, 0xe2, 0xa3, 0x9a,
+        0xef, 0xd5, 0x14, 0x60, 0x3b, 0xe6, 0x39, 0xb8, 0xce, 0x09, 0x6d, 0x63, 0x42, 0xf6, 0x7d,
+        0x51, 0x04, 0x1f, 0xbd, 0xd3, 0x0e, 0xd5, 0x64, 0x9a, 0xdc, 0x14, 0x28, 0x3c, 0x96, 0x10,
+        0x5e, 0x2b, 0xb2, 0x8a, 0xe3, 0xec, 0xf9, 0x73, 0x39, 0xf1, 0x89, 0x7c, 0x4c, 0xf5, 0x7e,
+        0x21, 0x0f, 0x99, 0x9f, 0x1e, 0x5a, 0xc6, 0x7e, 0x4f, 0xc4, 0x49, 0xa8, 0xa8, 0x25, 0x26,
+        0x78, 0x1b, 0xff, 0xc1, 0xb2, 0x65, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30,
+        0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0xb8, 0x45,
+        0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a, 0xa0, 0xe1, 0xe4,
+        0x1f, 0x7a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+        0x11, 0xb8, 0x45, 0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a,
+        0xa0, 0xe1, 0xe4, 0x1f, 0x7a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+        0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+        0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xa1, 0x7a, 0x3a, 0x61,
+        0x89, 0x85, 0x85, 0x05, 0xe4, 0x04, 0x42, 0xd3, 0xd8, 0x18, 0x6c, 0x12, 0x34, 0xed, 0x47,
+        0x83, 0x34, 0x61, 0xbe, 0xc7, 0x46, 0x28, 0x32, 0x54, 0xb5, 0x10, 0xc0, 0xbc, 0x33, 0xf1,
+        0x95, 0x13, 0xbc, 0x8e, 0x41, 0xa6, 0xad, 0x26, 0x83, 0xdd, 0x02, 0x54, 0x63, 0x86, 0xc2,
+        0x93, 0x1e, 0x5c, 0x4b, 0xd5, 0xbb, 0xa1, 0x1c, 0x72, 0x89, 0x46, 0xb1, 0x24, 0x5b, 0x70,
+        0xf4, 0xb6, 0xf1, 0x91, 0xce, 0x06, 0xde, 0xfd, 0x21, 0xa7, 0x16, 0x2a, 0x7d, 0x7e, 0x11,
+        0xe2, 0x5c, 0xcc, 0xf2, 0x85, 0x3f, 0xe7, 0x47, 0x0f, 0x12, 0x96, 0x46, 0x55, 0xa2, 0x19,
+        0x36, 0xba, 0x81, 0x89, 0x76, 0xdd, 0xc0, 0x5c, 0xcf, 0x4a, 0xff, 0xd4, 0x4d, 0x71, 0x41,
+        0x2a, 0x54, 0x79, 0x82, 0xb6, 0x13, 0x9a, 0xc8, 0x87, 0x08, 0x16, 0xc4, 0xbf, 0x46, 0xa9,
+        0x34, 0x93, 0x48, 0xd2,  // End of second.
+        0x30, 0x82, 0x02, 0x58, 0x30, 0x82, 0x01, 0xc1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14,
+        0x32, 0x91, 0xf9, 0xd9, 0x34, 0x5c, 0x2f, 0x58, 0x13, 0x92, 0x7b, 0x26, 0xe5, 0xe4, 0x7e,
+        0xc2, 0xf0, 0x86, 0xc4, 0xd3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+        0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+        0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+        0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x1a, 0x30, 0x18,
+        0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20,
+        0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x32,
+        0x30, 0x37, 0x33, 0x30, 0x30, 0x30, 0x33, 0x36, 0x35, 0x39, 0x5a, 0x30, 0x3e, 0x31, 0x0b,
+        0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
+        0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+        0x74, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x41, 0x6e,
+        0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+        0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+        0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcb,
+        0xab, 0xb2, 0x53, 0x5e, 0xf2, 0xf7, 0x12, 0xb5, 0x57, 0xd9, 0x95, 0x3d, 0x85, 0x0d, 0x0f,
+        0x2e, 0x79, 0x32, 0xc3, 0xdf, 0x38, 0xab, 0x07, 0x8d, 0x85, 0x0c, 0x3c, 0xc4, 0x8b, 0xf0,
+        0xcd, 0x3b, 0x37, 0x85, 0x7b, 0x55, 0xd0, 0xae, 0x21, 0x99, 0x62, 0x62, 0x3c, 0xac, 0x4e,
+        0xbf, 0x71, 0xfb, 0x43, 0xff, 0xd3, 0x39, 0xcc, 0x48, 0xeb, 0xe4, 0x29, 0xe2, 0xa3, 0x9a,
+        0xef, 0xd5, 0x14, 0x60, 0x3b, 0xe6, 0x39, 0xb8, 0xce, 0x09, 0x6d, 0x63, 0x42, 0xf6, 0x7d,
+        0x51, 0x04, 0x1f, 0xbd, 0xd3, 0x0e, 0xd5, 0x64, 0x9a, 0xdc, 0x14, 0x28, 0x3c, 0x96, 0x10,
+        0x5e, 0x2b, 0xb2, 0x8a, 0xe3, 0xec, 0xf9, 0x73, 0x39, 0xf1, 0x89, 0x7c, 0x4c, 0xf5, 0x7e,
+        0x21, 0x0f, 0x99, 0x9f, 0x1e, 0x5a, 0xc6, 0x7e, 0x4f, 0xc4, 0x49, 0xa8, 0xa8, 0x25, 0x26,
+        0x78, 0x1b, 0xff, 0xc1, 0xb2, 0x65, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30,
+        0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x11, 0xb8, 0x45,
+        0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a, 0xa0, 0xe1, 0xe4,
+        0x1f, 0x7a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+        0x11, 0xb8, 0x45, 0xe5, 0xf6, 0x24, 0x50, 0xf7, 0x21, 0x8f, 0xe1, 0x9d, 0x59, 0x7d, 0x5a,
+        0xa0, 0xe1, 0xe4, 0x1f, 0x7a, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+        0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+        0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xa1, 0x7a, 0x3a, 0x61,
+        0x89, 0x85, 0x85, 0x05, 0xe4, 0x04, 0x42, 0xd3, 0xd8, 0x18, 0x6c, 0x12, 0x34, 0xed, 0x47,
+        0x83, 0x34, 0x61, 0xbe, 0xc7, 0x46, 0x28, 0x32, 0x54, 0xb5, 0x10, 0xc0, 0xbc, 0x33, 0xf1,
+        0x95, 0x13, 0xbc, 0x8e, 0x41, 0xa6, 0xad, 0x26, 0x83, 0xdd, 0x02, 0x54, 0x63, 0x86, 0xc2,
+        0x93, 0x1e, 0x5c, 0x4b, 0xd5, 0xbb, 0xa1, 0x1c, 0x72, 0x89, 0x46, 0xb1, 0x24, 0x5b, 0x70,
+        0xf4, 0xb6, 0xf1, 0x91, 0xce, 0x06, 0xde, 0xfd, 0x21, 0xa7, 0x16, 0x2a, 0x7d, 0x7e, 0x11,
+        0xe2, 0x5c, 0xcc, 0xf2, 0x85, 0x3f, 0xe7, 0x47, 0x0f, 0x12, 0x96, 0x46, 0x55, 0xa2, 0x19,
+        0x36, 0xba, 0x81, 0x89, 0x76, 0xdd, 0xc0, 0x5c, 0xcf, 0x4a, 0xff, 0xd4, 0x4d, 0x71, 0x41,
+        0x2a, 0x54, 0x79, 0x82, 0xb6, 0x13, 0x9a, 0xc8, 0x87, 0x08, 0x16, 0xc4, 0xbf, 0x46, 0xa9,
+        0x34, 0x93, 0x48, 0xd2,
+    };
+
+    const std::string TESTALIAS = "LegacyKeystoreWifiTestAlias";
+
+    ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
+    ASSERT_TRUE(LegacyKeystorePut(TESTALIAS, TESTBLOB_DER_3CERT, AID_WIFI));
+
+    IKeystore::KeystoreStatusCode statusCode;
+    std::vector<uint8_t> blob;
+    auto rc = wifiKeystoreHal->getBlob(TESTALIAS,
+                                       [&](IKeystore::KeystoreStatusCode status,
+                                           const ::android::hardware::hidl_vec<uint8_t>& value) {
+                                           statusCode = status;
+                                           blob = value;
+                                       });
+
+    ASSERT_TRUE(rc.isOk()) << "Description: " << rc.description();
+    ASSERT_EQ(IKeystore::KeystoreStatusCode::SUCCESS, statusCode);
+
+    std::string blob_str(reinterpret_cast<const char*>(blob.data()),
+                         reinterpret_cast<const char*>(blob.data()) + blob.size());
+
+    // The output must include exactly three PEM certificate begin markers.
+    auto pos = blob_str.find("-----BEGIN CERTIFICATE-----", 0);
+    ASSERT_NE(pos, std::string::npos);
+    pos = blob_str.find("-----BEGIN CERTIFICATE-----", pos + 1);
+    ASSERT_NE(pos, std::string::npos);
+    pos = blob_str.find("-----BEGIN CERTIFICATE-----", pos + 1);
+    ASSERT_NE(pos, std::string::npos);
+    pos = blob_str.find("-----BEGIN CERTIFICATE-----", pos + 1);
+    ASSERT_EQ(pos, std::string::npos);
+
+    ASSERT_TRUE(LegacyKeystoreRemove(TESTALIAS, AID_WIFI));
+}
+
+TEST(WifiKeystoreUtilsTest, ExtractPublicKeyHandlesDer) {
+    auto cert = extractPubKey(kDerTestCert);
+    ASSERT_FALSE(cert.empty());
+}
+
+TEST(WifiKeystoreUtilsTest, ExtractPublicKeyHandlesPemFallback) {
+    const std::vector<uint8_t> TESTBLOB(std::begin(kPemTestCert), std::end(kPemTestCert));
+    auto cert = extractPubKey(TESTBLOB);
+    ASSERT_FALSE(cert.empty());
+}
+
 }  // namespace
diff --git a/wifi/keystore/1.0/default/wifikeystorehal_utils.h b/wifi/keystore/1.0/default/wifikeystorehal_utils.h
new file mode 100644
index 0000000..d7a790e
--- /dev/null
+++ b/wifi/keystore/1.0/default/wifikeystorehal_utils.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <android-base/logging.h>
+#include <openssl/base.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <vector>
+
+#define AT __func__ << ":" << __LINE__ << " "
+
+namespace {
+// Helper method to extract public key from the certificate.
+std::vector<uint8_t> extractPubKey(const std::vector<uint8_t>& cert_bytes) {
+    const uint8_t* p = cert_bytes.data();
+    bssl::UniquePtr<X509> decoded_cert(d2i_X509(nullptr, &p, cert_bytes.size()));
+    if (!decoded_cert) {
+        LOG(INFO) << AT << "Could not decode the cert, trying decoding as PEM";
+        bssl::UniquePtr<BIO> cert_bio(BIO_new_mem_buf(cert_bytes.data(), cert_bytes.size()));
+        if (!cert_bio) {
+            LOG(ERROR) << AT << "Failed to create BIO";
+            return {};
+        }
+        decoded_cert =
+            bssl::UniquePtr<X509>(PEM_read_bio_X509(cert_bio.get(), nullptr, nullptr, nullptr));
+    }
+    if (!decoded_cert) {
+        LOG(ERROR) << AT << "Could not decode the cert.";
+        return {};
+    }
+    bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(decoded_cert.get()));
+    if (!pub_key) {
+        LOG(ERROR) << AT << "Could not extract public key.";
+        return {};
+    }
+    bssl::UniquePtr<BIO> pub_key_bio(BIO_new(BIO_s_mem()));
+    if (!pub_key_bio || i2d_PUBKEY_bio(pub_key_bio.get(), pub_key.get()) <= 0) {
+        LOG(ERROR) << AT << "Could not serialize public key.";
+        return {};
+    }
+    const uint8_t* pub_key_bytes;
+    size_t pub_key_len;
+    if (!BIO_mem_contents(pub_key_bio.get(), &pub_key_bytes, &pub_key_len)) {
+        LOG(ERROR) << AT << "Could not get bytes from BIO.";
+        return {};
+    }
+
+    return {pub_key_bytes, pub_key_bytes + pub_key_len};
+}
+
+}  // namespace
\ No newline at end of file
diff --git a/wifi/keystore/1.0/vts/functional/VtsHalWifiKeystoreV1_0TargetTest.cpp b/wifi/keystore/1.0/vts/functional/VtsHalWifiKeystoreV1_0TargetTest.cpp
index cbac948..3139d8e 100644
--- a/wifi/keystore/1.0/vts/functional/VtsHalWifiKeystoreV1_0TargetTest.cpp
+++ b/wifi/keystore/1.0/vts/functional/VtsHalWifiKeystoreV1_0TargetTest.cpp
@@ -376,9 +376,12 @@
 
     IKeystore::KeystoreStatusCode statusCode;
 
-    auto callback = [&statusCode](IKeystore::KeystoreStatusCode status,
-                                  const ::android::hardware::hidl_vec<uint8_t>& /*value*/) {
+    std::string cert;
+    auto callback = [&statusCode, &cert](IKeystore::KeystoreStatusCode status,
+                                         const ::android::hardware::hidl_vec<uint8_t>& value) {
         statusCode = status;
+        cert = std::string(reinterpret_cast<const char*>(value.data()),
+                           reinterpret_cast<const char*>(value.data()) + value.size());
         return;
     };
 
@@ -389,6 +392,8 @@
 
     keystore->getBlob(std::string("USRCERT_") + kTestKeyName, callback);
     EXPECT_EQ(IKeystore::KeystoreStatusCode::SUCCESS, statusCode);
+    // Must return PEM encoded certificates.
+    EXPECT_EQ(cert.rfind("-----BEGIN CERTIFICATE-----", 0), 0);
 
     result = deleteKey(kTestKeyName, true);
     EXPECT_EQ(result, true);