wifi_keystore: Convert CERT to PEM format

The public keystore API used by framework puts the cert in DER format.
So, convert the CERT to PEM format when supplicant retrieves the key to
maintain compatibility. Wifi was previously converting the cert to PEM format
and storing it in keystore using the privileged API surface.

Bug: 142089671
Test: Connected to passpoint networks
Test: Will send for full regression test
Change-Id: I78cf826287765c22dbbc5e198dd4655e0bf70a9f
diff --git a/wifi/keystore/1.0/default/Android.bp b/wifi/keystore/1.0/default/Android.bp
index d5339ef..7996f16 100644
--- a/wifi/keystore/1.0/default/Android.bp
+++ b/wifi/keystore/1.0/default/Android.bp
@@ -10,12 +10,14 @@
         "android.system.wifi.keystore@1.0",
         "libbase",
         "libbinder",
+        "libcrypto",
         "libcutils",
         "libhidlbase",
         "libkeystore_aidl",
         "libkeystore_binder",
         "libkeystore_parcelables",
         "liblog",
+        "libssl",
         "libutils",
     ],
     export_include_dirs: ["include"],
diff --git a/wifi/keystore/1.0/default/keystore.cpp b/wifi/keystore/1.0/default/keystore.cpp
index 63c2330..da375aa 100644
--- a/wifi/keystore/1.0/default/keystore.cpp
+++ b/wifi/keystore/1.0/default/keystore.cpp
@@ -20,6 +20,17 @@
 #include <vector>
 #include "include/wifikeystorehal/keystore.h"
 
+#include <ctype.h>
+#include <openssl/base.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define AT __func__ << ":" << __LINE__ << " "
+
 using android::hardware::keymaster::V4_0::Algorithm;
 using android::hardware::keymaster::V4_0::authorizationValue;
 using android::hardware::keymaster::V4_0::Digest;
@@ -40,6 +51,7 @@
 using KSReturn = keystore::KeyStoreNativeReturnCode;
 
 namespace {
+
 constexpr const char kKeystoreServiceName[] = "android.security.keystore";
 constexpr int32_t UID_SELF = -1;
 
@@ -48,9 +60,51 @@
 using keystore::KeystoreResponsePromise;
 using keystore::OperationResultPromise;
 
+NullOr<const Algorithm&> getKeyAlgorithmFromKeyCharacteristics(
+    const ::android::security::keymaster::KeyCharacteristics& characteristics) {
+    for (const auto& param : characteristics.hardwareEnforced.getParameters()) {
+        auto algo = authorizationValue(TAG_ALGORITHM, param);
+        if (algo.isOk()) return algo;
+    }
+    for (const auto& param : characteristics.softwareEnforced.getParameters()) {
+        auto algo = authorizationValue(TAG_ALGORITHM, param);
+        if (algo.isOk()) return algo;
+    }
+    return {};
+}
+
+// Helper method to convert certs in DER format to PERM format required by
+// openssl library used by supplicant.
+std::vector<uint8_t> convertCertToPem(const std::vector<uint8_t>& cert_bytes) {
+    bssl::UniquePtr<BIO> cert_bio(BIO_new_mem_buf(cert_bytes.data(), cert_bytes.size()));
+    // Check if the cert is already in PEM format, on devices which have saved
+    // credentials from previous releases when upgrading to R.
+    bssl::UniquePtr<X509> cert_pem(PEM_read_bio_X509(cert_bio.get(), nullptr, nullptr, nullptr));
+    if (cert_pem) {
+        LOG(INFO) << AT << "Certificate already in PEM format, returning";
+        return cert_bytes;
+    }
+    // Reset the bio since the pointers will be moved by |PEM_read_bio_X509|.
+    BIO_reset(cert_bio.get());
+    bssl::UniquePtr<X509> cert(d2i_X509_bio(cert_bio.get(), nullptr));
+    if (!cert) {
+        LOG(ERROR) << AT << "Could not create cert from BIO";
+        return {};
+    }
+    bssl::UniquePtr<BIO> pem_bio(BIO_new(BIO_s_mem()));
+    if (!PEM_write_bio_X509(pem_bio.get(), cert.get())) {
+        LOG(ERROR) << AT << "Could not convert cert to PEM format";
+        return {};
+    }
+    const uint8_t* pem_bytes;
+    size_t pem_len;
+    if (!BIO_mem_contents(pem_bio.get(), &pem_bytes, &pem_len)) {
+        return {};
+    }
+    return {pem_bytes, pem_bytes + pem_len};
+}
 };  // namespace
 
-#define AT __func__ << ":" << __LINE__ << " "
 
 namespace android {
 namespace system {
@@ -75,7 +129,9 @@
         _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});
         return Void();
     }
-    _hidl_cb(KeystoreStatusCode::SUCCESS, (hidl_vec<uint8_t>)value);
+    // convert to PEM before sending it to openssl library.
+    std::vector<uint8_t> pem_cert = convertCertToPem(value);
+    _hidl_cb(KeystoreStatusCode::SUCCESS, pem_cert);
     return Void();
 }
 
@@ -116,23 +172,12 @@
         return Void();
     }
 
-    _hidl_cb(KeystoreStatusCode::SUCCESS, export_result.exportData);
+    // convert to PEM before sending it to openssl library.
+    std::vector<uint8_t> pem_cert = convertCertToPem(export_result.exportData);
+    _hidl_cb(KeystoreStatusCode::SUCCESS, pem_cert);
     return Void();
 }
 
-static NullOr<const Algorithm&> getKeyAlgoritmFromKeyCharacteristics(
-    const ::android::security::keymaster::KeyCharacteristics& characteristics) {
-    for (const auto& param : characteristics.hardwareEnforced.getParameters()) {
-        auto algo = authorizationValue(TAG_ALGORITHM, param);
-        if (algo.isOk()) return algo;
-    }
-    for (const auto& param : characteristics.softwareEnforced.getParameters()) {
-        auto algo = authorizationValue(TAG_ALGORITHM, param);
-        if (algo.isOk()) return algo;
-    }
-    return {};
-}
-
 Return<void> Keystore::sign(const hidl_string& keyId, const hidl_vec<uint8_t>& dataToSign,
                             sign_cb _hidl_cb) {
     sp<IServiceManager> sm = defaultServiceManager();
@@ -171,7 +216,7 @@
         return Void();
     }
 
-    auto algorithm = getKeyAlgoritmFromKeyCharacteristics(characteristics);
+    auto algorithm = getKeyAlgorithmFromKeyCharacteristics(characteristics);
     if (!algorithm.isOk()) {
         LOG(ERROR) << AT << "could not get algorithm from key characteristics";
         _hidl_cb(KeystoreStatusCode::ERROR_UNKNOWN, {});