diff --git a/src/Database.zig b/src/Database.zig index c7b6cdf..02383d5 100644 --- a/src/Database.zig +++ b/src/Database.zig @@ -46,3 +46,8 @@ setCredential: *const fn ( *const Self, data: Credential, ) Error!void, + +deleteCredential: *const fn ( + *const Self, + id: [36]u8, +) Error!void, diff --git a/src/cred_mgmt.zig b/src/cred_mgmt.zig index a2c42f8..b133976 100644 --- a/src/cred_mgmt.zig +++ b/src/cred_mgmt.zig @@ -4,6 +4,8 @@ const keylib = @import("keylib"); const Request = @import("cred_mgmt/Request.zig"); const Response = @import("cred_mgmt/Response.zig"); +const State = @import("state.zig"); + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; pub fn authenticatorCredentialManagement( @@ -56,6 +58,7 @@ pub fn authenticatorCredentialManagement( .enumerateRPsGetNextRP => enumerateRPsGetNextRP(&status, S), .enumerateCredentialsBegin => enumerateCredentialsBegin(auth, &cmReq, &status, S), .enumerateCredentialsGetNextCredential => enumerateCredentialsGetNextCredential(auth, &status), + .deleteCredential => deleteCredential(auth, &cmReq, &status, S), else => error.ctap2_err_other, } catch { return .ctap1_err_other; @@ -297,3 +300,60 @@ pub fn enumerateCredentialsGetNextCredential(auth: *keylib.ctap.authenticator.Au .credProtect = cred.policy, }; } + +pub fn deleteCredential(auth: *keylib.ctap.authenticator.Auth, req: *const Request, status: *keylib.ctap.StatusCodes, state: anytype) Response { + if (req.pinUvAuthParam == null) { + status.* = .ctap2_err_missing_parameter; + return .{}; + } + if (req.pinUvAuthProtocol == null) { + status.* = .ctap2_err_missing_parameter; + return .{}; + } + if (req.subCommandParams == null or req.subCommandParams.?.credentialID == null) { + status.* = .ctap2_err_missing_parameter; + return .{}; + } + if (req.pinUvAuthProtocol.? != auth.token.version) { + status.* = .ctap1_err_invalid_parameter; + return .{}; + } + + var m = std.ArrayList(u8).init(state.allocator); + defer m.deinit(); + m.append(0x06) catch { + status.* = .ctap1_err_other; + return .{}; + }; + cbor.stringify( + req.subCommandParams.?, + .{}, + m.writer(), + ) catch { + status.* = .ctap1_err_other; + return .{}; + }; + + if (!auth.token.verify_token(m.items, req.pinUvAuthParam.?.get())) { + status.* = .ctap2_err_pin_auth_invalid; + return .{}; + } + + if (auth.token.permissions & 0x04 == 0) { + status.* = .ctap2_err_pin_auth_invalid; + return .{}; + } + + const id = req.subCommandParams.?.credentialID.?.id.get(); + if (id.len != 36) { + status.* = .ctap2_err_no_credentials; + return .{}; + } + + State.database.?.deleteCredential(&State.database.?, id[0..36].*) catch { + status.* = .ctap2_err_no_credentials; + return .{}; + }; + + return .{}; +} diff --git a/src/database/ccdb.zig b/src/database/ccdb.zig index a0bfcbe..80e26f9 100644 --- a/src/database/ccdb.zig +++ b/src/database/ccdb.zig @@ -21,6 +21,7 @@ pub fn Database( .save = save, .getCredential = getCredential, .setCredential = setCredential, + .deleteCredential = deleteCredential, }; } @@ -80,6 +81,23 @@ fn save(self: *const TDatabase, a: std.mem.Allocator) TDatabase.Error!void { }; } +fn deleteCredential( + self: *const TDatabase, + id: [36]u8, +) TDatabase.Error!void { + const db = @as(*ccdb.Db, @alignCast(@ptrCast(self.db.?))); + + db.body.deleteEntryById(id) catch |e| { + std.log.err("Cannot to delete entry with id: {s} ({any})", .{ id, e }); + return error.DoesNotExist; + }; + + // persist data + save(self, self.allocator) catch { + return error.Other; + }; +} + fn getCredential( self: *const TDatabase, rp_id: ?[]const u8, diff --git a/src/main.zig b/src/main.zig index 6c1497e..02c121e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -396,6 +396,8 @@ pub fn my_delete( id: [*c]const u8, ) callconv(.C) Error { _ = id; + // TODO: remove this from keylib! + return Error.Other; }