[samples] Add sample hwcrypto app

Sample hwcrypto app illustrates implementing
HWRNG and HWKEY interfaces so it can be used
as a starting point for real implementation.
It MUST not be shipped as is.

Change-Id: I33be3b778ed392488bac81205771537c833b027b
diff --git a/hwcrypto/common.h b/hwcrypto/common.h
new file mode 100644
index 0000000..f40b518
--- /dev/null
+++ b/hwcrypto/common.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <compiler.h>
+#include <sys/types.h>
+#include <trusty_std.h>
+
+#define TLOGE(fmt, ...) \
+    fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__,  ## __VA_ARGS__)
+
+#if LOCAL_TRACE
+#define TLOGI(fmt, ...) \
+    fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__,  ## __VA_ARGS__)
+#else
+#define TLOGI(fmt, ...)
+#endif
+
+typedef void (*event_handler_proc_t) (const uevent_t *ev, void *ctx);
+
+typedef struct tipc_event_handler {
+	event_handler_proc_t proc;
+	void *priv;
+} tipc_event_handler_t;
+
+
+__BEGIN_CDECLS
+
+/*
+ *  tipc helpers
+ */
+void tipc_handle_port_errors(const uevent_t *ev);
+void tipc_handle_chan_errors(const uevent_t *ev);
+
+int tipc_send_single_buf(handle_t chan, const void *buf, size_t len);
+int tipc_recv_single_buf(handle_t chan, void *buf, size_t len);
+
+int tipc_send_two_segments(handle_t chan, const void *hdr, size_t hdr_len,
+			   const void *payload, size_t payload_len);
+
+int tipc_recv_two_segments(handle_t chan, void *hdr, size_t hdr_len,
+			   void *payload, size_t payload_len);
+
+/*
+ * tipc services
+ */
+int hwrng_setup_service(void);
+int hwkey_setup_service(void);
+
+__END_CDECLS
+
diff --git a/hwcrypto/hwkey_srv.c b/hwcrypto/hwkey_srv.c
new file mode 100644
index 0000000..b0984ae
--- /dev/null
+++ b/hwcrypto/hwkey_srv.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <compiler.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <trusty_std.h>
+#include <interface/hwkey/hwkey.h>
+
+#include "common.h"
+#include "uuids.h"
+#include "hwkey_srv_priv.h"
+
+#define LOCAL_TRACE  1
+#define LOG_TAG      "hwkey_srv"
+
+#define HWKEY_MAX_PAYLOAD_SIZE 2048
+
+struct hwkey_chan_ctx {
+	tipc_event_handler_t evt_handler;
+	handle_t chan;
+	uuid_t uuid;
+};
+
+static void hwkey_port_handler(const uevent_t *ev, void *priv);
+static void hwkey_chan_handler(const uevent_t *ev, void *priv);
+
+static tipc_event_handler_t hwkey_port_evt_handler = {
+	.proc = hwkey_port_handler,
+};
+
+static uint8_t req_data[HWKEY_MAX_PAYLOAD_SIZE+1];
+static uint8_t key_data[HWKEY_MAX_PAYLOAD_SIZE];
+
+static uint key_slot_cnt;
+static const struct hwkey_keyslot *key_slots;
+
+
+#if WITH_HWCRYPTO_UNITTEST
+/*
+ *  Support for hwcrypto unittest keys should be only enabled
+ *  to test hwcrypto related APIs
+ */
+
+/* UUID of HWCRYPTO_UNITTEST application */
+static const uuid_t hwcrypto_unittest_uuid = HWCRYPTO_UNITTEST_APP_UUID;
+
+static uint8_t _unittest_key32[32] = "unittestkeyslotunittestkeyslotun";
+static uint32_t get_unittest_key32(const struct hwkey_keyslot *slot,
+				   uint8_t *kbuf, size_t kbuf_len, size_t *klen)
+{
+	assert(kbuf);
+	assert(klen);
+	assert(kbuf_len >= sizeof(_unittest_key32));
+
+	/* just return predefined key */
+	memcpy(kbuf, _unittest_key32, sizeof(_unittest_key32));
+	*klen = sizeof(_unittest_key32);
+
+	return HWKEY_NO_ERROR;
+}
+
+static const struct hwkey_keyslot test_key_slots[] = {
+	{
+		.uuid = &hwcrypto_unittest_uuid,
+		.key_id = "com.android.trusty.hwcrypto.unittest.key32",
+		.handler = get_unittest_key32,
+	},
+};
+#endif /* WITH_HWCRYPTO_UNITTEST */
+
+/*
+ * Close specified hwkey context
+ */
+static void hwkey_ctx_close(struct hwkey_chan_ctx *ctx)
+{
+	close(ctx->chan);
+	free(ctx);
+}
+
+/*
+ * Send response message
+ */
+static int hwkey_send_rsp(struct hwkey_chan_ctx *ctx,
+			  struct hwkey_msg *rsp_hdr,
+			  uint8_t *rsp_data, size_t rsp_data_len)
+{
+	rsp_hdr->cmd |= HWKEY_RESP_BIT;
+	return tipc_send_two_segments(ctx->chan,
+				      rsp_hdr, sizeof(*rsp_hdr),
+				      rsp_data, rsp_data_len);
+}
+
+
+static uint32_t _handle_slots(struct hwkey_chan_ctx *ctx,
+			      const char *slot_id,
+			      const struct hwkey_keyslot *slots, uint slot_cnt,
+			      uint8_t *kbuf, size_t kbuf_len, size_t *klen)
+{
+	if (!slots)
+		return HWKEY_ERR_NOT_FOUND;
+
+	for (uint i = 0; i < slot_cnt; i++, slots++) {
+
+		/* check key id */
+		if (strcmp(slots->key_id, slot_id))
+			continue;
+
+		/* Check if the caller is allowed to get that key */
+		if (memcmp(&ctx->uuid, slots->uuid, sizeof(uuid_t)) == 0) {
+			if (slots->handler) {
+				return slots->handler(slots, kbuf, kbuf_len, klen);
+			}
+		}
+	}
+	return HWKEY_ERR_NOT_FOUND;
+}
+
+
+/*
+ * Handle get key slot command
+ */
+static int hwkey_handle_get_keyslot_cmd(struct hwkey_chan_ctx *ctx,
+					struct hwkey_msg *hdr,
+					const char *slot_id)
+{
+	int rc;
+	size_t klen = 0;
+
+	hdr->status = _handle_slots(ctx, slot_id,
+				    key_slots, key_slot_cnt,
+				    key_data,  sizeof(key_data), &klen);
+
+#if WITH_HWCRYPTO_UNITTEST
+	if (hdr->status == HWKEY_ERR_NOT_FOUND) {
+		/* also search test keys */
+		hdr->status  = _handle_slots(ctx, slot_id,
+					     test_key_slots, countof(test_key_slots),
+					     key_data,  sizeof(key_data), &klen);
+	}
+#endif
+
+	rc = hwkey_send_rsp(ctx, hdr, key_data, klen);
+	if (klen) {
+		/* sanitize key buffer */
+		memset(key_data, 0, klen);
+	}
+	return rc;
+}
+
+/*
+ * Handle Derive key cmd
+ */
+static int hwkey_handle_derive_key_cmd(struct hwkey_chan_ctx *ctx,
+				       struct hwkey_msg *hdr,
+				       const uint8_t *ikm_data, size_t ikm_len)
+{
+	int rc;
+	size_t key_len = sizeof(key_data);
+
+	/* check requested key derivation function */
+	if (hdr->arg1 == HWKEY_KDF_VERSION_BEST)
+		hdr->arg1 = HWKEY_KDF_VERSION_1; /* we only support V1 */
+
+	switch (hdr->arg1) {
+	case HWKEY_KDF_VERSION_1:
+		hdr->status = derive_key_v1(&ctx->uuid, ikm_data, ikm_len,
+					    key_data, &key_len);
+		break;
+
+	default:
+		TLOGE("%u is unsupported KDF function\n", hdr->arg1);
+		key_len = 0;
+		hdr->status = HWKEY_ERR_NOT_IMPLEMENTED;
+	}
+
+	rc = hwkey_send_rsp(ctx, hdr, key_data, key_len);
+	if (key_len) {
+		/* sanitize key buffer */
+		memset(key_data, 0, key_len);
+	}
+	return rc;
+}
+
+/*
+ *  Read and queue HWKEY request message
+ */
+static int hwkey_chan_handle_msg(struct hwkey_chan_ctx *ctx)
+{
+	int rc;
+	size_t req_data_len;
+	struct hwkey_msg hdr;
+
+	rc = tipc_recv_two_segments(ctx->chan, &hdr, sizeof(hdr),
+				    req_data, sizeof(req_data) - 1);
+	if (rc < 0) {
+		TLOGE("failed (%d) to recv msg from chan %d\n", rc, ctx->chan);
+		return rc;
+	}
+
+	/* calculate payload length */
+	req_data_len = (size_t)rc - sizeof(hdr);
+
+	/* handle it */
+	switch (hdr.cmd) {
+	case HWKEY_GET_KEYSLOT:
+		req_data[req_data_len] = 0; /* force zero termination */
+		rc = hwkey_handle_get_keyslot_cmd(ctx, &hdr, (const char *)req_data);
+		break;
+
+	case HWKEY_DERIVE:
+		rc = hwkey_handle_derive_key_cmd(ctx, &hdr, req_data, req_data_len);
+		memset(req_data, 0, req_data_len); /* sanitize request buffer */
+		break;
+
+	default:
+		TLOGE("Unsupported request: %d\n", (int)hdr.cmd);
+		hdr.status = HWKEY_ERR_NOT_IMPLEMENTED;
+		rc = hwkey_send_rsp(ctx, &hdr, NULL, 0);
+	}
+
+	return rc;
+}
+
+/*
+ *  HWKEY service channel event handler
+ */
+static void hwkey_chan_handler(const uevent_t *ev, void *priv)
+{
+	struct hwkey_chan_ctx *ctx = priv;
+
+	assert(ctx);
+	assert(ev->handle == ctx->chan);
+
+	tipc_handle_chan_errors(ev);
+
+	if (ev->event & IPC_HANDLE_POLL_HUP) {
+		/* closed by peer. */
+		hwkey_ctx_close(ctx);
+		return;
+	}
+
+	if (ev->event & IPC_HANDLE_POLL_MSG) {
+		int rc = hwkey_chan_handle_msg(ctx);
+		if (rc < 0) {
+			/* report an error and close channel */
+			TLOGE("failed (%d) to handle event on channel %d\n",
+			      rc, ev->handle);
+			hwkey_ctx_close(ctx);
+		}
+	}
+}
+
+/*
+ * HWKEY service port event handler
+ */
+static void hwkey_port_handler(const uevent_t *ev, void *priv)
+{
+	uuid_t peer_uuid;
+
+	tipc_handle_port_errors(ev);
+
+	if (ev->event & IPC_HANDLE_POLL_READY) {
+		/* incoming connection: accept it */
+		int rc = accept(ev->handle, &peer_uuid);
+		if (rc < 0) {
+			TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
+			return;
+		}
+
+		handle_t chan = (handle_t) rc;
+		struct hwkey_chan_ctx *ctx = calloc(1, sizeof(*ctx));
+		if (!ctx) {
+			TLOGE("failed (%d) to allocate context on chan %d\n", rc, chan);
+			close(chan);
+			return;
+		}
+
+		/* init channel state */
+		ctx->evt_handler.priv = ctx;
+		ctx->evt_handler.proc = hwkey_chan_handler;
+		ctx->chan = chan;
+		ctx->uuid = peer_uuid;
+
+		rc = set_cookie(chan, &ctx->evt_handler);
+		if (rc < 0) {
+			TLOGE("failed (%d) to set_cookie on chan %d\n",
+			       rc, chan);
+			hwkey_ctx_close(ctx);
+			return;
+		}
+	}
+}
+
+/*
+ *  Install Key slot provider
+ */
+void hwkey_install_keys(const struct hwkey_keyslot *keys, uint kcnt)
+{
+	assert(key_slots == NULL);
+	assert(key_slot_cnt == 0);
+	assert(keys && kcnt);
+
+	key_slots = keys;
+	key_slot_cnt = kcnt;
+}
+
+/*
+ *  Initialize HWKEY service
+ */
+int hwkey_start_service(void)
+{
+	int rc;
+	handle_t port;
+
+	TLOGI("Start HWKEY service\n");
+
+	/* Initialize service */
+	rc = port_create(HWKEY_PORT, 1, sizeof(struct hwkey_msg) + HWKEY_MAX_PAYLOAD_SIZE,
+			 IPC_PORT_ALLOW_TA_CONNECT);
+	if (rc < 0) {
+		TLOGE("Failed (%d) to create port %s\n", rc, HWKEY_PORT);
+		return rc;
+	}
+
+	port = (handle_t) rc;
+	rc = set_cookie(port, &hwkey_port_evt_handler);
+	if (rc) {
+		TLOGE("failed (%d) to set_cookie on port %d\n", rc, port);
+		close(port);
+		return rc;
+	}
+
+	return NO_ERROR;
+}
diff --git a/hwcrypto/hwkey_srv_fake_provider.c b/hwcrypto/hwkey_srv_fake_provider.c
new file mode 100644
index 0000000..c8c1a85
--- /dev/null
+++ b/hwcrypto/hwkey_srv_fake_provider.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <trusty_std.h>
+#include <interface/hwkey/hwkey.h>
+#include <openssl/cipher.h>
+#include <openssl/aes.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/hkdf.h>
+
+#include "common.h"
+#include "uuids.h"
+#include "hwkey_srv_priv.h"
+
+#define LOCAL_TRACE  1
+#define LOG_TAG      "hwkey_fake_srv"
+
+#warning "Compiling FAKE HWKEY provider"
+
+/*
+ *  This module is a sample only. For real device, this code
+ *  needs to be rewritten to operate on real per device key that
+ *  should come directly or indirectly from hardware.
+ */
+static uint8_t fake_device_key[32] = "this is a fake unique device key";
+
+/* This input vector is taken from RFC 5869 (Extract-and-Expand HKDF) */
+static const uint8_t IKM[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+			       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+
+static const uint8_t salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+				0x08, 0x09, 0x0a, 0x0b, 0x0c };
+
+static const uint8_t info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
+
+/* Expected pseudorandom key */
+static const uint8_t exp_PRK[] = { 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+				   0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+				   0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+				   0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 };
+
+/* Expected Output Key */
+static const uint8_t exp_OKM[42]= { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+				    0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+				    0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+				    0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+				    0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+				    0x58, 0x65 };
+
+static bool hkdf_self_test(void)
+{
+	int res;
+	uint8_t OKM[sizeof(exp_OKM)];
+
+	TLOGI("hkdf self test\n");
+
+	/* Check if OKM is OK */
+	memset(OKM, 0x55, sizeof(OKM));
+
+	res = HKDF(OKM, sizeof(OKM), EVP_sha256(),
+		   IKM, sizeof(IKM), salt, sizeof(salt), info, sizeof(info));
+	if (!res) {
+		TLOGE("hkdf: failed 0x%x\n", ERR_get_error());
+		return false;
+	}
+
+	res = memcmp(OKM, exp_OKM, sizeof(OKM));
+	if (res) {
+		TLOGE("hkdf: data mismatch\n");
+		return false;
+	}
+
+	TLOGI("hkdf self test: PASSED\n");
+	return true;
+}
+
+/*
+ * Derive key V1 - HMAC SHA256 based Key derivation function
+ */
+uint32_t derive_key_v1(const uuid_t *uuid,
+		       const uint8_t *ikm_data, size_t ikm_len,
+		       uint8_t *key_buf, size_t *key_len)
+{
+	if (!ikm_len) {
+		*key_len = 0;
+		return HWKEY_ERR_BAD_LEN;
+	}
+
+	if (!HKDF(key_buf, ikm_len, EVP_sha256(),
+		  (const uint8_t *)fake_device_key, sizeof(fake_device_key),
+		  (const uint8_t *)uuid, sizeof(uuid),
+		  ikm_data, ikm_len)) {
+		TLOGE("HDKF failed 0x%x\n", ERR_get_error());
+		*key_len = 0;
+		memset(key_buf, 0, ikm_len);
+		return HWKEY_ERR_GENERIC;
+	}
+
+	*key_len = ikm_len;
+
+	return HWKEY_NO_ERROR;
+}
+
+/*
+ *  RPMB Key support
+ */
+#define RPMB_SS_AUTH_KEY_SIZE    32
+#define RPMB_SS_AUTH_KEY_ID      "com.android.trusty.storage_auth.rpmb"
+
+/* Secure storage service app uuid */
+static const uuid_t ss_uuid = SECURE_STORAGE_SERVER_APP_UUID;
+
+static uint8_t rpmb_salt[RPMB_SS_AUTH_KEY_SIZE] = {
+	0x42, 0x18, 0xa9, 0xf2, 0xf6, 0xb1, 0xf5, 0x35,
+	0x06, 0x37, 0x9f, 0xba, 0xcc, 0x1a, 0xc9, 0x36,
+	0xf4, 0x83, 0x04, 0xd4, 0xf1, 0x65, 0x91, 0x32,
+	0xa6, 0xae, 0xda, 0x27, 0x4d, 0x21, 0xdb, 0x40
+};
+
+/*
+ * Generate RPMB Secure Storage Authentication key
+ */
+static uint32_t get_rpmb_ss_auth_key(const struct hwkey_keyslot *slot,
+				     uint8_t *kbuf, size_t kbuf_len, size_t *klen)
+{
+	int rc;
+	int out_len;
+	EVP_CIPHER_CTX evp;
+
+	assert(kbuf);
+	assert(klen);
+
+	EVP_CIPHER_CTX_init(&evp);
+
+	rc = EVP_EncryptInit_ex(&evp, EVP_aes_256_cbc(), NULL, fake_device_key, NULL);
+	if (!rc)
+		goto evp_err;
+
+	rc = EVP_CIPHER_CTX_set_padding(&evp, 0);
+	if (!rc)
+		goto evp_err;
+
+	uint min_kbuf_len = RPMB_SS_AUTH_KEY_SIZE + EVP_CIPHER_CTX_key_length(&evp);
+	if (kbuf_len < min_kbuf_len) {
+		TLOGE("buffer too small: (%zd vs. %zd )\n", kbuf_len,  min_kbuf_len);
+		goto other_err;
+	}
+
+	rc = EVP_EncryptUpdate(&evp, kbuf, &out_len, rpmb_salt, sizeof(rpmb_salt));
+	if (!rc)
+		goto evp_err;
+
+	if ((size_t)out_len != RPMB_SS_AUTH_KEY_SIZE) {
+		TLOGE("output length mismatch (%zd vs %zd)\n",
+			(size_t)out_len, sizeof(rpmb_salt));
+		goto other_err;
+	}
+
+	rc = EVP_EncryptFinal_ex(&evp, NULL, &out_len);
+	if (!rc)
+		goto evp_err;
+
+	*klen = RPMB_SS_AUTH_KEY_SIZE;
+
+	EVP_CIPHER_CTX_cleanup(&evp);
+	return HWKEY_NO_ERROR;
+
+evp_err:
+	TLOGE("EVP err 0x%x\n", ERR_get_error());
+other_err:
+	EVP_CIPHER_CTX_cleanup(&evp);
+	return HWKEY_ERR_GENERIC;
+}
+
+/*
+ *  List of keys slots that hwkey service supports
+ */
+static const struct hwkey_keyslot _keys[] = {
+	{
+		.uuid = &ss_uuid,
+		.key_id = RPMB_SS_AUTH_KEY_ID,
+		.handler = get_rpmb_ss_auth_key,
+	},
+};
+
+/*
+ *  Run Self test
+ */
+static bool hwkey_self_test(void)
+{
+	TLOGI("hwkey self test\n");
+
+	if (!hkdf_self_test())
+		return false;
+
+	TLOGI("hwkey self test: PASSED\n");
+	return true;
+}
+
+/*
+ *  Initialize Fake HWKEY service provider
+ */
+void hwkey_init_srv_provider(void)
+{
+	int rc;
+
+	TLOGE("Init FAKE!!!! HWKEY service provider\n");
+	TLOGE("FAKE HWKEY service provider MUST be replaced with the REAL one\n");
+
+	/* run self test */
+	if (!hwkey_self_test()) {
+		TLOGE("hwkey_self_test failed\n");
+		abort();
+	}
+
+	/* install key handlers */
+	hwkey_install_keys(_keys, countof(_keys));
+
+	/* start service */
+	rc = hwkey_start_service();
+	if (rc != NO_ERROR ) {
+		TLOGE("failed (%d) to start HWKEY service\n", rc);
+	}
+}
diff --git a/hwcrypto/hwkey_srv_priv.h b/hwcrypto/hwkey_srv_priv.h
new file mode 100644
index 0000000..1836bb6
--- /dev/null
+++ b/hwcrypto/hwkey_srv_priv.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include <compiler.h>
+#include <sys/types.h>
+#include <trusty_uuid.h>
+
+struct hwkey_keyslot {
+	const char *key_id;
+	const uuid_t *uuid;
+	const void *priv;
+	uint32_t (*handler)(const struct hwkey_keyslot *slot,
+			    uint8_t *kbuf, size_t kbuf_len, size_t *klen);
+};
+
+__BEGIN_CDECLS
+
+void hwkey_init_srv_provider(void);
+
+void hwkey_install_keys(const struct hwkey_keyslot *keys, uint kcnt);
+
+int  hwkey_start_service(void);
+
+uint32_t derive_key_v1(const uuid_t *uuid,
+		       const uint8_t *ikm_data, size_t ikm_len,
+		       uint8_t *key_data, size_t *key_len);
+
+__END_CDECLS
+
+
diff --git a/hwcrypto/hwrng_srv.c b/hwcrypto/hwrng_srv.c
new file mode 100644
index 0000000..9f6e4e9
--- /dev/null
+++ b/hwcrypto/hwrng_srv.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <err.h>
+#include <list.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <trusty_std.h>
+#include <interface/hwrng/hwrng.h>
+
+#include "common.h"
+#include "hwrng_srv_priv.h"
+
+#define LOCAL_TRACE       1
+#define LOG_TAG           "hwrng_srv"
+
+#define HWRNG_SRV_NAME       HWRNG_PORT
+#define MAX_HWRNG_MSG_SIZE   4096
+
+struct hwrng_chan_ctx {
+	tipc_event_handler_t evt_handler;
+	struct list_node node;
+	handle_t chan;
+	size_t req_size;
+	bool send_blocked;
+};
+
+static void hwrng_port_handler(const uevent_t *ev, void *priv);
+static void hwrng_chan_handler(const uevent_t *ev, void *priv);
+
+static handle_t hwrng_port  = INVALID_IPC_HANDLE;
+
+static tipc_event_handler_t hwrng_port_evt_handler = {
+	.proc = hwrng_port_handler,
+};
+
+static uint8_t rng_data[MAX_HWRNG_MSG_SIZE];
+
+static struct list_node hwrng_req_list = LIST_INITIAL_VALUE(hwrng_req_list);
+
+/****************************************************************************/
+
+/*
+ *  Hexdump content of memory region
+ */
+static void _hexdump8(const void *ptr, size_t len)
+{
+	addr_t address = (addr_t)ptr;
+	size_t count;
+	size_t i;
+
+	for (count = 0 ; count < len; count += 16) {
+		fprintf(stderr, "0x%08lx: ", address);
+		for (i=0; i < MIN(len - count, 16); i++) {
+			fprintf(stderr, "0x%02hhx ", *(const uint8_t *)(address + i));
+		}
+		fprintf(stderr, "\n");
+		address += 16;
+	}
+}
+
+/*
+ * Close specified HWRNG service channel
+ */
+static void hwrng_close_chan(struct hwrng_chan_ctx *ctx)
+{
+	close(ctx->chan);
+
+	if (list_in_list(&ctx->node))
+		list_delete(&ctx->node);
+
+	free(ctx);
+}
+
+/*
+ * Handle HWRNG request queue
+ */
+static bool hwrng_handle_req_queue(void)
+{
+	struct hwrng_chan_ctx *ctx;
+	struct hwrng_chan_ctx *temp;
+
+	/* service channels */
+	bool need_more = false;
+
+	/* for all pending requests */
+	list_for_every_entry_safe(&hwrng_req_list, ctx, temp,
+				  struct hwrng_chan_ctx, node) {
+
+		if (ctx->send_blocked)
+			continue; /* cant service it rignt now */
+
+		size_t len = ctx->req_size;
+
+		if (len > MAX_HWRNG_MSG_SIZE)
+			len = MAX_HWRNG_MSG_SIZE;
+
+		/* get rng data */
+		hwrng_dev_get_rng_data(rng_data, len);
+
+		/* send reply */
+		int rc = tipc_send_single_buf(ctx->chan, rng_data, len);
+		if (rc < 0) {
+			if (rc == ERR_NOT_ENOUGH_BUFFER) {
+				/* mark it as send_blocked */
+				ctx->send_blocked = true;
+			} else {
+				/* just close HWRNG request channel */
+				TLOGE("failed (%d) to send_reply\n", rc);
+				hwrng_close_chan(ctx);
+			}
+			continue;
+		}
+
+		ctx->req_size -= len;
+
+		if (ctx->req_size == 0) {
+			/* remove it from pending list */
+			list_delete(&ctx->node);
+		} else {
+			need_more = true;
+		}
+	}
+
+	return need_more;
+}
+
+/*
+ * Check if we can handle request queue
+ */
+static void hwrng_kick_req_queue(void)
+{
+	hwrng_handle_req_queue();
+}
+
+/*
+ *  Read and queue HWRNG request message
+ */
+static int hwrng_chan_handle_msg(struct hwrng_chan_ctx *ctx)
+{
+	int rc;
+	struct hwrng_req req;
+
+	assert(ctx);
+
+	/* read request */
+	rc = tipc_recv_single_buf(ctx->chan, &req, sizeof(req));
+	if (rc != sizeof(req)) {
+		TLOGE("failed (%d) to receive msg for chan %d\n",
+		      rc, ctx->chan);
+		return rc;
+	}
+
+	/* check if we already have request in progress */
+	if (list_in_list(&ctx->node)) {
+		/* extend it */
+		ctx->req_size += req.len;
+	} else {
+		/* queue it */
+		ctx->req_size = req.len;
+		list_add_tail(&hwrng_req_list, &ctx->node);
+	}
+
+	return 0;
+}
+
+/*
+ *  Channel handler where HWRNG requests are coming from
+ */
+static void hwrng_chan_handler(const uevent_t *ev, void *priv)
+{
+	struct hwrng_chan_ctx *ctx = priv;
+
+	assert(ctx);
+	assert(ev->handle == ctx->chan);
+
+	tipc_handle_chan_errors(ev);
+
+	if (ev->event & IPC_HANDLE_POLL_HUP) {
+		hwrng_close_chan(ctx);
+	} else {
+		if (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
+			ctx->send_blocked = false;
+		}
+
+		if (ev->event & IPC_HANDLE_POLL_MSG) {
+			int rc = hwrng_chan_handle_msg(ctx);
+			if (rc) {
+				hwrng_close_chan(ctx);
+			}
+		}
+	}
+
+	/* kick state machine */
+	hwrng_kick_req_queue();
+}
+
+/*
+ * Port were HWRNG requests are coming from
+ */
+static void hwrng_port_handler(const uevent_t *ev, void *priv)
+{
+	uuid_t peer_uuid;
+
+	tipc_handle_port_errors(ev);
+
+	if (ev->event & IPC_HANDLE_POLL_READY) {
+		handle_t chan;
+
+		/* incoming connection: accept it */
+		int rc = accept(ev->handle, &peer_uuid);
+		if (rc < 0) {
+			TLOGE("failed (%d) to accept on port %d\n",
+			       rc, ev->handle);
+			return;
+		}
+		chan = (handle_t) rc;
+
+		/* allocate state */
+		struct hwrng_chan_ctx *ctx = calloc(1, sizeof(*ctx));
+		if (!ctx) {
+			TLOGE("failed to alloc state for chan %d\n", chan);
+			close(chan);
+			return;
+		}
+
+		/* init channel state */
+		ctx->evt_handler.priv = ctx;
+		ctx->evt_handler.proc = hwrng_chan_handler;
+		ctx->chan = chan;
+
+		/* attach channel handler */
+		rc = set_cookie(chan, &ctx->evt_handler);
+		if (rc) {
+			TLOGE("failed (%d) to set_cookie on chan %d\n",
+			       rc, chan);
+			free(ctx);
+			close(chan);
+			return;
+		}
+	}
+}
+
+/*
+ *  Initialize HWRNG services
+ */
+int hwrng_start_service(void)
+{
+	int rc;
+
+	TLOGI("Start HWRNG service\n");
+
+	/* create HWRNG port */
+	rc = port_create(HWRNG_SRV_NAME, 1, MAX_HWRNG_MSG_SIZE,
+			 IPC_PORT_ALLOW_TA_CONNECT);
+	if (rc < 0) {
+		TLOGE("Failed (%d) to create port '%s'\n", rc, HWRNG_SRV_NAME);
+		return rc;
+	} else {
+		hwrng_port = (handle_t)rc;
+		set_cookie(hwrng_port, &hwrng_port_evt_handler);
+	}
+
+	return NO_ERROR;
+}
diff --git a/hwcrypto/hwrng_srv_fake_provider.c b/hwcrypto/hwrng_srv_fake_provider.c
new file mode 100644
index 0000000..cc26858
--- /dev/null
+++ b/hwcrypto/hwrng_srv_fake_provider.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "hwrng_srv_priv.h"
+
+#define LOCAL_TRACE  1
+#define LOG_TAG      "hwrng_fake_srv"
+
+#warning "Compiling FAKE HWRNG provider"
+
+void hwrng_dev_get_rng_data(uint8_t *buf, size_t buf_len)
+{
+	memset(buf, 0, buf_len);
+}
+
+void hwrng_init_srv_provider(void)
+{
+	int rc;
+
+	TLOGE("Init FAKE!!!! HWRNG service provider\n");
+	TLOGE("FAKE HWRNG service provider MUST be replaced with the REAL one\n");
+
+	/* Nothing to initialize here, just start service */
+	rc = hwrng_start_service();
+	if (rc != NO_ERROR) {
+		TLOGE("failed (%d) to start HWRNG service\n", rc);
+	}
+}
+
diff --git a/hwcrypto/hwrng_srv_priv.h b/hwcrypto/hwrng_srv_priv.h
new file mode 100644
index 0000000..1fa3690
--- /dev/null
+++ b/hwcrypto/hwrng_srv_priv.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include <compiler.h>
+
+__BEGIN_CDECLS
+
+void hwrng_init_srv_provider(void);
+int  hwrng_start_service(void);
+
+void hwrng_dev_get_rng_data(uint8_t *buf, size_t buf_len);
+
+__END_CDECLS
diff --git a/hwcrypto/main.c b/hwcrypto/main.c
new file mode 100644
index 0000000..cf4e25b
--- /dev/null
+++ b/hwcrypto/main.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <trusty_std.h>
+
+
+#define LOCAL_TRACE  1
+#define LOG_TAG      "hwcrypto_srv"
+
+#include "common.h"
+#include "hwrng_srv_priv.h"
+#include "hwkey_srv_priv.h"
+
+
+/*
+ *  Hexdump content of memory region
+ */
+void _hexdump8(const void *ptr, size_t len)
+{
+	addr_t address = (addr_t)ptr;
+	size_t count;
+	size_t i;
+
+	for (count = 0 ; count < len; count += 16) {
+		fprintf(stderr, "0x%08lx: ", address);
+		for (i=0; i < MIN(len - count, 16); i++) {
+			fprintf(stderr, "0x%02hhx ", *(const uint8_t *)(address + i));
+		}
+		fprintf(stderr, "\n");
+		address += 16;
+	}
+}
+
+
+/*
+ * Handle common unexpected port events
+ */
+void tipc_handle_port_errors(const uevent_t *ev)
+{
+	if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
+	    (ev->event & IPC_HANDLE_POLL_HUP) ||
+	    (ev->event & IPC_HANDLE_POLL_MSG) ||
+	    (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
+		/* should never happen with port handles */
+		TLOGE("error event (0x%x) for port (%d)\n",
+		       ev->event, ev->handle);
+		abort();
+	}
+}
+
+/*
+ * Handle common unexpected channel events
+ */
+void tipc_handle_chan_errors(const uevent_t *ev)
+{
+	if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
+	    (ev->event & IPC_HANDLE_POLL_READY)) {
+		/* close it as it is in an error state */
+		TLOGE("error event (0x%x) for chan (%d)\n",
+		       ev->event, ev->handle);
+		abort();
+	}
+}
+
+/*
+ *  Send single buf message
+ */
+int tipc_send_single_buf(handle_t chan, const void *buf, size_t len)
+{
+	iovec_t iov = {
+			.base = (void *)buf,
+			.len  = len,
+	};
+	ipc_msg_t msg = {
+			.iov = &iov,
+			.num_iov = 1,
+
+	};
+	return send_msg(chan, &msg);
+}
+
+/*
+ *  Receive single buf message
+ */
+int tipc_recv_single_buf(handle_t chan, void *buf, size_t len)
+{
+	int rc;
+	ipc_msg_info_t msg_inf;
+
+	rc = get_msg(chan, &msg_inf);
+	if (rc)
+		return rc;
+
+	if (msg_inf.len != len) {
+		/* unexpected msg size */
+		rc = ERR_BAD_LEN;
+	} else {
+		iovec_t iov = {
+				.base = buf,
+				.len  = len,
+		};
+		ipc_msg_t msg = {
+				.iov = &iov,
+				.num_iov = 1,
+		};
+		rc = read_msg(chan, msg_inf.id, 0, &msg);
+	}
+
+	put_msg(chan, msg_inf.id);
+	return rc;
+}
+
+/*
+ * Send message consisting of two segments (header and payload)
+ */
+int tipc_send_two_segments(handle_t chan, const void *hdr, size_t hdr_len,
+			   const void *payload, size_t payload_len)
+{
+	iovec_t iovs[2] = {
+		{
+			.base = (void *)hdr,
+			.len =  hdr_len,
+		},
+		{
+			.base = (void *)payload,
+			.len  = payload_len,
+		},
+	};
+	ipc_msg_t msg = {
+		.iov = iovs,
+		.num_iov = countof(iovs),
+	};
+	return send_msg(chan, &msg);
+}
+
+/*
+ * Receive message consisting of two segments (header and payload).
+ */
+int tipc_recv_two_segments(handle_t chan, void *hdr, size_t hdr_len,
+			   void *payload, size_t payload_len)
+{
+	int rc;
+	ipc_msg_info_t msg_inf;
+
+	rc = get_msg(chan, &msg_inf);
+	if (rc)
+		return rc;
+
+	if (msg_inf.len < hdr_len) {
+		/* unexpected msg size */
+		rc = ERR_BAD_LEN;
+	} else {
+		iovec_t iovs[2] = {
+			{
+				.base = hdr,
+				.len =  hdr_len,
+			},
+			{
+				.base = payload,
+				.len =  payload_len,
+			}
+		};
+		ipc_msg_t msg = {
+				.iov = iovs,
+				.num_iov = countof(iovs),
+		};
+		rc = read_msg(chan, msg_inf.id, 0, &msg);
+	}
+
+	put_msg(chan, msg_inf.id);
+	return rc;
+}
+
+/*
+ *  Dispatch event
+ */
+static void dispatch_event(const uevent_t *ev)
+{
+	assert(ev);
+
+	if (ev->event == IPC_HANDLE_POLL_NONE) {
+		/* not really an event, do nothing */
+		TLOGI("got an empty event\n");
+		return;
+	}
+
+	/* check if we have handler */
+	struct tipc_event_handler *handler = ev->cookie;
+	if (handler && handler->proc) {
+		/* invoke it */
+		handler->proc(ev, handler->priv);
+		return;
+	}
+
+	/* no handler? close it */
+	TLOGE("no handler for event (0x%x) with handle %d\n",
+	       ev->event, ev->handle);
+
+	close(ev->handle);
+
+	return;
+}
+
+/*
+ *  Main application event loop
+ */
+int main(void)
+{
+	int rc;
+	uevent_t event;
+
+	TLOGI("Initializing\n");
+
+	/* initialize service providers */
+	hwrng_init_srv_provider();
+	hwkey_init_srv_provider();
+
+	TLOGI("enter main event loop\n");
+
+	/* enter main event loop */
+	while (true) {
+		event.handle = INVALID_IPC_HANDLE;
+		event.event  = 0;
+		event.cookie = NULL;
+
+		rc = wait_any(&event, -1);
+		if (rc < 0) {
+			TLOGE("wait_any failed (%d)\n", rc);
+			break;
+		}
+
+		if (rc == NO_ERROR) { /* got an event */
+			dispatch_event(&event);
+		}
+	}
+
+	return rc;
+}
diff --git a/hwcrypto/manifest.c b/hwcrypto/manifest.c
new file mode 100644
index 0000000..1f6c175
--- /dev/null
+++ b/hwcrypto/manifest.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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 <stddef.h>
+#include <stdio.h>
+#include <trusty_app_manifest.h>
+
+#include "uuids.h"
+
+trusty_app_manifest_t TRUSTY_APP_MANIFEST_ATTRS trusty_app_manifest =
+{
+	.uuid = GEN_HWCRYPTO_UUID,
+
+	.config_options =
+	/* optional configuration options here */
+	{
+		TRUSTY_APP_CONFIG_MIN_HEAP_SIZE(6 * 4096),
+	},
+};
diff --git a/hwcrypto/rules.mk b/hwcrypto/rules.mk
new file mode 100644
index 0000000..bcb1c0d
--- /dev/null
+++ b/hwcrypto/rules.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/manifest.c \
+	$(LOCAL_DIR)/main.c \
+	$(LOCAL_DIR)/hwrng_srv.c \
+	$(LOCAL_DIR)/hwkey_srv.c \
+
+ifeq (true,$(call TOBOOL,$(WITH_FAKE_HWRNG)))
+MODULE_SRCS += $(LOCAL_DIR)/hwrng_srv_fake_provider.c
+endif
+
+ifeq (true,$(call TOBOOL,$(WITH_FAKE_HWKEY)))
+MODULE_SRCS += $(LOCAL_DIR)/hwkey_srv_fake_provider.c
+endif
+
+MODULE_DEPS := \
+	app/trusty \
+	lib/libc-trusty \
+	interface/hwrng \
+	interface/hwkey \
+	openssl \
+
+include make/module.mk
diff --git a/hwcrypto/uuids.h b/hwcrypto/uuids.h
new file mode 100644
index 0000000..c8866a9
--- /dev/null
+++ b/hwcrypto/uuids.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+/* This App UUID:   {23fe5938-ccd5-4a78-8baf-0f3d05ffc2df} */
+#define GEN_HWCRYPTO_UUID \
+	{ 0x23fe5938, 0xccd5, 0x4a78, \
+		{ 0x8b, 0xaf, 0x0f, 0x3d, 0x05, 0xff, 0xc2, 0xdf }}
+
+/* HWCRYPTO unittest App UUID */
+#define HWCRYPTO_UNITTEST_APP_UUID \
+	{ 0xab742471, 0xd6e6, 0x4806, \
+		{ 0x85, 0xf6, 0x05, 0x55, 0xb0, 0x24, 0xf4, 0xda }}
+
+/* Secure Storage Server App UUID */
+#define SECURE_STORAGE_SERVER_APP_UUID \
+	{0xcea8706d, 0x6cb4, 0x49f3,\
+		{ 0xb9, 0x94, 0x29, 0xe0, 0xe4, 0x78, 0xbd, 0x29 }}