From ed28008d78e5d5f315d08058679dfc10e607fd9d Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Sun, 18 Apr 2021 13:40:40 +0430 Subject: LibCrypo: Add an ASN.1/DER pretty-printer It's much easier to debug things when we can actually *see* them :P --- Userland/Libraries/LibCrypto/ASN1/DER.cpp | 141 ++++++++++++++++++++++++++++++ Userland/Libraries/LibCrypto/ASN1/DER.h | 2 + 2 files changed, 143 insertions(+) (limited to 'Userland/Libraries/LibCrypto') diff --git a/Userland/Libraries/LibCrypto/ASN1/DER.cpp b/Userland/Libraries/LibCrypto/ASN1/DER.cpp index d09c7ee87e..50b7149a8b 100644 --- a/Userland/Libraries/LibCrypto/ASN1/DER.cpp +++ b/Userland/Libraries/LibCrypto/ASN1/DER.cpp @@ -273,6 +273,147 @@ Optional Decoder::leave() return {}; } +void pretty_print(Decoder& decoder, OutputStream& stream, int indent) +{ + while (!decoder.eof()) { + auto tag = decoder.peek(); + if (tag.is_error()) { + dbgln("PrettyPrint error: {}", tag.error()); + return; + } + + StringBuilder builder; + for (int i = 0; i < indent; ++i) + builder.append(' '); + builder.appendff("<{}> ", class_name(tag.value().class_)); + if (tag.value().type == Type::Constructed) { + builder.appendff("[{}] {} ({})", type_name(tag.value().type), static_cast(tag.value().kind), kind_name(tag.value().kind)); + if (auto error = decoder.enter(); error.has_value()) { + dbgln("Constructed PrettyPrint error: {}", error.value()); + return; + } + + builder.append('\n'); + stream.write(builder.string_view().bytes()); + + pretty_print(decoder, stream, indent + 2); + + if (auto error = decoder.leave(); error.has_value()) { + dbgln("Constructed PrettyPrint error: {}", error.value()); + return; + } + + continue; + } else { + if (tag.value().class_ != Class::Universal) + builder.appendff("[{}] {} {}", type_name(tag.value().type), static_cast(tag.value().kind), kind_name(tag.value().kind)); + else + builder.appendff("[{}] {}", type_name(tag.value().type), kind_name(tag.value().kind)); + switch (tag.value().kind) { + case Kind::Eol: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("EOL PrettyPrint error: {}", value.error()); + return; + } + break; + } + case Kind::Boolean: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("Bool PrettyPrint error: {}", value.error()); + return; + } + builder.appendff(" {}", value.value()); + break; + } + case Kind::Integer: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("Integer PrettyPrint error: {}", value.error()); + return; + } + builder.append(" 0x"); + for (auto ch : value.value()) + builder.appendff("{:0>2x}", ch); + break; + } + case Kind::BitString: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("BitString PrettyPrint error: {}", value.error()); + return; + } + builder.append(" 0b"); + for (size_t i = 0; i < value.value().size(); ++i) + builder.append(value.value().get(i) ? '1' : '0'); + break; + } + case Kind::OctetString: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("OctetString PrettyPrint error: {}", value.error()); + return; + } + builder.append(" 0x"); + for (auto ch : value.value()) + builder.appendff("{:0>2x}", ch); + break; + } + case Kind::Null: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("Bool PrettyPrint error: {}", value.error()); + return; + } + break; + } + case Kind::ObjectIdentifier: { + auto value = decoder.read>(); + if (value.is_error()) { + dbgln("Identifier PrettyPrint error: {}", value.error()); + return; + } + for (auto& id : value.value()) + builder.appendff(" {}", id); + break; + } + case Kind::UTCTime: + case Kind::GeneralizedTime: + case Kind::IA5String: + case Kind::PrintableString: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("String PrettyPrint error: {}", value.error()); + return; + } + builder.append(' '); + builder.append(value.value()); + break; + } + case Kind::Utf8String: { + auto value = decoder.read(); + if (value.is_error()) { + dbgln("UTF8 PrettyPrint error: {}", value.error()); + return; + } + builder.append(' '); + for (auto cp : value.value()) + builder.append_code_point(cp); + break; + } + case Kind::Sequence: + case Kind::Set: + dbgln("Seq/Sequence PrettyPrint error: Unexpected Primtive"); + return; + } + } + + builder.append('\n'); + stream.write(builder.string_view().bytes()); + } +} + } void AK::Formatter::format(FormatBuilder& fmtbuilder, Crypto::ASN1::DecodeError error) diff --git a/Userland/Libraries/LibCrypto/ASN1/DER.h b/Userland/Libraries/LibCrypto/ASN1/DER.h index 3e092353ff..1fbc960788 100644 --- a/Userland/Libraries/LibCrypto/ASN1/DER.h +++ b/Userland/Libraries/LibCrypto/ASN1/DER.h @@ -216,6 +216,8 @@ private: Optional m_current_tag; }; +void pretty_print(Decoder&, OutputStream&, int indent = 0); + } template<> -- cgit v1.2.3