Skip to content

Read System.keychain as well as SystemRootCertificates.keychain for MacOS CA Bundle #22701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 44 additions & 37 deletions lib/std/crypto/Certificate/Bundle/macos.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,68 @@ 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 keychainPaths = [2][]const u8{
"/System/Library/Keychains/SystemRootCertificates.keychain",
"/Library/Keychains/System.keychain",
};

const bytes = try file.readToEndAlloc(gpa, std.math.maxInt(u32));
defer gpa.free(bytes);
for (keychainPaths) |keychainPath| {
const file = try fs.openFileAbsolute(keychainPath, .{});
defer file.close();

var stream = std.io.fixedBufferStream(bytes);
const reader = stream.reader();
const bytes = try file.readToEndAlloc(gpa, std.math.maxInt(u32));
defer gpa.free(bytes);

const db_header = try reader.readStructEndian(ApplDbHeader, .big);
assert(mem.eql(u8, &db_header.signature, "kych"));
var stream = std.io.fixedBufferStream(bytes);
const reader = stream.reader();

try stream.seekTo(db_header.schema_offset);
const db_header = try reader.readStructEndian(ApplDbHeader, .big);
assert(mem.eql(u8, &db_header.signature, "kych"));

const db_schema = try reader.readStructEndian(ApplDbSchema, .big);
try stream.seekTo(db_header.schema_offset);

var table_list = try gpa.alloc(u32, db_schema.table_count);
defer gpa.free(table_list);
const db_schema = try reader.readStructEndian(ApplDbSchema, .big);

var table_idx: u32 = 0;
while (table_idx < table_list.len) : (table_idx += 1) {
table_list[table_idx] = try reader.readInt(u32, .big);
}
var table_list = try gpa.alloc(u32, db_schema.table_count);
defer gpa.free(table_list);

const now_sec = std.time.timestamp();
var table_idx: u32 = 0;
while (table_idx < table_list.len) : (table_idx += 1) {
table_list[table_idx] = try reader.readInt(u32, .big);
}

for (table_list) |table_offset| {
try stream.seekTo(db_header.schema_offset + table_offset);
const now_sec = std.time.timestamp();

const table_header = try reader.readStructEndian(TableHeader, .big);
for (table_list) |table_offset| {
try stream.seekTo(db_header.schema_offset + table_offset);

if (@as(std.c.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) {
continue;
}
const table_header = try reader.readStructEndian(TableHeader, .big);

var record_list = try gpa.alloc(u32, table_header.record_count);
defer gpa.free(record_list);
if (@as(std.c.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) {
continue;
}

var record_idx: u32 = 0;
while (record_idx < record_list.len) : (record_idx += 1) {
record_list[record_idx] = try reader.readInt(u32, .big);
}
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.readInt(u32, .big);
}

for (record_list) |record_offset| {
try stream.seekTo(db_header.schema_offset + table_offset + record_offset);
for (record_list) |record_offset| {
try stream.seekTo(db_header.schema_offset + table_offset + record_offset);

const cert_header = try reader.readStructEndian(X509CertHeader, .big);
const cert_header = try reader.readStructEndian(X509CertHeader, .big);

try cb.bytes.ensureUnusedCapacity(gpa, cert_header.cert_size);
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);
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);
try cb.parseCert(gpa, cert_start, now_sec);
}
}
}

Expand Down
Loading