Как можно преобразовать ASN1_TIME
в формат time_t
? Я хотел преобразовать возвращаемое значение X509_get_notAfter()
в секунды.ASN1_TIME to time_t conversion
ответ
Времена хранятся в виде строки внутри, в формате YYmmddHHMMSS
или YYYYmmddHHMMSS
.
В конце строки есть место для долей секунд и часовой пояс, но давайте проигнорируем это на данный момент и получим некоторый (непроверенный) код.
Примечание: также увидеть ответ Брайана Олсона ниже, который обсуждает неопределенное поведение из-за i++
-х гг. Также см. Ответ Seak, который устраняет неопределенное поведение.
static time_t ASN1_GetTimeT(ASN1_TIME* time)
{
struct tm t;
const char* str = (const char*) time->data;
size_t i = 0;
memset(&t, 0, sizeof(t));
if (time->type == V_ASN1_UTCTIME) /* two digit year */
{
t.tm_year = (str[i++] - '0') * 10 + (str[++i] - '0');
if (t.tm_year < 70)
t.tm_year += 100;
}
else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
{
t.tm_year = (str[i++] - '0') * 1000 + (str[++i] - '0') * 100 + (str[++i] - '0') * 10 + (str[++i] - '0');
t.tm_year -= 1900;
}
t.tm_mon = ((str[i++] - '0') * 10 + (str[++i] - '0')) - 1; // -1 since January is 0 not 1.
t.tm_mday = (str[i++] - '0') * 10 + (str[++i] - '0');
t.tm_hour = (str[i++] - '0') * 10 + (str[++i] - '0');
t.tm_min = (str[i++] - '0') * 10 + (str[++i] - '0');
t.tm_sec = (str[i++] - '0') * 10 + (str[++i] - '0');
/* Note: we did not adjust the time based on time zone information */
return mktime(&t);
}
ответ Яна в основном работает в этой ситуации, однако, аккумулятор i
должен последовательно использовать i++
:
static time_t ASN1_GetTimeT(ASN1_TIME* time)
{
struct tm t;
const char* str = (const char*) time->data;
size_t i = 0;
memset(&t, 0, sizeof(t));
if (time->type == V_ASN1_UTCTIME) /* two digit year */
{
t.tm_year = (str[i++] - '0') * 10 + (str[i++] - '0');
if (t.tm_year < 70)
t.tm_year += 100;
}
else if (time->type == V_ASN1_GENERALIZEDTIME) /* four digit year */
{
t.tm_year = (str[i++] - '0') * 1000 + (str[i++] - '0') * 100 + (str[i++] - '0') * 10 + (str[i++] - '0');
t.tm_year -= 1900;
}
t.tm_mon = ((str[i++] - '0') * 10 + (str[i++] - '0')) - 1; // -1 since January is 0 not 1.
t.tm_mday = (str[i++] - '0') * 10 + (str[i++] - '0');
t.tm_hour = (str[i++] - '0') * 10 + (str[i++] - '0');
t.tm_min = (str[i++] - '0') * 10 + (str[i++] - '0');
t.tm_sec = (str[i++] - '0') * 10 + (str[i++] - '0');
/* Note: we did not adjust the time based on time zone information */
return mktime(&t);
}
i ++ подразумевает, что i увеличивается с шагом ПОСЛЕ завершения инструкции. Это означает, что в течение года, скажем, это 2014 год, это составляет 322 (2222) внутри структуры tm, поэтому правильный ответ i ++ для первого и ++ i для каждого последующего. –
Нет, ваш код _still_ неправ. Вы просто не можете _not_ иметь более одного «i ++» в одном выражении, так как порядок оценки не гарантируется (слева направо и справа налево). –
Я не согласен с Яном и Джеком. Кто-то действительно скопировал и использовал данный код, где я работаю, и он терпит неудачу. Вот почему, от стандарта C99:
Между предыдущей и следующей точкой последовательности объект должен бы его сохраненное значение изменено в самый раз по оценке выражения « - ISO/IEC 9899.: 1999, "Языки программирования - C", раздел 6.5, пункт 1.
При составлении данного кода, GCC (версия 4.1.2) говорит, девять раз,
предупреждение: операция на ' i 'может быть undefin ed
Код имеет неопределенное поведение. Ошибка, которую я на самом деле видел, был годом «13», считающимся 11. Это связано с тем, что:
Результатом оператора postfix ++ является значение операнда. После того, как результат будет получен, значение операнда будет увеличено. [...] Побочный эффект обновления сохраненного значения операнда должен быть равен между предыдущей и следующей точками последовательности. - Там же, раздел 6.5.2.4, пункт 2.
Оба экземпляра ул [я ++] в:
t.tm_year = (ул [я ++] - '0') * 10 + (str [i ++] - '0');
читать «1» в «13», потому что они оба произошли до обновления i. Все строки, обновляющие i несколько раз, имеют те же проблемы.
Легкое решение состоит в том, чтобы избавиться от «i» и заменить все эти строки на один вызов sscanf().
Даже с этим исправлением, мне не понравился бы код.В дополнение к игнорированию суффикса часового пояса он не проверяет наличие ошибок или неожиданных значений. Сертификаты - это механизм безопасности, а код безопасности имеет строгие требования к надежности. Угловые случаи, в которых ваша программа не обрабатывается правильно, - это те, которые ваши нападающие заполняют.
* «Легкое решение состоит в том, чтобы избавиться от« i »и заменить все эти строки на один вызов sscanf()» * - вам, вероятно, следует предоставить пример, поскольку его простой в использовании 'sscanf' неправильно. Нет смысла торговать одной ошибкой для другой. – jww
Ну, я не знаю обо всем остальном, но этот код просто неверен для случаев, когда ASN1_TIME находится в формате UTCTime: YYMMDDHHMMSSZ.
Я попытался и вернул значение неправильно, даже с исправлением от ++ i до i ++, тем не менее ... код не является примером хорошего кодирования.
мне удалось это исправить, это суммы типов гольцов:
static time_t ASN1_GetTimeT(ASN1_TIME* time){
struct tm t;
const char* str = (const char*) time->data;
size_t i = 0;
memset(&t, 0, sizeof(t));
if (time->type == V_ASN1_UTCTIME) {/* two digit year */
t.tm_year = (str[i++] - '0') * 10;
t.tm_year += (str[i++] - '0');
if (t.tm_year < 70)
t.tm_year += 100;
} else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
t.tm_year = (str[i++] - '0') * 1000;
t.tm_year+= (str[i++] - '0') * 100;
t.tm_year+= (str[i++] - '0') * 10;
t.tm_year+= (str[i++] - '0');
t.tm_year -= 1900;
}
t.tm_mon = (str[i++] - '0') * 10;
t.tm_mon += (str[i++] - '0') - 1; // -1 since January is 0 not 1.
t.tm_mday = (str[i++] - '0') * 10;
t.tm_mday+= (str[i++] - '0');
t.tm_hour = (str[i++] - '0') * 10;
t.tm_hour+= (str[i++] - '0');
t.tm_min = (str[i++] - '0') * 10;
t.tm_min += (str[i++] - '0');
t.tm_sec = (str[i++] - '0') * 10;
t.tm_sec += (str[i++] - '0');
/* Note: we did not adjust the time based on time zone information */
return mktime(&t);
}
rfc 5280 говорит, что 1 - время ввода в UTC, и поэтому 'mktime()' может возвращать неверный результат здесь ('mktime()' ожидает время ввода в локальном часовом поясе). 2- 'YY> = 50' должно быть интерпретировано как' 19YY' 3- '99991231235959Z' - специальное значение. Вот пример кода, который может быть исправлен. (Https://stackoverflow.com/a/47015958/4279). – jfs
Из кода OpenSSL, это, кажется, плохая идея:
/*
* FIXME: mktime assumes the current timezone
* instead of UTC, and unless we rewrite OpenSSL
* in Lisp we cannot locally change the timezone
* without possibly interfering with other parts
* of the program. timegm, which uses UTC, is
* non-standard.
* Also time_t is inappropriate for general
* UTC times because it may a 32 bit type.
*/
Обратите внимание, что вы можете используйте ASN1_TIME_diff(), чтобы получить количество дней/секунд между двумя ASN1_TIME *. Если вы передадите NULL как ASN1_TIME *, вы можете получить разницу с текущим временем.
time_t
может иметь более узкий диапазон, чем ASN1_TIME
, и поэтому функции ASN1_TIME_*
могут быть более надежными. Например, чтобы сравнить времена, вы можете использовать ASN1_TIME_diff()
(это позволяет избежать возможных проблем безопасности при переполнении, если используется time_t
). Для печати в удобочитаемом формате, вызовите ASN1_TIME_print()
и т.д.
До сих пор ни один из ответов не следуют rfc 5280, который указывает, что входные времена в UTC (mktime()
ожидает время в местной временной зоны, т.е., ответы неверны, если местный часовой пояс не UTC). Also:
Соответствующие системы должны интерпретировать поле год (YY) следующим образом: где ГГ больше или равна 50, год ДОЛЖНА быть истолковано как 19YY; и Где YY меньше 50, год ДОЛЖЕН быть интерпретирован как 20YY.
i.e., if (tm_year < 70) tm_year += 100;
нарушает rfc. В этом ответе используется year += year < 50 ? 2000 : 1900
.
Кроме того, 99991231235959Z
in the input означает, что сертификат не имеет четкой даты истечения срока действия (функция должна возвращать (time_t)-1
- ошибка).
Для преобразования UTCTime или GeneralizedTime строки (ASN1_TIME*
) в seconds since Epoch (time_t
):
typedef unsigned U;
time_t ASN1_TIME_to_posix_time(const ASN1_TIME* time) {
if(!time) return -1;
const char *s = (const char*)time->data;
if (!s) return -1;
U two_digits_to_uint() // nested function: gcc extension
{
U n = 10 * (*s++ - '0');
return n + (*s++ - '0');
}
U year, month, day, hour, min, sec;
switch(time->type) {
// https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
case V_ASN1_UTCTIME: // YYMMDDHHMMSSZ
year = two_digits_to_uint();
year += year < 50 ? 2000 : 1900;
break;
case V_ASN1_GENERALIZEDTIME: // YYYYMMDDHHMMSSZ
year = 100 * two_digits_to_uint();
year += two_digits_to_uint();
break;
default:
return -1; // error
}
month = two_digits_to_uint();
day = two_digits_to_uint();
hour = two_digits_to_uint();
min = two_digits_to_uint();
sec = two_digits_to_uint();
if (*s != 'Z') return -1;
if (year == 9999 && month == 12 && day == 31 && hour == 23 && min == 59
&& sec == 59) // 99991231235959Z rfc 5280
return -1;
return posix_time(year, month, day, hour, min, sec);
}
где posix_time()
используется для преобразования сломанного вниз времени UTC к календарному времени. Seconds Since the Epoch:
time_t posix_time(U year, U month, U day, U hour, U min, U sec)
{
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|| hour > 23 || min > 59 || sec > 60)
return -1;
// days upto months for non-leap years
static const U month_day[13] =
{-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
year -= 1900;
// number of Februaries since 1900
const U year_for_leap = (month > 2) ? year + 1 : year;
// XXX may overflow
return sec + min*60 + hour*3600 + (month_day[month] + day - 1)*86400 +
(year-70)*31536000 + ((year_for_leap-69)/4)*86400 -
((year_for_leap-1)/100)*86400 + ((year_for_leap+299)/400)*86400;
}
month_day
и year_for_leap
взяты из @DTiedy's answer.
- 1. Преобразование double to time_t
- 2. convert wxString to time_t
- 3. Преобразование stable_clock :: time_point to time_t
- 4. EDI to XML Conversion
- 5. Curl to Python Conversion
- 6. Eregi to preg_match conversion
- 7. Cursor to Int Conversion
- 8. ColdFusion to JSP conversion
- 9. Flash to HTML5 Conversion
- 10. CCPoint to float conversion
- 11. Datetime to Varchar2 conversion
- 12. Array to string conversion
- 13. VRML to X3D Conversion
- 14. Swagger2.0 to RAML conversion
- 15. RGB to YIQ conversion
- 16. emf to jpg conversion
- 17. .wac to .wav conversion
- 18. Dojo to jQuery conversion
- 19. DataTable to excel conversion
- 20. string to base64 conversion
- 21. MathProg to C++ conversion
- 22. ByteString to Vector conversion
- 23. wav-to-midi conversion
- 24. svn to git conversion
- 25. Ascii to hex conversion
- 26. int to string conversion
- 27. wstring to wchar_t conversion
- 28. jpeg to png conversion
- 29. Revit to Pdf Conversion
- 30. char [] to CString Conversion
Этот код неверен, так как он полагается на неопределенное поведение с 'i ++' (или '++ i') в том же выражении: порядок оценки не гарантирован. –