mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-12 13:25:45 +00:00
Merge 50189d7ebd
into 52f5593f28
This commit is contained in:
commit
0274335b22
@ -1151,12 +1151,10 @@ secbool storage_has(const uint16_t key) {
|
||||
return storage_get(key, NULL, 0, &len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the data stored under key and writes its length to len. If val_dest is
|
||||
* not NULL and max_len >= len, then the data is copied to val_dest.
|
||||
*/
|
||||
secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
|
||||
uint16_t *len) {
|
||||
static secbool storage_get_uni(const uint16_t key, uint16_t offset,
|
||||
void *val_dest, const uint16_t max_len,
|
||||
uint16_t *total_len, uint16_t *slice_len,
|
||||
secbool slice) {
|
||||
const uint8_t app = key >> 8;
|
||||
// APP == 0 is reserved for PIN related values
|
||||
if (sectrue != initialized || app == APP_STORAGE) {
|
||||
@ -1167,25 +1165,60 @@ secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
|
||||
// read from a locked device.
|
||||
if ((app & FLAG_PUBLIC) != 0) {
|
||||
const void *val_stored = NULL;
|
||||
if (sectrue != norcow_get(key, &val_stored, len)) {
|
||||
if (sectrue != norcow_get(key, &val_stored, total_len)) {
|
||||
return secfalse;
|
||||
}
|
||||
if (val_dest == NULL) {
|
||||
return sectrue;
|
||||
}
|
||||
if (*len > max_len) {
|
||||
return secfalse;
|
||||
if (slice == sectrue) {
|
||||
if (*total_len < offset) {
|
||||
return secfalse;
|
||||
}
|
||||
} else {
|
||||
if (*total_len > max_len) {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
memcpy(val_dest, val_stored, *len);
|
||||
|
||||
uint16_t remaining_len = *total_len - offset;
|
||||
uint16_t copy_len = remaining_len > max_len ? max_len : remaining_len;
|
||||
|
||||
memcpy(val_dest, ((uint8_t *)val_stored) + offset, copy_len);
|
||||
|
||||
if (slice_len != NULL) {
|
||||
*slice_len = copy_len;
|
||||
}
|
||||
|
||||
return sectrue;
|
||||
} else {
|
||||
if (sectrue != unlocked) {
|
||||
return secfalse;
|
||||
}
|
||||
return storage_get_encrypted(key, val_dest, max_len, len);
|
||||
if (slice == sectrue) {
|
||||
// slices of encrypted data are not supported
|
||||
return secfalse;
|
||||
}
|
||||
return storage_get_encrypted(key, val_dest, max_len, total_len);
|
||||
}
|
||||
}
|
||||
|
||||
secbool storage_get_slice(const uint16_t key, uint16_t offset, void *val_dest,
|
||||
const uint16_t max_len, uint16_t *total_len,
|
||||
uint16_t *slice_len) {
|
||||
return storage_get_uni(key, offset, val_dest, max_len, total_len, slice_len,
|
||||
sectrue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the data stored under key and writes its length to len. If val_dest is
|
||||
* not NULL and max_len >= len, then the data is copied to val_dest.
|
||||
*/
|
||||
secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
|
||||
uint16_t *len) {
|
||||
return storage_get_uni(key, 0, val_dest, max_len, len, NULL, secfalse);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypts the data at val using cached_dek as the encryption key and stores
|
||||
* the ciphertext under key.
|
||||
|
@ -93,6 +93,9 @@ secbool storage_change_wipe_code(const uint8_t *pin, size_t pin_len,
|
||||
secbool storage_has(const uint16_t key);
|
||||
secbool storage_get(const uint16_t key, void *val, const uint16_t max_len,
|
||||
uint16_t *len);
|
||||
secbool storage_get_slice(const uint16_t key, uint16_t offset, void *val,
|
||||
const uint16_t max_len, uint16_t *total_len,
|
||||
uint16_t *slice_len);
|
||||
secbool storage_set(const uint16_t key, const void *val, const uint16_t len);
|
||||
secbool storage_delete(const uint16_t key);
|
||||
secbool storage_set_counter(const uint16_t key, const uint32_t count);
|
||||
|
@ -74,6 +74,20 @@ class Storage:
|
||||
raise RuntimeError("Failed to get value from storage.")
|
||||
return s.raw
|
||||
|
||||
def get_slice(self, key: int, offset: int, len: int) -> bytes:
|
||||
val_len = c.c_uint16()
|
||||
slice_len = c.c_uint16()
|
||||
if sectrue != self.lib.storage_get(c.c_uint16(key), None, 0, c.byref(val_len)):
|
||||
raise RuntimeError("Failed to find key in storage.")
|
||||
if len > val_len.value - offset > 0:
|
||||
len = val_len.value - offset
|
||||
s = c.create_string_buffer(len)
|
||||
if sectrue != self.lib.storage_get_slice(
|
||||
c.c_uint16(key), offset, s, len, c.byref(val_len), c.byref(slice_len)
|
||||
):
|
||||
raise RuntimeError("Failed to get value from storage.")
|
||||
return s.raw
|
||||
|
||||
def set(self, key: int, val: bytes) -> None:
|
||||
if sectrue != self.lib.storage_set(c.c_uint16(key), val, c.c_uint16(len(val))):
|
||||
raise RuntimeError("Failed to set value in storage.")
|
||||
|
@ -136,6 +136,16 @@ class Storage:
|
||||
raise RuntimeError("Failed to find key in storage.")
|
||||
return value
|
||||
|
||||
def get_slice(self, key: int, offset: int, max_len: int) -> bytes:
|
||||
if not consts.is_app_public(key >> 8):
|
||||
raise RuntimeError("Only public values can be read by slices")
|
||||
value = self.get(key)
|
||||
if offset + max_len > len(value):
|
||||
end = len(value)
|
||||
else:
|
||||
end = offset + max_len
|
||||
return value[offset:end]
|
||||
|
||||
def set(self, key: int, val: bytes) -> bool:
|
||||
app = key >> 8
|
||||
self._check_lock(app)
|
||||
|
@ -285,3 +285,21 @@ def test_counter(nc_class):
|
||||
s.next_counter(0xC001)
|
||||
|
||||
assert common.memory_equals(sc, sp)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("nc_class", NC_CLASSES)
|
||||
def test_streaming(nc_class):
|
||||
sc, sp = common.init(nc_class, unlock=True)
|
||||
|
||||
test_data = [
|
||||
b"HelloString",
|
||||
b"HelloSomeVeryVeryVeryVeryLongString",
|
||||
bytes([j % 256 for j in range(0, 133)]),
|
||||
]
|
||||
|
||||
for s in (sc, sp):
|
||||
for data in test_data:
|
||||
s.set(0x8102, data)
|
||||
for j in range(1, len(data)):
|
||||
for i in range(0, len(data), j):
|
||||
assert s.get_slice(0x8102, i, j) == data[i : i + j]
|
||||
|
Loading…
Reference in New Issue
Block a user