Как получить метку времени UTC в доверенном приложении OP-TEE (TA) в формате даты и времени?
Отказ от ответственности: у меня ушло 4-5 часов на поиск ответа, и, выяснив его, я решил опубликовать его здесь для людей в том же месте.
OP-TEE - довольно хорошая среда для разработки ТА и ЦС, однако нет простого метода получения правильно отформатированной даты и времени. Здесь нет
Я долго пытался использовать уже поддерживаемые
Однако, к сожалению,
Так как же узнать время UTC в OP-TEE TA?
2 ответа
Вся разработка OP-TEE для ARMv8 выполняется с использованием C. Однако в нем отсутствует основная поддержка libc. На практике у него очень мало библиотек (например, string.h), которые представляют собой скимнутые версии из исходных соответствующих библиотек libc.
При этом предоставленные
<time.h>
в OP-TEE не содержится ничего, кроме
typedef
для
time_t
и это все.
Проблему можно разбить на два раздела:
- Как вы получаете эпохи с 1 января 1970 г., 00:00:00?
Это интересная проблема, и простое решение - просто сделать это:
TEE_Time tt;
TEE_GetREETime(&tt);
Это решение может быть неудовлетворительным для многих людей, которые не хотели бы полагаться на счет эпох REE (Rich Execution Environment, также известный как уязвимая среда). Это может быть проблематично для операций, чувствительных к безопасности, когда вам нужно время, чтобы быть законным, и у REE нет места, чтобы изменить его для выполнения определенной атаки.
В случае, описанном выше, вам нужно будет получить эпохи из аппаратных часов, которые будут зависеть от аппаратной платы, на которой вы разрабатываете TA. Вы даже можете получить его с устройств определения местоположения, которые также возвращают время UTC в заявлениях NMEA. Хотя это может быть не на 100% с точностью до секунды, этого может быть достаточно. Если вам нужна очень высокая точность, вам нужно будет безопасно получить ее с аппаратного устройства.
В любом случае, вы должны выяснить, как получить эпохи самостоятельно. Этот ответ сосредоточен на второй части: получении даты и времени.
- Получение даты и времени по эпохам. После того, как вы решили шаг 1, вам нужно обработать его до datetime. Для этого вам понадобится
gmtime
которого нет в OP-TEE. Реализации нет. И вам нужна минималистичная реализация, чтобы все было просто.
К счастью, мне удалось найти ответ . Какие ссылки на
newlib
библиотеки, разработанные для Free BSD, которые идеально подходят для встраиваемых систем. Следовательно, почему это полезно здесь!
Мне удалось собрать его из их реализации, и вы можете использовать его здесь:
gmtime_r.h:
#include <inttypes.h>
#define SECSPERMIN 60L
#define MINSPERHOUR 60L
#define HOURSPERDAY 24L
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
#define DAYSPERWEEK 7
#define MONSPERYEAR 12
#define YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY 4
#define EPOCH_YEARS_SINCE_LEAP 2
#define EPOCH_YEARS_SINCE_CENTURY 70
#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
typedef int64_t time_t;
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
struct tm* gmtime_r (time_t tim_p, struct tm* res);
gmtime_r.c:
#include "gmtime_r.h"
#define EPOCH_ADJUSTMENT_DAYS 719468L
/* year to which the adjustment was made */
#define ADJUSTED_EPOCH_YEAR 0
/* 1st March of year 0 is Wednesday */
#define ADJUSTED_EPOCH_WDAY 3
/* there are 97 leap years in 400-year periods. ((400 - 97) * 365 + 97 * 366) */
#define DAYS_PER_ERA 146097L
/* there are 24 leap years in 100-year periods. ((100 - 24) * 365 + 24 * 366) */
#define DAYS_PER_CENTURY 36524L
/* there is one leap year every 4 years */
#define DAYS_PER_4_YEARS (3 * 365 + 366)
/* number of days in a non-leap year */
#define DAYS_PER_YEAR 365
/* number of days in January */
#define DAYS_IN_JANUARY 31
/* number of days in non-leap February */
#define DAYS_IN_FEBRUARY 28
/* number of years per era */
#define YEARS_PER_ERA 400
struct tm* gmtime_r (time_t tim_p, struct tm* res)
{
time_t days, rem;
const time_t lcltime = tim_p;
int era, weekday, year;
unsigned erayear, yearday, month, day;
unsigned long eraday;
days = lcltime / SECSPERDAY + EPOCH_ADJUSTMENT_DAYS;
rem = lcltime % SECSPERDAY;
if (rem < 0)
{
rem += SECSPERDAY;
--days;
}
/* compute hour, min, and sec */
res->tm_hour = (int) (rem / SECSPERHOUR);
rem %= SECSPERHOUR;
res->tm_min = (int) (rem / SECSPERMIN);
res->tm_sec = (int) (rem % SECSPERMIN);
/* compute day of week */
if ((weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
weekday += DAYSPERWEEK;
res->tm_wday = weekday;
/* compute year, month, day & day of year */
/* for description of this algorithm see
* http://howardhinnant.github.io/date_algorithms.html#civil_from_days */
era = (days >= 0 ? days : days - (DAYS_PER_ERA - 1)) / DAYS_PER_ERA;
eraday = days - era * DAYS_PER_ERA; /* [0, 146096] */
erayear = (eraday - eraday / (DAYS_PER_4_YEARS - 1) + eraday / DAYS_PER_CENTURY -
eraday / (DAYS_PER_ERA - 1)) / 365; /* [0, 399] */
yearday = eraday - (DAYS_PER_YEAR * erayear + erayear / 4 - erayear / 100); /* [0, 365] */
month = (5 * yearday + 2) / 153; /* [0, 11] */
day = yearday - (153 * month + 2) / 5 + 1; /* [1, 31] */
month += month < 10 ? 2 : -10;
year = ADJUSTED_EPOCH_YEAR + erayear + era * YEARS_PER_ERA + (month <= 1);
res->tm_yday = yearday >= DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY ?
yearday - (DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY) :
yearday + DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + isleap(erayear);
res->tm_year = year - YEAR_BASE;
res->tm_mon = month;
res->tm_mday = day;
res->tm_isdst = 0;
return (res);
}
Вы можете поместить оба этих файла в свою папку TA и обязательно добавить
gmtime.c
в списке источников в
sub.mk
. И, наконец, в самом ТА вы можете его использовать:
TEE_Time tt;
TEE_GetREETime(&tt);
struct tm *lt, temp;
lt = gmtime((time_t)tt.seconds, &temp);
DMSG("%4d-%2d-%2d %2d:%2d:%2d", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
Это напечатает время и дату в правильном формате.
В настоящее время я еще не портировал реализацию
strftime
, но скоро я сделаю и это, что автоматически отформатирует
tm
struct и добавить
1900
к
tm_year
и
1
к
tm_mon
.
А пока я надеюсь, что это найдет кого-нибудь в нужде.
Таймер безопасности
Чтобы получить текущее время в миллисекундах с 1 января 1970 года, вызовите . Уровень безопасности зависит от того, какие безопасные часы доступны в конкретной системе. Абсолютная минимальная гарантия заключается в том, что это значение не может уменьшиться во время работы доверенного приложения, но REE может контролировать, с какой скоростью это происходит. Гарантии на перезагрузку нет.
OP-TEE поставляется с реализацией
TEE_GetSystemTime
на основе CNTPCT
. Его можно настроить так, чтобы он был эксклюзивным для безопасного мира TrustZone на любом чипе armv8, но я не знаю, действительно ли все производители чипов делают это.
Когда таймер защищен, это является гарантией того, что короткие задержки будут соблюдены. Например, если вы хотите заблокировать хотя бы 1 секунду между попытками аутентификации, этого достаточно.
Многие платформы не могут надежно хранить дату, потому что для этого требуются часы, которые всегда включены, а для этого требуется батарея, которая не разряжается. Часто ненадежный мир может договориться о том, чтобы установить время на произвольное значение после перезагрузки системы. Поэтому, если вам нужна текущая дата с достаточной точностью, чтобы убедиться, что срок действия сертификата не истек, этого недостаточно, и вам нужно сделать что-то вроде установки соединения с безопасным сервером времени. Это проблема начальной загрузки, поскольку вы не можете убедиться, что срок действия сертификата сервера времени не истек.
Разбивая время
OP-TEE предоставляет тонкую библиотеку C, не включающую ничего похожего на . Если вы хотите рассчитать дату и время по эпохе, вам необходимо предоставить собственную реализацию .
Mbed TLS является потребителем, а не поставщикомgmtime
(точнееgmtime_r
). Эта функция используется для проверки действительности сертификатов.