Commit 1f9fa82235

star-tek-mb <noob.tek.mb@gmail.com>
2023-01-06 18:41:55
windows root certificate scanning
1 parent d56a65a
Changed files (3)
lib
std
crypto
Certificate
os
lib/std/crypto/Certificate/Bundle.zig
@@ -57,10 +57,8 @@ pub fn deinit(cb: *Bundle, gpa: Allocator) void {
 pub fn rescan(cb: *Bundle, gpa: Allocator) !void {
     switch (builtin.os.tag) {
         .linux => return rescanLinux(cb, gpa),
-        .windows => {
-            // TODO
-        },
         .macos => return rescanMac(cb, gpa),
+        .windows => return rescanWindows(cb, gpa),
         else => {},
     }
 }
@@ -109,6 +107,34 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void {
     cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
 }
 
+pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void {
+    cb.bytes.clearRetainingCapacity();
+    cb.map.clearRetainingCapacity();
+
+    const store = try os.windows.crypt32.certOpenSystemStoreW(null, &[4:0]u16{ 'R', 'O', 'O', 'T' });
+    defer os.windows.crypt32.certCloseStore(store, 0) catch unreachable;
+
+    var ctx = os.windows.crypt32.CertEnumCertificatesInStore(store, null);
+    while (ctx) |context| : (ctx = os.windows.crypt32.CertEnumCertificatesInStore(store, ctx)) {
+        var start = @intCast(u32, cb.bytes.items.len);
+        try cb.bytes.appendSlice(gpa, context.pbCertEncoded[0..context.cbCertEncoded]);
+        var parsed = Certificate.parse(.{
+            .buffer = cb.bytes.items,
+            .index = start,
+        }) catch {
+            cb.bytes.items.len = start;
+            continue;
+        };
+        const gop = try cb.map.getOrPutContext(gpa, parsed.subject_slice, .{ .cb = cb });
+        if (gop.found_existing) {
+            cb.bytes.items.len = start;
+        } else {
+            gop.value_ptr.* = start;
+        }
+    }
+    cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
+}
+
 pub fn addCertsFromDirPath(
     cb: *Bundle,
     gpa: Allocator,
@@ -224,6 +250,7 @@ pub fn parseCert(cb: *Bundle, gpa: Allocator, decoded_start: u32, now_sec: i64)
 const builtin = @import("builtin");
 const std = @import("../../std.zig");
 const assert = std.debug.assert;
+const os = std.os;
 const fs = std.fs;
 const mem = std.mem;
 const crypto = std.crypto;
lib/std/os/windows/crypt32.zig
@@ -0,0 +1,54 @@
+const std = @import("../../std.zig");
+const windows = std.os.windows;
+const BOOL = windows.BOOL;
+const DWORD = windows.DWORD;
+const BYTE = windows.BYTE;
+const LPCWSTR = windows.LPCWSTR;
+const WINAPI = windows.WINAPI;
+const GetLastError = windows.kernel32.GetLastError;
+
+pub const CERT_INFO = *opaque {};
+pub const HCERTSTORE = *opaque {};
+pub const CERT_CONTEXT = extern struct {
+    dwCertEncodingType: DWORD,
+    pbCertEncoded: [*]BYTE,
+    cbCertEncoded: DWORD,
+    pCertInfo: CERT_INFO,
+    hCertStore: HCERTSTORE,
+};
+
+pub extern "crypt32" fn CertOpenSystemStoreW(
+    _: ?*const anyopaque,
+    szSubsystemProtocol: LPCWSTR,
+) callconv(WINAPI) ?HCERTSTORE;
+pub fn certOpenSystemStoreW(
+    hProv: ?*const anyopaque,
+    szSubsystemProtocol: LPCWSTR,
+) !HCERTSTORE {
+    const value = CertOpenSystemStoreW(hProv, szSubsystemProtocol);
+    return if (value) |store|
+        store
+    else switch (GetLastError()) {
+        .FILE_NOT_FOUND => error.FileNotFound,
+        else => |err| windows.unexpectedError(err),
+    };
+}
+
+pub extern "crypt32" fn CertCloseStore(
+    hCertStore: HCERTSTORE,
+    dwFlags: DWORD,
+) callconv(WINAPI) BOOL;
+pub fn certCloseStore(
+    hCertStore: HCERTSTORE,
+    dwFlags: DWORD,
+) !void {
+    const value = CertCloseStore(hCertStore, dwFlags);
+    if (value == 0) {
+        return windows.unexpectedError(GetLastError());
+    }
+}
+
+pub extern "crypt32" fn CertEnumCertificatesInStore(
+    hCertStore: HCERTSTORE,
+    pPrevCertContext: ?*CERT_CONTEXT,
+) callconv(WINAPI) ?*CERT_CONTEXT;
lib/std/os/windows.zig
@@ -28,6 +28,7 @@ pub const user32 = @import("windows/user32.zig");
 pub const ws2_32 = @import("windows/ws2_32.zig");
 pub const gdi32 = @import("windows/gdi32.zig");
 pub const winmm = @import("windows/winmm.zig");
+pub const crypt32 = @import("windows/crypt32.zig");
 
 pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));