keymaster: fix authorization set serialization

Invalid and unknown tags were treated as zero size but they where still
counted as entry. This lead to invalid tags being persisted. When
Serialized blobs were used to cache key characteristics, these invalid
tags were send to clients of keystore. However, the serialization cannot
cope with invalid tags.

Bug: 119414176
Test: Successfully used the Skype app which triggered the problem
Change-Id: Ia46ac4a16395db3d10f93d3722eda69d523db478
(cherry picked from commit 93959a5e425d2666542e9618529816a74a0ae159)
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index b6cba61..d6b50f5 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -203,6 +203,7 @@
 struct OutStreams {
     std::ostream& indirect;
     std::ostream& elements;
+    size_t skipped;
 };
 
 OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
@@ -241,6 +242,7 @@
 
 OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
     // skip invalid entries.
+    ++out.skipped;
     return out;
 }
 template <typename T>
@@ -261,8 +263,9 @@
 template <>
 struct choose_serializer<> {
     static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
-        LOG(ERROR) << "Trying to serialize unknown tag " << unsigned(param.tag)
-                   << ". Did you forget to add it to all_tags_t?";
+        LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag)
+                     << ". Did you forget to add it to all_tags_t?";
+        ++out.skipped;
         return out;
     }
 };
@@ -285,7 +288,7 @@
 std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
     std::stringstream indirect;
     std::stringstream elements;
-    OutStreams streams = {indirect, elements};
+    OutStreams streams = {indirect, elements, 0};
     for (const auto& param : params) {
         serialize(streams, param);
     }
@@ -305,7 +308,7 @@
         return out;
     }
     uint32_t elements_size = pos;
-    uint32_t element_count = params.size();
+    uint32_t element_count = params.size() - streams.skipped;
 
     out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
 
@@ -326,6 +329,7 @@
 struct InStreams {
     std::istream& indirect;
     std::istream& elements;
+    size_t invalids;
 };
 
 InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
@@ -347,6 +351,7 @@
 
 InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
     // there should be no invalid KeyParamaters but if handle them as zero sized.
+    ++in.invalids;
     return in;
 }
 
@@ -414,13 +419,28 @@
     // TODO write one-shot stream buffer to avoid copying here
     std::stringstream indirect(indirect_buffer);
     std::stringstream elements(elements_buffer);
-    InStreams streams = {indirect, elements};
+    InStreams streams = {indirect, elements, 0};
 
     params->resize(element_count);
 
     for (uint32_t i = 0; i < element_count; ++i) {
         deserialize(streams, &(*params)[i]);
     }
+
+    /*
+     * There are legacy blobs which have invalid tags in them due to a bug during serialization.
+     * This makes sure that invalid tags are filtered from the result before it is returned.
+     */
+    if (streams.invalids > 0) {
+        std::vector<KeyParameter> filtered(element_count - streams.invalids);
+        auto ifiltered = filtered.begin();
+        for (auto& p : *params) {
+            if (p.tag != Tag::INVALID) {
+                *ifiltered++ = std::move(p);
+            }
+        }
+        *params = std::move(filtered);
+    }
     return in;
 }