Restore support for old unversioned OCB-encrypted blobs.

This support was inadvertently removed in a refactor.  There aren't many
of these keys around, since they were only created by pre-release
verions of Nexus 9 software, but we'll support them anyway.

Change-Id: I46c4e9a2866c02b8030d7aef97bb64c45441168b
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index 2b4f5db..afc21c2 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -2562,6 +2562,23 @@
     EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
+TEST_P(Keymaster0AdapterTest, UnversionedSoftwareKeymaster1RsaBlob) {
+    // Load and use an old-style Keymaster1 software key blob, without the version byte.  These
+    // blobs contain OCB-encrypted key data.
+    string km1_sw = read_file("km1_sw_rsa_512_unversioned.blob");
+    EXPECT_EQ(477U, km1_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+    memcpy(key_data, km1_sw.data(), km1_sw.length());
+    set_key_blob(key_data, km1_sw.length());
+
+    string message(64, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
 TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1EcdsaBlob) {
     // Load and use an old-style Keymaster1 software key blob.  These blobs contain OCB-encrypted
     // key data.
diff --git a/auth_encrypted_key_blob.cpp b/auth_encrypted_key_blob.cpp
index eb9e2ca..64e0d63 100644
--- a/auth_encrypted_key_blob.cpp
+++ b/auth_encrypted_key_blob.cpp
@@ -54,6 +54,32 @@
     return KM_ERROR_OK;
 }
 
+static keymaster_error_t DeserializeUnversionedBlob(const KeymasterKeyBlob& key_blob,
+                                                    KeymasterKeyBlob* encrypted_key_material,
+                                                    AuthorizationSet* hw_enforced,
+                                                    AuthorizationSet* sw_enforced, Buffer* nonce,
+                                                    Buffer* tag) {
+    const uint8_t* tmp = key_blob.key_material;
+    const uint8_t** buf_ptr = &tmp;
+    const uint8_t* end = tmp + key_blob.key_material_size;
+
+    if (!nonce->reserve(OCB_NONCE_LENGTH) || !tag->reserve(OCB_TAG_LENGTH))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (!copy_from_buf(buf_ptr, end, nonce->peek_write(), OCB_NONCE_LENGTH) ||
+        !encrypted_key_material->Deserialize(buf_ptr, end) ||
+        !copy_from_buf(buf_ptr, end, tag->peek_write(), OCB_TAG_LENGTH) ||
+        !hw_enforced->Deserialize(buf_ptr, end) ||  //
+        !sw_enforced->Deserialize(buf_ptr, end)) {
+        LOG_E("Failed to deserialize unversioned blob", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+    nonce->advance_write(OCB_NONCE_LENGTH);
+    tag->advance_write(OCB_TAG_LENGTH);
+
+    return KM_ERROR_OK;
+}
+
 keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
                                                KeymasterKeyBlob* encrypted_key_material,
                                                AuthorizationSet* hw_enforced,
@@ -69,8 +95,37 @@
         !encrypted_key_material->Deserialize(buf_ptr, end) ||  //
         !tag->Deserialize(buf_ptr, end) || tag->available_read() != OCB_TAG_LENGTH ||
         !hw_enforced->Deserialize(buf_ptr, end) ||  //
-        !sw_enforced->Deserialize(buf_ptr, end))
-        return KM_ERROR_INVALID_KEY_BLOB;
+        !sw_enforced->Deserialize(buf_ptr, end)) {
+        // This blob failed to parse.  Either it's corrupted or it's a blob generated by an earlier
+        // version of keymaster using a previous blob format which did not include the version byte
+        // or the nonce or tag length fields.  So we try to parse it as that previous version.
+        //
+        // Note that it's not really a problem if we erronously parse a corrupted blob, because
+        // decryption will fail the authentication check.
+        //
+        // A bigger potential problem is: What if a valid unversioned blob appears to parse
+        // correctly as a versioned blob?  It would then be rejected during decryption, causing a
+        // valid key to become unusable.  If this is a disk encryption key, upgrading to a keymaster
+        // version with the new format would destroy the user's data.
+        //
+        // What is the probability that an unversioned key could be successfully parsed as a version
+        // 0 key?  The first 12 bytes of an unversioned key are the nonce, which, in the only
+        // keymaster version released with unversioned keys, is chosen randomly.  In order for an
+        // unversioned key to parse as a version 0 key, the following must be true about the first
+        // five of those random bytes:
+        //
+        // 1.  The first byte must be zero.  This will happen with probability 1/2^8.
+        //
+        // 2.  The second through fifth bytes must contain an unsigned integer value equal to
+        //     NONCE_LENGTH.  This will happen with probability 1/2^32.
+        //
+        // Based on those two checks alone, the probability of interpreting an unversioned blob as a
+        // version 0 blob is 1/2^40.  That's small enough to be negligible, but there are additional
+        // checks which lower it further.
+        LOG_I("Failed to deserialize versioned key blob.  Assuming unversioned.", 0);
+        return DeserializeUnversionedBlob(key_blob, encrypted_key_material, hw_enforced,
+                                          sw_enforced, nonce, tag);
+    }
     return KM_ERROR_OK;
 }
 
diff --git a/km1_sw_rsa_512_unversioned.blob b/km1_sw_rsa_512_unversioned.blob
new file mode 100644
index 0000000..e4f6a11
--- /dev/null
+++ b/km1_sw_rsa_512_unversioned.blob
Binary files differ