14
14
15
15
@testable import WebAuthn
16
16
import XCTest
17
+ import SwiftCBOR
17
18
18
19
// swiftlint:disable line_length
19
20
@@ -86,14 +87,30 @@ final class WebAuthnManagerTests: XCTestCase {
86
87
}
87
88
88
89
func testFinishRegistrationFailsIfAuthDataIsInvalid( ) async throws {
89
- let hexAttestationObjectWithInvalidAuthData : URLEncodedBase64 = " A363666D74667061636B65646761747453746D74A263616C67266373696758473045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C68617574684461746101 "
90
+ // {
91
+ // "fmt": "packed",
92
+ // "attStmt": {
93
+ // "alg": -7,
94
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
95
+ // },
96
+ // "authData": 1
97
+ // }
98
+ let hexAttestationObjectWithInvalidAuthData : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YQE "
90
99
try await assertThrowsError (
91
100
await finishRegistration ( attestationObject: hexAttestationObjectWithInvalidAuthData) ,
92
101
expect: WebAuthnError . invalidAuthData
93
102
)
94
103
}
95
104
96
105
func testFinishRegistrationFailsIfFmtIsInvalid( ) async throws {
106
+ // {
107
+ // "fmt": 1,
108
+ // "attStmt": {
109
+ // "alg": -7,
110
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
111
+ // },
112
+ // "authData": h'49960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D97634500000000ADCE000235BCC60A648B0B25F1F0550300203A3EE56DCABABEC0EF2F4B7F0EE28E11317C2CF7FF972830440D63FCBAA7E26BA50102032620012158209AFFC8BA186D85A071FEDA41C77BA5C8D48FEDE8F1B89A7D6407DBC5A28D04AF2258203C8D8AAAA450DBA28AB85689D321FB9E8B8206BCC7BBCA9138D5BE08F6BD5433'
113
+ // }
97
114
let hexAttestationObjectWithInvalidFmt : URLEncodedBase64 = " o2NmbXQBZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAIDo-5W3Kur7A7y9Lfw7ijhExfCz3_5coMEQNY_y6p-JrpQECAyYgASFYIJr_yLoYbYWgcf7aQcd7pcjUj-3o8biafWQH28WijQSvIlggPI2KqqRQ26KKuFaJ0yH7nouCBrzHu8qRONW-CPa9VDM "
98
115
try await assertThrowsError (
99
116
await finishRegistration ( attestationObject: hexAttestationObjectWithInvalidFmt) ,
@@ -102,6 +119,10 @@ final class WebAuthnManagerTests: XCTestCase {
102
119
}
103
120
104
121
func testFinishRegistrationFailsIfAttStmtIsMissing( ) async throws {
122
+ // {
123
+ // "fmt": "packed",
124
+ // "authData": h'49960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D97634500000000ADCE000235BCC60A648B0B25F1F0550300203A3EE56DCABABEC0EF2F4B7F0EE28E11317C2CF7FF972830440D63FCBAA7E26BA50102032620012158209AFFC8BA186D85A071FEDA41C77BA5C8D48FEDE8F1B89A7D6407DBC5A28D04AF2258203C8D8AAAA450DBA28AB85689D321FB9E8B8206BCC7BBCA9138D5BE08F6BD5433'
125
+ // }
105
126
let hexAttestationObjectWithMissingAttStmt : URLEncodedBase64 = " omNmbXRmcGFja2VkaGF1dGhEYXRhWKRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0UAAAAArc4AAjW8xgpkiwsl8fBVAwAgOj7lbcq6vsDvL0t_DuKOETF8LPf_lygwRA1j_Lqn4mulAQIDJiABIVggmv_IuhhthaBx_tpBx3ulyNSP7ejxuJp9ZAfbxaKNBK8iWCA8jYqqpFDbooq4VonTIfuei4IGvMe7ypE41b4I9r1UMw "
106
127
try await assertThrowsError (
107
128
await finishRegistration ( attestationObject: hexAttestationObjectWithMissingAttStmt) ,
@@ -110,6 +131,14 @@ final class WebAuthnManagerTests: XCTestCase {
110
131
}
111
132
112
133
func testFinishRegistrationFailsIfAuthDataIsTooShort( ) async throws {
134
+ // {
135
+ // "fmt": "packed",
136
+ // "attStmt": {
137
+ // "alg": -7,
138
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
139
+ // },
140
+ // "authData": h'49960D'
141
+ // }
113
142
let hexAttestationObjectInvalidAuthData : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YUNJlg0 "
114
143
try await assertThrowsError (
115
144
await finishRegistration ( attestationObject: hexAttestationObjectInvalidAuthData) ,
@@ -118,6 +147,14 @@ final class WebAuthnManagerTests: XCTestCase {
118
147
}
119
148
120
149
func testFinishRegistrationFailsIfAttestedCredentialDataFlagIsSetButThereIsNotCredentialData( ) async throws {
150
+ // {
151
+ // "fmt": "packed",
152
+ // "attStmt": {
153
+ // "alg": -7,
154
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
155
+ // },
156
+ // "authData": h'5647686C5647686C5647686C5647686C5647686C5647686C686C5647686C686C4000000000'
157
+ // }
121
158
let hexAttestationObjectMissingCredentialData : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVglVkdobFZHaGxWR2hsVkdobFZHaGxWR2hsaGxWR2hsaGxAAAAAAA "
122
159
try await assertThrowsError (
123
160
await finishRegistration ( attestationObject: hexAttestationObjectMissingCredentialData) ,
@@ -126,6 +163,14 @@ final class WebAuthnManagerTests: XCTestCase {
126
163
}
127
164
128
165
func testFinishRegistrationFailsIfAttestedCredentialDataFlagIsNotSetButThereIsCredentialData( ) async throws {
166
+ // {
167
+ // "fmt": "packed",
168
+ // "attStmt": {
169
+ // "alg": -7,
170
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
171
+ // },
172
+ // "authData": h'5647686C5647686C5647686C5647686C5647686C5647686C686C5647686C686C000000000000'
173
+ // }
129
174
let hexAttestationObjectWithCredentialData : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVgmVkdobFZHaGxWR2hsVkdobFZHaGxWR2hsaGxWR2hsaGwAAAAAAAA "
130
175
try await assertThrowsError (
131
176
await finishRegistration ( attestationObject: hexAttestationObjectWithCredentialData) ,
@@ -134,6 +179,14 @@ final class WebAuthnManagerTests: XCTestCase {
134
179
}
135
180
136
181
func testFinishRegistrationFailsIfExtensionDataFlagIsSetButThereIsNoExtensionData( ) async throws {
182
+ // {
183
+ // "fmt": "packed",
184
+ // "attStmt": {
185
+ // "alg": -7,
186
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
187
+ // },
188
+ // "authData": h'5647686C5647686C5647686C5647686C5647686C5647686C686C5647686C686C8000000000'
189
+ // }
137
190
let hexAttestationObjectMissingExtensionData : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVglVkdobFZHaGxWR2hsVkdobFZHaGxWR2hsaGxWR2hsaGyAAAAAAA "
138
191
try await assertThrowsError (
139
192
await finishRegistration ( attestationObject: hexAttestationObjectMissingExtensionData) ,
@@ -142,6 +195,14 @@ final class WebAuthnManagerTests: XCTestCase {
142
195
}
143
196
144
197
func testFinishRegistrationFailsIfCredentialIdIsTooShort( ) async throws {
198
+ // {
199
+ // "fmt": "packed",
200
+ // "attStmt": {
201
+ // "alg": -7,
202
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
203
+ // },
204
+ // "authData": h'5647686C5647686C5647686C5647686C5647686C5647686C686C5647686C686C40000000005647686C5647686C5647686C5647686C00022A'
205
+ // }
145
206
let hexAttestationShortCredentialID : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4VkdobFZHaGxWR2hsVkdobFZHaGxWR2hsaGxWR2hsaGxAAAAAAFZHaGxWR2hsVkdobFZHaGwAAio "
146
207
try await assertThrowsError (
147
208
await finishRegistration ( attestationObject: hexAttestationShortCredentialID) ,
@@ -150,15 +211,31 @@ final class WebAuthnManagerTests: XCTestCase {
150
211
}
151
212
152
213
func testFinishRegistrationFailsIfCeremonyTypeDoesNotMatch( ) async throws {
153
- let clientDataJSONWrongCeremonyType : URLEncodedBase64 = " eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0 "
214
+ let clientDataJSONWrongCeremonyType = String . base64URL ( fromBase64: """
215
+ {
216
+ " type " : " webauthn.get " ,
217
+ " challenge " : " cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg " ,
218
+ " origin " : " http://localhost:8080 " ,
219
+ " crossOrigin " : false,
220
+ " other_keys_can_be_added_here " : " do not compare clientDataJSON against a template. See https://goo.gl/yabPex "
221
+ }
222
+ """ . toBase64 ( ) )
154
223
try await assertThrowsError (
155
224
await finishRegistration ( clientDataJSON: clientDataJSONWrongCeremonyType) ,
156
225
expect: CollectedClientData . CollectedClientDataVerifyError. ceremonyTypeDoesNotMatch
157
226
)
158
227
}
159
228
160
229
func testFinishRegistrationFailsIfChallengeDoesNotMatch( ) async throws {
161
- let clientDataJSONWrongChallenge : URLEncodedBase64 = " eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0 "
230
+ let clientDataJSONWrongChallenge = String . base64URL ( fromBase64: """
231
+ {
232
+ " type " : " webauthn.create " ,
233
+ " challenge " : " cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg " ,
234
+ " origin " : " http://localhost:8080 " ,
235
+ " crossOrigin " : false,
236
+ " other_keys_can_be_added_here " : " do not compare clientDataJSON against a template. See https://goo.gl/yabPex "
237
+ }
238
+ """ . toBase64 ( ) )
162
239
try await assertThrowsError (
163
240
await finishRegistration (
164
241
challenge: " definitelyAnotherChallenge " ,
@@ -169,9 +246,15 @@ final class WebAuthnManagerTests: XCTestCase {
169
246
}
170
247
171
248
func testFinishRegistrationFailsIfOriginDoesNotMatch( ) async throws {
172
- // origin = http://johndoe.com
173
- let clientDataJSONWrongOrigin : URLEncodedBase64 = " eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiY21GdVpHOXRVM1J5YVc1blJuSnZiVk5sY25abGNnIiwib3JpZ2luIjoiaHR0cDovL2pvaG5kb2UuY29tIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0 "
174
-
249
+ let clientDataJSONWrongOrigin : URLEncodedBase64 = String . base64URL ( fromBase64: """
250
+ {
251
+ " type " : " webauthn.create " ,
252
+ " challenge " : " cmFuZG9tU3RyaW5nRnJvbVNlcnZlcg " ,
253
+ " origin " : " http://johndoe.com " ,
254
+ " crossOrigin " : false,
255
+ " other_keys_can_be_added_here " : " do not compare clientDataJSON against a template. See https://goo.gl/yabPex "
256
+ }
257
+ """ . toBase64 ( ) )
175
258
// `webAuthnManager` is configured with origin = https://example.com
176
259
try await assertThrowsError (
177
260
await finishRegistration (
@@ -190,6 +273,14 @@ final class WebAuthnManagerTests: XCTestCase {
190
273
}
191
274
192
275
func testFinishRegistrationFailsIfRelyingPartyIDHashDoesNotMatch( ) async throws {
276
+ // {
277
+ // "fmt": "packed",
278
+ // "attStmt": {
279
+ // "alg": -7,
280
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
281
+ // },
282
+ // "authData": h'49960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D97634500000000ADCE000235BCC60A648B0B25F1F0550300013A'
283
+ // }
193
284
let hexAttestationObjectMismatchingRpId : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo "
194
285
try await assertThrowsError (
195
286
await finishRegistration ( attestationObject: hexAttestationObjectMismatchingRpId) ,
@@ -198,14 +289,30 @@ final class WebAuthnManagerTests: XCTestCase {
198
289
}
199
290
200
291
func testFinishRegistrationFailsIfUserPresentFlagIsNotSet( ) async throws {
201
- let hexAttestationObjectMismatchingRpId : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdAAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo "
292
+ // {
293
+ // "fmt": "packed",
294
+ // "attStmt": {
295
+ // "alg": -7,
296
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
297
+ // },
298
+ // "authData": h'A379A6F6EEAFB9A55E378C118034E2751E682FAB9F2D30AB13D2125586CE19474000000000ADCE000235BCC60A648B0B25F1F0550300013A'
299
+ // }
300
+ let hexAttestationObjectUPFlagNotSet : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdAAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo "
202
301
try await assertThrowsError (
203
- await finishRegistration ( attestationObject: hexAttestationObjectMismatchingRpId ) ,
302
+ await finishRegistration ( attestationObject: hexAttestationObjectUPFlagNotSet ) ,
204
303
expect: WebAuthnError . userPresentFlagNotSet
205
304
)
206
305
}
207
306
208
307
func testFinishRegistrationFailsIfUserVerificationFlagIsNotSetButRequired( ) async throws {
308
+ // {
309
+ // "fmt": "packed",
310
+ // "attStmt": {
311
+ // "alg": -7,
312
+ // "sig": h'3045022035346DA48FD238E655CD4D6937FE1C5FEA2CA943E21CC396E3CAAAABDD435DF5022100BE30789A231B7639D23182A627C940C771E7AF34E31F3E26DE9DA6D01AF5E08C'
313
+ // },
314
+ // "authData": h'A379A6F6EEAFB9A55E378C118034E2751E682FAB9F2D30AB13D2125586CE19474100000000ADCE000235BCC60A648B0B25F1F0550300013A'
315
+ // }
209
316
let hexAttestationObjectUVFlagNotSet : URLEncodedBase64 = " o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgNTRtpI_SOOZVzU1pN_4cX-osqUPiHMOW48qqq91DXfUCIQC-MHiaIxt2OdIxgqYnyUDHceevNOMfPibenabQGvXgjGhhdXRoRGF0YVg4o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdBAAAAAK3OAAI1vMYKZIsLJfHwVQMAATo "
210
317
try await assertThrowsError (
211
318
await finishRegistration (
@@ -217,6 +324,13 @@ final class WebAuthnManagerTests: XCTestCase {
217
324
}
218
325
219
326
func testFinishRegistrationFailsIfAttFmtIsNoneButAttStmtIsIncluded( ) async throws {
327
+ // {
328
+ // "fmt": "none",
329
+ // "attStmt": {
330
+ // "hello": "world"
331
+ // },
332
+ // "authData": h'A379A6F6EEAFB9A55E378C118034E2751E682FAB9F2D30AB13D2125586CE19474100000000A379A6F6EEAFB9A55E378C118034E27500010000'
333
+ // }
220
334
let hexAttestationObjectAttStmtNoneWithAttStmt : URLEncodedBase64 = " o2NmbXRkbm9uZWdhdHRTdG10oWVoZWxsb2V3b3JsZGhhdXRoRGF0YVg5o3mm9u6vuaVeN4wRgDTidR5oL6ufLTCrE9ISVYbOGUdBAAAAAKN5pvbur7mlXjeMEYA04nUAAQAA "
221
335
try await assertThrowsError (
222
336
await finishRegistration ( attestationObject: hexAttestationObjectAttStmtNoneWithAttStmt) ,
0 commit comments