From 2d2cef01fbf0f8d1891d00b7e31dd6d02398ac8c Mon Sep 17 00:00:00 2001 From: Vladimir Asantsev <51046969+tawnysoul28@users.noreply.github.com> Date: Sat, 15 Aug 2026 18:17:20 +0700 Subject: [PATCH] typeClass() misidentifies `private` class (0xC0) tags as `application` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ASN1Identifier.typeClass()` never returns `.private`, even for tag bytes where both class bits are set (`11`, i.e. the `private` class). Such bytes are always misclassified as `.application` instead. **Root cause** ```swift public func typeClass() -> Class { for tc in [Class.application, Class.contextSpecific, Class.private] where (rawValue & tc.rawValue) == tc.rawValue { return tc } return .universal } ``` The loop checks `.application` (`0x40`) before `.private` (`0xC0`). The check `(rawValue & 0x40) == 0x40` only tests whether bit `0x40` is set — it does not exclude the case where bit `0x80` is *also* set. Since `0xC0 & 0x40 == 0x40`, any byte with both class bits set satisfies the `.application` condition first, and the loop returns before ever reaching `.private`. **Reproduction** ```swift ASN1Identifier(rawValue: 0xC1).typeClass() // Actual: .application // Expected: .private ``` **Suggested fix** Since `Class`'s raw values already occupy the full 2-bit space (`0x00`, `0x40`, `0x80`, `0xC0`), a single mask-and-lookup replaces the loop: ```swift public func typeClass() -> Class { return Class(rawValue: rawValue & 0xC0) ?? .universal } ``` Happy to open a PR with this change if useful. --- ASN1Decoder/ASN1Identifier.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ASN1Decoder/ASN1Identifier.swift b/ASN1Decoder/ASN1Identifier.swift index 318a366..c2855fb 100644 --- a/ASN1Decoder/ASN1Identifier.swift +++ b/ASN1Decoder/ASN1Identifier.swift @@ -73,10 +73,7 @@ public class ASN1Identifier: CustomStringConvertible { } public func typeClass() -> Class { - for tc in [Class.application, Class.contextSpecific, Class.private] where (rawValue & tc.rawValue) == tc.rawValue { - return tc - } - return .universal + return Class(rawValue: rawValue & 0xC0) ?? .universal } public func isPrimitive() -> Bool {