1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-15 14:44:58 +00:00
serenity/Userland/Libraries/LibCrypto/ASN1/ASN1.cpp
Michiel Visser f8ce0eb648 LibTLS: ASN1 parse_utc_time handle pre 2000 years
In this format the year is specified using two digits. In the case that
these digits are 50 or more, we should assume that the year is in
1950-1999. If it is 49 or less, the year is 2000-2049.

This is specified in RFC5280 section 4.1.2.5.1.
2022-04-17 10:10:19 +04:30

192 lines
5.4 KiB
C++

/*
* Copyright (c) 2021, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/GenericLexer.h>
#include <LibCrypto/ASN1/ASN1.h>
namespace Crypto::ASN1 {
String kind_name(Kind kind)
{
switch (kind) {
case Kind::Eol:
return "EndOfList";
case Kind::Boolean:
return "Boolean";
case Kind::Integer:
return "Integer";
case Kind::BitString:
return "BitString";
case Kind::OctetString:
return "OctetString";
case Kind::Null:
return "Null";
case Kind::ObjectIdentifier:
return "ObjectIdentifier";
case Kind::IA5String:
return "IA5String";
case Kind::PrintableString:
return "PrintableString";
case Kind::Utf8String:
return "UTF8String";
case Kind::UTCTime:
return "UTCTime";
case Kind::GeneralizedTime:
return "GeneralizedTime";
case Kind::Sequence:
return "Sequence";
case Kind::Set:
return "Set";
}
return "InvalidKind";
}
String class_name(Class class_)
{
switch (class_) {
case Class::Application:
return "Application";
case Class::Context:
return "Context";
case Class::Private:
return "Private";
case Class::Universal:
return "Universal";
}
return "InvalidClass";
}
String type_name(Type type)
{
switch (type) {
case Type::Constructed:
return "Constructed";
case Type::Primitive:
return "Primitive";
}
return "InvalidType";
}
Optional<Core::DateTime> parse_utc_time(StringView time)
{
// YYMMDDhhmm[ss]Z or YYMMDDhhmm[ss](+|-)hhmm
GenericLexer lexer(time);
auto year_in_century = lexer.consume(2).to_uint();
auto month = lexer.consume(2).to_uint();
auto day = lexer.consume(2).to_uint();
auto hour = lexer.consume(2).to_uint();
auto minute = lexer.consume(2).to_uint();
Optional<unsigned> seconds, offset_hours, offset_minutes;
[[maybe_unused]] bool negative_offset = false;
if (!lexer.next_is('Z')) {
if (!lexer.next_is(is_any_of("+-"))) {
seconds = lexer.consume(2).to_uint();
if (!seconds.has_value()) {
return {};
}
}
if (lexer.next_is(is_any_of("+-"))) {
negative_offset = lexer.consume() == '-';
offset_hours = lexer.consume(2).to_uint();
offset_minutes = lexer.consume(2).to_uint();
if (!offset_hours.has_value() || !offset_minutes.has_value()) {
return {};
}
} else {
lexer.consume();
}
} else {
lexer.consume();
}
if (!year_in_century.has_value() || !month.has_value() || !day.has_value() || !hour.has_value() || !minute.has_value()) {
return {};
}
// RFC5280 section 4.1.2.5.1.
auto full_year = year_in_century.value();
full_year += (full_year < 50) ? 2000 : 1900;
auto full_seconds = seconds.value_or(0);
// FIXME: Handle offsets!
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);
}
Optional<Core::DateTime> parse_generalized_time(StringView time)
{
// YYYYMMDDhh[mm[ss[.fff]]] or YYYYMMDDhh[mm[ss[.fff]]]Z or YYYYMMDDhh[mm[ss[.fff]]](+|-)hhmm
GenericLexer lexer(time);
auto year = lexer.consume(4).to_uint();
auto month = lexer.consume(2).to_uint();
auto day = lexer.consume(2).to_uint();
auto hour = lexer.consume(2).to_uint();
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;
if (!lexer.next_is(is_any_of("+-"))) {
minute = lexer.consume(2).to_uint();
if (!minute.has_value()) {
return {};
}
if (lexer.consume_specific('Z'))
goto done_parsing;
}
if (!lexer.next_is(is_any_of("+-"))) {
seconds = lexer.consume(2).to_uint();
if (!seconds.has_value()) {
return {};
}
if (lexer.consume_specific('Z'))
goto done_parsing;
}
if (lexer.consume_specific('.')) {
milliseconds = lexer.consume(3).to_uint();
if (!milliseconds.has_value()) {
return {};
}
if (lexer.consume_specific('Z'))
goto done_parsing;
}
if (lexer.next_is(is_any_of("+-"))) {
negative_offset = lexer.consume() == '-';
offset_hours = lexer.consume(2).to_uint();
offset_minutes = lexer.consume(2).to_uint();
if (!offset_hours.has_value() || !offset_minutes.has_value()) {
return {};
}
} else {
lexer.consume();
}
}
done_parsing:;
if (!year.has_value() || !month.has_value() || !day.has_value() || !hour.has_value()) {
return {};
}
// FIXME: Handle offsets!
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));
}
}