mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-26 04:35:41 +03:00
LibCrypto: Store ASN1 certificate timestamps as UnixDateTime
We are currently using Core::DateTime, which is meant to represent local time. However, we are doing no conversion between the parsed time in UTC and local time, so we end up comparing time stamps from different time zones. Instead, store the parsed times as UnixDateTime, which is UTC. Then we can always compare the parsed times against the current UTC time. This also lets us store parsed milliseconds.
This commit is contained in:
parent
da118f2adf
commit
928287b782
Notes:
sideshowbarker
2024-07-17 06:51:48 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/928287b782 Pull-request: https://github.com/SerenityOS/serenity/pull/23510 Issue: https://github.com/SerenityOS/serenity/issues/23502 Reviewed-by: https://github.com/fdellwing
@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Time.h>
|
||||
#include <LibCrypto/ASN1/ASN1.h>
|
||||
#include <LibTest/TestCase.h>
|
||||
|
||||
#define EXPECT_DATETIME(sv, y, mo, d, h, mi, s) \
|
||||
EXPECT_EQ(Crypto::ASN1::parse_utc_time(sv).value(), Core::DateTime::create(y, mo, d, h, mi, s))
|
||||
EXPECT_EQ(Crypto::ASN1::parse_utc_time(sv).value(), UnixDateTime::from_unix_time_parts(y, mo, d, h, mi, s, 0))
|
||||
|
||||
TEST_CASE(test_utc_boring)
|
||||
{
|
||||
@ -65,79 +66,76 @@ TEST_CASE(test_utc_missing_z)
|
||||
}
|
||||
|
||||
#undef EXPECT_DATETIME
|
||||
#define EXPECT_DATETIME(sv, y, mo, d, h, mi, s) \
|
||||
EXPECT_EQ(Crypto::ASN1::parse_generalized_time(sv).value(), Core::DateTime::create(y, mo, d, h, mi, s))
|
||||
#define EXPECT_DATETIME(sv, y, mo, d, h, mi, s, ms) \
|
||||
EXPECT_EQ(Crypto::ASN1::parse_generalized_time(sv).value(), UnixDateTime::from_unix_time_parts(y, mo, d, h, mi, s, ms))
|
||||
|
||||
TEST_CASE(test_generalized_boring)
|
||||
{
|
||||
// YYYYMMDDhh[mm[ss[.fff]]]
|
||||
EXPECT_DATETIME("20010101010101Z"sv, 2001, 1, 1, 1, 1, 1);
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20020406081012Z"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("200204060810Z"sv, 2002, 4, 6, 8, 10, 0);
|
||||
EXPECT_DATETIME("2002040608Z"sv, 2002, 4, 6, 8, 0, 0);
|
||||
// TODO: We probably should not discard the milliseconds.
|
||||
EXPECT_DATETIME("20020406081012.567Z"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("20220911220000Z"sv, 2022, 9, 11, 22, 0, 0);
|
||||
EXPECT_DATETIME("20010101010101Z"sv, 2001, 1, 1, 1, 1, 1, 0);
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("20020406081012Z"sv, 2002, 4, 6, 8, 10, 12, 0);
|
||||
EXPECT_DATETIME("200204060810Z"sv, 2002, 4, 6, 8, 10, 0, 0);
|
||||
EXPECT_DATETIME("2002040608Z"sv, 2002, 4, 6, 8, 0, 0, 0);
|
||||
EXPECT_DATETIME("20020406081012.567Z"sv, 2002, 4, 6, 8, 10, 12, 567);
|
||||
EXPECT_DATETIME("20220911220000Z"sv, 2022, 9, 11, 22, 0, 0, 0);
|
||||
}
|
||||
|
||||
TEST_CASE(test_generalized_offset)
|
||||
{
|
||||
// YYYYMMDDhh[mm[ss[.fff]]](+|-)hhmm
|
||||
// We don't yet support storing the offset anywhere and instead just assume that the offset is just +0000.
|
||||
EXPECT_DATETIME("20010101010101+0000"sv, 2001, 1, 1, 1, 1, 1);
|
||||
EXPECT_DATETIME("20010203040506+0000"sv, 2001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20020406081012+0000"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("200204060810+0000"sv, 2002, 4, 6, 8, 10, 0);
|
||||
EXPECT_DATETIME("2002040608+0000"sv, 2002, 4, 6, 8, 0, 0);
|
||||
// TODO: We probably should not discard the milliseconds.
|
||||
EXPECT_DATETIME("20020406081012.567+0000"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("20220911220000+0000"sv, 2022, 9, 11, 22, 0, 0);
|
||||
EXPECT_DATETIME("20010101010101+0000"sv, 2001, 1, 1, 1, 1, 1, 0);
|
||||
EXPECT_DATETIME("20010203040506+0000"sv, 2001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("20020406081012+0000"sv, 2002, 4, 6, 8, 10, 12, 0);
|
||||
EXPECT_DATETIME("200204060810+0000"sv, 2002, 4, 6, 8, 10, 0, 0);
|
||||
EXPECT_DATETIME("2002040608+0000"sv, 2002, 4, 6, 8, 0, 0, 0);
|
||||
EXPECT_DATETIME("20020406081012.567+0000"sv, 2002, 4, 6, 8, 10, 12, 567);
|
||||
EXPECT_DATETIME("20220911220000+0000"sv, 2022, 9, 11, 22, 0, 0, 0);
|
||||
// Designed to fail once we support offsets:
|
||||
EXPECT_DATETIME("20220911220000+0600"sv, 2022, 9, 11, 22, 0, 0);
|
||||
EXPECT_DATETIME("20220911220000+0600"sv, 2022, 9, 11, 22, 0, 0, 0);
|
||||
}
|
||||
|
||||
TEST_CASE(test_generalized_missing_z)
|
||||
{
|
||||
// YYYYMMDDhh[mm[ss[.fff]]]
|
||||
EXPECT_DATETIME("20010101010101"sv, 2001, 1, 1, 1, 1, 1);
|
||||
EXPECT_DATETIME("20010203040506"sv, 2001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20020406081012"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("200204060810"sv, 2002, 4, 6, 8, 10, 0);
|
||||
EXPECT_DATETIME("2002040608"sv, 2002, 4, 6, 8, 0, 0);
|
||||
// TODO: We probably should not discard the milliseconds.
|
||||
EXPECT_DATETIME("20020406081012.567"sv, 2002, 4, 6, 8, 10, 12);
|
||||
EXPECT_DATETIME("20220911220000"sv, 2022, 9, 11, 22, 0, 0);
|
||||
EXPECT_DATETIME("20010101010101"sv, 2001, 1, 1, 1, 1, 1, 0);
|
||||
EXPECT_DATETIME("20010203040506"sv, 2001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("20020406081012"sv, 2002, 4, 6, 8, 10, 12, 0);
|
||||
EXPECT_DATETIME("200204060810"sv, 2002, 4, 6, 8, 10, 0, 0);
|
||||
EXPECT_DATETIME("2002040608"sv, 2002, 4, 6, 8, 0, 0, 0);
|
||||
EXPECT_DATETIME("20020406081012.567"sv, 2002, 4, 6, 8, 10, 12, 567);
|
||||
EXPECT_DATETIME("20220911220000"sv, 2022, 9, 11, 22, 0, 0, 0);
|
||||
}
|
||||
|
||||
TEST_CASE(test_generalized_unusual_year)
|
||||
{
|
||||
// Towards the positive
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20110203040506Z"sv, 2011, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("21010203040506Z"sv, 2101, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("30010203040506Z"sv, 3001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("40010203040506Z"sv, 4001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("90010203040506Z"sv, 9001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("99990203040506Z"sv, 9999, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("20110203040506Z"sv, 2011, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("21010203040506Z"sv, 2101, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("30010203040506Z"sv, 3001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("40010203040506Z"sv, 4001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("90010203040506Z"sv, 9001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("99990203040506Z"sv, 9999, 2, 3, 4, 5, 6, 0);
|
||||
|
||||
// Towards zero
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("19990203040506Z"sv, 1999, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("19500203040506Z"sv, 1950, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("19010203040506Z"sv, 1901, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("18010203040506Z"sv, 1801, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("15010203040506Z"sv, 1501, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("10010203040506Z"sv, 1001, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("01010203040506Z"sv, 101, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("00110203040506Z"sv, 11, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("00010203040506Z"sv, 1, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("00000203040506Z"sv, 0, 2, 3, 4, 5, 6);
|
||||
EXPECT_DATETIME("20010203040506Z"sv, 2001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("19990203040506Z"sv, 1999, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("19500203040506Z"sv, 1950, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("19010203040506Z"sv, 1901, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("18010203040506Z"sv, 1801, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("15010203040506Z"sv, 1501, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("10010203040506Z"sv, 1001, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("01010203040506Z"sv, 101, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("00110203040506Z"sv, 11, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("00010203040506Z"sv, 1, 2, 3, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("00000203040506Z"sv, 0, 2, 3, 4, 5, 6, 0);
|
||||
|
||||
// Problematic dates
|
||||
EXPECT_DATETIME("20200229040506Z"sv, 2020, 2, 29, 4, 5, 6);
|
||||
EXPECT_DATETIME("20000229040506Z"sv, 2000, 2, 29, 4, 5, 6);
|
||||
EXPECT_DATETIME("24000229040506Z"sv, 2400, 2, 29, 4, 5, 6);
|
||||
EXPECT_DATETIME("20200229040506Z"sv, 2020, 2, 29, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("20000229040506Z"sv, 2000, 2, 29, 4, 5, 6, 0);
|
||||
EXPECT_DATETIME("24000229040506Z"sv, 2400, 2, 29, 4, 5, 6, 0);
|
||||
}
|
||||
|
||||
TEST_CASE(test_generalized_nonexistent_dates)
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "CertificateStoreWidget.h"
|
||||
#include <AK/String.h>
|
||||
#include <LibCore/DateTime.h>
|
||||
#include <LibCrypto/ASN1/PEM.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <LibFileSystemAccessClient/Client.h>
|
||||
@ -74,7 +75,7 @@ GUI::Variant CertificateStoreModel::data(GUI::ModelIndex const& index, GUI::Mode
|
||||
return issued_by;
|
||||
}
|
||||
case Column::Expire:
|
||||
return cert.validity.not_after.to_byte_string("%Y-%m-%d"sv);
|
||||
return Core::DateTime::from_timestamp(cert.validity.not_after.seconds_since_epoch()).to_byte_string("%Y-%m-%d"sv);
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ ByteString type_name(Type type)
|
||||
return "InvalidType";
|
||||
}
|
||||
|
||||
Optional<Core::DateTime> parse_utc_time(StringView time)
|
||||
Optional<UnixDateTime> parse_utc_time(StringView time)
|
||||
{
|
||||
// YYMMDDhhmm[ss]Z or YYMMDDhhmm[ss](+|-)hhmm
|
||||
GenericLexer lexer(time);
|
||||
@ -164,10 +164,10 @@ Optional<Core::DateTime> parse_utc_time(StringView time)
|
||||
if (offset_hours.has_value() || offset_minutes.has_value())
|
||||
dbgln("FIXME: Implement UTCTime with offset!");
|
||||
|
||||
return Core::DateTime::create(full_year, month.value(), day.value(), hour.value(), minute.value(), full_seconds);
|
||||
return UnixDateTime::from_unix_time_parts(full_year, month.value(), day.value(), hour.value(), minute.value(), full_seconds, 0);
|
||||
}
|
||||
|
||||
Optional<Core::DateTime> parse_generalized_time(StringView time)
|
||||
Optional<UnixDateTime> parse_generalized_time(StringView time)
|
||||
{
|
||||
// YYYYMMDDhh[mm[ss[.fff]]] or YYYYMMDDhh[mm[ss[.fff]]]Z or YYYYMMDDhh[mm[ss[.fff]]](+|-)hhmm
|
||||
GenericLexer lexer(time);
|
||||
@ -177,6 +177,7 @@ Optional<Core::DateTime> parse_generalized_time(StringView time)
|
||||
auto hour = lexer.consume(2).to_number<unsigned>();
|
||||
Optional<unsigned> minute, seconds, milliseconds, offset_hours, offset_minutes;
|
||||
[[maybe_unused]] bool negative_offset = false;
|
||||
|
||||
if (!lexer.is_eof()) {
|
||||
if (lexer.consume_specific('Z'))
|
||||
goto done_parsing;
|
||||
@ -233,7 +234,6 @@ done_parsing:;
|
||||
if (offset_hours.has_value() || offset_minutes.has_value())
|
||||
dbgln("FIXME: Implement GeneralizedTime with offset!");
|
||||
|
||||
// Unceremoniously drop the milliseconds on the floor.
|
||||
return Core::DateTime::create(year.value(), month.value(), day.value(), hour.value(), minute.value_or(0), seconds.value_or(0));
|
||||
return UnixDateTime::from_unix_time_parts(year.value(), month.value(), day.value(), hour.value(), minute.value_or(0), seconds.value_or(0), milliseconds.value_or(0));
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Time.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibCore/DateTime.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
|
||||
namespace Crypto::ASN1 {
|
||||
@ -75,7 +75,7 @@ ByteString kind_name(Kind);
|
||||
ByteString class_name(Class);
|
||||
ByteString type_name(Type);
|
||||
|
||||
Optional<Core::DateTime> parse_utc_time(StringView);
|
||||
Optional<Core::DateTime> parse_generalized_time(StringView);
|
||||
Optional<UnixDateTime> parse_utc_time(StringView);
|
||||
Optional<UnixDateTime> parse_generalized_time(StringView);
|
||||
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ static ErrorOr<RelativeDistinguishedName> parse_name(Crypto::ASN1::Decoder& deco
|
||||
return rdn;
|
||||
}
|
||||
|
||||
static ErrorOr<Core::DateTime> parse_time(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
|
||||
static ErrorOr<UnixDateTime> parse_time(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
|
||||
{
|
||||
// Time ::= Choice {
|
||||
// utc_time UTCTime,
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Time.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibCore/ConfigFile.h>
|
||||
#include <LibCore/DateTime.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
#include <LibCrypto/PK/RSA.h>
|
||||
#include <LibTLS/Extensions.h>
|
||||
@ -233,8 +233,8 @@ private:
|
||||
};
|
||||
|
||||
struct Validity {
|
||||
Core::DateTime not_before;
|
||||
Core::DateTime not_after;
|
||||
UnixDateTime not_before;
|
||||
UnixDateTime not_after;
|
||||
};
|
||||
|
||||
class SubjectPublicKey {
|
||||
|
@ -104,15 +104,15 @@ void TLSv12::consume(ReadonlyBytes record)
|
||||
|
||||
bool Certificate::is_valid() const
|
||||
{
|
||||
auto now = Core::DateTime::now();
|
||||
auto now = UnixDateTime::now();
|
||||
|
||||
if (now < validity.not_before) {
|
||||
dbgln("certificate expired (not yet valid, signed for {})", validity.not_before.to_byte_string());
|
||||
dbgln("certificate expired (not yet valid, signed for {})", Core::DateTime::from_timestamp(validity.not_before.seconds_since_epoch()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (validity.not_after < now) {
|
||||
dbgln("certificate expired (expiry date {})", validity.not_after.to_byte_string());
|
||||
dbgln("certificate expired (expiry date {})", Core::DateTime::from_timestamp(validity.not_after.seconds_since_epoch()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user