From 7435ac81de2ebe5b312b2435795c4c027d6add75 Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Wed, 8 Apr 2015 16:38:45 -0400 Subject: Add EIM HAL. The eim and i2c support are copied from core/platform/novena. In future, we should maybe build a library there, and link it here. --- src/cryptech_novena_i2c_trng.c | 430 +++++------------------------------------ 1 file changed, 51 insertions(+), 379 deletions(-) (limited to 'src/cryptech_novena_i2c_trng.c') diff --git a/src/cryptech_novena_i2c_trng.c b/src/cryptech_novena_i2c_trng.c index 5877acc..92f851a 100644 --- a/src/cryptech_novena_i2c_trng.c +++ b/src/cryptech_novena_i2c_trng.c @@ -1,6 +1,6 @@ /* * cryptech_novena_i2c_trng.c - * ------------------------------ + * -------------------------- * * This is an early prototype Hardware Adaption Layer (HAL) for using * Cryptlib with the Cryptech project's FGPA cores over an I2C bus on @@ -14,7 +14,7 @@ * use, this is just a prototype. * * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein - * Copyright (c) 2014, SUNET + * Copyright (c) 2014-2015, SUNET * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -53,6 +53,7 @@ #include #include #include +#include #if defined( INC_ALL ) #include "crypt.h" @@ -64,87 +65,13 @@ #include "device/hardware.h" #endif /* Compiler-specific includes */ -/* - * I2C_SLAVE comes from /usr/include/linux/i2c-dev.h, but if we - * include that we won't be able to compile this except on Linux. It - * won't *run* anywhere but on Linux, but it's useful to be able to do - * compilation tests on other platforms, eg, with Clang, so for now we - * take the small risk that this one magic constant might change. - */ - -#define I2C_SLAVE 0x0703 +#include "tc_i2c.h" +/* XXX This is gross, but it saves us from having to build a library. */ +#include "tc_i2c.c" #ifdef USE_HARDWARE -/* - * I2C-related parameters, copied from hash_tester.c - */ - -/* I2C configuration */ -#define I2C_DEV "/dev/i2c-2" -#define I2C_ADDR 0x0f - -/* Command codes */ -#define SOC 0x55 -#define EOC 0xaa -#define READ_CMD 0x10 -#define WRITE_CMD 0x11 -#define RESET_CMD 0x01 - -/* Response codes */ -#define SOR 0xaa -#define EOR 0x55 -#define READ_OK 0x7f -#define WRITE_OK 0x7e -#define RESET_OK 0x7d -#define UNKNOWN 0xfe -#define ERROR 0xfd - -/* Addresses and codes common to all cores */ -#define ADDR_NAME0 0x00 -#define ADDR_NAME1 0x01 -#define ADDR_VERSION 0x02 -#define ADDR_CTRL 0x08 -#define CTRL_INIT_CMD 1 -#define CTRL_NEXT_CMD 2 -#define ADDR_STATUS 0x09 -#define STATUS_READY_BIT 1 -#define STATUS_VALID_BIT 2 - -/* - * Addresses and codes for the specific hash cores. - * Lengths here are in bytes (not bits, not 32-bit words). - */ - -#define SHA1_ADDR_PREFIX 0x10 -#define SHA1_ADDR_BLOCK 0x10 -#define SHA1_BLOCK_LEN bitsToBytes(512) -#define SHA1_LENGTH_LEN bitsToBytes(64) -#define SHA1_ADDR_DIGEST 0x20 -#define SHA1_DIGEST_LEN bitsToBytes(160) - -#define SHA256_ADDR_PREFIX 0x20 -#define SHA256_ADDR_BLOCK 0x10 -#define SHA256_BLOCK_LEN bitsToBytes(512) -#define SHA256_LENGTH_LEN bitsToBytes(64) -#define SHA256_ADDR_DIGEST 0x20 -#define SHA256_DIGEST_LEN bitsToBytes(256) - -#define SHA512_ADDR_PREFIX 0x30 -#define SHA512_CTRL_MODE_LOW 2 -#define SHA512_CTRL_MODE_HIGH 3 -#define SHA512_ADDR_BLOCK 0x10 -#define SHA512_BLOCK_LEN bitsToBytes(1024) -#define SHA512_LENGTH_LEN bitsToBytes(128) -#define SHA512_ADDR_DIGEST 0x40 -#define SHA384_DIGEST_LEN bitsToBytes(384) -#define SHA512_DIGEST_LEN bitsToBytes(512) -#define MODE_SHA_512_224 (0 << SHA512_CTRL_MODE_LOW) -#define MODE_SHA_512_256 (1 << SHA512_CTRL_MODE_LOW) -#define MODE_SHA_384 (2 << SHA512_CTRL_MODE_LOW) -#define MODE_SHA_512 (3 << SHA512_CTRL_MODE_LOW) - /* Longest digest block we support at the moment */ #define MAX_BLOCK_LEN SHA512_BLOCK_LEN @@ -158,251 +85,7 @@ typedef struct { unsigned block_count; /* Blocks sent */ } hash_state_t; -/* - * Address for reading 32 bits of entropy from the noise board. - * TRNG_VALID is nonzero if valid random bits are available. - */ - -#define TRNG_PREFIX 0x0b -#define TRNG_DATA 0x20 -#define TRNG_VALID 0x11 - -static int i2cfd = -1; -static int debug = 0; - -/* - * I2C low-level code - */ - -static int i2c_open(void) -{ - if (i2cfd >= 0) - return 1; - - i2cfd = open(I2C_DEV, O_RDWR); - - if (i2cfd < 0) { - perror("Unable to open " I2C_DEV); - i2cfd = -1; - return 0; - } - - if (ioctl(i2cfd, I2C_SLAVE, I2C_ADDR) < 0) { - perror("Unable to set i2c slave device"); - return 0; - } - - if (debug) - fprintf(stderr, "[ Opened %s, fd %d ]\n", I2C_DEV, i2cfd); - - return 1; -} - -static int i2c_write_bytes(const unsigned char *buf, const size_t len) -{ - if (debug) { - int i; - fprintf(stderr, "write ["); - for (i = 0; i < len; ++i) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, " ]\n"); - } - - if (!i2c_open()) - return 0; - - if (write(i2cfd, buf, len) != len) { - perror("i2c write failed"); - return 0; - } - - return 1; -} - - -static int i2c_read_byte(unsigned char *b) -{ - /* - * read() on the i2c device only returns one byte at a time, - * and we need to parse the response one byte at a time anyway. - */ - - if (!i2c_open()) - return 0; - - if (read(i2cfd, b, 1) != 1) { - perror("i2c read failed"); - return 0; - } - - return 1; -} - -static int i2c_send_write_cmd(const unsigned char addr0, const unsigned char addr1, const unsigned char data[]) -{ - unsigned char buf[9]; - - buf[0] = SOC; - buf[1] = WRITE_CMD; - buf[2] = addr0; - buf[3] = addr1; - buf[4] = data[0]; - buf[5] = data[1]; - buf[6] = data[2]; - buf[7] = data[3]; - buf[8] = EOC; - - return i2c_write_bytes(buf, sizeof(buf)); -} - -static int i2c_send_read_cmd(const unsigned char addr0, const unsigned char addr1) -{ - unsigned char buf[5]; - - buf[0] = SOC; - buf[1] = READ_CMD; - buf[2] = addr0; - buf[3] = addr1; - buf[4] = EOC; - - return i2c_write_bytes(buf, sizeof(buf)); -} - -static int i2c_get_resp(unsigned char *buf, const size_t length) -{ - int i, len = length; - - for (i = 0; i < len; ++i) { - assert(len <= length); /* Paranoia */ - - if (!i2c_read_byte(&buf[i])) - return 0; - - switch (i) { /* Special handling for certain positions in response */ - - case 0: - if (buf[i] == SOR) /* Start of record (we hope) */ - continue; - fprintf(stderr, "Lost sync: expected 0x%02x (SOR), got 0x%02x\n", SOR, buf[0]); - return 0; - - case 1: /* Response code */ - switch (buf[i]) { - case READ_OK: - len = 9; - continue; - case WRITE_OK: - len = 5; - continue; - case RESET_OK: - len = 3; - continue; - case ERROR: - case UNKNOWN: - len = 4; - continue; - default: - fprintf(stderr, "Lost sync: unknown response code 0x%02x\n", buf[i]); - return 0; - } - } - } - - if (debug) { - fprintf(stderr, "read ["); - for (i = 0; i < len; ++i) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, " ]\n"); - } - - return 1; -} - -static int i2c_check_expected(const unsigned char buf[], const int i, const unsigned char expected) -{ - if (buf[i] == expected) - return 1; - fprintf(stderr, "Response byte %d: expected 0x%02x, got 0x%02x\n", i, expected, buf[i]); - return 0; -} - - -static int i2c_write(const unsigned char addr0, const unsigned char addr1, const unsigned char data[]) -{ - unsigned char buf[5]; - - if (!i2c_send_write_cmd(addr0, addr1, data) || - !i2c_get_resp(buf, sizeof(buf)) || - !i2c_check_expected(buf, 0, SOR) || - !i2c_check_expected(buf, 1, WRITE_OK) || - !i2c_check_expected(buf, 2, addr0) || - !i2c_check_expected(buf, 3, addr1) || - !i2c_check_expected(buf, 4, EOR)) - return 0; - - return 1; -} - -static int i2c_read(const unsigned char addr0, const unsigned char addr1, unsigned char data[]) -{ - unsigned char buf[9]; - - if (!i2c_send_read_cmd(addr0, addr1) || - !i2c_get_resp(buf, sizeof(buf)) || - !i2c_check_expected(buf, 0, SOR) || - !i2c_check_expected(buf, 1, READ_OK) || - !i2c_check_expected(buf, 2, addr0) || - !i2c_check_expected(buf, 3, addr1) || - !i2c_check_expected(buf, 8, EOR)) - return 0; - - data[0] = buf[4]; - data[1] = buf[5]; - data[2] = buf[6]; - data[3] = buf[7]; - return 1; -} - -static int i2c_ctrl(const unsigned char addr0, const unsigned char ctrl_cmd) -{ - unsigned char data[4]; - memset(data, 0, sizeof(data)); - data[3] = ctrl_cmd; - return i2c_write(addr0, ADDR_CTRL, data); -} - -static int i2c_wait(const unsigned char addr0, const unsigned char status) -{ - unsigned char buf[9]; - - do { - if (!i2c_send_read_cmd(addr0, ADDR_STATUS)) - return 0; - if (!i2c_get_resp(buf, sizeof(buf))) - return 0; - if (buf[1] != READ_OK) - return 0; - } while ((buf[7] & status) != status); - - if (debug) - fprintf(stderr, "[ Done waiting ]\n"); - - return 1; -} - -static int i2c_wait_ready(const unsigned char addr0) -{ - if (debug) - fprintf(stderr, "[ Waiting for ready ]\n"); - return i2c_wait(addr0, STATUS_READY_BIT); -} - -static int i2c_wait_valid(const unsigned char addr0) -{ - if (debug) - fprintf(stderr, "[ Waiting for valid ]\n"); - return i2c_wait(addr0, STATUS_VALID_BIT); -} +int debug = 0; /**************************************************************************** * * @@ -414,47 +97,44 @@ static int i2c_wait_valid(const unsigned char addr0) * Send one block to a core. */ -static int hash_write_block(const unsigned char addr_prefix, - const unsigned char addr_block, - const unsigned char ctrl_mode, +static int hash_write_block(const off_t offset, + const uint8_t ctrl_mode, const hash_state_t *state) { - unsigned char ctrl_cmd; - int i; + uint8_t ctrl_cmd[4] = { 0 }; + off_t base = offset & ~(0xff); assert(state != NULL && state->block_length % 4 == 0); - for (i = 0; i + 3 < state->block_length; i += 4) - if (!i2c_write(addr_prefix, addr_block + i/4, state->block + i)) - return 0; + if (tc_write(offset, state->block, state->block_length) != 0) + return CRYPT_ERROR_FAILED; - ctrl_cmd = state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD; + ctrl_cmd[3] = (state->block_count == 0 ? CTRL_INIT_CMD : CTRL_NEXT_CMD) | ctrl_mode; if (debug) fprintf(stderr, "[ %s ]\n", state->block_count == 0 ? "init" : "next"); - return i2c_ctrl(addr_prefix, ctrl_cmd|ctrl_mode) && i2c_wait_ready(addr_prefix); + return + tc_write(base + ADDR_CTRL, ctrl_cmd, 4) || + tc_wait_ready(base + ADDR_STATUS); } /* * Read hash result from core. */ -static int hash_read_digest(const unsigned char addr_prefix, const unsigned char addr_digest, - unsigned char *digest, const size_t digest_length) +static int hash_read_digest(const off_t offset, + unsigned char *digest, + const size_t digest_length) { - int i; - assert(digest_length % 4 == 0); - if (!i2c_wait_valid(addr_prefix)) - return 0; - - for (i = 0; i + 3 < digest_length; i += 4) - if (!i2c_read(addr_prefix, addr_digest + i/4, digest + i)) - return 0; + /* Technically, we should poll the status register for the "valid" bit, but + * hash_write_block() has already polled for the "ready" bit, and we know + * that the sha cores always set valid one clock cycle before ready. + */ - return 1; + return tc_read(offset, digest, digest_length); } /**************************************************************************** @@ -475,7 +155,7 @@ static int hash_read_digest(const unsigned char addr_prefix, const unsigned char * signals this (deliberately?) by returning all zeros. */ -#define WAIT_FOR_TRNG_VALID 0 +#define WAIT_FOR_TRNG_VALID 0 static int readRandom(void *buffer, const int length) { @@ -492,26 +172,16 @@ static int readRandom(void *buffer, const int length) for (i = 0; i < length; i += 4) { #if WAIT_FOR_TRNG_VALID - if (!i2c_wait_valid(TRNG_PREFIX)) { - fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n"); - return 0; - } - do { - if (!i2c_read(TRNG_PREFIX, TRNG_VALID, temp)) { - fprintf(stderr, "[ i2c_read(TRNG_VALID) failed ]\n"); - return 0; - } - } while (!temp[3]); - if (!i2c_wait_valid(TRNG_PREFIX)) { - fprintf(stderr, "[ i2c_wait_valid(TRNG_PREFIX) failed ]\n"); - return 0; + if (tc_wait_ready(CSPRNG_ADDR_STATUS) != 0) { + fprintf(stderr, "[ tc_wait_valid(CSPRNG_ADDR_STATUS) failed ]\n"); + return CRYPT_ERROR_FAILED; } #endif /* WAIT_FOR_TRNG_VALID */ last = (length - i) < 4; - if (!i2c_read(TRNG_PREFIX, TRNG_DATA, (last ? temp : (buf + i)))) { - fprintf(stderr, "[ i2c_read(TRNG_DATA) failed ]\n"); - return 0; + if (tc_read(CSPRNG_ADDR_RANDOM, (last ? temp : (buf + i)), 4) != 0) { + fprintf(stderr, "[ tc_read(CSPRNG_ADDR_RANDOM) failed ]\n"); + return CRYPT_ERROR_FAILED; } if (last) { for (; i < length; i++) @@ -521,10 +191,10 @@ static int readRandom(void *buffer, const int length) for (i = 0, buf = buffer; i < length; i++, buf++) if (*buf != 0) - return 1; + return CRYPT_OK; fprintf(stderr, "[ \"Random\" data all zeros, guess TRNG is not installed ]\n"); - return 0; + return CRYPT_ERROR_FAILED; } /**************************************************************************** @@ -562,9 +232,14 @@ static int hashGetInfo(const CAPABILITY_INFO_TYPE type, * with a few parameters which we handle via closures below. */ -static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int length, - const size_t block_length, const unsigned char addr_prefix, const unsigned char addr_block, - const size_t digest_length, const unsigned char addr_digest, const unsigned char ctrl_mode, +static int doHash(CONTEXT_INFO *contextInfoPtr, + const unsigned char *buffer, + int length, + const size_t block_length, + const off_t addr_block, + const size_t digest_length, + const off_t addr_digest, + const unsigned char ctrl_mode, const size_t length_length) { hash_state_t *state = NULL; @@ -605,7 +280,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int state->block_used = 0; length -= n; p += n; - if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state)) + if (hash_write_block(addr_block, ctrl_mode, state) != 0) return CRYPT_ERROR_FAILED; state->block_count++; } @@ -642,7 +317,7 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int (unsigned long) length, (unsigned long) state->block_used, (unsigned long) n, state->msg_length_low); if (n > 0) memset(state->block + state->block_used, 0, n); - if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state)) + if (hash_write_block(addr_block, ctrl_mode, state) != 0) return CRYPT_ERROR_FAILED; state->block_count++; state->block_used = 0; @@ -667,14 +342,14 @@ static int doHash(CONTEXT_INFO *contextInfoPtr, const unsigned char *buffer, int } /* Push final block */ - if (!hash_write_block(addr_prefix, addr_block, ctrl_mode, state)) + if (hash_write_block(addr_block, ctrl_mode, state) != 0) return CRYPT_ERROR_FAILED; state->block_count++; /* All data pushed to core, now we just need to read back the result */ assert(digest_length <= sizeof(contextInfoPtr->ctxHash->hash)); - if (!hash_read_digest(addr_prefix, addr_digest, contextInfoPtr->ctxHash->hash, digest_length)) + if (hash_read_digest(addr_digest, contextInfoPtr->ctxHash->hash, digest_length) != 0) return CRYPT_ERROR_FAILED; } @@ -697,7 +372,7 @@ static int sha1SelfTest(void) static int sha1Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int length) { return doHash(contextInfoPtr, buffer, length, - SHA1_BLOCK_LEN, SHA1_ADDR_PREFIX, SHA1_ADDR_BLOCK, + SHA1_BLOCK_LEN, SHA1_ADDR_BLOCK, SHA1_DIGEST_LEN, SHA1_ADDR_DIGEST, 0, SHA1_LENGTH_LEN); } @@ -722,18 +397,18 @@ static int sha2Hash(CONTEXT_INFO *contextInfoPtr, unsigned char *buffer, int len case bitsToBytes(256): return doHash(contextInfoPtr, buffer, length, - SHA256_BLOCK_LEN, SHA256_ADDR_PREFIX, SHA256_ADDR_BLOCK, + SHA256_BLOCK_LEN, SHA256_ADDR_BLOCK, SHA256_DIGEST_LEN, SHA256_ADDR_DIGEST, 0, SHA256_LENGTH_LEN); case bitsToBytes(384): return doHash(contextInfoPtr, buffer, length, - SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, + SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK, SHA384_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_384, SHA512_LENGTH_LEN); case bitsToBytes(512): return doHash(contextInfoPtr, buffer, length, - SHA512_BLOCK_LEN, SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, + SHA512_BLOCK_LEN, SHA512_ADDR_BLOCK, SHA512_DIGEST_LEN, SHA512_ADDR_DIGEST, MODE_SHA_512, SHA512_LENGTH_LEN); @@ -837,10 +512,7 @@ int hwGetRandom(void *buffer, const int length) REQUIRES(length >= 1 && length < MAX_INTLENGTH); - if (readRandom(buffer, length)) - return CRYPT_OK; - else - return CRYPT_ERROR_RANDOM; + return readRandom(buffer, length); } /* -- cgit v1.2.3