123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834 |
- /*
- * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
- * Copyright (c) 2023, stelar7 <dudedbz@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "Certificate.h"
- #include <AK/Debug.h>
- #include <AK/IPv4Address.h>
- #include <LibCrypto/ASN1/ASN1.h>
- #include <LibCrypto/ASN1/DER.h>
- #include <LibCrypto/ASN1/PEM.h>
- namespace {
- static String s_error_string;
- }
- namespace TLS {
- #define ERROR_WITH_SCOPE(error) \
- do { \
- s_error_string = TRY(String::formatted("{}: {}", current_scope, error)); \
- return Error::from_string_view(s_error_string.bytes_as_string_view()); \
- } while (0)
- #define ENTER_TYPED_SCOPE(tag_kind_name, scope) \
- do { \
- if (auto tag = decoder.peek(); tag.is_error() || tag.value().kind != Crypto::ASN1::Kind::tag_kind_name) { \
- if (tag.is_error()) \
- ERROR_WITH_SCOPE(TRY(String::formatted(scope " data was invalid: {}", tag.error()))); \
- else \
- ERROR_WITH_SCOPE(TRY(String::formatted(scope " data was not of kind " #tag_kind_name " was {}", Crypto::ASN1::kind_name(tag.value().kind)))); \
- } \
- ENTER_SCOPE(scope); \
- } while (0)
- #define ENTER_SCOPE(scope) \
- do { \
- if (auto result = decoder.enter(); result.is_error()) { \
- ERROR_WITH_SCOPE(TRY(String::formatted("Failed to enter scope: {}", scope))); \
- } \
- PUSH_SCOPE(scope) \
- } while (0)
- #define PUSH_SCOPE(scope) current_scope.append(#scope##sv);
- #define EXIT_SCOPE() \
- do { \
- if (auto error = decoder.leave(); error.is_error()) { \
- ERROR_WITH_SCOPE(TRY(String::formatted("Failed to exit scope: {}", error.error()))); \
- } \
- POP_SCOPE(); \
- } while (0)
- #define POP_SCOPE() current_scope.remove(current_scope.size() - 1);
- #define READ_OBJECT(kind_name, type_name, value_name) \
- auto value_name##_result = decoder.read<type_name>(Crypto::ASN1::Class::Universal, Crypto::ASN1::Kind::kind_name); \
- if (value_name##_result.is_error()) { \
- ERROR_WITH_SCOPE(TRY(String::formatted("Read of kind " #kind_name " failed: {}", value_name##_result.error()))); \
- } \
- auto value_name = value_name##_result.release_value();
- #define REWRITE_TAG(kind_name) \
- auto value_name##_result = decoder.rewrite_tag(Crypto::ASN1::Kind::kind_name); \
- if (value_name##_result.is_error()) { \
- ERROR_WITH_SCOPE(TRY(String::formatted("Rewrite of kind " #kind_name " failed: {}", value_name##_result.error()))); \
- }
- #define DROP_OBJECT() \
- do { \
- if (auto error = decoder.drop(); error.is_error()) { \
- ERROR_WITH_SCOPE(TRY(String::formatted("Drop failed: {}", error.error()))); \
- } \
- } while (0)
- static ErrorOr<SupportedGroup> oid_to_curve(Vector<int> curve)
- {
- if (curve == curve_ansip384r1)
- return SupportedGroup::SECP384R1;
- else if (curve == curve_prime256)
- return SupportedGroup::SECP256R1;
- return Error::from_string_view("Unknown curve oid"sv);
- }
- static ErrorOr<Crypto::UnsignedBigInteger> parse_certificate_version(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // Version ::= INTEGER {v1(0), v2(1), v3(2)}
- if (auto tag = decoder.peek(); !tag.is_error() && tag.value().type == Crypto::ASN1::Type::Constructed) {
- ENTER_SCOPE("Version"sv);
- READ_OBJECT(Integer, Crypto::UnsignedBigInteger, version);
- if (version > 3) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Invalid version value at {}", current_scope)));
- }
- EXIT_SCOPE();
- return version;
- } else {
- return Crypto::UnsignedBigInteger { 0 };
- }
- }
- static ErrorOr<Crypto::UnsignedBigInteger> parse_serial_number(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // CertificateSerialNumber ::= INTEGER
- PUSH_SCOPE("CertificateSerialNumber"sv);
- READ_OBJECT(Integer, Crypto::UnsignedBigInteger, serial);
- POP_SCOPE();
- return serial;
- }
- static ErrorOr<SupportedGroup> parse_ec_parameters(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // ECParameters ::= CHOICE {
- // namedCurve OBJECT IDENTIFIER
- // }
- PUSH_SCOPE("ECParameters"sv);
- READ_OBJECT(ObjectIdentifier, Vector<int>, named_curve);
- // Note: namedCurve sometimes has 5 nodes, but we need 7 for the comparison below to work.
- while (named_curve.size() < 7) {
- named_curve.append(0);
- }
- POP_SCOPE();
- bool is_known_curve = false;
- for (auto const& curves : known_curve_identifiers) {
- if (curves.span() == named_curve.span()) {
- is_known_curve = true;
- break;
- }
- }
- if (!is_known_curve) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Unknown named curve {}", named_curve)));
- }
- return oid_to_curve(named_curve);
- }
- static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // AlgorithmIdentifier{ALGORITHM:SupportedAlgorithms} ::= SEQUENCE {
- // algorithm ALGORITHM.&id({SupportedAlgorithms}),
- // parameters ALGORITHM.&Type({SupportedAlgorithms}{@algorithm}) OPTIONAL,
- // ... }
- ENTER_TYPED_SCOPE(Sequence, "AlgorithmIdentifier"sv);
- PUSH_SCOPE("algorithm"sv);
- READ_OBJECT(ObjectIdentifier, Vector<int>, algorithm);
- // Note: ecPublicKey only has 6 nodes, but we need 7 for the comparison below to work.
- while (algorithm.size() < 7) {
- algorithm.append(0);
- }
- POP_SCOPE();
- bool is_known_algorithm = false;
- for (auto const& inner : known_algorithm_identifiers) {
- if (inner.span() == algorithm.span()) {
- is_known_algorithm = true;
- break;
- }
- }
- if (!is_known_algorithm) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Unknown algorithm {}", algorithm)));
- }
- // -- When the following OIDs are used in an AlgorithmIdentifier, the
- // -- parameters MUST be present and MUST be NULL.
- // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
- // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
- // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
- // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
- // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
- // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
- // sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 }
- Array<Array<int, 7>, 8> rsa_null_algorithms = {
- rsa_encryption_oid,
- rsa_md5_encryption_oid,
- rsa_sha1_encryption_oid,
- rsa_sha256_encryption_oid,
- rsa_sha384_encryption_oid,
- rsa_sha512_encryption_oid,
- rsa_sha224_encryption_oid,
- };
- bool is_rsa_null_algorithm = false;
- for (auto const& inner : rsa_null_algorithms) {
- if (inner.span() == algorithm.span()) {
- is_rsa_null_algorithm = true;
- break;
- }
- }
- if (is_rsa_null_algorithm) {
- PUSH_SCOPE("RSA null parameter"sv);
- READ_OBJECT(Null, void*, forced_null);
- (void)forced_null;
- POP_SCOPE();
- EXIT_SCOPE();
- return AlgorithmIdentifier(algorithm);
- }
- // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
- // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
- // as an AlgorithmIdentifier, the encoding MUST omit the parameters
- // field.
- Array<Array<int, 7>, 8> no_parameter_algorithms = {
- ecdsa_with_sha224_encryption_oid,
- ecdsa_with_sha256_encryption_oid,
- ecdsa_with_sha384_encryption_oid,
- ecdsa_with_sha512_encryption_oid,
- };
- bool is_no_parameter_algorithm = false;
- for (auto const& inner : no_parameter_algorithms) {
- if (inner.span() == algorithm.span()) {
- is_no_parameter_algorithm = true;
- }
- }
- if (is_no_parameter_algorithm) {
- EXIT_SCOPE();
- return AlgorithmIdentifier(algorithm);
- }
- if (algorithm.span() == ec_public_key_encryption_oid.span()) {
- // The parameters associated with id-ecPublicKey SHOULD be absent or ECParameters,
- // and NULL is allowed to support legacy implementations.
- if (decoder.eof()) {
- EXIT_SCOPE();
- return AlgorithmIdentifier(algorithm);
- }
- auto tag = TRY(decoder.peek());
- if (tag.kind == Crypto::ASN1::Kind::Null) {
- PUSH_SCOPE("ecPublicKey null parameter"sv);
- READ_OBJECT(Null, void*, forced_null);
- (void)forced_null;
- POP_SCOPE();
- EXIT_SCOPE();
- return AlgorithmIdentifier(algorithm);
- }
- auto algorithm_identifier = AlgorithmIdentifier(algorithm);
- algorithm_identifier.ec_parameters = TRY(parse_ec_parameters(decoder, current_scope));
- EXIT_SCOPE();
- return algorithm_identifier;
- }
- ERROR_WITH_SCOPE(TRY(String::formatted("Unhandled parameters for algorithm {}", algorithm)));
- }
- static ErrorOr<RelativeDistinguishedName> parse_name(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- RelativeDistinguishedName rdn {};
- // Name ::= Choice {
- // rdn_sequence RDNSequence
- // } // NOTE: since this is the only alternative, there's no index
- // RDNSequence ::= Sequence OF RelativeDistinguishedName
- ENTER_TYPED_SCOPE(Sequence, "Name"sv);
- while (!decoder.eof()) {
- // RelativeDistinguishedName ::= Set OF AttributeTypeAndValue
- ENTER_TYPED_SCOPE(Set, "RDNSequence"sv);
- while (!decoder.eof()) {
- // AttributeTypeAndValue ::= Sequence {
- // type AttributeType,
- // value AttributeValue
- // }
- ENTER_TYPED_SCOPE(Sequence, "AttributeTypeAndValue"sv);
- // AttributeType ::= ObjectIdentifier
- PUSH_SCOPE("AttributeType"sv)
- READ_OBJECT(ObjectIdentifier, Vector<int>, attribute_type_oid);
- POP_SCOPE();
- // AttributeValue ::= Any
- PUSH_SCOPE("AttributeValue"sv)
- READ_OBJECT(PrintableString, StringView, attribute_value);
- POP_SCOPE();
- auto attribute_type_string = TRY(String::join("."sv, attribute_type_oid));
- auto attribute_value_string = TRY(String::from_utf8(attribute_value));
- TRY(rdn.set(attribute_type_string, attribute_value_string));
- EXIT_SCOPE();
- }
- EXIT_SCOPE();
- }
- EXIT_SCOPE();
- return rdn;
- }
- static ErrorOr<Core::DateTime> parse_time(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // Time ::= Choice {
- // utc_time UTCTime,
- // general_time GeneralizedTime
- // }
- auto tag = TRY(decoder.peek());
- if (tag.kind == Crypto::ASN1::Kind::UTCTime) {
- PUSH_SCOPE("UTCTime"sv);
- READ_OBJECT(UTCTime, StringView, utc_time);
- auto parse_result = Crypto::ASN1::parse_utc_time(utc_time);
- if (!parse_result.has_value()) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Failed to parse UTCTime {}", utc_time)));
- }
- POP_SCOPE();
- return parse_result.release_value();
- }
- if (tag.kind == Crypto::ASN1::Kind::GeneralizedTime) {
- PUSH_SCOPE("GeneralizedTime"sv);
- READ_OBJECT(UTCTime, StringView, generalized_time);
- auto parse_result = Crypto::ASN1::parse_generalized_time(generalized_time);
- if (!parse_result.has_value()) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Failed to parse GeneralizedTime {}", generalized_time)));
- }
- POP_SCOPE();
- return parse_result.release_value();
- }
- ERROR_WITH_SCOPE(TRY(String::formatted("Unrecognised Time format {}", kind_name(tag.kind))));
- }
- static ErrorOr<Validity> parse_validity(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- Validity validity {};
- // Validity ::= SEQUENCE {
- // notBefore Time,
- // notAfter Time }
- ENTER_TYPED_SCOPE(Sequence, "Validity"sv);
- validity.not_before = TRY(parse_time(decoder, current_scope));
- validity.not_after = TRY(parse_time(decoder, current_scope));
- EXIT_SCOPE();
- return validity;
- }
- static ErrorOr<SubjectPublicKey> parse_subject_public_key_info(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // SubjectPublicKeyInfo ::= Sequence {
- // algorithm AlgorithmIdentifier,
- // subject_public_key BitString
- // }
- SubjectPublicKey public_key;
- ENTER_TYPED_SCOPE(Sequence, "SubjectPublicKeyInfo"sv);
- public_key.algorithm = TRY(parse_algorithm_identifier(decoder, current_scope));
- PUSH_SCOPE("subjectPublicKey"sv);
- READ_OBJECT(BitString, Crypto::ASN1::BitStringView, value);
- POP_SCOPE();
- public_key.raw_key = TRY(ByteBuffer::copy(TRY(value.raw_bytes())));
- if (public_key.algorithm.identifier.span() == rsa_encryption_oid.span()) {
- auto key = Crypto::PK::RSA::parse_rsa_key(TRY(value.raw_bytes()));
- if (!key.public_key.length()) {
- return Error::from_string_literal("Invalid RSA key");
- }
- public_key.rsa = move(key.public_key);
- EXIT_SCOPE();
- return public_key;
- }
- if (public_key.algorithm.identifier.span() == ec_public_key_encryption_oid.span()) {
- // Note: Raw key is already stored, so we can just exit out at this point.
- EXIT_SCOPE();
- return public_key;
- }
- String algo_oid = TRY(String::join("."sv, public_key.algorithm.identifier));
- ERROR_WITH_SCOPE(TRY(String::formatted("Unhandled algorithm {}", algo_oid)));
- EXIT_SCOPE();
- return public_key;
- }
- static ErrorOr<Crypto::ASN1::BitStringView> parse_unique_identifier(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // UniqueIdentifier ::= BIT STRING
- PUSH_SCOPE("UniqueIdentifier"sv);
- READ_OBJECT(BitString, Crypto::ASN1::BitStringView, value);
- POP_SCOPE();
- return value;
- }
- static ErrorOr<String> parse_general_name(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // GeneralName ::= CHOICE {
- // otherName [0] INSTANCE OF OTHER-NAME,
- // rfc822Name [1] IA5String,
- // dNSName [2] IA5String,
- // x400Address [3] ORAddress,
- // directoryName [4] Name,
- // ediPartyName [5] EDIPartyName,
- // uniformResourceIdentifier [6] IA5String,
- // iPAddress [7] OCTET STRING,
- // registeredID [8] OBJECT IDENTIFIER,
- // }
- auto tag = TRY(decoder.peek());
- auto tag_value = static_cast<u8>(tag.kind);
- switch (tag_value) {
- case 0:
- // Note: We don't know how to use this.
- PUSH_SCOPE("otherName"sv)
- DROP_OBJECT();
- POP_SCOPE();
- break;
- case 1: {
- PUSH_SCOPE("rfc822Name"sv)
- READ_OBJECT(IA5String, StringView, name);
- POP_SCOPE();
- return String::from_utf8(name);
- }
- case 2: {
- PUSH_SCOPE("dNSName"sv)
- READ_OBJECT(IA5String, StringView, name);
- POP_SCOPE();
- return String::from_utf8(name);
- }
- case 3:
- // Note: We don't know how to use this.
- PUSH_SCOPE("x400Address"sv)
- DROP_OBJECT();
- POP_SCOPE();
- break;
- case 4: {
- PUSH_SCOPE("directoryName"sv);
- READ_OBJECT(OctetString, StringView, directory_name);
- Crypto::ASN1::Decoder decoder { directory_name.bytes() };
- auto names = TRY(parse_name(decoder, current_scope));
- POP_SCOPE();
- return names.to_string();
- }
- case 5:
- // Note: We don't know how to use this.
- PUSH_SCOPE("ediPartyName");
- DROP_OBJECT();
- POP_SCOPE();
- break;
- case 6: {
- PUSH_SCOPE("uniformResourceIdentifier"sv);
- READ_OBJECT(IA5String, StringView, name);
- POP_SCOPE();
- return String::from_utf8(name);
- }
- case 7: {
- PUSH_SCOPE("iPAddress"sv);
- READ_OBJECT(OctetString, StringView, ip_addr_sv);
- IPv4Address ip_addr { ip_addr_sv.bytes().data() };
- POP_SCOPE();
- return ip_addr.to_string();
- }
- case 8: {
- PUSH_SCOPE("registeredID"sv);
- READ_OBJECT(ObjectIdentifier, Vector<int>, identifier);
- POP_SCOPE();
- return String::join("."sv, identifier);
- }
- default:
- ERROR_WITH_SCOPE("Unknown tag in GeneralNames choice"sv);
- }
- ERROR_WITH_SCOPE("Unknown tag in GeneralNames choice"sv);
- }
- static ErrorOr<Vector<String>> parse_general_names(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // GeneralNames ::= Sequence OF GeneralName
- ENTER_TYPED_SCOPE(Sequence, "GeneralNames");
- Vector<String> names;
- while (!decoder.eof()) {
- names.append(TRY(parse_general_name(decoder, current_scope)));
- }
- EXIT_SCOPE();
- return names;
- }
- static ErrorOr<Vector<String>> parse_subject_alternative_names(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // SubjectAlternativeName ::= GeneralNames
- PUSH_SCOPE("SubjectAlternativeName"sv);
- auto values = TRY(parse_general_names(decoder, current_scope));
- POP_SCOPE();
- return values;
- }
- static ErrorOr<Vector<String>> parse_issuer_alternative_names(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // issuerAltName ::= GeneralNames
- PUSH_SCOPE("issuerAltName"sv);
- auto values = TRY(parse_general_names(decoder, current_scope));
- POP_SCOPE();
- return values;
- }
- static ErrorOr<Crypto::ASN1::BitStringView> parse_key_usage(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // KeyUsage ::= BIT STRING {
- // digitalSignature (0),
- // contentCommitment (1),
- // keyEncipherment (2),
- // dataEncipherment (3),
- // keyAgreement (4),
- // keyCertSign (5),
- // cRLSign (6),
- // encipherOnly (7),
- // decipherOnly (8)
- // }
- PUSH_SCOPE("KeyUsage"sv);
- READ_OBJECT(BitString, Crypto::ASN1::BitStringView, usage);
- POP_SCOPE();
- return usage;
- }
- static ErrorOr<BasicConstraints> parse_basic_constraints(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // BasicConstraints ::= SEQUENCE {
- // cA BOOLEAN DEFAULT FALSE,
- // pathLenConstraint INTEGER (0..MAX) OPTIONAL
- // }
- BasicConstraints constraints {};
- ENTER_TYPED_SCOPE(Sequence, "BasicConstraints"sv);
- if (decoder.eof()) {
- EXIT_SCOPE();
- return constraints;
- }
- auto ca_tag = TRY(decoder.peek());
- if (ca_tag.kind == Crypto::ASN1::Kind::Boolean) {
- PUSH_SCOPE("cA"sv);
- READ_OBJECT(Boolean, bool, is_certificate_authority);
- constraints.is_certificate_authority = is_certificate_authority;
- POP_SCOPE();
- }
- if (decoder.eof()) {
- EXIT_SCOPE();
- return constraints;
- }
- auto path_length_tag = TRY(decoder.peek());
- if (path_length_tag.kind == Crypto::ASN1::Kind::Integer) {
- PUSH_SCOPE("pathLenConstraint"sv);
- READ_OBJECT(Integer, Crypto::UnsignedBigInteger, path_length_constraint);
- constraints.path_length_constraint = path_length_constraint;
- POP_SCOPE();
- }
- EXIT_SCOPE();
- return constraints;
- }
- static ErrorOr<void> parse_extension(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope, Certificate& certificate)
- {
- // Extension ::= Sequence {
- // extension_id ObjectIdentifier,
- // critical Boolean DEFAULT false,
- // extension_value OctetString (DER-encoded)
- // }
- ENTER_TYPED_SCOPE(Sequence, "Extension"sv);
- PUSH_SCOPE("extension_id"sv);
- READ_OBJECT(ObjectIdentifier, Vector<int>, extension_id);
- POP_SCOPE();
- bool is_critical = false;
- auto peek = TRY(decoder.peek());
- if (peek.kind == Crypto::ASN1::Kind::Boolean) {
- PUSH_SCOPE("critical"sv);
- READ_OBJECT(Boolean, bool, extension_critical);
- is_critical = extension_critical;
- POP_SCOPE();
- }
- PUSH_SCOPE("extension_value"sv);
- READ_OBJECT(OctetString, StringView, extension_value);
- POP_SCOPE();
- bool is_known_extension = false;
- Crypto::ASN1::Decoder extension_decoder { extension_value.bytes() };
- Vector<StringView, 8> extension_scope {};
- if (extension_id == subject_alternative_name_oid) {
- is_known_extension = true;
- auto alternate_names = TRY(parse_subject_alternative_names(extension_decoder, extension_scope));
- certificate.SAN = alternate_names;
- }
- if (extension_id == key_usage_oid) {
- is_known_extension = true;
- auto usage = TRY(parse_key_usage(extension_decoder, extension_scope));
- certificate.is_allowed_to_sign_certificate = usage.get(5);
- }
- if (extension_id == basic_constraints_oid) {
- is_known_extension = true;
- auto constraints = TRY(parse_basic_constraints(extension_decoder, extension_scope));
- certificate.is_certificate_authority = constraints.is_certificate_authority;
- certificate.path_length_constraint = constraints.path_length_constraint.to_u64();
- }
- if (extension_id == issuer_alternative_name_oid) {
- is_known_extension = true;
- auto alternate_names = TRY(parse_issuer_alternative_names(extension_decoder, extension_scope));
- certificate.IAN = alternate_names;
- }
- EXIT_SCOPE();
- if (is_critical && !is_known_extension) {
- ERROR_WITH_SCOPE(TRY(String::formatted("Extension {} is critical, but we do not support it", extension_id)));
- }
- if (!is_known_extension) {
- dbgln_if(TLS_DEBUG, TRY(String::formatted("{}: Unhandled extension: {}", current_scope, extension_id)));
- }
- return {};
- }
- static ErrorOr<void> parse_extensions(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope, Certificate& certificate)
- {
- // Extensions ::= Sequence OF Extension
- ENTER_TYPED_SCOPE(Sequence, "Extensions"sv);
- while (!decoder.eof()) {
- TRY(parse_extension(decoder, current_scope, certificate));
- }
- EXIT_SCOPE();
- return {};
- }
- static ErrorOr<Certificate> parse_tbs_certificate(Crypto::ASN1::Decoder& decoder, Vector<StringView> current_scope)
- {
- // TBSCertificate ::= SEQUENCE {
- // version [0] Version DEFAULT v1,
- // serialNumber CertificateSerialNumber,
- // signature AlgorithmIdentifier{{SupportedAlgorithms}},
- // issuer Name,
- // validity Validity,
- // subject Name,
- // subjectPublicKeyInfo SubjectPublicKeyInfo,
- // issuerUniqueIdentifier [1] IMPLICIT UniqueIdentifier OPTIONAL,
- // ...,
- // [[2: -- if present, version shall be v2 or v3
- // subjectUniqueIdentifier [2] IMPLICIT UniqueIdentifier OPTIONAL]],
- // [[3: -- if present, version shall be v2 or v3
- // extensions [3] Extensions OPTIONAL]]
- // -- If present, version shall be v3]]
- // }
- // Note: Parse out the ASN.1 of this object, since its used for TLS verification.
- // To do this, we get the bytes of our parent, the size of ourself, and slice the parent buffer.
- auto pre_cert_buffer = TRY(decoder.peek_entry_bytes());
- // FIXME: Dont assume this value.
- // Note: we assume this to be 4. 1 for the tag, and 3 for the length.
- auto entry_length_byte_count = 4;
- ENTER_TYPED_SCOPE(Sequence, "TBSCertificate"sv);
- auto post_cert_buffer = TRY(decoder.peek_entry_bytes());
- if (pre_cert_buffer.size() < post_cert_buffer.size() + entry_length_byte_count) {
- ERROR_WITH_SCOPE("Unexpected end of file");
- }
- Certificate certificate;
- certificate.version = TRY(parse_certificate_version(decoder, current_scope)).to_u64();
- certificate.serial_number = TRY(parse_serial_number(decoder, current_scope));
- certificate.algorithm = TRY(parse_algorithm_identifier(decoder, current_scope));
- certificate.issuer = TRY(parse_name(decoder, current_scope));
- certificate.validity = TRY(parse_validity(decoder, current_scope));
- certificate.subject = TRY(parse_name(decoder, current_scope));
- certificate.public_key = TRY(parse_subject_public_key_info(decoder, current_scope));
- certificate.tbs_asn1 = TRY(ByteBuffer::copy(pre_cert_buffer.slice(0, post_cert_buffer.size() + entry_length_byte_count)));
- if (!decoder.eof()) {
- auto tag = TRY(decoder.peek());
- if (static_cast<u8>(tag.kind) == 1) {
- REWRITE_TAG(BitString)
- TRY(parse_unique_identifier(decoder, current_scope));
- }
- }
- if (!decoder.eof()) {
- auto tag = TRY(decoder.peek());
- if (static_cast<u8>(tag.kind) == 2) {
- REWRITE_TAG(BitString)
- TRY(parse_unique_identifier(decoder, current_scope));
- }
- }
- if (!decoder.eof()) {
- auto tag = TRY(decoder.peek());
- if (static_cast<u8>(tag.kind) == 3) {
- REWRITE_TAG(Sequence)
- ENTER_TYPED_SCOPE(Sequence, "extensions"sv);
- TRY(parse_extensions(decoder, current_scope, certificate));
- EXIT_SCOPE();
- }
- }
- if (!decoder.eof()) {
- ERROR_WITH_SCOPE("Reached end of TBS parse with more data left"sv);
- }
- certificate.is_self_issued = TRY(certificate.issuer.to_string()) == TRY(certificate.subject.to_string());
- EXIT_SCOPE();
- return certificate;
- }
- ErrorOr<Certificate> Certificate::parse_certificate(ReadonlyBytes buffer, bool)
- {
- Crypto::ASN1::Decoder decoder { buffer };
- Vector<StringView, 8> current_scope {};
- // Certificate ::= SIGNED{TBSCertificate}
- // SIGNED{ToBeSigned} ::= SEQUENCE {
- // toBeSigned ToBeSigned,
- // COMPONENTS OF SIGNATURE{ToBeSigned},
- // }
- // SIGNATURE{ToBeSigned} ::= SEQUENCE {
- // algorithmIdentifier AlgorithmIdentifier{{SupportedAlgorithms}},
- // encrypted ENCRYPTED-HASH{ToBeSigned},
- // }
- // ENCRYPTED-HASH{ToBeSigned} ::= BIT STRING (CONSTRAINED BY {
- // -- shall be the result of applying a hashing procedure to the DER-encoded (see 6.2)
- // -- octets of a value of -- ToBeSigned -- and then applying an encipherment procedure
- // -- to those octets -- } )
- ENTER_TYPED_SCOPE(Sequence, "Certificate"sv);
- Certificate certificate = TRY(parse_tbs_certificate(decoder, current_scope));
- certificate.original_asn1 = TRY(ByteBuffer::copy(buffer));
- certificate.signature_algorithm = TRY(parse_algorithm_identifier(decoder, current_scope));
- PUSH_SCOPE("signature"sv);
- READ_OBJECT(BitString, Crypto::ASN1::BitStringView, signature);
- certificate.signature_value = TRY(ByteBuffer::copy(TRY(signature.raw_bytes())));
- POP_SCOPE();
- if (!decoder.eof()) {
- ERROR_WITH_SCOPE("Reached end of Certificate parse with more data left"sv);
- }
- EXIT_SCOPE();
- return certificate;
- }
- #undef PUSH_SCOPE
- #undef ENTER_SCOPE
- #undef ENTER_TYPED_SCOPE
- #undef POP_SCOPE
- #undef EXIT_SCOPE
- #undef READ_OBJECT
- #undef DROP_OBJECT
- #undef REWRITE_TAG
- ErrorOr<String> RelativeDistinguishedName::to_string() const
- {
- #define ADD_IF_RECOGNIZED(identifier, shorthand_code) \
- if (it->key == identifier) { \
- cert_name.appendff("\\{}={}", shorthand_code, it->value); \
- continue; \
- }
- StringBuilder cert_name;
- for (auto it = m_members.begin(); it != m_members.end(); ++it) {
- ADD_IF_RECOGNIZED(enum_value(AttributeType::SerialNumber), "SERIALNUMBER");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Email), "MAIL");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Title), "T");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::PostalCode), "PC");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::DnQualifier), "DNQ");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::GivenName), "GIVENNAME");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Surname), "SN");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Cn), "CN");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::L), "L");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::St), "ST");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::O), "O");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Ou), "OU");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::C), "C");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Street), "STREET");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Dc), "DC");
- ADD_IF_RECOGNIZED(enum_value(AttributeType::Uid), "UID");
- cert_name.appendff("\\{}={}", it->key, it->value);
- }
- #undef ADD_IF_RECOGNIZED
- return cert_name.to_string();
- }
- }
|