Certificate.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Certificate.h"
  7. #include <AK/Debug.h>
  8. #include <LibCrypto/ASN1/ASN1.h>
  9. #include <LibCrypto/ASN1/DER.h>
  10. #include <LibCrypto/ASN1/PEM.h>
  11. namespace TLS {
  12. constexpr static Array<int, 4>
  13. common_name_oid { 2, 5, 4, 3 },
  14. country_name_oid { 2, 5, 4, 6 },
  15. locality_name_oid { 2, 5, 4, 7 },
  16. organization_name_oid { 2, 5, 4, 10 },
  17. organizational_unit_name_oid { 2, 5, 4, 11 };
  18. constexpr static Array<int, 7>
  19. rsa_encryption_oid { 1, 2, 840, 113549, 1, 1, 1 },
  20. rsa_md5_encryption_oid { 1, 2, 840, 113549, 1, 1, 4 },
  21. rsa_sha1_encryption_oid { 1, 2, 840, 113549, 1, 1, 5 },
  22. rsa_sha256_encryption_oid { 1, 2, 840, 113549, 1, 1, 11 },
  23. rsa_sha384_encryption_oid { 1, 2, 840, 113549, 1, 1, 12 },
  24. rsa_sha512_encryption_oid { 1, 2, 840, 113549, 1, 1, 13 };
  25. constexpr static Array<int, 4>
  26. subject_alternative_name_oid { 2, 5, 29, 17 };
  27. Optional<Certificate> Certificate::parse_asn1(ReadonlyBytes buffer, bool)
  28. {
  29. #define ENTER_SCOPE_WITHOUT_TYPECHECK(scope) \
  30. do { \
  31. if (auto result = decoder.enter(); result.has_value()) { \
  32. dbgln_if(TLS_DEBUG, "Failed to enter object (" scope "): {}", result.value()); \
  33. return {}; \
  34. } \
  35. } while (0)
  36. #define ENTER_SCOPE_OR_FAIL(kind_name, scope) \
  37. do { \
  38. if (auto tag = decoder.peek(); tag.is_error() || tag.value().kind != Crypto::ASN1::Kind::kind_name) { \
  39. if constexpr (TLS_DEBUG) { \
  40. if (tag.is_error()) \
  41. dbgln(scope " data was invalid: {}", tag.error()); \
  42. else \
  43. dbgln(scope " data was not of kind " #kind_name); \
  44. } \
  45. return {}; \
  46. } \
  47. ENTER_SCOPE_WITHOUT_TYPECHECK(scope); \
  48. } while (0)
  49. #define EXIT_SCOPE(scope) \
  50. do { \
  51. if (auto error = decoder.leave(); error.has_value()) { \
  52. dbgln_if(TLS_DEBUG, "Error while exiting scope " scope ": {}", error.value()); \
  53. return {}; \
  54. } \
  55. } while (0)
  56. #define ENSURE_OBJECT_KIND(_kind_name, scope) \
  57. do { \
  58. if (auto tag = decoder.peek(); tag.is_error() || tag.value().kind != Crypto::ASN1::Kind::_kind_name) { \
  59. if constexpr (TLS_DEBUG) { \
  60. if (tag.is_error()) \
  61. dbgln(scope " data was invalid: {}", tag.error()); \
  62. else \
  63. dbgln(scope " data was not of kind " #_kind_name ", it was {}", Crypto::ASN1::kind_name(tag.value().kind)); \
  64. } \
  65. return {}; \
  66. } \
  67. } while (0)
  68. #define READ_OBJECT_OR_FAIL(kind_name, type_name, value_name, scope) \
  69. auto value_name##_result = decoder.read<type_name>(Crypto::ASN1::Class::Universal, Crypto::ASN1::Kind::kind_name); \
  70. if (value_name##_result.is_error()) { \
  71. dbgln_if(TLS_DEBUG, scope " read of kind " #kind_name " failed: {}", value_name##_result.error()); \
  72. return {}; \
  73. } \
  74. auto value_name = value_name##_result.release_value();
  75. #define DROP_OBJECT_OR_FAIL(scope) \
  76. do { \
  77. if (auto error = decoder.drop(); error.has_value()) { \
  78. dbgln_if(TLS_DEBUG, scope " read failed: {}", error.value()); \
  79. } \
  80. } while (0)
  81. Certificate certificate;
  82. auto copy_buffer_result = ByteBuffer::copy(buffer.data(), buffer.size());
  83. if (copy_buffer_result.is_error())
  84. return {};
  85. certificate.original_asn1 = copy_buffer_result.release_value();
  86. Crypto::ASN1::Decoder decoder { buffer };
  87. // Certificate ::= Sequence {
  88. // certificate TBSCertificate,
  89. // signature_algorithm AlgorithmIdentifier,
  90. // signature_value BitString
  91. // }
  92. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate");
  93. // TBSCertificate ::= Sequence {
  94. // version (0) EXPLICIT Version DEFAULT v1,
  95. // serial_number CertificateSerialNumber,
  96. // signature AlgorithmIdentifier,
  97. // issuer Name,
  98. // validity Validity,
  99. // subject Name,
  100. // subject_public_key_info SubjectPublicKeyInfo,
  101. // issuer_unique_id (1) IMPLICIT UniqueIdentifier OPTIONAL (if present, version > v1),
  102. // subject_unique_id (2) IMPLICIT UniqueIdentifier OPTIONAL (if present, version > v1),
  103. // extensions (3) EXPLICIT Extensions OPTIONAL (if present, version > v2)
  104. // }
  105. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate");
  106. // version
  107. {
  108. // Version :: Integer { v1(0), v2(1), v3(2) } (Optional)
  109. if (auto tag = decoder.peek(); !tag.is_error() && tag.value().type == Crypto::ASN1::Type::Constructed) {
  110. ENTER_SCOPE_WITHOUT_TYPECHECK("Certificate::version");
  111. READ_OBJECT_OR_FAIL(Integer, Crypto::UnsignedBigInteger, value, "Certificate::version");
  112. if (!(value < 3)) {
  113. dbgln_if(TLS_DEBUG, "Certificate::version Invalid value for version: {}", value.to_base(10));
  114. return {};
  115. }
  116. certificate.version = value.words()[0];
  117. EXIT_SCOPE("Certificate::version");
  118. } else {
  119. certificate.version = 0;
  120. }
  121. }
  122. // serial_number
  123. {
  124. // CertificateSerialNumber :: Integer
  125. READ_OBJECT_OR_FAIL(Integer, Crypto::UnsignedBigInteger, value, "Certificate::serial_number");
  126. certificate.serial_number = move(value);
  127. }
  128. auto parse_algorithm_identifier = [&](CertificateKeyAlgorithm& field) -> Optional<bool> {
  129. // AlgorithmIdentifier ::= Sequence {
  130. // algorithm ObjectIdentifier,
  131. // parameters ANY OPTIONAL
  132. // }
  133. ENTER_SCOPE_OR_FAIL(Sequence, "AlgorithmIdentifier");
  134. READ_OBJECT_OR_FAIL(ObjectIdentifier, Vector<int>, identifier, "AlgorithmIdentifier::algorithm");
  135. if (identifier == rsa_encryption_oid)
  136. field = CertificateKeyAlgorithm ::RSA_RSA;
  137. else if (identifier == rsa_md5_encryption_oid)
  138. field = CertificateKeyAlgorithm ::RSA_MD5;
  139. else if (identifier == rsa_sha1_encryption_oid)
  140. field = CertificateKeyAlgorithm ::RSA_SHA1;
  141. else if (identifier == rsa_sha256_encryption_oid)
  142. field = CertificateKeyAlgorithm ::RSA_SHA256;
  143. else if (identifier == rsa_sha384_encryption_oid)
  144. field = CertificateKeyAlgorithm ::RSA_SHA384;
  145. else if (identifier == rsa_sha512_encryption_oid)
  146. field = CertificateKeyAlgorithm ::RSA_SHA512;
  147. else
  148. return {};
  149. EXIT_SCOPE("AlgorithmIdentifier");
  150. return true;
  151. };
  152. // signature
  153. {
  154. if (!parse_algorithm_identifier(certificate.algorithm).has_value())
  155. return {};
  156. }
  157. auto parse_name = [&](auto& name_struct) -> Optional<bool> {
  158. // Name ::= Choice {
  159. // rdn_sequence RDNSequence
  160. // } // NOTE: since this is the only alternative, there's no index
  161. // RDNSequence ::= Sequence OF RelativeDistinguishedName
  162. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::issuer/subject");
  163. // RelativeDistinguishedName ::= Set OF AttributeTypeAndValue
  164. // AttributeTypeAndValue ::= Sequence {
  165. // type AttributeType,
  166. // value AttributeValue
  167. // }
  168. // AttributeType ::= ObjectIdentifier
  169. // AttributeValue ::= Any
  170. while (!decoder.eof()) {
  171. // Parse only the the required fields, and ignore the rest.
  172. ENTER_SCOPE_OR_FAIL(Set, "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName");
  173. while (!decoder.eof()) {
  174. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue");
  175. ENSURE_OBJECT_KIND(ObjectIdentifier, "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::type");
  176. if (auto type_identifier_or_error = decoder.read<Vector<int>>(); !type_identifier_or_error.is_error()) {
  177. // Figure out what type of identifier this is
  178. auto& identifier = type_identifier_or_error.value();
  179. if (identifier == common_name_oid) {
  180. READ_OBJECT_OR_FAIL(PrintableString, StringView, name,
  181. "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::Value");
  182. name_struct.subject = name;
  183. } else if (identifier == country_name_oid) {
  184. READ_OBJECT_OR_FAIL(PrintableString, StringView, name,
  185. "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::Value");
  186. name_struct.country = name;
  187. } else if (identifier == locality_name_oid) {
  188. READ_OBJECT_OR_FAIL(PrintableString, StringView, name,
  189. "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::Value");
  190. name_struct.location = name;
  191. } else if (identifier == organization_name_oid) {
  192. READ_OBJECT_OR_FAIL(PrintableString, StringView, name,
  193. "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::Value");
  194. name_struct.entity = name;
  195. } else if (identifier == organizational_unit_name_oid) {
  196. READ_OBJECT_OR_FAIL(PrintableString, StringView, name,
  197. "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::Value");
  198. name_struct.unit = name;
  199. }
  200. } else {
  201. dbgln_if(TLS_DEBUG, "Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue::type data was invalid: {}", type_identifier_or_error.error());
  202. return {};
  203. }
  204. EXIT_SCOPE("Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName::$::AttributeTypeAndValue");
  205. }
  206. EXIT_SCOPE("Certificate::TBSCertificate::issuer/subject::$::RelativeDistinguishedName");
  207. }
  208. EXIT_SCOPE("Certificate::TBSCertificate::issuer/subject");
  209. return true;
  210. };
  211. // issuer
  212. {
  213. if (!parse_name(certificate.issuer).has_value())
  214. return {};
  215. }
  216. // validity
  217. {
  218. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::Validity");
  219. auto parse_time = [&](Core::DateTime& datetime) -> Optional<bool> {
  220. // Time ::= Choice {
  221. // utc_time UTCTime,
  222. // general_time GeneralizedTime
  223. // }
  224. auto tag = decoder.peek();
  225. if (tag.is_error()) {
  226. dbgln_if(1, "Certificate::TBSCertificate::Validity::$::Time failed to read tag: {}", tag.error());
  227. return {};
  228. };
  229. if (tag.value().kind == Crypto::ASN1::Kind::UTCTime) {
  230. READ_OBJECT_OR_FAIL(UTCTime, StringView, time, "Certificate::TBSCertificate::Validity::$");
  231. auto result = Crypto::ASN1::parse_utc_time(time);
  232. if (!result.has_value()) {
  233. dbgln_if(1, "Certificate::TBSCertificate::Validity::$::Time Invalid UTC Time: {}", time);
  234. return {};
  235. }
  236. datetime = result.release_value();
  237. return true;
  238. }
  239. if (tag.value().kind == Crypto::ASN1::Kind::GeneralizedTime) {
  240. READ_OBJECT_OR_FAIL(UTCTime, StringView, time, "Certificate::TBSCertificate::Validity::$");
  241. auto result = Crypto::ASN1::parse_generalized_time(time);
  242. if (!result.has_value()) {
  243. dbgln_if(1, "Certificate::TBSCertificate::Validity::$::Time Invalid Generalized Time: {}", time);
  244. return {};
  245. }
  246. datetime = result.release_value();
  247. return true;
  248. }
  249. dbgln_if(1, "Unrecognised Time format {}", Crypto::ASN1::kind_name(tag.value().kind));
  250. return {};
  251. };
  252. if (!parse_time(certificate.not_before).has_value())
  253. return {};
  254. if (!parse_time(certificate.not_after).has_value())
  255. return {};
  256. EXIT_SCOPE("Certificate::TBSCertificate::Validity");
  257. }
  258. // subject
  259. {
  260. if (!parse_name(certificate.subject).has_value())
  261. return {};
  262. }
  263. // subject_public_key_info
  264. {
  265. // SubjectPublicKeyInfo ::= Sequence {
  266. // algorithm AlgorithmIdentifier,
  267. // subject_public_key BitString
  268. // }
  269. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::subject_public_key_info");
  270. if (!parse_algorithm_identifier(certificate.key_algorithm).has_value())
  271. return {};
  272. READ_OBJECT_OR_FAIL(BitString, Crypto::ASN1::BitStringView, value, "Certificate::TBSCertificate::subject_public_key_info::subject_public_key_info");
  273. // Note: Once we support other kinds of keys, make sure to check the kind here!
  274. auto key = Crypto::PK::RSA::parse_rsa_key(value.raw_bytes());
  275. if (!key.public_key.length()) {
  276. dbgln_if(TLS_DEBUG, "Certificate::TBSCertificate::subject_public_key_info::subject_public_key_info: Invalid key");
  277. return {};
  278. }
  279. certificate.public_key = move(key.public_key);
  280. EXIT_SCOPE("Certificate::TBSCertificate::subject_public_key_info");
  281. }
  282. auto parse_unique_identifier = [&]() -> Optional<bool> {
  283. if (certificate.version == 0)
  284. return true;
  285. auto tag = decoder.peek();
  286. if (tag.is_error()) {
  287. dbgln_if(TLS_DEBUG, "Certificate::TBSCertificate::*::UniqueIdentifier could not read tag: {}", tag.error());
  288. return {};
  289. }
  290. // The spec says to just ignore these.
  291. if (static_cast<u8>(tag.value().kind) == 1 || static_cast<u8>(tag.value().kind) == 2)
  292. DROP_OBJECT_OR_FAIL("UniqueIdentifier");
  293. return true;
  294. };
  295. // issuer_unique_identifier
  296. {
  297. if (!parse_unique_identifier().has_value())
  298. return {};
  299. }
  300. // subject_unique_identifier
  301. {
  302. if (!parse_unique_identifier().has_value())
  303. return {};
  304. }
  305. // extensions
  306. {
  307. if (certificate.version == 2) {
  308. auto tag = decoder.peek();
  309. if (tag.is_error()) {
  310. dbgln_if(TLS_DEBUG, "Certificate::TBSCertificate::*::UniqueIdentifier could not read tag: {}", tag.error());
  311. return {};
  312. }
  313. if (static_cast<u8>(tag.value().kind) == 3) {
  314. // Extensions ::= Sequence OF Extension
  315. // Extension ::= Sequence {
  316. // extension_id ObjectIdentifier,
  317. // critical Boolean DEFAULT false,
  318. // extension_value OctetString (DER-encoded)
  319. // }
  320. ENTER_SCOPE_WITHOUT_TYPECHECK("Certificate::TBSCertificate::Extensions(IMPLICIT)");
  321. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::Extensions");
  322. while (!decoder.eof()) {
  323. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::Extensions::$::Extension");
  324. READ_OBJECT_OR_FAIL(ObjectIdentifier, Vector<int>, extension_id, "Certificate::TBSCertificate::Extensions::$::Extension::extension_id");
  325. bool is_critical = false;
  326. if (auto tag = decoder.peek(); !tag.is_error() && tag.value().kind == Crypto::ASN1::Kind::Boolean) {
  327. // Read the 'critical' property
  328. READ_OBJECT_OR_FAIL(Boolean, bool, critical, "Certificate::TBSCertificate::Extensions::$::Extension::critical");
  329. is_critical = critical;
  330. }
  331. READ_OBJECT_OR_FAIL(OctetString, StringView, extension_value, "Certificate::TBSCertificate::Extensions::$::Extension::extension_value");
  332. // Figure out what this extension is.
  333. if (extension_id == subject_alternative_name_oid) {
  334. Crypto::ASN1::Decoder decoder { extension_value.bytes() };
  335. // SubjectAlternativeName ::= GeneralNames
  336. // GeneralNames ::= Sequence OF GeneralName
  337. // GeneralName ::= CHOICE {
  338. // other_name (0) OtherName,
  339. // rfc_822_name (1) IA5String,
  340. // dns_name (2) IA5String,
  341. // x400Address (3) ORAddress,
  342. // directory_name (4) Name,
  343. // edi_party_name (5) EDIPartyName,
  344. // uri (6) IA5String,
  345. // ip_address (7) OctetString,
  346. // registered_id (8) ObjectIdentifier,
  347. // }
  348. ENTER_SCOPE_OR_FAIL(Sequence, "Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName");
  349. while (!decoder.eof()) {
  350. auto tag = decoder.peek();
  351. if (tag.is_error()) {
  352. dbgln_if(TLS_DEBUG, "Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$ could not read tag: {}", tag.error());
  353. return {};
  354. }
  355. auto tag_value = static_cast<u8>(tag.value().kind);
  356. switch (tag_value) {
  357. case 0:
  358. // OtherName
  359. // We don't know how to use this.
  360. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::OtherName");
  361. break;
  362. case 1:
  363. // RFC 822 name
  364. // We don't know how to use this.
  365. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::RFC822Name");
  366. break;
  367. case 2: {
  368. // DNS Name
  369. READ_OBJECT_OR_FAIL(IA5String, StringView, name, "Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::Name");
  370. certificate.SAN.append(name);
  371. break;
  372. }
  373. case 3:
  374. // x400Address
  375. // We don't know how to use this.
  376. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::X400Address");
  377. break;
  378. case 4:
  379. // Directory name
  380. // We don't know how to use this.
  381. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::DirectoryName");
  382. break;
  383. case 5:
  384. // edi party name
  385. // We don't know how to use this.
  386. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::EDIPartyName");
  387. break;
  388. case 6: {
  389. // URI
  390. READ_OBJECT_OR_FAIL(IA5String, StringView, name, "Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::URI");
  391. certificate.SAN.append(name);
  392. break;
  393. }
  394. case 7:
  395. // IP Address
  396. // We can't handle these.
  397. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::IPAddress");
  398. break;
  399. case 8:
  400. // Registered ID
  401. // We can't handle these.
  402. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::RegisteredID");
  403. break;
  404. default:
  405. dbgln_if(TLS_DEBUG, "Unknown tag in SAN choice {}", tag_value);
  406. if (is_critical)
  407. return {};
  408. else
  409. DROP_OBJECT_OR_FAIL("Certificate::TBSCertificate::Extensions::$::Extension::extension_value::SubjectAlternativeName::$::???");
  410. }
  411. }
  412. }
  413. EXIT_SCOPE("Certificate::TBSCertificate::Extensions::$::Extension");
  414. }
  415. EXIT_SCOPE("Certificate::TBSCertificate::Extensions");
  416. EXIT_SCOPE("Certificate::TBSCertificate::Extensions(IMPLICIT)");
  417. }
  418. }
  419. }
  420. EXIT_SCOPE("Certificate::TBSCertificate");
  421. // signature_algorithm
  422. {
  423. if (!parse_algorithm_identifier(certificate.signature_algorithm).has_value())
  424. return {};
  425. }
  426. // signature_value
  427. {
  428. READ_OBJECT_OR_FAIL(BitString, Crypto::ASN1::BitStringView, value, "Certificate");
  429. auto signature_data_result = ByteBuffer::copy(value.raw_bytes());
  430. if (signature_data_result.is_error()) {
  431. dbgln("Certificate::signature_value: out of memory");
  432. return {};
  433. }
  434. certificate.signature_value = signature_data_result.release_value();
  435. }
  436. EXIT_SCOPE("Certificate");
  437. dbgln_if(TLS_DEBUG, "Certificate issued for {} by {}", certificate.subject.subject, certificate.issuer.subject);
  438. return certificate;
  439. #undef DROP_OBJECT_OR_FAIL
  440. #undef ENSURE_OBJECT_KIND
  441. #undef ENTER_SCOPE_OR_FAIL
  442. #undef ENTER_SCOPE_WITHOUT_TYPECHECK
  443. #undef EXIT_SCOPE
  444. #undef READ_OBJECT_OR_FAIL
  445. }
  446. }