Add attestation support to keystore.

Bug: 22914603
Change-Id: I14fbfbe30b96c5c29278fa548e06b65f15942fe2
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 8ed09c4..466ac24 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -208,6 +208,69 @@
     }
 }
 
+KeymasterCertificateChain::KeymasterCertificateChain() {
+    memset(&chain, 0, sizeof(chain));
+}
+
+KeymasterCertificateChain::~KeymasterCertificateChain() {
+    keymaster_free_cert_chain(&chain);
+}
+
+static bool readKeymasterBlob(const Parcel& in, keymaster_blob_t* blob) {
+    if (in.readInt32() != 1) {
+        return false;
+    }
+
+    blob->data_length = 0;
+    ssize_t length = in.readInt32();
+    if (length <= 0) {
+        blob->data = nullptr;
+        return false;
+    }
+
+    blob->data = reinterpret_cast<const uint8_t*>(in.readInplace(length));
+    if (blob->data) {
+        blob->data_length = static_cast<size_t>(length);
+    }
+    return true;
+}
+
+void KeymasterCertificateChain::readFromParcel(const Parcel& in) {
+    ssize_t count = in.readInt32();
+    size_t ucount = count;
+    if (count < 0) {
+        ucount = 0;
+    }
+    keymaster_free_cert_chain(&chain);
+    chain.entries = new keymaster_blob_t[ucount];
+    memset(chain.entries, 0, sizeof(keymaster_blob_t) * ucount);
+    for (size_t i = 0; i < ucount; ++i) {
+        if (!readKeymasterBlob(in, &chain.entries[i])) {
+            keymaster_free_cert_chain(&chain);
+            return;
+        }
+    }
+}
+
+void KeymasterCertificateChain::writeToParcel(Parcel* out) const {
+    out->writeInt32(chain.entry_count);
+    for (size_t i = 0; i < chain.entry_count; ++i) {
+        if (chain.entries[i].data) {
+            out->writeInt32(1); // Tell Java side that object is not NULL
+            out->writeInt32(chain.entries[i].data_length);
+            void* buf = out->writeInplace(chain.entries[i].data_length);
+            if (buf) {
+                memcpy(buf, chain.entries[i].data, chain.entries[i].data_length);
+            } else {
+                ALOGE("Failed to writeInplace keymaster cert chain entry");
+            }
+        } else {
+            out->writeInt32(0); // Tell Java side this object is NULL.
+            ALOGE("Found NULL certificate chain entry");
+        }
+    }
+}
+
 void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out) {
     switch (keymaster_tag_get_type(param.tag)) {
         case KM_ENUM:
@@ -369,23 +432,9 @@
 }
 
 static std::unique_ptr<keymaster_blob_t> readKeymasterBlob(const Parcel& in) {
-    std::unique_ptr<keymaster_blob_t> blob;
-    if (in.readInt32() != 1) {
-        blob.reset(NULL);
-        return blob;
-    }
-    ssize_t length = in.readInt32();
-    blob.reset(new keymaster_blob_t);
-    if (length > 0) {
-        blob->data = reinterpret_cast<const uint8_t*>(in.readInplace(length));
-        if (blob->data) {
-            blob->data_length = static_cast<size_t>(length);
-        } else {
-            blob->data_length = 0;
-        }
-    } else {
-        blob->data = NULL;
-        blob->data_length = 0;
+    std::unique_ptr<keymaster_blob_t> blob (new keymaster_blob_t);
+    if (!readKeymasterBlob(in, blob.get())) {
+        blob.reset();
     }
     return blob;
 }
@@ -1257,6 +1306,34 @@
         return ret;
     }
 
+    virtual int32_t attestKey(const String16& name, const KeymasterArguments& params,
+                              KeymasterCertificateChain* outChain) {
+        if (!outChain)
+            return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(name);
+        data.writeInt32(1);  // params is not NULL.
+        params.writeToParcel(&data);
+
+        status_t status = remote()->transact(BnKeystoreService::ATTEST_KEY, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("attestkey() count not contact remote: %d\n", status);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("attestKey() caught exception %d\n", err);
+            return KM_ERROR_UNKNOWN_ERROR;
+        }
+        if (reply.readInt32() != 0) {
+            outChain->readFromParcel(reply);
+        }
+        return ret;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService");