Openssl ASN1_时间到时间的转换
如何将Openssl ASN1_时间到时间的转换,openssl,ssl-certificate,asn.1,Openssl,Ssl Certificate,Asn.1,如何将ASN1\u TIME转换为TIME\t格式?我想将X509\u get\u notAfter()的返回值转换为秒。时间在内部以字符串形式存储,格式为yymmddhhmss或YYYYmmddHHMMSS 在字符串的末尾有几秒钟和时区的空间,但是现在我们忽略这一点,使用一些(未测试的)代码 注意:另请参见下面Bryan Olson的回答,其中讨论了由于i++而导致的未定义行为。另请参见Seak的答案,其中删除了未定义的行为 static time_t ASN1_GetTimeT(ASN1_T
ASN1\u TIME
转换为TIME\t
格式?我想将X509\u get\u notAfter()
的返回值转换为秒。时间在内部以字符串形式存储,格式为yymmddhhmss
或YYYYmmddHHMMSS
在字符串的末尾有几秒钟和时区的空间,但是现在我们忽略这一点,使用一些(未测试的)代码
注意:另请参见下面Bryan Olson的回答,其中讨论了由于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);
}
static time\t ASN1\u gettime(ASN1\u time*time)
{
struct-tm-t;
常量字符*str=(常量字符*)时间->数据;
尺寸i=0;
memset(&t,0,sizeof(t));
如果(时间->类型==V_ASN1_UTCTIME)/*两位数年份*/
{
t、 tm_year=(str[i++]-'0')*10+(str[++i]-'0');
如果(t.tm_年<70)
t、 tm_年+=100;
}
如果(时间->类型==V_ASN1_广义时间)/*四位数年份*/
{
t、 tm_year=(str[i++]-'0')*1000+(str[++i]-'0')*100+(str[++i]-'0')*10+(str[++i]-'0');
t、 tm_年-=1900;
}
t、 tm_mon=((str[i++]-'0')*10+(str[++i]-'0'))-1;//-1,因为一月是0而不是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');
/*注意:我们没有根据时区信息调整时间*/
返回时间(&t);
}
Jan的答案主要适用于这种情况,但是,累加器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);
}
static time\t ASN1\u gettime(ASN1\u time*time)
{
struct-tm-t;
常量字符*str=(常量字符*)时间->数据;
尺寸i=0;
memset(&t,0,sizeof(t));
如果(时间->类型==V_ASN1_UTCTIME)/*两位数年份*/
{
t、 tm_year=(str[i++]-'0')*10+(str[i++]-'0');
如果(t.tm_年<70)
t、 tm_年+=100;
}
如果(时间->类型==V_ASN1_广义时间)/*四位数年份*/
{
t、 tm_year=(str[i++]-'0')*1000+(str[i++]-'0')*100+(str[i++]-'0')*10+(str[i++]-'0');
t、 tm_年-=1900;
}
t、 tm_mon=((str[i++]-'0')*10+(str[i++]-'0'))-1;//-1,因为一月是0而不是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');
/*注意:我们没有根据时区信息调整时间*/
返回时间(&t);
}
我不同意简和杰克的观点。有人在我工作的地方复制并使用了给定的代码,但失败了。以下是C99标准的原因:
在上一个序列点和下一个序列点之间,对象应
通过评估最多修改一次其存储值
一种表达方式。”
--ISO/IEC 9899:1999,“编程语言-C”,第6.5节,第1条
在编译给定代码时,gcc(版本4.1.2)说,9次
警告:“i”上的操作可能未定义
代码有未定义的行为。我实际看到的错误是“13”年被解读为11年。这是因为:
后缀++运算符的结果是操作数的值。
获得结果后,操作数的值将递增。
[...]
更新操作数存储值的副作用应
发生在上一个序列点和下一个序列点之间。
--同上,第6.5.2.4节,第2条
str[i++]的两个实例在:
t、 tm_year=(str[i++]-'0')*10+(str[i++]-'0')
请阅读“13”中的“1”,因为它们都发生在更新i之前。所有多次更新i的行都有相同的问题
简单的解决方法是去掉“i”,用对sscanf()的一次调用替换所有这些行
即使有这样的修复,我也不喜欢代码。除了忽略时区后缀外,它不会检查错误或意外值。证书是一种安全机制,安全代码对健壮性有严格的要求。您的程序没有正确处理的角落案例就是攻击者填充的案例。好吧,我不知道其他的,但是对于ASN1_时间是UTCTime格式的情况,代码是错误的:YYMMDDHHMMSZ 我尝试过并返回了错误的值,即使从++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);
}
static time\t ASN1\u gettime(ASN1\u time*time){
struct-tm-t;
常量字符*str=(常量字符*)时间->数据;
尺寸i=0;
memset(&t,0,sizeof(t));
如果(时间->类型==V_ASN1_UTCTIME){/*两位数年份*/
t、 tm_year=(str[i++]-'0')*10;
t、 tm_year+=(str[i++]-'0');
如果(t.tm_年<70)
t、 tm_年+=100;
}如果(time->type==V_ASN1_GENERALIZEDTIME){/*四位数年份*/
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_年-=1900;
}
t、 tm_mon=(str[i++]-'0')*10;
t、 tm_mon+=(str[i++]-'0')-1;//-1,因为一月是0而不是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');
/*注意:我们没有根据时区信息调整时间*/
返回时间(&t);
}
从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.
*/
bool _ASN1_TIME_to_tm(const ASN1_TIME *pTime, struct tm *pTm)
{
int days = 0, seconds = 0;
ASN1_TIME *epochTime = ASN1_TIME_new();
ASN1_TIME_set(epochTime, time_t(0));
if (!ASN1_TIME_diff(&days, &seconds, epochTime, pTime))
return false;
time_t sinceEpoch = time_t(86400LL * days + seconds); // No of seconds in a day = 86400
gmtime_r(&sinceEpoch, pTm);
std::cout << "DateTime: " << TOS::convertTmToStr(*pTm) << std::endl;
ASN1_TIME_free(epochTime);
return true;
}
bool _ASN1_TIME_to_tm(const ASN1_TIME *pTime, struct tm *pTm)
{
bool result = false;
time_t sinceEpoch = 0;
int days = 0, seconds = 0;
if (!pTime)
return false;
ASN1_TIME *epochTime = ASN1_TIME_new();
if (!epochTime)
return false;
do {
if (!ASN1_TIME_set(epochTime, time_t(0)))
break;
if (!ASN1_TIME_diff(&days, &seconds, epochTime, pTime))
break;
// No of seconds in a day = 86400
sinceEpoch = time_t(86400LL * days + seconds);
gmtime_r(&sinceEpoch, pTm);
std::cout << "DateTime: " << TOS::convertTmToStr(*pTm) << std::endl;
result = true;
} while (0);
ASN1_TIME_free(epochTime);
return result;
}