18

形式に変換ASN1_TIMEするにはどうすればよいですか? の戻り値を秒time_tに変換したかったのです。X509_get_notAfter()

4

7 に答える 7

11

時刻は、YYmmddHHMMSSまたはの形式で内部的に文字列として保存されます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);
}
于 2012-06-29T14:33:15.300 に答える
11

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()を使用して、2 つの ASN1_TIME* の間の日数 / 秒を取得できることに注意してください。ASN1_TIME *from に NULL を渡すと、現在時刻との差を取得できます。

于 2015-08-26T16:22:35.213 に答える
8

残りの部分についてはわかりませんが、ASN1_TIME が UTCTime 形式の YYMMDDHHMMSSZ の場合、そのコードは間違っています。

++i から i++ への修正を行っても、間違った値を返してみましたが、それでも ... コードは適切なコーディングの例ではありません。

私はなんとかそれを修正しました。それはchar型の合計でした:

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);
}
于 2014-06-05T17:00:39.900 に答える
6

私はジャンとジャックに反対しなければなりません。誰かが実際に私が働いている特定のコードをコピーして使用しましたが、失敗しました。C99標準からの理由は次のとおりです。

前のシーケンス ポイントと次のシーケンス ポイントの間で、オブジェクトの格納値は、式の評価によって最大 1 回変更されます。" -- 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');

どちらも i. i を複数回更新するすべての行には、同じ問題があります。

簡単な修正は、「i」を取り除き、これらすべての行を sscanf() への 1 回の呼び出しに置き換えることです。

その修正があっても、私はコードが好きではありません。タイムゾーン サフィックスを無視するだけでなく、エラーや予期しない値をチェックしません。証明書はセキュリティ メカニズムであり、セキュリティ コードには堅牢性に関する厳しい要件があります。プログラムが正しく処理しないコーナー ケースは、攻撃者がプログラムに与えるものです。

于 2014-01-03T00:58:15.677 に答える
2

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);
}
于 2013-02-20T15:19:36.087 に答える
2

手遅れでopenssl、関数ASN1_TIME_to_tmが導入されていることはわかっていますが、このメソッドを持たない古いバージョンの openssl を使用する必要がありました。

この質問に対するさまざまな回答があり、彼らはコード内の時間文字列を解析していましたが、ロジックの解析で何かを見落としている可能性があり、コードが壊れたり、すべてのコーナー ケースを処理できない可能性があると考えたため、そのアプローチには満足できませんでした。opensslそのため、変換を行うためだけに関数を使用する C++ 用の関数を実装しました。

ASN1_TIME_diffを使用して、エポックからの秒数を計算します。ASN1_TIMEエポックを取得するために、引数を 0 として渡してASN1_TIME_SETを使用しました。time_t

気軽にコメントしてテストしてください。

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;
}
于 2020-01-13T17:32:48.237 に答える