@@ -16,11 +16,11 @@ public struct ChallengeResponse: Encodable {
1616public struct ChallengeArgs {
1717 public let rpId : String
1818 public let validCredentials : [ String ]
19- public let devPin : String
19+ public let devPin : String ?
2020 public let challenge : String
2121 public let origin : String
2222
23- public init ( rpId: String , validCredentials: [ String ] , devPin: String , challenge: String , origin: String ) {
23+ public init ( rpId: String , validCredentials: [ String ] , devPin: String ? , challenge: String , origin: String ) {
2424 self . rpId = rpId
2525 self . validCredentials = validCredentials
2626 self . devPin = devPin
@@ -66,6 +66,21 @@ public class FIDO2 {
6666
6767 public init ( ) { }
6868
69+ public func deviceHasPin( ) throws -> Bool {
70+ let devPath = try findFirstDevicePath ( )
71+
72+ var dev = fido_dev_new ( )
73+ defer { fido_dev_free ( & dev) }
74+
75+ let openResult = fido_dev_open ( dev, devPath)
76+ guard openResult == FIDO_OK else {
77+ throw FIDO2Error . internalError
78+ }
79+ defer { fido_dev_close ( dev) }
80+
81+ return fido_dev_has_pin ( dev)
82+ }
83+
6984 /// Responds to the given WebAuthn challenge
7085 /// Note that this is a **blocking** method if the challenge requires user verification (don't call it on the main thread!)
7186 /// (The method blocks waiting for the user to touch the security device)
@@ -107,14 +122,10 @@ public class FIDO2 {
107122 throw FIDO2Error . notFido2Device
108123 }
109124
110- guard let matchingCredId = try getMatchingCredId ( from: dev, validCredentials: validCredentials, rpId: rpId, devPin: devPin) else {
111- // The device has no valid credentials, we cannot continue
112- throw FIDO2Error . errorNoValidCredentials
113- }
114-
115125 try makeAssertion ( using: dev, fidoAssertion: fa, devicePin: devPin)
116126
117127 let authDataBase64Str = try getAuthData ( fidoAssertion: fa)
128+ let credentialId = try getCredentialIdUsed ( fidoAssertion: fa)
118129 let signatureDataBase64Str = try getSignatureData ( fidoAssertion: fa)
119130 let userHandleBase64Str = try getUserData ( fidoAssertion: fa)
120131
@@ -124,7 +135,7 @@ public class FIDO2 {
124135 signatureData: signatureDataBase64Str,
125136 authenticatorData: authDataBase64Str,
126137 userHandle: userHandleBase64Str,
127- credentialID: matchingCredId ,
138+ credentialID: credentialId ,
128139 rpId: rpId)
129140 return response
130141 }
@@ -169,34 +180,7 @@ public class FIDO2 {
169180 return String ( cString: devPath)
170181 }
171182
172- private func getMatchingCredId( from dev: OpaquePointer ? , validCredentials: [ String ] , rpId: String , devPin: String ) throws -> String ? {
173- var rk = fido_credman_rk_new ( ) // Resident credentials array
174- defer { fido_credman_rk_free ( & rk) }
175-
176- let get_dev_array_result = fido_credman_get_dev_rk ( dev, rpId, rk, devPin)
177- guard get_dev_array_result == FIDO_OK else {
178- throw FIDO2Error . libfido2ErrorInternal ( get_dev_array_result)
179- }
180-
181- let rkCount = fido_credman_rk_count ( rk)
182- for i in 0 ..< rkCount {
183- let cred = fido_credman_rk ( rk, i)
184- guard let idPtr = fido_cred_id_ptr ( cred) else {
185- throw FIDO2Error . internalError
186- }
187- let idLen = fido_cred_id_len ( cred)
188- let idData = Data ( bytes: idPtr, count: idLen)
189- let idBase64 = idData. base64EncodedString ( )
190- if validCredentials. contains ( idBase64) {
191- // Return the first found, valid credential
192- return idBase64
193- }
194- }
195-
196- return nil
197- }
198-
199- private func makeAssertion( using device: OpaquePointer ? , fidoAssertion: OpaquePointer ? , devicePin: String ) throws {
183+ private func makeAssertion( using device: OpaquePointer ? , fidoAssertion: OpaquePointer ? , devicePin: String ? ) throws {
200184 let assertResult = fido_dev_get_assert ( device, fidoAssertion, devicePin)
201185 guard assertResult == FIDO_OK else {
202186 if assertResult == FIDO_ERR_ACTION_TIMEOUT {
@@ -220,6 +204,16 @@ public class FIDO2 {
220204 return authDataBase64Str
221205 }
222206
207+ private func getCredentialIdUsed( fidoAssertion fa: OpaquePointer ? ) throws -> String {
208+ guard let credentialIdPtr = fido_assert_id_ptr ( fa, 0 ) else {
209+ throw FIDO2Error . internalError
210+ }
211+ let credIdLen = fido_assert_id_len ( fa, 0 )
212+ let credIdData = Data ( bytes: credentialIdPtr, count: credIdLen)
213+ let credIdBase64Str = credIdData. base64EncodedString ( )
214+ return credIdBase64Str
215+ }
216+
223217 private func getSignatureData( fidoAssertion fa: OpaquePointer ? ) throws -> String {
224218 guard let signatureDataPtr = fido_assert_sig_ptr ( fa, 0 ) else {
225219 throw FIDO2Error . internalError
0 commit comments