Skip to content

Commit 3ebcd30

Browse files
authored
Merge pull request #37 from dimitribouniol/dimitri/auth-data-decoding
2 parents e02886e + 7f2c93c commit 3ebcd30

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

Sources/WebAuthn/Ceremonies/Shared/AuthenticatorData.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import Foundation
1616
import Crypto
17+
import SwiftCBOR
1718

1819
/// Data created and/ or used by the authenticator during authentication/ registration.
1920
/// The data contains, for example, whether a user was present or verified.
@@ -93,7 +94,13 @@ extension AuthenticatorData {
9394
throw WebAuthnError.credentialIDTooShort
9495
}
9596
let credentialID = data[55..<credentialIDEndIndex]
96-
let publicKeyBytes = data[credentialIDEndIndex...]
97+
98+
/// **credentialPublicKey** (variable): The credential public key encoded in COSE_Key format, as defined in Section 7 of [RFC9052], using the CTAP2 canonical CBOR encoding form.
99+
/// Assuming valid CBOR, verify the public key's length by decoding the next CBOR item.
100+
let inputStream = ByteInputStream(data[credentialIDEndIndex...])
101+
let decoder = CBORDecoder(stream: inputStream)
102+
_ = try decoder.decodeItem()
103+
let publicKeyBytes = data[credentialIDEndIndex..<(data.count - inputStream.remainingBytes)]
97104

98105
let data = AttestedCredentialData(
99106
aaguid: Array(aaguid),
@@ -107,3 +114,27 @@ extension AuthenticatorData {
107114
return (data, length)
108115
}
109116
}
117+
118+
/// A helper type to determine how many bytes were consumed when decoding CBOR items.
119+
class ByteInputStream: CBORInputStream {
120+
private var slice : ArraySlice<UInt8>
121+
122+
init(_ slice: Data) {
123+
self.slice = Array(slice)[...]
124+
}
125+
126+
/// The remaining bytes in the original data buffer.
127+
var remainingBytes: Int { slice.count }
128+
129+
func popByte() throws -> UInt8 {
130+
if slice.count < 1 { throw CBORError.unfinishedSequence }
131+
return slice.removeFirst()
132+
}
133+
134+
func popBytes(_ n: Int) throws -> ArraySlice<UInt8> {
135+
if slice.count < n { throw CBORError.unfinishedSequence }
136+
let result = slice.prefix(n)
137+
slice = slice.dropFirst(n)
138+
return result
139+
}
140+
}

Tests/WebAuthnTests/Utils/TestModels/TestAuthData.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ struct TestAuthDataBuilder {
6262
func validMock() -> Self {
6363
self
6464
.rpIDHash(fromRpID: "example.com")
65-
.flags(0b01000101)
65+
.flags(0b11000101)
6666
.counter([0b00000000, 0b00000000, 0b00000000, 0b00000000])
6767
.attestedCredData(
6868
aaguid: [UInt8](repeating: 0, count: 16),
@@ -139,6 +139,7 @@ struct TestAuthDataBuilder {
139139

140140
func noExtensionData() -> Self {
141141
var temp = self
142+
temp.wrapped.flags = temp.wrapped.flags.map{ $0 & 0b01111111 }
142143
temp.wrapped.extensions = nil
143144
return temp
144145
}

Tests/WebAuthnTests/WebAuthnManagerRegistrationTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ final class WebAuthnManagerRegistrationTests: XCTestCase {
200200
await finishRegistration(
201201
attestationObject: TestAttestationObjectBuilder()
202202
.validMock()
203-
.authData(TestAuthDataBuilder().validMock().flags(0b11000001).noExtensionData())
203+
.authData(TestAuthDataBuilder().validMock().noExtensionData().flags(0b11000001))
204204
.build()
205205
.cborEncoded
206206
),
@@ -248,7 +248,7 @@ final class WebAuthnManagerRegistrationTests: XCTestCase {
248248
await finishRegistration(
249249
attestationObject: TestAttestationObjectBuilder()
250250
.validMock()
251-
.authData(TestAuthDataBuilder().validMock().flags(0b01000000))
251+
.authData(TestAuthDataBuilder().validMock().flags(0b11000000))
252252
.build()
253253
.cborEncoded
254254
),
@@ -261,7 +261,7 @@ final class WebAuthnManagerRegistrationTests: XCTestCase {
261261
await finishRegistration(
262262
attestationObject: TestAttestationObjectBuilder()
263263
.validMock()
264-
.authData(TestAuthDataBuilder().validMock().flags(0b01000001))
264+
.authData(TestAuthDataBuilder().validMock().flags(0b11000001))
265265
.build()
266266
.cborEncoded,
267267
requireUserVerification: true

0 commit comments

Comments
 (0)