Implement GetKeyCharacteristics.

Still need to add serialization to the messages.

Change-Id: I572c48474bf4d4f553d53cad475b57fa8937a02a
diff --git a/authorization_set.cpp b/authorization_set.cpp
index 1fb9d82..35a12b2 100644
--- a/authorization_set.cpp
+++ b/authorization_set.cpp
@@ -33,35 +33,7 @@
 
 AuthorizationSet::AuthorizationSet(const AuthorizationSet& set)
     : elems_(NULL), indirect_data_(NULL) {
-    elems_ = new keymaster_key_param_t[set.elems_size_];
-    if (elems_ == NULL) {
-        error_ = ALLOCATION_FAILURE;
-        return;
-    }
-    memcpy(elems_, set.elems_, set.elems_size_ * sizeof(keymaster_key_param_t));
-    elems_size_ = set.elems_size_;
-    elems_capacity_ = elems_size_;
-
-    if (set.indirect_data_ == NULL) {
-        indirect_data_ = NULL;
-        indirect_data_size_ = 0;
-        indirect_data_capacity_ = 0;
-    } else {
-        indirect_data_ = new uint8_t[set.indirect_data_size_];
-        if (indirect_data_ == NULL) {
-            error_ = ALLOCATION_FAILURE;
-            return;
-        }
-        memcpy(indirect_data_, set.indirect_data_, set.indirect_data_size_);
-        for (size_t i = 0; i < elems_size_; ++i) {
-            if (is_blob_tag(elems_[i].tag))
-                elems_[i].blob.data = indirect_data_ + (elems_[i].blob.data - set.indirect_data_);
-        }
-
-        indirect_data_size_ = set.indirect_data_size_;
-        indirect_data_capacity_ = indirect_data_size_;
-    }
-    error_ = OK;
+    Reinitialize(set.elems_, set.elems_size_);
 }
 
 AuthorizationSet::~AuthorizationSet() {
@@ -105,7 +77,6 @@
 }
 
 keymaster_key_param_t empty;
-
 keymaster_key_param_t AuthorizationSet::operator[](int at) const {
     if (at < (int)elems_size_) {
         return elems_[at];
@@ -114,6 +85,60 @@
     return empty;
 }
 
+template <typename T> int comparator(const T& a, const T& b) {
+    if (a < b)
+        return -1;
+    else if (a > b)
+        return 1;
+    else
+        return 0;
+}
+
+static int param_comparator(const void* a, const void* b) {
+    const keymaster_key_param_t* lhs = static_cast<const keymaster_key_param_t*>(a);
+    const keymaster_key_param_t* rhs = static_cast<const keymaster_key_param_t*>(b);
+
+    if (lhs->tag < rhs->tag)
+        return -1;
+    else if (lhs->tag > rhs->tag)
+        return 1;
+    else
+        switch (keymaster_tag_get_type(lhs->tag)) {
+        default:
+        case KM_INVALID:
+            return 0;
+        case KM_ENUM:
+        case KM_ENUM_REP:
+            return comparator(lhs->enumerated, rhs->enumerated);
+        case KM_INT:
+        case KM_INT_REP:
+            return comparator(lhs->integer, rhs->integer);
+        case KM_LONG:
+            return comparator(lhs->long_integer, rhs->long_integer);
+        case KM_DATE:
+            return comparator(lhs->date_time, rhs->date_time);
+        case KM_BOOL:
+            return comparator(lhs->boolean, rhs->boolean);
+        case KM_BIGNUM:
+        case KM_BYTES: {
+            size_t min_len = lhs->blob.data_length;
+            if (rhs->blob.data_length < min_len)
+                min_len = rhs->blob.data_length;
+
+            if (lhs->blob.data_length == rhs->blob.data_length && min_len > 0)
+                return memcmp(lhs->blob.data, rhs->blob.data, min_len);
+            int cmp_result = memcmp(lhs->blob.data, rhs->blob.data, min_len);
+            if (cmp_result == 0) {
+                // The blobs are equal up to the length of the shortest (which may have length 0),
+                // so the shorter is less, the longer is greater and if they have the same length
+                // they're identical.
+                return comparator(lhs->blob.data_length, rhs->blob.data_length);
+            }
+            return cmp_result;
+        } break;
+        }
+}
+
 bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
     if (elems_size_ >= elems_capacity_) {
         size_t new_capacity = elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY;