summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/tpm2/hash.c212
-rw-r--r--include/extension.h19
2 files changed, 228 insertions, 3 deletions
diff --git a/board/cr50/tpm2/hash.c b/board/cr50/tpm2/hash.c
index 157e8526ef..ec036c8497 100644
--- a/board/cr50/tpm2/hash.c
+++ b/board/cr50/tpm2/hash.c
@@ -137,3 +137,215 @@ uint16_t _cpri__CompleteHash(CPRI_HASH_STATE *state,
memcpy(out, DCRYPTO_HASH_final(ctx), out_len);
return out_len;
}
+
+#ifdef CRYPTO_TEST_SETUP
+
+#include "console.h"
+#include "extension.h"
+#include "shared_mem.h"
+
+#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args)
+
+struct test_context {
+ int context_handle;
+ CPRI_HASH_STATE hstate;
+};
+
+static struct {
+ int current_context_count;
+ int max_contexts;
+ struct test_context *contexts;
+} hash_test_db;
+
+struct test_context *find_context(int handle)
+{
+ int i;
+
+ for (i = 0; i < hash_test_db.current_context_count; i++)
+ if (hash_test_db.contexts[i].context_handle == handle)
+ return hash_test_db.contexts + i;
+ return NULL;
+}
+
+static void process_start(TPM_ALG_ID alg, int handle, void *response_body,
+ size_t *response_size)
+{
+ uint8_t *response = response_body;
+ struct test_context *new_context;
+
+ if (find_context(handle)) {
+ *response = EXC_HASH_DUPLICATED_HANDLE;
+ *response_size = 1;
+ return;
+ }
+
+ if (!hash_test_db.max_contexts) {
+ /* Check how many contexts could possible fit. */
+ hash_test_db.max_contexts = shared_mem_size() /
+ sizeof(struct test_context);
+ }
+
+ if (!hash_test_db.contexts)
+ shared_mem_acquire(shared_mem_size(),
+ (char **)&hash_test_db.contexts);
+
+ if (!hash_test_db.contexts ||
+ (hash_test_db.current_context_count == hash_test_db.max_contexts)) {
+ *response = EXC_HASH_TOO_MANY_HANDLES;
+ *response_size = 1;
+ return;
+ }
+
+ new_context = hash_test_db.contexts +
+ hash_test_db.current_context_count++;
+ new_context->context_handle = handle;
+ _cpri__StartHash(alg, 0, &new_context->hstate);
+}
+
+static void process_continue(int handle, void *cmd_body, uint16_t text_len,
+ void *response_body, size_t *response_size)
+{
+ struct test_context *context = find_context(handle);
+
+ if (!context) {
+ *((uint8_t *)response_body) = EXC_HASH_UNKNOWN_CONTEXT;
+ *response_size = 1;
+ return;
+ }
+
+ _cpri__UpdateHash(&context->hstate, text_len, cmd_body);
+}
+
+static void process_finish(int handle, void *response_body,
+ size_t *response_size)
+{
+ struct test_context *context = find_context(handle);
+
+ if (!context) {
+ *((uint8_t *)response_body) = EXC_HASH_UNKNOWN_CONTEXT;
+ *response_size = 1;
+ return;
+ }
+
+ /* There for sure is enough room in the TPM buffer. */
+ *response_size = _cpri__CompleteHash(&context->hstate,
+ SHA_DIGEST_MAX_BYTES,
+ response_body);
+
+ /* drop this context from the database. */
+ hash_test_db.current_context_count--;
+ if (!hash_test_db.current_context_count) {
+ shared_mem_release(hash_test_db.contexts);
+ return;
+ }
+
+ /* Nothing to do, if the deleted context is the last one in memory. */
+ if (context == (hash_test_db.contexts +
+ hash_test_db.current_context_count))
+ return;
+
+ memcpy(context,
+ hash_test_db.contexts + hash_test_db.current_context_count,
+ sizeof(*context));
+}
+
+static void hash_command_handler(void *cmd_body,
+ size_t cmd_size,
+ size_t *response_size)
+{
+ int mode;
+ int hash_mode;
+ int handle;
+ uint16_t text_len;
+ uint8_t *cmd;
+ size_t response_room = *response_size;
+ TPM_ALG_ID alg;
+
+ cmd = cmd_body;
+
+ /*
+ * Empty response is sent as a success indication when the digest is
+ * not yet expected (i.e. in response to 'start' and 'cont' commands,
+ * as defined below).
+ *
+ * Single byte responses indicate errors, test successes are
+ * communicated as responses of the size of the appropriate digests.
+ */
+ *response_size = 0;
+
+ /*
+ * Command structure, shared out of band with the test driver running
+ * on the host:
+ *
+ * field | size | note
+ * ===================================================================
+ * mode | 1 | 0 - start, 1 - cont., 2 - finish, 3 - single
+ * hash_mode | 1 | 0 - sha1, 1 - sha256
+ * handle | 1 | seassion handle, ignored in 'single' mode
+ * text_len | 2 | size of the text to process, big endian
+ * text | text_len | text to hash
+ */
+
+ mode = *cmd++;
+ hash_mode = *cmd++;
+ handle = *cmd++;
+ text_len = *cmd++;
+ text_len = text_len * 256 + *cmd++;
+
+ switch (hash_mode) {
+ case 0:
+ alg = TPM_ALG_SHA1;
+ break;
+ case 1:
+ alg = TPM_ALG_SHA256;
+ break;
+
+ default:
+ return;
+ }
+
+ switch (mode) {
+ case 0: /* Start a new hash context. */
+ process_start(alg, handle, cmd_body, response_size);
+ if (*response_size)
+ break; /* Something went wrong. */
+ process_continue(handle, cmd, text_len,
+ cmd_body, response_size);
+ break;
+
+ case 1:
+ process_continue(handle, cmd, text_len,
+ cmd_body, response_size);
+ break;
+
+ case 2:
+ process_continue(handle, cmd, text_len,
+ cmd_body, response_size);
+ if (*response_size)
+ break; /* Something went wrong. */
+
+ process_finish(handle, cmd_body, response_size);
+ CPRINTF("%s:%d response size %d\n", __func__, __LINE__,
+ *response_size);
+ break;
+
+ case 3: /* Process a buffer in a single shot. */
+ if (!text_len)
+ break;
+ /*
+ * Error responses are just 1 byte in size, valid responses
+ * are of various hash sizes.
+ */
+ *response_size = _cpri__HashBlock(alg, text_len,
+ cmd, response_room, cmd_body);
+ CPRINTF("%s:%d response size %d\n", __func__,
+ __LINE__, *response_size);
+ break;
+ default:
+ break;
+ }
+}
+
+DECLARE_EXTENSION_COMMAND(EXTENSION_HASH, hash_command_handler);
+
+#endif /* CRYPTO_TEST_SETUP */
diff --git a/include/extension.h b/include/extension.h
index 45637d9518..f9757c1510 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -30,8 +30,9 @@ typedef void (*extension_handler)(void *buffer,
* @param buffer Data to be processd by the handler, the same space
* is used for data returned by the handler.
* @command_size Size of the input data.
- * @param size On input - max size of the buffer, on output - actual
- * number of data returned by the handler.
+ * @param size On input - max size of the buffer, on output - actual number of
+ * data returned by the handler. A single byte return
+ * usually indicates an error and contains the error code.
*/
void extension_route_command(uint16_t command_code,
void *buffer,
@@ -43,9 +44,21 @@ struct extension_command {
extension_handler handler;
} __packed;
-/* Values for different extension commands. */
+/* Values for different extension subcommands. */
enum {
EXTENSION_AES = 0,
+ EXTENSION_HASH = 1,
+};
+
+
+/* Error codes reported by extension commands. */
+enum {
+ /* EXTENSION_HASH error codes */
+ /* Attempt to start a session on an active handle. */
+ EXC_HASH_DUPLICATED_HANDLE = 1,
+ EXC_HASH_TOO_MANY_HANDLES = 2, /* No room to allocate a new context. */
+ /* Continuation/finish on unknown context. */
+ EXC_HASH_UNKNOWN_CONTEXT = 3
};
#define DECLARE_EXTENSION_COMMAND(code, handler) \