aboutsummaryrefslogtreecommitdiff
path: root/projects/cli-test/filetransfer
blob: 92b117f8d6a49f804d60e278651183b0e70e1d8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/python

import os
import sys
import time
import struct
import serial

from binascii import crc32


def _write(dst, data):
    dst.write(data)
    if len(data) == 4:
        print("Wrote 0x{:02x}{:02x}{:02x}{:02x}".format(ord(data[0]), ord(data[1]), ord(data[2]), ord(data[3])))
    else:
        print("Wrote {!r}".format(data))


def _read(dst):
    res = ''
    while True:
        x = dst.read(1)
        if not x:
            break
        res += x
    print ("Read {!r}".format(res))
    return res


def _execute(dst, cmd):
    _write(dst, '\r')
    prompt = _read(dst)
    if prompt.endswith('Username: '):
        _write(dst, 'ct\r')
        prompt = _read(dst)
    if prompt.endswith('Password: '):
        _write(dst, 'ct\r')
        prompt = _read(dst)
    if not prompt.endswith('> '):
        sys.stderr.write('Device does not seem to be ready for a file transfer (got {!r})\n'.format(prompt))
        return False
    _write(dst, cmd + '\r')
    response = _read(dst)
    return response

def send_file(filename, device='/dev/ttyUSB0', initiate=True):
    s = os.stat(filename)
    size = s.st_size
    src = open(filename, 'rb')

    dst = serial.Serial(device, 115200, timeout=0.5)

    if initiate:
        response = _execute(dst, 'filetransfer')
        if 'OK' not in response:
            sys.stderr.write('Device did not accept the filetransfer command (got {!r})\n'.format(response))
            return False

    # 1. Write size of file (4 bytes)
    _write(dst, struct.pack('<I', size))
    _read(dst)
    # 2. Write file contents while calculating CRC-32
    crc = 0
    while True:
        data = src.read(1024)
        if not data:
            break
        dst.write(data)
        print("Wrote {!s} bytes".format(len(data)))
        crc = crc32(data, crc) & 0xffffffff
    # 3. Write CRC-32 (4 bytes)
    _write(dst, struct.pack('<I', crc))
    _read(dst)

    src.close()
    dst.close()
    return True


if len(sys.argv) != 2:
    sys.stderr.write('Syntax: {!s} filename\n'.format(sys.argv[0]))
    sys.exit(1)

if send_file(sys.argv[1]):
    sys.exit(0)

sys.exit(1)
pages for flash sector state, PINs and future additions. * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252). */ uint32_t offset = KEYSTORE_PAGE_SIZE * 2; uint32_t key_size = sizeof(*db->keys); uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1); offset += num * bytes_per_key; return offset; } const hal_ks_keydb_t *hal_ks_get_keydb(void) { uint32_t offset, i, idx = 0, active_sector_offset; hal_ks_key_t *key; uint8_t page_buf[KEYSTORE_PAGE_SIZE]; memset(db, 0, sizeof(*db)); if (keystore_check_id() != 1) return NULL; active_sector_offset = _active_sector_offset(); /* The PINs are in the second page of the sector. */ offset = active_sector_offset + KEYSTORE_PAGE_SIZE; if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL; offset = 0; memcpy(&db->wheel_pin, page_buf + offset, sizeof(db->wheel_pin)); offset += sizeof(db->wheel_pin); memcpy(&db->so_pin, page_buf + offset, sizeof(db->so_pin)); offset += sizeof(db->so_pin); memcpy(&db->user_pin, page_buf + offset, sizeof(db->user_pin)); for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) { offset = _get_key_offset(i); if (offset > KEYSTORE_SECTOR_SIZE) { idx++; continue; } offset += active_sector_offset; if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL; key = (hal_ks_key_t *) page_buf; if (key->in_use == 0xff) { /* unprogrammed data */ idx++; continue; } if (key->in_use == 1) { uint8_t *dst = (uint8_t *) &db->keys[idx]; uint32_t to_read = sizeof(*db->keys); /* We already have the first page in page_buf. Put it into place. */ memcpy(dst, page_buf, sizeof(page_buf)); to_read -= sizeof(page_buf); dst += sizeof(page_buf); /* Read as many more full pages as possible */ if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1) return NULL; dst += to_read & ~PAGE_SIZE_MASK; to_read &= PAGE_SIZE_MASK; if (to_read) { /* Partial last page. We can only read full pages so load it into page_buf. */ if (keystore_read_data(offset + sizeof(*db->keys) - to_read, page_buf, sizeof(page_buf)) != 1) return NULL; memcpy(dst, page_buf, to_read); } } idx++; } return db; } hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len) { uint8_t page_buf[KEYSTORE_PAGE_SIZE]; uint32_t to_write = len; if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1) { return HAL_ERROR_KEYSTORE_ACCESS; } to_write &= PAGE_SIZE_MASK; if (to_write) { /* Use page_buf to write the remaining bytes, since we must write a full page each time. */ memset(page_buf, 0xff, sizeof(page_buf)); memcpy(page_buf, data + len - to_write, to_write); if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1) { return HAL_ERROR_KEYSTORE_ACCESS; } } return LIBHAL_OK; } /* * Write the full DB to flash, PINs and all. */ hal_error_t _write_db_to_flash(const uint32_t sector_offset) { hal_error_t status; uint8_t page_buf[KEYSTORE_PAGE_SIZE]; uint32_t i, offset; if (sizeof(db->wheel_pin) + sizeof(db->so_pin) + sizeof(db->user_pin) > sizeof(page_buf)) { return HAL_ERROR_BAD_ARGUMENTS; } /* Put the three PINs into page_buf */ offset = 0; memcpy(page_buf + offset, &db->wheel_pin, sizeof(db->wheel_pin)); offset += sizeof(db->wheel_pin); memcpy(page_buf + offset, &db->so_pin, sizeof(db->so_pin)); offset += sizeof(db->so_pin); memcpy(page_buf + offset, &db->user_pin, sizeof(db->user_pin)); /* Write PINs into the second of the two reserved pages at the start of the sector. */ offset = sector_offset + KEYSTORE_PAGE_SIZE; if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK) { return status; } for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) { offset = _get_key_offset(i); if (offset > KEYSTORE_SECTOR_SIZE) { return HAL_ERROR_BAD_ARGUMENTS; } offset += sector_offset; if ((status =_write_data_to_flash(offset, (uint8_t *) &db->keys[i], sizeof(*db->keys))) != LIBHAL_OK) { return status; } } return LIBHAL_OK; } hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key, const int loc, const int updating) { hal_error_t status; uint32_t offset, active_sector_offset; hal_ks_key_t *tmp_key; uint8_t page_buf[KEYSTORE_PAGE_SIZE]; if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating)) return HAL_ERROR_BAD_ARGUMENTS; offset = _get_key_offset(loc); if (offset > KEYSTORE_SECTOR_SIZE) return HAL_ERROR_BAD_ARGUMENTS; active_sector_offset = _active_sector_offset(); offset += active_sector_offset; if (keystore_check_id() != 1) return HAL_ERROR_KEYSTORE_ACCESS; /* Check if there is a key occupying this slot in the flash already. * Don't trust the in-memory representation since it would mean data * corruption in flash if it had been altered. */ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) { return HAL_ERROR_KEYSTORE_ACCESS; } tmp_key = (hal_ks_key_t *) page_buf; db->keys[loc] = *key; db->keys[loc].in_use = 1; if (tmp_key->in_use == 0xff) { /* Key slot was unused in flash. Write the new key there. */ if ((status = _write_data_to_flash(offset, (uint8_t *) key, sizeof(*db->keys))) != LIBHAL_OK) { return status; } } else { /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */ if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE, active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) { return HAL_ERROR_KEYSTORE_ACCESS; } if ((status =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK) { return status; } } return LIBHAL_OK; } hal_error_t hal_ks_del_keydb(const int loc) { uint32_t offset; if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys)) return HAL_ERROR_BAD_ARGUMENTS; offset = _get_key_offset(loc); if (offset > KEYSTORE_SECTOR_SIZE) { return HAL_ERROR_BAD_ARGUMENTS; } offset += _active_sector_offset(); memset(&db->keys[loc], 0, sizeof(*db->keys)); /* Setting bits to 0 never requires erasing flash. Just write it. */ return _write_data_to_flash(offset, (uint8_t *) &db->keys[loc], sizeof(*db->keys)); } hal_error_t hal_ks_set_pin(const hal_user_t user, const hal_ks_pin_t * const pin) { uint32_t active_sector_offset; if (pin == NULL) return HAL_ERROR_BAD_ARGUMENTS; hal_ks_pin_t *p = NULL; switch (user) { case HAL_USER_WHEEL: p = &db->wheel_pin; break; case HAL_USER_SO: p = &db->so_pin; break; case HAL_USER_NORMAL: p = &db->user_pin; break; default: return HAL_ERROR_BAD_ARGUMENTS; } memcpy(p, pin, sizeof(*p)); active_sector_offset = _active_sector_offset(); /* TODO: Could check if the PIN is currently all 0xff, in which case we wouldn't have to * erase and re-write the whole DB. */ /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */ if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE, active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) { return HAL_ERROR_KEYSTORE_ACCESS; } return _write_db_to_flash(active_sector_offset); } hal_error_t hal_ks_get_kek(uint8_t *kek, size_t *kek_len, const size_t kek_max) { if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) return HAL_ERROR_BAD_ARGUMENTS; const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : bitsToBytes(256)); if (masterkey_volatile_read(kek, len) == HSM_MASTERKEY_SET) { *kek_len = len; return LIBHAL_OK; } if (masterkey_flash_read(kek, len) == HSM_MASTERKEY_SET) { *kek_len = len; return LIBHAL_OK; } return HAL_ERROR_KEYSTORE_ACCESS; } /* * Local variables: * indent-tabs-mode: nil * End: */