Skip to content

Commit 364d0a6

Browse files
committed
wrap up AuthenticatorData tests
1 parent ad80344 commit 364d0a6

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

Sources/WebAuthn/Ceremonies/Shared/AuthenticatorData.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ extension AuthenticatorData {
8989
let idLength: UInt16 = idLengthData.toInteger(endian: .big)
9090
let credentialIDEndIndex = Int(idLength) + 55
9191

92+
guard data.count >= credentialIDEndIndex else {
93+
throw WebAuthnError.credentialIDTooShort
94+
}
9295
let credentialID = data[55..<credentialIDEndIndex]
9396
let publicKeyBytes = data[credentialIDEndIndex...]
9497

Sources/WebAuthn/WebAuthnError.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public enum WebAuthnError: Error {
5252
case attestedCredentialFlagNotSet
5353
case extensionDataMissing
5454
case leftOverBytesInAuthenticatorData
55+
case credentialIDTooShort
5556

5657
// MARK: CredentialPublicKey
5758
case badPublicKeyBytes
Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import XCTest
22
@testable import WebAuthn
33

4-
// swiftlint:disable line_length
5-
64
final class AuthenticatorDataTests: XCTestCase {
75
// Information about authenticator data: https://w3c.github.io/webauthn/#authenticator-data
86

7+
// Authenticator data
8+
let rpIdHash = [UInt8](repeating: 0, count: 32)
9+
let signCount = [UInt8](repeating: 0, count: 4)
10+
11+
// Attested credential data
12+
let aaguid = [UInt8](repeating: 0, count: 16)
13+
let publicKeyBytes: [UInt8] = [1, 2, 3, 4, 5, 6]
14+
915
func testInitFromBytesFailsIfAuthDataIsTooShort() throws {
1016
let tooManyBytes = [UInt8](repeating: 1, count: 36)
1117
XCTAssertThrowsError(try AuthenticatorData(bytes: Data(tooManyBytes))) { error in
@@ -14,9 +20,7 @@ final class AuthenticatorDataTests: XCTestCase {
1420
}
1521

1622
func testInitFromBytesFailsIfAttestedCredentialDataFlagIsSetButDataIsActuallyNotThere() throws {
17-
let rpIdHash = [UInt8](repeating: 0, count: 32)
1823
let flagsByte: [UInt8] = [0b01000000] // "attested credential data included"
19-
let signCount = [UInt8](repeating: 0, count: 4)
2024

2125
let bytes = rpIdHash + flagsByte + signCount
2226

@@ -26,9 +30,7 @@ final class AuthenticatorDataTests: XCTestCase {
2630
}
2731

2832
func testInitFromBytesFailsIfAttestedCredentialDataFlagIsNotSetButThereActuallyIsData() throws {
29-
let rpIdHash = [UInt8](repeating: 0, count: 32)
30-
let flagsByte: [UInt8] = [0b00000000] // "attested credential data included"
31-
let signCount = [UInt8](repeating: 0, count: 4)
33+
let flagsByte: [UInt8] = [0b00000000] // "attested credential data not included"
3234
let fakeAttestedCredentialData: [UInt8] = [UInt8](repeating: 0, count: 4)
3335

3436
let bytes = rpIdHash + flagsByte + signCount + fakeAttestedCredentialData
@@ -37,4 +39,58 @@ final class AuthenticatorDataTests: XCTestCase {
3739
XCTAssertEqual(error as? WebAuthnError, .attestedCredentialFlagNotSet)
3840
}
3941
}
42+
43+
func testInitFromBytesFailsIfExtensionDataFlagIsSetButDataIsNotIncluded() throws {
44+
let flagsByte: [UInt8] = [0b10000000] // "extension data included"
45+
46+
let bytes = rpIdHash + flagsByte + signCount
47+
48+
XCTAssertThrowsError(try AuthenticatorData(bytes: Data(bytes))) { error in
49+
XCTAssertEqual(error as? WebAuthnError, .extensionDataMissing)
50+
}
51+
}
52+
53+
func testInitFromBytesFailsIfCredentialIdIsTooShort() throws {
54+
let flagsByte: [UInt8] = [0b01000000] // "attested credential data included"
55+
56+
let credentialLength: [UInt8] = [0, 0b00000010] // here we say credentialId has length 2
57+
let credentialID: [UInt8] = [13] // but we only provide a credentialId of length 1
58+
59+
let attestedCredentialData = aaguid + credentialLength + credentialID
60+
let bytes = rpIdHash + flagsByte + signCount + attestedCredentialData
61+
62+
XCTAssertThrowsError(try AuthenticatorData(bytes: Data(bytes))) { error in
63+
XCTAssertEqual(error as? WebAuthnError, .credentialIDTooShort)
64+
}
65+
}
66+
67+
func testInitFromBytesSucceeds() throws {
68+
let flagsByte: [UInt8] = [0b01000000] // "attested credential data included"
69+
70+
let credentialLength: [UInt8] = [0, 0b00000010] // here we say credentialId has length 2
71+
let credentialID: [UInt8] = [13, 12] // but we only provide a credentialId of length 1
72+
73+
let attestedCredentialData = aaguid + credentialLength + credentialID
74+
let bytes = rpIdHash + flagsByte + signCount + attestedCredentialData + publicKeyBytes
75+
76+
let authenticatorData = try AuthenticatorData(bytes: Data(bytes))
77+
78+
XCTAssertEqual(authenticatorData.relyingPartyIDHash, rpIdHash)
79+
XCTAssertEqual(
80+
authenticatorData.flags,
81+
.init(
82+
userPresent: false,
83+
userVerified: false,
84+
isBackupEligible: false,
85+
isCurrentlyBackedUp: false,
86+
attestedCredentialData: true,
87+
extensionDataIncluded: false
88+
)
89+
)
90+
XCTAssertEqual(authenticatorData.counter, Data(signCount).toInteger(endian: .big))
91+
XCTAssertEqual(authenticatorData.extData, nil)
92+
XCTAssertEqual(authenticatorData.attestedData?.aaguid, aaguid)
93+
XCTAssertEqual(authenticatorData.attestedData?.credentialID, credentialID)
94+
XCTAssertEqual(authenticatorData.attestedData?.publicKey, publicKeyBytes)
95+
}
4096
}

0 commit comments

Comments
 (0)