trusty: keymaster: Add set_attestation_key

Add tool to provision keymaster attestation keys.

Bug: 154033394
Test: keys from soft_attestation_cert then VtsHalKeymasterV4_0TargetTest

Change-Id: Ic96e9a8676991b3126bbae99118a1f23ee0744a5
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6840baa..27e1a3f 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -75,3 +75,36 @@
 
     vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }
+
+prebuilt_etc {
+    name: "keymaster_soft_attestation_keys.xml",
+    vendor: true,
+    src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
+}
+
+cc_binary {
+    name: "trusty_keymaster_set_attestation_key",
+    vendor: true,
+
+    srcs: [
+        "set_attestation_key/set_attestation_key.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+    ],
+
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "libc",
+        "libcrypto",
+        "liblog",
+        "libtrusty",
+        "libhardware",
+        "libkeymaster_messages",
+        "libxml2",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 13e6725..ce2cc2e 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -53,6 +53,19 @@
     KM_DELETE_ALL_KEYS              = (23 << KEYMASTER_REQ_SHIFT),
     KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
     KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
+
+    // Bootloader/provisioning calls.
+    KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT),
+    KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_GET_CA_REQUEST = (0x4000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_BEGIN = (0x5000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_UPDATE = (0x6000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_FINISH = (0x7000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_READ_UUID = (0x8000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
+    KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
new file mode 100644
index 0000000..fce2ac2
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<AndroidAttestation>
+  <NumberOfKeyboxes>10</NumberOfKeyboxes>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="rsa">
+      <PrivateKey format="pem">
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
+KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
+O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
+AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
+wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
+woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
+NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
+0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
+DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
+ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
+TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
+qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
+fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
+-----END RSA PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
+MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
+aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
+qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
+4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
+XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
+k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
+BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
+M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
+Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
+9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
+MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
+CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
+Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
+t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
+AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
+FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
+HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
+DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
+Lvtc9mL1J1IXvmM=
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="ecdsa">
+      <PrivateKey format="pem">
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
+AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
+uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
+-----END EC PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
+VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
+ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
+MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
+bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
+dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
+efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
+U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
+qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
+AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
+wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
+Xvsiu+f+uXc/WT/7
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
+EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
+dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
+VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
+HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
+QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
+dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
+BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
+EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
+SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
+C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+</AndroidAttestation>
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
new file mode 100644
index 0000000..a89a4a8
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libxml/xmlreader.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string>
+
+using std::string;
+
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+static const char* _sopts = "h";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options] xml-file\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "\n";
+
+static void print_usage_and_exit(const char* prog, int code) {
+    fprintf(stderr, usage, prog);
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE);
+        }
+    }
+}
+
+struct SetAttestationKeyRequest : public keymaster::KeymasterMessage {
+    explicit SetAttestationKeyRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t) + key_data.SerializedSize(); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = keymaster::append_uint32_to_buf(buf, end, algorithm);
+        return key_data.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+               key_data.Deserialize(buf_ptr, end);
+    }
+
+    keymaster_algorithm_t algorithm;
+    keymaster::Buffer key_data;
+};
+
+struct KeymasterNoResponse : public keymaster::KeymasterResponse {
+    explicit KeymasterNoResponse(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : keymaster::KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct SetAttestationKeyResponse : public KeymasterNoResponse {};
+
+struct ClearAttestationCertChainRequest : public keymaster::KeymasterMessage {
+    explicit ClearAttestationCertChainRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return keymaster::append_uint32_to_buf(buf, end, algorithm);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm);
+    }
+
+    keymaster_algorithm_t algorithm;
+};
+
+struct ClearAttestationCertChainResponse : public KeymasterNoResponse {};
+
+static int set_attestation_key_or_cert_bin(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const void* key_data, size_t key_data_size) {
+    int ret;
+
+    SetAttestationKeyRequest req;
+    req.algorithm = algorithm;
+    req.key_data.Reinitialize(key_data, key_data_size);
+    SetAttestationKeyResponse rsp;
+
+    ret = trusty_keymaster_send(cmd, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int set_attestation_key_or_cert_pem(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const xmlChar* pemkey) {
+    int ret;
+    int sslret;
+
+    /* Convert from pem to binary */
+    BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
+    if (!bio) {
+        fprintf(stderr, "BIO_new_mem_buf failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    char* key_name;
+    char* key_header;
+    uint8_t* key;
+    long keylen;
+    sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
+    BIO_free(bio);
+
+    if (!sslret) {
+        fprintf(stderr, "PEM_read_bio failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    OPENSSL_free(key_name);
+    OPENSSL_free(key_header);
+    OPENSSL_free(key);
+
+    return ret;
+}
+
+static int set_attestation_key_or_cert_iecs(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                            const xmlChar* key_base64) {
+    int ret;
+    int sslret;
+
+    /* Remove all whitespace. EVP_DecodeBase64 does not support whitespace. */
+    string key_base64_str((const char*)key_base64);
+    key_base64_str.erase(remove_if(key_base64_str.begin(), key_base64_str.end(), isspace),
+                         key_base64_str.end());
+
+    /* Convert from base64 to binary */
+    uint8_t* key;
+    size_t keylen;
+    size_t key_base64_len = key_base64_str.length();
+
+    sslret = EVP_DecodedLength(&keylen, key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "invalid input length, %zu\n", key_base64_len);
+        return -1;
+    }
+    key = (uint8_t*)malloc(keylen);
+    if (!key) {
+        fprintf(stderr, "failed to allocate key, size %zu\n", key_base64_len);
+        return -1;
+    }
+    sslret = EVP_DecodeBase64(key, &keylen, keylen, (const uint8_t*)key_base64_str.data(),
+                              key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "EVP_DecodeBase64 failed\n");
+        ERR_print_errors_fp(stderr);
+        free(key);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    free(key);
+
+    return ret;
+}
+
+static int str_to_algorithm(keymaster_algorithm_t* algorithm, const xmlChar* algorithm_str) {
+    if (xmlStrEqual(algorithm_str, BAD_CAST "rsa")) {
+        *algorithm = KM_ALGORITHM_RSA;
+    } else if (xmlStrEqual(algorithm_str, BAD_CAST "ecdsa")) {
+        *algorithm = KM_ALGORITHM_EC;
+    } else {
+        printf("unsupported algorithm: %s\n", algorithm_str);
+        return -1;
+    }
+    return 0;
+}
+
+static int set_attestation_key_or_cert(uint32_t cmd, const xmlChar* algorithm_str,
+                                       const xmlChar* format, const xmlChar* str) {
+    int ret;
+    keymaster_algorithm_t algorithm;
+
+    ret = str_to_algorithm(&algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    if (xmlStrEqual(format, BAD_CAST "pem")) {
+        ret = set_attestation_key_or_cert_pem(cmd, algorithm, str);
+    } else if (xmlStrEqual(format, BAD_CAST "iecs")) {
+        ret = set_attestation_key_or_cert_iecs(cmd, algorithm, str);
+    } else {
+        printf("unsupported key/cert format: %s\n", format);
+        return -1;
+    }
+    return ret;
+}
+
+static int clear_cert_chain(const xmlChar* algorithm_str) {
+    int ret;
+    ClearAttestationCertChainRequest req;
+    ClearAttestationCertChainResponse rsp;
+
+    ret = str_to_algorithm(&req.algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    ret = trusty_keymaster_send(KM_CLEAR_ATTESTATION_CERT_CHAIN, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
+        return ret;
+    }
+    return 0;
+}
+
+static int process_xml(xmlTextReaderPtr xml) {
+    int ret;
+    const xmlChar* algorithm = NULL;
+    const xmlChar* element = NULL;
+    const xmlChar* element_format = NULL;
+
+    while ((ret = xmlTextReaderRead(xml)) == 1) {
+        int nodetype = xmlTextReaderNodeType(xml);
+        const xmlChar *name, *value;
+        name = xmlTextReaderConstName(xml);
+        switch (nodetype) {
+            case XML_READER_TYPE_ELEMENT:
+                element = name;
+                element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
+                if (xmlStrEqual(name, BAD_CAST "Key")) {
+                    algorithm = xmlTextReaderGetAttribute(xml, BAD_CAST "algorithm");
+                } else if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
+                    ret = clear_cert_chain(algorithm);
+                    if (ret) {
+                        fprintf(stderr, "%s, algorithm %s: Clear cert chain cmd failed, %d\n",
+                                element, algorithm, ret);
+                        return ret;
+                    }
+                    printf("%s, algorithm %s: Clear cert chain cmd done\n", element, algorithm);
+                }
+                break;
+            case XML_READER_TYPE_TEXT:
+                value = xmlTextReaderConstValue(xml);
+                uint32_t cmd;
+                if (xmlStrEqual(element, BAD_CAST "PrivateKey")) {
+                    cmd = KM_SET_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "WrappedPrivateKey")) {
+                    cmd = KM_SET_WRAPPED_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "Certificate")) {
+                    cmd = KM_APPEND_ATTESTATION_CERT_CHAIN;
+                } else {
+                    break;
+                }
+
+                ret = set_attestation_key_or_cert(cmd, algorithm, element_format, value);
+                if (ret) {
+                    fprintf(stderr, "%s, algorithm %s, format %s: Cmd 0x%x failed, %d\n", element,
+                            algorithm, element_format, cmd, ret);
+                    return ret;
+                }
+                printf("%s, algorithm %s, format %s: Cmd 0x%x done\n", element, algorithm,
+                       element_format, cmd);
+                break;
+            case XML_READER_TYPE_END_ELEMENT:
+                element = NULL;
+                break;
+        }
+    }
+    return ret;
+}
+
+static int parse_xml_file(const char* filename) {
+    int ret;
+    xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
+    if (!xml) {
+        fprintf(stderr, "failed to open %s\n", filename);
+        return -1;
+    }
+
+    ret = process_xml(xml);
+
+    xmlFreeTextReader(xml);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to parse or process %s\n", filename);
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    int ret = 0;
+
+    parse_options(argc, argv);
+    if (optind + 1 != argc) {
+        print_usage_and_exit(argv[0], EXIT_FAILURE);
+    }
+
+    ret = trusty_keymaster_connect();
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
+    } else {
+        ret = parse_xml_file(argv[optind]);
+        trusty_keymaster_disconnect();
+    }
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
index fd353d1..dc4c962 100644
--- a/trusty/trusty-test.mk
+++ b/trusty/trusty-test.mk
@@ -14,3 +14,5 @@
 
 PRODUCT_PACKAGES += \
 	spiproxyd \
+	trusty_keymaster_set_attestation_key \
+	keymaster_soft_attestation_keys.xml \
\ No newline at end of file