Skip to content

Commit 9717762

Browse files
authored
Return error message for iOS authenticator requests (#101)
1 parent d3540c6 commit 9717762

File tree

2 files changed

+76
-19
lines changed

2 files changed

+76
-19
lines changed

src/webauthn/authenticator/native.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ mod ios {
2222
pub struct AuthenticatorRequestResponse {
2323
pub auth_data_bytes: Vec<u8>,
2424
pub signature: Vec<u8>,
25+
pub success: bool,
26+
pub error_message: String,
2527
}
2628

2729
#[repr(C)]
@@ -129,25 +131,42 @@ mod ios {
129131

130132
let auth_data = WebauthnAuthenticator::generate_authenticator_data(rp_id_str.as_str(), u8::from_be(attestation_flags), None);
131133

132-
if auth_data.is_err() {
133-
return null_mut();
134+
if let Err(e) = auth_data {
135+
return Box::into_raw(Box::new(AuthenticatorRequestResponse {
136+
auth_data_bytes: Vec::new(),
137+
signature: Vec::new(),
138+
success: false,
139+
error_message: format!("Error generating auth data: {e:?}"),
140+
}));
134141
}
135142

136143
let auth_data_bytes = auth_data.expect("Checked above").to_vec();
137-
if auth_data_bytes.is_err() {
138-
return null_mut();
144+
if let Err(e) = auth_data_bytes {
145+
return Box::into_raw(Box::new(AuthenticatorRequestResponse {
146+
auth_data_bytes: Vec::new(),
147+
signature: Vec::new(),
148+
success: false,
149+
error_message: format!("Error converting auth data to bytes: {e:?}"),
150+
}));
139151
}
140152
let auth_data_bytes = auth_data_bytes.expect("Checked above");
141153

142154
let signature = WebauthnAuthenticator::generate_signature(auth_data_bytes.as_slice(), client_data_hash.as_slice(), private_key);
143155

144-
if signature.is_err() {
145-
return null_mut();
156+
if let Err(e) = signature {
157+
return Box::into_raw(Box::new(AuthenticatorRequestResponse {
158+
auth_data_bytes: Vec::new(),
159+
signature: Vec::new(),
160+
success: false,
161+
error_message: format!("Error signing data: {e:?}"),
162+
}));
146163
}
147164

148165
Box::into_raw(Box::new(AuthenticatorRequestResponse {
149166
auth_data_bytes,
150167
signature: signature.expect("Checked above"),
168+
success: true,
169+
error_message: String::new(),
151170
}))
152171
}
153172

@@ -163,6 +182,28 @@ mod ios {
163182
}
164183
}
165184

185+
#[no_mangle]
186+
pub unsafe extern "C" fn is_success(res: *mut AuthenticatorRequestResponse) -> bool {
187+
if res.is_null() {
188+
return false;
189+
}
190+
191+
(*res).success
192+
}
193+
194+
#[no_mangle]
195+
pub unsafe extern "C" fn get_error_message(res: *mut AuthenticatorRequestResponse) -> *mut c_char {
196+
if res.is_null() {
197+
return null_mut();
198+
}
199+
200+
let cstring = CString::new((*res).error_message.clone());
201+
match cstring {
202+
Ok(cstring) => cstring.into_raw(),
203+
Err(_) => null_mut(),
204+
}
205+
}
206+
166207
#[no_mangle]
167208
pub unsafe extern "C" fn get_signature_from_response(res: *mut AuthenticatorRequestResponse) -> Buffer {
168209
if res.is_null() {
Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
@available(iOS 15.0, *)
22
public class WebAuthnRequestResponse: NSObject, RustObject {
33

4-
var raw: OpaquePointer
4+
var raw: OpaquePointer
55

6-
required init(raw: OpaquePointer) {
7-
self.raw = raw
8-
}
6+
required init(raw: OpaquePointer) {
7+
self.raw = raw
8+
}
99

10-
func intoRaw() -> OpaquePointer {
11-
return self.raw
12-
}
10+
func intoRaw() -> OpaquePointer {
11+
return self.raw
12+
}
1313

14-
public func getAuthData() -> Data {
14+
public func getAuthData() -> Data {
1515
let buffer = get_auth_data_from_response(self.raw)
1616
return Data(bytes: buffer.data, count: Int(buffer.len))
1717
}
@@ -21,16 +21,32 @@ public class WebAuthnRequestResponse: NSObject, RustObject {
2121
return Data(bytes: buffer.data, count: Int(buffer.len))
2222
}
2323

24-
public convenience init(rpId: String, attestationFlags: UInt8, clientDataHash: Data, privateKey: String) throws {
25-
let clientDataHashPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: clientDataHash.count)
24+
public func isSuccess() -> Bool {
25+
return is_success(self.raw)
26+
}
27+
28+
public func getErrorMessage() -> String {
29+
let cString = get_error_message(self.raw)
30+
let errorMessage = String(cString: cString!)
31+
free(cString)
32+
return errorMessage
33+
}
34+
35+
public convenience init(
36+
rpId: String, attestationFlags: UInt8, clientDataHash: Data, privateKey: String
37+
) throws {
38+
let clientDataHashPointer = UnsafeMutablePointer<UInt8>.allocate(
39+
capacity: clientDataHash.count)
2640
clientDataHash.copyBytes(to: clientDataHashPointer, count: clientDataHash.count)
2741

28-
let r = generate_credential_request_response(rpId, privateKey, attestationFlags.bigEndian, clientDataHashPointer, UInt(clientDataHash.count))
42+
let r = generate_credential_request_response(
43+
rpId, privateKey, attestationFlags.bigEndian, clientDataHashPointer,
44+
UInt(clientDataHash.count))
2945
if r == nil {
3046
throw Err(message: "Invalid parameters")
3147
} else {
3248
self.init(raw: r!)
3349
}
3450
clientDataHashPointer.deallocate()
35-
}
36-
}
51+
}
52+
}

0 commit comments

Comments
 (0)