Skip to content

Commit 810496c

Browse files
Craz1k0ekBram Kolkman
andauthored
Fixed BMPString encoding (#111)
* Fixed #110 by using UTF-16 to encode the string literal * Added a unit test to test the added functionality Co-authored-by: Bram Kolkman <bramkolkman@thinkerium.com>
1 parent 823291a commit 810496c

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

Sources/SwiftASN1/Basic ASN1 Types/ASN1Strings.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,19 @@ public struct ASN1BMPString: DERImplicitlyTaggable, BERImplicitlyTaggable, Hasha
284284

285285
@inlinable
286286
public init(stringLiteral value: StringLiteralType) {
287-
self.bytes = ArraySlice(value.utf8)
287+
guard
288+
value.utf16.allSatisfy({ codeUnit in
289+
!(0xD800...0xDFFF).contains(codeUnit)
290+
})
291+
else {
292+
fatalError("BMPString cannot contain characters outside the Basic Multilingual Plane: '\(value)'")
293+
}
294+
295+
self.bytes = ArraySlice(
296+
value.utf16.flatMap { codeUnit in
297+
[UInt8(truncatingIfNeeded: codeUnit >> 8), UInt8(truncatingIfNeeded: codeUnit)]
298+
}
299+
)
288300
}
289301

290302
@inlinable

Tests/SwiftASN1Tests/ASN1StringTests.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,37 @@ final class ASN1StringTests: XCTestCase {
103103
string.withUnsafeBytes { XCTAssertTrue($0.elementsEqual([1, 2, 3, 4])) }
104104
}
105105

106+
func testBMPStringStringLiteral() throws {
107+
typealias TestCase = (literal: String, utf16: [UInt8], asn1: [UInt8])
108+
109+
let testCases: [TestCase] = [
110+
TestCase(
111+
"Test",
112+
[0, 84, 0, 101, 0, 115, 0, 116],
113+
[30, 8, 0, 84, 0, 101, 0, 115, 0, 116]
114+
),
115+
TestCase(
116+
"Tests",
117+
[0, 84, 0, 101, 0, 115, 0, 116, 0, 115],
118+
[30, 10, 0, 84, 0, 101, 0, 115, 0, 116, 0, 115]
119+
),
120+
TestCase(
121+
"中文",
122+
[78, 45, 101, 135],
123+
[30, 4, 78, 45, 101, 135]
124+
),
125+
]
126+
127+
try testCases.forEach { testCase in
128+
let string = ASN1BMPString(stringLiteral: testCase.literal)
129+
XCTAssertEqual(Array(string.bytes), testCase.utf16)
130+
131+
var serializer = DER.Serializer()
132+
try serializer.serialize(string)
133+
XCTAssertEqual(serializer.serializedBytes, testCase.asn1)
134+
}
135+
}
136+
106137
func testUTF8StringCanCreateAString() throws {
107138
let string = "hello, world!"
108139
let utf8String = ASN1UTF8String(string)

0 commit comments

Comments
 (0)