Skip to content

Commit ce1ca2b

Browse files
committed
add more tests
1 parent 3429ad9 commit ce1ca2b

File tree

4 files changed

+86
-5
lines changed

4 files changed

+86
-5
lines changed

Sources/WebAuthn/Ceremonies/Registration/AttestationObject.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public struct AttestationObject: Equatable {
4343
case .none:
4444
// if format is `none` statement must be empty
4545
guard attestationStatement == .map([:]) else {
46-
throw WebAuthnError.attestationStatementMissing
46+
throw WebAuthnError.attestationStatementMustBeEmpty
4747
}
4848
default:
4949
throw WebAuthnError.attestationVerificationNotSupported

Sources/WebAuthn/WebAuthnError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public enum WebAuthnError: Error, Equatable {
2222

2323
// MARK: AttestationObject
2424
case userVerificationRequiredButFlagNotSet
25-
case attestationStatementMissing
25+
case attestationStatementMustBeEmpty
2626
case attestationVerificationNotSupported
2727

2828
// MARK: WebAuthnManager

Tests/WebAuthnTests/Utils/assert+async.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ func assertThrowsError<T, E: Error>(
1313
XCTFail(message(), file: file, line: line)
1414
} catch {
1515
guard let error = error as? E else {
16-
XCTFail("Error was thrown, but didn't match expected type '\(E.self)'. Got: '\(type(of: error))'")
16+
XCTFail("""
17+
Error was thrown, but didn't match expected type '\(E.self)'.
18+
Got error of type '\(type(of: error))'.
19+
Error: \(error)
20+
""")
1721
return
1822
}
1923
errorHandler(error)

Tests/WebAuthnTests/WebAuthnManagerTests.swift

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,89 @@ final class WebAuthnManagerTests: XCTestCase {
149149
)
150150
}
151151

152+
func testFinishRegistrationFailsIfCeremonyTypeDoesNotMatch() async throws {
153+
let clientDataJSONWrongCeremonyType: URLEncodedBase64 = "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0"
154+
try await assertThrowsError(
155+
await finishRegistration(clientDataJSON: clientDataJSONWrongCeremonyType),
156+
expect: CollectedClientData.CollectedClientDataVerifyError.ceremonyTypeDoesNotMatch
157+
)
158+
}
159+
160+
func testFinishRegistrationFailsIfChallengeDoesNotMatch() async throws {
161+
let clientDataJSONWrongChallenge: URLEncodedBase64 = "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0"
162+
try await assertThrowsError(
163+
await finishRegistration(
164+
challenge: "definitelyAnotherChallenge",
165+
clientDataJSON: clientDataJSONWrongChallenge
166+
),
167+
expect: CollectedClientData.CollectedClientDataVerifyError.challengeDoesNotMatch
168+
)
169+
}
170+
171+
func testFinishRegistrationFailsIfOriginDoesNotMatch() async throws {
172+
// origin = http://johndoe.com
173+
let clientDataJSONWrongOrigin: URLEncodedBase64 = "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2pvaG5kb2UuY29tIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0"
174+
175+
// `webAuthnManager` is configured with origin = https://example.com
176+
try await assertThrowsError(
177+
await finishRegistration(
178+
challenge: "cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg",
179+
clientDataJSON: clientDataJSONWrongOrigin
180+
),
181+
expect: CollectedClientData.CollectedClientDataVerifyError.originDoesNotMatch
182+
)
183+
}
184+
185+
func testFinishRegistrationFailsIfClientDataJSONIsInvalid() async throws {
186+
try await assertThrowsError(
187+
await finishRegistration(clientDataJSON: "%"),
188+
expect: WebAuthnError.invalidClientDataJSON
189+
)
190+
}
191+
192+
func testFinishRegistrationFailsIfRelyingPartyIDHashDoesNotMatch() async throws {
193+
let hexAttestationObjectMismatchingRpId: URLEncodedBase64 = "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo"
194+
try await assertThrowsError(
195+
await finishRegistration(attestationObject: hexAttestationObjectMismatchingRpId),
196+
expect: WebAuthnError.relyingPartyIDHashDoesNotMatch
197+
)
198+
}
199+
200+
func testFinishRegistrationFailsIfUserPresentFlagIsNotSet() async throws {
201+
let hexAttestationObjectMismatchingRpId: URLEncodedBase64 = "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdAAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo"
202+
try await assertThrowsError(
203+
await finishRegistration(attestationObject: hexAttestationObjectMismatchingRpId),
204+
expect: WebAuthnError.userPresentFlagNotSet
205+
)
206+
}
207+
208+
func testFinishRegistrationFailsIfUserVerificationFlagIsNotSetButRequired() async throws {
209+
let hexAttestationObjectUVFlagNotSet: URLEncodedBase64 = "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdBAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo"
210+
try await assertThrowsError(
211+
await finishRegistration(
212+
attestationObject: hexAttestationObjectUVFlagNotSet,
213+
requireUserVerification: true
214+
),
215+
expect: WebAuthnError.userVerificationRequiredButFlagNotSet
216+
)
217+
}
218+
219+
func testFinishRegistrationFailsIfAttFmtIsNoneButAttStmtIsIncluded() async throws {
220+
let hexAttestationObjectAttStmtNoneWithAttStmt: URLEncodedBase64 = "o2NmbXRkbm9uZWdhdHRTdG10oWVoZWxsb2V3b3JsZGhhdXRoRGF0YVg5o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdBAAAAAKN5pvbur7mlXjeMEYA04nUAAQAA"
221+
try await assertThrowsError(
222+
await finishRegistration(attestationObject: hexAttestationObjectAttStmtNoneWithAttStmt),
223+
expect: WebAuthnError.attestationStatementMustBeEmpty
224+
)
225+
}
226+
152227
private func finishRegistration(
153-
challenge: EncodedBase64 = "xxi54jsOKKj7GrikECpuQyenfMC31FADtT6/fE9+fMY=",
228+
challenge: EncodedBase64 = "cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg",
154229
id: EncodedBase64 = "4PrJNQUJ9xdI2DeCzK9rTBRixhXHDiVdoTROQIh8j80",
155230
type: String = "public-key",
156231
rawID: EncodedBase64 = "4PrJNQUJ9xdI2DeCzK9rTBRixhXHDiVdoTROQIh8j80",
157-
clientDataJSON: String = "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0",
232+
clientDataJSON: String = "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9",
158233
attestationObject: String = "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAIDo-5W3Kur7A7y9Lfw7ijhExfCz3_5coMEQNY_y6p-JrpQECAyYgASFYIJr_yLoYbYWgcf7aQcd7pcjUj-3o8biafWQH28WijQSvIlggPI2KqqRQ26KKuFaJ0yH7nouCBrzHu8qRONW-CPa9VDM",
234+
requireUserVerification: Bool = false,
159235
confirmCredentialIDNotRegisteredYet: (String) async throws -> Bool = { _ in true }
160236
) async throws -> Credential {
161237
try await webAuthnManager.finishRegistration(
@@ -169,6 +245,7 @@ final class WebAuthnManagerTests: XCTestCase {
169245
attestationObject: attestationObject
170246
)
171247
),
248+
requireUserVerification: requireUserVerification,
172249
confirmCredentialIDNotRegisteredYet: confirmCredentialIDNotRegisteredYet
173250
)
174251
}

0 commit comments

Comments
 (0)