@@ -149,13 +149,89 @@ final class WebAuthnManagerTests: XCTestCase {
149
149
)
150
150
}
151
151
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
+
152
227
private func finishRegistration(
153
- challenge: EncodedBase64 = " xxi54jsOKKj7GrikECpuQyenfMC31FADtT6/fE9+fMY= " ,
228
+ challenge: EncodedBase64 = " cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg " ,
154
229
id: EncodedBase64 = " 4PrJNQUJ9xdI2DeCzK9rTBRixhXHDiVdoTROQIh8j80 " ,
155
230
type: String = " public-key " ,
156
231
rawID: EncodedBase64 = " 4PrJNQUJ9xdI2DeCzK9rTBRixhXHDiVdoTROQIh8j80 " ,
157
- clientDataJSON: String = " eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0 " ,
232
+ clientDataJSON: String = " eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsImNyb3NzT3JpZ2luIjpmYWxzZSwib3RoZXJfa2V5c19jYW5fYmVfYWRkZWRfaGVyZSI6ImRvIG5vdCBjb21wYXJlIGNsaWVudERhdGFKU09OIGFnYWluc3QgYSB0ZW1wbGF0ZS4gU2VlIGh0dHBzOi8vZ29vLmdsL3lhYlBleCJ9 " ,
158
233
attestationObject: String = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAIDo-5W3Kur7A7y9Lfw7ijhExfCz3_5coMEQNY_y6p-JrpQECAyYgASFYIJr_yLoYbYWgcf7aQcd7pcjUj-3o8biafWQH28WijQSvIlggPI2KqqRQ26KKuFaJ0yH7nouCBrzHu8qRONW-CPa9VDM " ,
234
+ requireUserVerification: Bool = false ,
159
235
confirmCredentialIDNotRegisteredYet: ( String ) async throws -> Bool = { _ in true }
160
236
) async throws -> Credential {
161
237
try await webAuthnManager. finishRegistration (
@@ -169,6 +245,7 @@ final class WebAuthnManagerTests: XCTestCase {
169
245
attestationObject: attestationObject
170
246
)
171
247
) ,
248
+ requireUserVerification: requireUserVerification,
172
249
confirmCredentialIDNotRegisteredYet: confirmCredentialIDNotRegisteredYet
173
250
)
174
251
}
0 commit comments