Skip to content

Commit b174260

Browse files
authored
Merge pull request #10 from apple/dn-implicitly-tagged-optional-field
Add support for implicitly tagged optional fields
2 parents 63ec702 + 4363483 commit b174260

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

Sources/SwiftASN1/ASN1.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,41 @@ extension DER {
223223
// We're good: pass the node on.
224224
return try T(derEncoded: &nodes, withIdentifier: tag)
225225
}
226+
227+
/// Parses an optional implicitly tagged element.
228+
///
229+
/// - parameters:
230+
/// - nodes: The ``ASN1NodeCollection/Iterator`` to parse this element out of.
231+
/// - tagNumber: The number of the explicit tag.
232+
/// - tagClass: The class of the explicit tag.
233+
/// - builder: A closure that will be called with the node for the element, if the element is present.
234+
///
235+
/// - returns: The result of `builder` if the element was present, or `nil` if it was not.
236+
@inlinable
237+
public static func optionalImplicitlyTagged<Result>(
238+
_ nodes: inout ASN1NodeCollection.Iterator,
239+
tagNumber: UInt,
240+
tagClass: ASN1Identifier.TagClass,
241+
_ builder: (ASN1Node) throws -> Result
242+
) rethrows -> Result? {
243+
var localNodesCopy = nodes
244+
guard let node = localNodesCopy.next() else {
245+
// Node not present, return nil.
246+
return nil
247+
}
248+
249+
let expectedNodeID = ASN1Identifier(tagWithNumber: tagNumber, tagClass: tagClass)
250+
guard node.identifier == expectedNodeID else {
251+
// Node is a mismatch, with the wrong tag. Our optional isn't present.
252+
return nil
253+
}
254+
255+
// We have the right optional, so let's consume it.
256+
nodes = localNodesCopy
257+
258+
// We're good: pass the node on.
259+
return try builder(node)
260+
}
226261
}
227262

228263
// MARK: - DEFAULT

Tests/SwiftASN1Tests/ASN1Tests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,24 @@ O9zxi7HTvuXyQr7QKSBtdC%mHym+WoPsbA==
783783
}
784784
XCTAssertEqual(int, 1)
785785
}
786+
787+
func testOptionalImplicitlyTaggedWithBuilder() throws {
788+
var serializer = DER.Serializer()
789+
try serializer.appendConstructedNode(identifier: .sequence) { serializer in
790+
try serializer.serializeOptionalImplicitlyTagged(1, withIdentifier: ASN1Identifier(tagWithNumber: 1, tagClass: .contextSpecific))
791+
}
792+
let bytes = serializer.serializedBytes
793+
794+
XCTAssertEqual(bytes, [0x30, 0x03, 0x81, 0x1, 0x1])
795+
796+
let parseResult = try DER.parse(bytes)
797+
let int = try DER.sequence(parseResult, identifier: .sequence) { nodes in
798+
try DER.optionalImplicitlyTagged(&nodes, tagNumber: 1, tagClass: .contextSpecific) { node in
799+
try Int(derEncoded: node, withIdentifier: .init(tagWithNumber: 1, tagClass: .contextSpecific))
800+
}
801+
}
802+
XCTAssertEqual(int, 1)
803+
}
786804

787805
func testPrintingOIDs() {
788806
let oid: ASN1ObjectIdentifier = [1, 2, 865, 11241, 3]

0 commit comments

Comments
 (0)