Handle keystore2 blob prefixes

The keystore2 km_compat layer that wraps Keymaster hardware
implementations prefixes the Keymaster blobs with some magic and an
indicator value.  When Keymaster is upgraded in-place to KeyMint,
keystore2 will stop using km_compat and pass the prefixed blobs to
KeyMint as-is.  This change causes Trusty KeyMint to look for and
strip those prefixes.

Bug: 177729159
Test: Manually create keys, update HAL and verify keys work
Change-Id: I5a7f322206bce1c5a384666fa3200afaa62f1f5a
diff --git a/trusty_keymaster_context.cpp b/trusty_keymaster_context.cpp
index aded6a7..d2e978a 100644
--- a/trusty_keymaster_context.cpp
+++ b/trusty_keymaster_context.cpp
@@ -15,11 +15,8 @@
  */
 
 #include "trusty_keymaster_context.h"
-#include "secure_storage_manager.h"
 
-#include <lib/hwkey/hwkey.h>
-#include <lib/rng/trusty_rng.h>
-#include <openssl/hmac.h>
+#include <array>
 
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/contexts/soft_attestation_cert.h>
@@ -37,7 +34,11 @@
 #include <keymaster/logger.h>
 #include <keymaster/operation.h>
 #include <keymaster/wrapped_key.h>
+#include <lib/hwkey/hwkey.h>
+#include <lib/rng/trusty_rng.h>
+#include <openssl/hmac.h>
 
+#include "secure_storage_manager.h"
 #include "trusty_aes_key.h"
 
 #ifdef KEYMASTER_DEBUG
@@ -378,6 +379,11 @@
                                       upgraded_key);
 }
 
+constexpr std::array<uint8_t, 7> kKeystoreKeyBlobMagic = {'p', 'K', 'M', 'b',
+                                                          'l', 'o', 'b'};
+constexpr size_t kKeystoreKeyTypeOffset = kKeystoreKeyBlobMagic.size();
+constexpr size_t kKeystoreKeyBlobPrefixSize = kKeystoreKeyTypeOffset + 1;
+
 keymaster_error_t TrustyKeymasterContext::ParseKeyBlob(
         const KeymasterKeyBlob& blob,
         const AuthorizationSet& additional_params,
@@ -388,8 +394,49 @@
     if (!key) {
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
     }
-    DeserializedKey deserialized_key =
-            DeserializeAuthEncryptedBlob(blob, &error);
+
+    DeserializedKey deserialized_key;
+    if (blob.size() >= kKeystoreKeyBlobPrefixSize &&
+        std::equal(kKeystoreKeyBlobMagic.begin(), kKeystoreKeyBlobMagic.end(),
+                   blob.begin())) {
+        // This blob has a keystore km_compat prefix.  This means that it was
+        // created by keystore calling TrustyKeymaster through the km_compat
+        // layer.  The km_compat layer adds this prefix to determine whether
+        // it's actually a hardware blob that should be passed through to
+        // Keymaster, or whether it's a software only key and should be used by
+        // the emulation layer.
+        //
+        // In the case of hardware blobs, km_compat strips the prefix before
+        // handing the blob to Keymaster.  In the case of software blobs,
+        // km_compat never hands the blob to Keymaster.
+        //
+        // The fact that we've received this prefixed blob means that it was
+        // created through km_compat... but the device has now been upgraded
+        // from TrustyKeymaster to TrustyKeyMint, and so keystore is no longer
+        // using the km_compat layer, and the blob is just passed through with
+        // its prefix intact.
+        auto keyType = *(blob.begin() + kKeystoreKeyTypeOffset);
+        switch (keyType) {
+        case 0:
+            LOG_E("Software key blobs are not supported.", 0);
+            return KM_ERROR_INVALID_KEY_BLOB;
+
+        case 1:
+            // This is a hardware blob. Strip the prefix and use the blob.
+            deserialized_key = DeserializeAuthEncryptedBlob(
+                    KeymasterKeyBlob(blob.begin() + kKeystoreKeyBlobPrefixSize,
+                                     blob.size() - kKeystoreKeyBlobPrefixSize),
+                    &error);
+            break;
+
+        default:
+            LOG_E("Invalid keystore blob prefix value %d", keyType);
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+    } else {
+        deserialized_key = DeserializeAuthEncryptedBlob(blob, &error);
+    }
+
     if (error != KM_ERROR_OK) {
         return error;
     }