diff --git a/readme.md b/readme.md index 0001f65..898ef50 100644 --- a/readme.md +++ b/readme.md @@ -22,7 +22,7 @@ pub fn main() !void { var client = HttpClient{ .allocator = allocator }; defer client.deinit(); - const url = "https://bing.com"; + const url = "https://httpbin.org"; const uri = try std.Uri.parse(url); var headers = std.http.Headers{ .allocator = allocator }; diff --git a/src/crypto/Bundle.zig b/src/crypto/Bundle.zig index c3cabbd..3ab090c 100644 --- a/src/crypto/Bundle.zig +++ b/src/crypto/Bundle.zig @@ -68,8 +68,8 @@ pub fn rescan(cb: *Bundle, gpa: Allocator) RescanError!void { } } -const rescanMac = std.crypto.Certificate.Bundle.rescan; -const RescanMacError = std.crypto.Certificate.Bundle.RescanError; +const rescanMac = @import("Bundle/macos.zig").rescanMac; +const RescanMacError = @import("Bundle/macos.zig").RescanMacError; const RescanLinuxError = AddCertsFromFilePathError || AddCertsFromDirPathError; diff --git a/src/crypto/Bundle/macos.zig b/src/crypto/Bundle/macos.zig new file mode 100644 index 0000000..028275a --- /dev/null +++ b/src/crypto/Bundle/macos.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const assert = std.debug.assert; +const fs = std.fs; +const mem = std.mem; +const Allocator = std.mem.Allocator; +const Bundle = @import("../Bundle.zig"); + +pub const RescanMacError = Allocator.Error || fs.File.OpenError || fs.File.ReadError || fs.File.SeekError || Bundle.ParseCertError || error{EndOfStream}; + +pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void { + cb.bytes.clearRetainingCapacity(); + cb.map.clearRetainingCapacity(); + + const file = try fs.openFileAbsolute("/System/Library/Keychains/SystemRootCertificates.keychain", .{}); + defer file.close(); + + const bytes = try file.readToEndAlloc(gpa, std.math.maxInt(u32)); + defer gpa.free(bytes); + + var stream = std.io.fixedBufferStream(bytes); + const reader = stream.reader(); + + const db_header = try reader.readStructBig(ApplDbHeader); + assert(mem.eql(u8, "kych", &@as([4]u8, @bitCast(db_header.signature)))); + + try stream.seekTo(db_header.schema_offset); + + const db_schema = try reader.readStructBig(ApplDbSchema); + + var table_list = try gpa.alloc(u32, db_schema.table_count); + defer gpa.free(table_list); + + var table_idx: u32 = 0; + while (table_idx < table_list.len) : (table_idx += 1) { + table_list[table_idx] = try reader.readIntBig(u32); + } + + const now_sec = std.time.timestamp(); + + for (table_list) |table_offset| { + try stream.seekTo(db_header.schema_offset + table_offset); + + const table_header = try reader.readStructBig(TableHeader); + + if (@as(std.os.darwin.cssm.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) { + continue; + } + + var record_list = try gpa.alloc(u32, table_header.record_count); + defer gpa.free(record_list); + + var record_idx: u32 = 0; + while (record_idx < record_list.len) : (record_idx += 1) { + record_list[record_idx] = try reader.readIntBig(u32); + } + + for (record_list) |record_offset| { + try stream.seekTo(db_header.schema_offset + table_offset + record_offset); + + const cert_header = try reader.readStructBig(X509CertHeader); + + try cb.bytes.ensureUnusedCapacity(gpa, cert_header.cert_size); + + const cert_start = @as(u32, @intCast(cb.bytes.items.len)); + const dest_buf = cb.bytes.allocatedSlice()[cert_start..]; + cb.bytes.items.len += try reader.readAtLeast(dest_buf, cert_header.cert_size); + + try cb.parseCert(gpa, cert_start, now_sec); + } + } + + cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); +} + +const ApplDbHeader = extern struct { + signature: @Vector(4, u8), + version: u32, + header_size: u32, + schema_offset: u32, + auth_offset: u32, +}; + +const ApplDbSchema = extern struct { + schema_size: u32, + table_count: u32, +}; + +const TableHeader = extern struct { + table_size: u32, + table_id: u32, + record_count: u32, + records: u32, + indexes_offset: u32, + free_list_head: u32, + record_numbers_count: u32, +}; + +const X509CertHeader = extern struct { + record_size: u32, + record_number: u32, + unknown1: u32, + unknown2: u32, + cert_size: u32, + unknown3: u32, + cert_type: u32, + cert_encoding: u32, + print_name: u32, + alias: u32, + subject: u32, + issuer: u32, + serial_number: u32, + subject_key_identifier: u32, + public_key_hash: u32, +}; diff --git a/src/example.zig b/src/example.zig index 2d5367b..ab06183 100644 --- a/src/example.zig +++ b/src/example.zig @@ -9,7 +9,7 @@ pub fn main() !void { var client = HttpClient{ .allocator = allocator }; defer client.deinit(); - const url = "https://bing.com"; + const url = "https://httpbin.org"; const uri = try std.Uri.parse(url); var headers = std.http.Headers{ .allocator = allocator };