Skip to content

Commit ae33e59

Browse files
Lukasabaarde
andauthored
Merge commit from fork
* Throw error instead of halting when the encoding is invalid Signed-off-by: Cory Benfield <lukasa@apple.com> * Avoid extra precondition failure --------- Signed-off-by: Cory Benfield <lukasa@apple.com> Co-authored-by: Nicolas Bachschmidt <nicolas@nunk.net>
1 parent c27bcbd commit ae33e59

File tree

8 files changed

+75
-25
lines changed

8 files changed

+75
-25
lines changed

Sources/SwiftASN1/Basic ASN1 Types/ASN1BitString.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public struct ASN1BitString: DERImplicitlyTaggable, BERImplicitlyTaggable {
5757
}
5858

5959
guard case .primitive(let content) = node.content else {
60-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
60+
throw ASN1Error.invalidASN1Object(reason: "ASN1BitString encoded with constructed encoding")
6161
}
6262

6363
// The initial octet explains how many of the bits in the _final_ octet are not part of the bitstring.

Sources/SwiftASN1/Basic ASN1 Types/ASN1Integer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extension ASN1IntegerRepresentable {
5353
}
5454

5555
guard case .primitive(var dataBytes) = node.content else {
56-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
56+
throw ASN1Error.invalidASN1Object(reason: "INTEGER encoded with constructed encoding")
5757
}
5858

5959
// Zero bytes of integer is not an acceptable encoding.
@@ -93,7 +93,7 @@ extension ASN1IntegerRepresentable {
9393
}
9494

9595
guard case .primitive(var dataBytes) = node.content else {
96-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
96+
throw ASN1Error.invalidASN1Object(reason: "INTEGER encoded with constructed encoding")
9797
}
9898

9999
// Zero bytes of integer is not an acceptable encoding.

Sources/SwiftASN1/Basic ASN1 Types/ASN1OctetString.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public struct ASN1OctetString: DERImplicitlyTaggable, BERImplicitlyTaggable {
3030
}
3131

3232
guard case .primitive(let content) = node.content else {
33-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
33+
throw ASN1Error.invalidASN1Object(reason: "ASN1OctetString encoded with constructed encoding")
3434
}
3535

3636
self.bytes = content

Sources/SwiftASN1/Basic ASN1 Types/GeneralizedTime.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,15 @@ public struct GeneralizedTime: DERImplicitlyTaggable, BERImplicitlyTaggable, Has
206206

207207
@inlinable
208208
public init(derEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws {
209-
guard node.identifier == identifier else {
210-
throw ASN1Error.unexpectedFieldType(node.identifier)
211-
}
212-
213-
guard case .primitive(let content) = node.content else {
214-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
215-
}
216-
209+
let content = try ASN1OctetString(derEncoded: node, withIdentifier: identifier).bytes
217210
self = try TimeUtilities.generalizedTimeFromBytes(content)
218211
}
219212

220213
@inlinable
221214
public init(berEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws {
222215
// TODO: BER supports relaxed timestamp parsing, which is not yet supported
223-
self = try .init(derEncoded: node, withIdentifier: identifier)
216+
let content = try ASN1OctetString(berEncoded: node, withIdentifier: identifier).bytes
217+
self = try TimeUtilities.generalizedTimeFromBytes(content)
224218
}
225219

226220
@inlinable

Sources/SwiftASN1/Basic ASN1 Types/ObjectIdentifier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public struct ASN1ObjectIdentifier: DERImplicitlyTaggable, BERImplicitlyTaggable
4242
}
4343

4444
guard case .primitive(let content) = node.content else {
45-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
45+
throw ASN1Error.invalidASN1Object(reason: "OID encoded with constructed encoding")
4646
}
4747

4848
try Self.validateObjectIdentifierInEncodedForm(content)

Sources/SwiftASN1/Basic ASN1 Types/UTCTime.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,20 +128,14 @@ public struct UTCTime: DERImplicitlyTaggable, BERImplicitlyTaggable, Hashable, S
128128

129129
@inlinable
130130
public init(derEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws {
131-
guard node.identifier == identifier else {
132-
throw ASN1Error.unexpectedFieldType(node.identifier)
133-
}
134-
135-
guard case .primitive(let content) = node.content else {
136-
preconditionFailure("ASN.1 parser generated primitive node with constructed content")
137-
}
138-
131+
let content = try ASN1OctetString(derEncoded: node, withIdentifier: identifier).bytes
139132
self = try TimeUtilities.utcTimeFromBytes(content)
140133
}
141134

142135
@inlinable
143136
public init(berEncoded node: ASN1Node, withIdentifier identifier: ASN1Identifier) throws {
144-
self = try .init(derEncoded: node, withIdentifier: identifier)
137+
let content = try ASN1OctetString(berEncoded: node, withIdentifier: identifier).bytes
138+
self = try TimeUtilities.utcTimeFromBytes(content)
145139
}
146140

147141
@inlinable

Sources/SwiftASN1/DER.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,9 @@ extension DER {
233233

234234
// We expect a single child.
235235
guard case .constructed(let nodes) = node.content else {
236-
// This error is an internal parser error: the tag above is always constructed.
237-
preconditionFailure("Explicit tags are always constructed")
236+
throw ASN1Error.invalidASN1Object(
237+
reason: "Explicit tags should always be constructed, got \(node.identifier) which is not."
238+
)
238239
}
239240

240241
var nodeIterator = nodes.makeIterator()

Tests/SwiftASN1Tests/ASN1Tests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,23 @@ class ASN1Tests: XCTestCase {
967967
}
968968
}
969969

970+
func testPrimitiveTaggedObject() throws {
971+
// We should error if primitive encoding is used for an explicitly tagged object.
972+
let weirdASN1: [UInt8] = [
973+
0x30, 0x05, // Sequence, containing...
974+
0x82, 0x03, // Context specific tag 2, 3 byte body, containing...
975+
0x02, 0x01, 0x00, // Integer 0
976+
]
977+
let parsed = try DER.parse(weirdASN1)
978+
try DER.sequence(parsed, identifier: .sequence) { nodes in
979+
XCTAssertThrowsError(
980+
try DER.optionalExplicitlyTagged(&nodes, tagNumber: 2, tagClass: .contextSpecific, { _ in })
981+
) { error in
982+
XCTAssertEqual((error as? ASN1Error)?.code, .invalidASN1Object)
983+
}
984+
}
985+
}
986+
970987
func testSPKIWithUnexpectedKeyTypeOID() throws {
971988
// This is an SPKI object for RSA instead of EC. This is a 1024-bit RSA key, so hopefully no-one will think to use it.
972989
let rsaSPKI =
@@ -1366,4 +1383,48 @@ class ASN1Tests: XCTestCase {
13661383
XCTAssertEqual(asn1OctetString.bytes, [0xFE, 0xED, 0xFA, 0xCE])
13671384
XCTAssertThrowsError(try DER.parse(berOctetString))
13681385
}
1386+
1387+
func testConstructedBoolean() throws {
1388+
let weirdASN1: [UInt8] = [0x21, 0x00]
1389+
let node = try DER.parse(weirdASN1)
1390+
XCTAssertThrowsError(try Bool(berEncoded: node))
1391+
XCTAssertThrowsError(try Bool(derEncoded: node))
1392+
}
1393+
1394+
func testConstructedInteger() throws {
1395+
let weirdASN1: [UInt8] = [0x22, 0x00]
1396+
let node = try DER.parse(weirdASN1)
1397+
XCTAssertThrowsError(try Int(berEncoded: node))
1398+
XCTAssertThrowsError(try Int(derEncoded: node))
1399+
}
1400+
1401+
func testConstructedBitString() throws {
1402+
let weirdASN1: [UInt8] = [0x23, 0x08, 0x03, 0x02, 0x00, 0xAB, 0x03, 0x02, 0x04, 0xC]
1403+
let node = try DER.parse(weirdASN1)
1404+
// Not yet supported
1405+
// XCTAssertEqual(try ASN1BitString(berEncoded: node), ASN1BitString(bytes: [0xAB, 0xC], paddingBits: 4))
1406+
XCTAssertThrowsError(try ASN1BitString(berEncoded: node))
1407+
XCTAssertThrowsError(try ASN1BitString(derEncoded: node))
1408+
}
1409+
1410+
func testConstructedOctetString() throws {
1411+
let weirdASN1: [UInt8] = [0x24, 0x06, 0x04, 0x01, 0xAB, 0x04, 0x01, 0xCD]
1412+
let node = try DER.parse(weirdASN1)
1413+
XCTAssertEqual(try ASN1OctetString(berEncoded: node), ASN1OctetString(contentBytes: [0xAB, 0xCD]))
1414+
XCTAssertThrowsError(try ASN1OctetString(derEncoded: node))
1415+
}
1416+
1417+
func testConstructedNull() throws {
1418+
let weirdASN1: [UInt8] = [0x25, 0x00]
1419+
let node = try DER.parse(weirdASN1)
1420+
XCTAssertThrowsError(try ASN1Null(berEncoded: node))
1421+
XCTAssertThrowsError(try ASN1Null(derEncoded: node))
1422+
}
1423+
1424+
func testConstructedOID() throws {
1425+
let weirdASN1: [UInt8] = [0x26, 0x03, 0x02, 0x01, 0x00]
1426+
let node = try DER.parse(weirdASN1)
1427+
XCTAssertThrowsError(try ASN1ObjectIdentifier(berEncoded: node))
1428+
XCTAssertThrowsError(try ASN1ObjectIdentifier(derEncoded: node))
1429+
}
13691430
}

0 commit comments

Comments
 (0)