authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-17 07:35:25-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-17 07:35:25-05:00
logf4b4e570d87c53d31cb4bee27b0468bdc8b826ae
tree2b8af517d767df8cddc6476e1adc30f88f3e99e0
parentd56a65a8c4609a740eee43fd7073c2485c87c2c6
parentd35d086ae6206b706c9116d0376cabbdf6a25650
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14229 from star-tek-mb/wincerts

windows root certificate scanning

5 files changed, 208 insertions(+), 34 deletions(-)

lib/std/crypto/Certificate.zig+49-2
...@@ -15,6 +15,8 @@ pub const Algorithm = enum {...@@ -15,6 +15,8 @@ pub const Algorithm = enum {
15 ecdsa_with_SHA256,15 ecdsa_with_SHA256,
16 ecdsa_with_SHA384,16 ecdsa_with_SHA384,
17 ecdsa_with_SHA512,17 ecdsa_with_SHA512,
18 md2WithRSAEncryption,
19 md5WithRSAEncryption,
1820
19 pub const map = std.ComptimeStringMap(Algorithm, .{21 pub const map = std.ComptimeStringMap(Algorithm, .{
20 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption },22 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption },
...@@ -26,6 +28,8 @@ pub const Algorithm = enum {...@@ -26,6 +28,8 @@ pub const Algorithm = enum {
26 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }, .ecdsa_with_SHA256 },28 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }, .ecdsa_with_SHA256 },
27 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 }, .ecdsa_with_SHA384 },29 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 }, .ecdsa_with_SHA384 },
28 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 },30 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 },
31 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02 }, .md2WithRSAEncryption },
32 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 }, .md5WithRSAEncryption },
29 });33 });
3034
31 pub fn Hash(comptime algorithm: Algorithm) type {35 pub fn Hash(comptime algorithm: Algorithm) type {
...@@ -35,6 +39,8 @@ pub const Algorithm = enum {...@@ -35,6 +39,8 @@ pub const Algorithm = enum {
35 .ecdsa_with_SHA256, .sha256WithRSAEncryption => crypto.hash.sha2.Sha256,39 .ecdsa_with_SHA256, .sha256WithRSAEncryption => crypto.hash.sha2.Sha256,
36 .ecdsa_with_SHA384, .sha384WithRSAEncryption => crypto.hash.sha2.Sha384,40 .ecdsa_with_SHA384, .sha384WithRSAEncryption => crypto.hash.sha2.Sha384,
37 .ecdsa_with_SHA512, .sha512WithRSAEncryption => crypto.hash.sha2.Sha512,41 .ecdsa_with_SHA512, .sha512WithRSAEncryption => crypto.hash.sha2.Sha512,
42 .md2WithRSAEncryption => @compileError("unimplemented"),
43 .md5WithRSAEncryption => crypto.hash.Md5,
38 };44 };
39 }45 }
40};46};
...@@ -55,10 +61,13 @@ pub const Attribute = enum {...@@ -55,10 +61,13 @@ pub const Attribute = enum {
55 countryName,61 countryName,
56 localityName,62 localityName,
57 stateOrProvinceName,63 stateOrProvinceName,
64 streetAddress,
58 organizationName,65 organizationName,
59 organizationalUnitName,66 organizationalUnitName,
67 postalCode,
60 organizationIdentifier,68 organizationIdentifier,
61 pkcs9_emailAddress,69 pkcs9_emailAddress,
70 domainComponent,
6271
63 pub const map = std.ComptimeStringMap(Attribute, .{72 pub const map = std.ComptimeStringMap(Attribute, .{
64 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },73 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },
...@@ -66,19 +75,24 @@ pub const Attribute = enum {...@@ -66,19 +75,24 @@ pub const Attribute = enum {
66 .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName },75 .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName },
67 .{ &[_]u8{ 0x55, 0x04, 0x07 }, .localityName },76 .{ &[_]u8{ 0x55, 0x04, 0x07 }, .localityName },
68 .{ &[_]u8{ 0x55, 0x04, 0x08 }, .stateOrProvinceName },77 .{ &[_]u8{ 0x55, 0x04, 0x08 }, .stateOrProvinceName },
78 .{ &[_]u8{ 0x55, 0x04, 0x09 }, .streetAddress },
69 .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName },79 .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName },
70 .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName },80 .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName },
81 .{ &[_]u8{ 0x55, 0x04, 0x11 }, .postalCode },
71 .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier },82 .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier },
72 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01 }, .pkcs9_emailAddress },83 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01 }, .pkcs9_emailAddress },
84 .{ &[_]u8{ 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 }, .domainComponent },
73 });85 });
74};86};
7587
76pub const NamedCurve = enum {88pub const NamedCurve = enum {
77 secp384r1,89 secp384r1,
90 secp521r1,
78 X9_62_prime256v1,91 X9_62_prime256v1,
7992
80 pub const map = std.ComptimeStringMap(NamedCurve, .{93 pub const map = std.ComptimeStringMap(NamedCurve, .{
81 .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 },94 .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 },
95 .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 },
82 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 },96 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 },
83 });97 });
84};98};
...@@ -93,17 +107,40 @@ pub const ExtensionId = enum {...@@ -93,17 +107,40 @@ pub const ExtensionId = enum {
93 crl_number,107 crl_number,
94 certificate_policies,108 certificate_policies,
95 authority_key_identifier,109 authority_key_identifier,
110 msCertsrvCAVersion,
111 commonName,
112 ext_key_usage,
113 crl_distribution_points,
114 info_access,
115 entrustVersInfo,
116 enroll_certtype,
117 pe_logotype,
118 netscape_cert_type,
119 netscape_comment,
96120
97 pub const map = std.ComptimeStringMap(ExtensionId, .{121 pub const map = std.ComptimeStringMap(ExtensionId, .{
122 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },
123 .{ &[_]u8{ 0x55, 0x1D, 0x01 }, .authority_key_identifier },
124 .{ &[_]u8{ 0x55, 0x1D, 0x07 }, .subject_alt_name },
98 .{ &[_]u8{ 0x55, 0x1D, 0x0E }, .subject_key_identifier },125 .{ &[_]u8{ 0x55, 0x1D, 0x0E }, .subject_key_identifier },
99 .{ &[_]u8{ 0x55, 0x1D, 0x0F }, .key_usage },126 .{ &[_]u8{ 0x55, 0x1D, 0x0F }, .key_usage },
127 .{ &[_]u8{ 0x55, 0x1D, 0x0A }, .basic_constraints },
100 .{ &[_]u8{ 0x55, 0x1D, 0x10 }, .private_key_usage_period },128 .{ &[_]u8{ 0x55, 0x1D, 0x10 }, .private_key_usage_period },
101 .{ &[_]u8{ 0x55, 0x1D, 0x11 }, .subject_alt_name },129 .{ &[_]u8{ 0x55, 0x1D, 0x11 }, .subject_alt_name },
102 .{ &[_]u8{ 0x55, 0x1D, 0x12 }, .issuer_alt_name },130 .{ &[_]u8{ 0x55, 0x1D, 0x12 }, .issuer_alt_name },
103 .{ &[_]u8{ 0x55, 0x1D, 0x13 }, .basic_constraints },131 .{ &[_]u8{ 0x55, 0x1D, 0x13 }, .basic_constraints },
104 .{ &[_]u8{ 0x55, 0x1D, 0x14 }, .crl_number },132 .{ &[_]u8{ 0x55, 0x1D, 0x14 }, .crl_number },
133 .{ &[_]u8{ 0x55, 0x1D, 0x1F }, .crl_distribution_points },
105 .{ &[_]u8{ 0x55, 0x1D, 0x20 }, .certificate_policies },134 .{ &[_]u8{ 0x55, 0x1D, 0x20 }, .certificate_policies },
106 .{ &[_]u8{ 0x55, 0x1D, 0x23 }, .authority_key_identifier },135 .{ &[_]u8{ 0x55, 0x1D, 0x23 }, .authority_key_identifier },
136 .{ &[_]u8{ 0x55, 0x1D, 0x25 }, .ext_key_usage },
137 .{ &[_]u8{ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01 }, .msCertsrvCAVersion },
138 .{ &[_]u8{ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 }, .info_access },
139 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF6, 0x7D, 0x07, 0x41, 0x00 }, .entrustVersInfo },
140 .{ &[_]u8{ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02 }, .enroll_certtype },
141 .{ &[_]u8{ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c }, .pe_logotype },
142 .{ &[_]u8{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01 }, .netscape_cert_type },
143 .{ &[_]u8{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d }, .netscape_comment },
107 });144 });
108};145};
109146
...@@ -238,6 +275,10 @@ pub const Parsed = struct {...@@ -238,6 +275,10 @@ pub const Parsed = struct {
238 parsed_issuer.pub_key_algo,275 parsed_issuer.pub_key_algo,
239 parsed_issuer.pubKey(),276 parsed_issuer.pubKey(),
240 ),277 ),
278
279 .md2WithRSAEncryption, .md5WithRSAEncryption => {
280 return error.CertificateSignatureAlgorithmUnsupported;
281 },
241 }282 }
242 }283 }
243284
...@@ -354,13 +395,16 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -354,13 +395,16 @@ pub fn parse(cert: Certificate) !Parsed {
354 var atav_i = atav.slice.start;395 var atav_i = atav.slice.start;
355 while (atav_i < atav.slice.end) {396 while (atav_i < atav.slice.end) {
356 const ty_elem = try der.Element.parse(cert_bytes, atav_i);397 const ty_elem = try der.Element.parse(cert_bytes, atav_i);
357 const ty = try parseAttribute(cert_bytes, ty_elem);
358 const val = try der.Element.parse(cert_bytes, ty_elem.slice.end);398 const val = try der.Element.parse(cert_bytes, ty_elem.slice.end);
399 atav_i = val.slice.end;
400 const ty = parseAttribute(cert_bytes, ty_elem) catch |err| switch (err) {
401 error.CertificateHasUnrecognizedObjectId => continue,
402 else => |e| return e,
403 };
359 switch (ty) {404 switch (ty) {
360 .commonName => common_name = val.slice,405 .commonName => common_name = val.slice,
361 else => {},406 else => {},
362 }407 }
363 atav_i = val.slice.end;
364 }408 }
365 rdn_i = atav.slice.end;409 rdn_i = atav.slice.end;
366 }410 }
...@@ -712,6 +756,9 @@ fn verify_ecdsa(...@@ -712,6 +756,9 @@ fn verify_ecdsa(
712 };756 };
713757
714 switch (sig_named_curve) {758 switch (sig_named_curve) {
759 .secp521r1 => {
760 return error.CertificateSignatureNamedCurveUnsupported;
761 },
715 .secp384r1 => {762 .secp384r1 => {
716 const P = crypto.ecc.P384;763 const P = crypto.ecc.P384;
717 const Ecdsa = crypto.sign.ecdsa.Ecdsa(P, Hash);764 const Ecdsa = crypto.sign.ecdsa.Ecdsa(P, Hash);
lib/std/crypto/Certificate/Bundle.zig+33-3
...@@ -57,10 +57,8 @@ pub fn deinit(cb: *Bundle, gpa: Allocator) void {...@@ -57,10 +57,8 @@ pub fn deinit(cb: *Bundle, gpa: Allocator) void {
57pub fn rescan(cb: *Bundle, gpa: Allocator) !void {57pub fn rescan(cb: *Bundle, gpa: Allocator) !void {
58 switch (builtin.os.tag) {58 switch (builtin.os.tag) {
59 .linux => return rescanLinux(cb, gpa),59 .linux => return rescanLinux(cb, gpa),
60 .windows => {
61 // TODO
62 },
63 .macos => return rescanMac(cb, gpa),60 .macos => return rescanMac(cb, gpa),
61 .windows => return rescanWindows(cb, gpa),
64 else => {},62 else => {},
65 }63 }
66}64}
...@@ -109,6 +107,38 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void {...@@ -109,6 +107,38 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void {
109 cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);107 cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
110}108}
111109
110pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void {
111 cb.bytes.clearRetainingCapacity();
112 cb.map.clearRetainingCapacity();
113
114 const w = std.os.windows;
115 const GetLastError = w.kernel32.GetLastError;
116 const root = [4:0]u16{ 'R', 'O', 'O', 'T' };
117 const store = w.crypt32.CertOpenSystemStoreW(null, &root) orelse switch (GetLastError()) {
118 .FILE_NOT_FOUND => return error.FileNotFound,
119 else => |err| return w.unexpectedError(err),
120 };
121 defer _ = w.crypt32.CertCloseStore(store, 0);
122
123 var ctx = w.crypt32.CertEnumCertificatesInStore(store, null);
124 while (ctx) |context| : (ctx = w.crypt32.CertEnumCertificatesInStore(store, ctx)) {
125 const decoded_start = @intCast(u32, cb.bytes.items.len);
126 const encoded_cert = context.pbCertEncoded[0..context.cbCertEncoded];
127 try cb.bytes.appendSlice(gpa, encoded_cert);
128 const parsed_cert = try Certificate.parse(.{
129 .buffer = cb.bytes.items,
130 .index = decoded_start,
131 });
132 const gop = try cb.map.getOrPutContext(gpa, parsed_cert.subject_slice, .{ .cb = cb });
133 if (gop.found_existing) {
134 cb.bytes.items.len = decoded_start;
135 } else {
136 gop.value_ptr.* = decoded_start;
137 }
138 }
139 cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
140}
141
112pub fn addCertsFromDirPath(142pub fn addCertsFromDirPath(
113 cb: *Bundle,143 cb: *Bundle,
114 gpa: Allocator,144 gpa: Allocator,
lib/std/net.zig+75-14
...@@ -746,7 +746,79 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A...@@ -746,7 +746,79 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
746 const arena = result.arena.allocator();746 const arena = result.arena.allocator();
747 errdefer result.deinit();747 errdefer result.deinit();
748748
749 if (builtin.target.os.tag == .windows or builtin.link_libc) {749 if (builtin.target.os.tag == .windows) {
750 const name_c = try std.cstr.addNullByte(allocator, name);
751 defer allocator.free(name_c);
752
753 const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
754 defer allocator.free(port_c);
755
756 const ws2_32 = os.windows.ws2_32;
757 const hints = os.addrinfo{
758 .flags = ws2_32.AI.NUMERICSERV,
759 .family = os.AF.UNSPEC,
760 .socktype = os.SOCK.STREAM,
761 .protocol = os.IPPROTO.TCP,
762 .canonname = null,
763 .addr = null,
764 .addrlen = 0,
765 .next = null,
766 };
767 var res: *os.addrinfo = undefined;
768 var first = true;
769 while (true) {
770 const rc = ws2_32.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);
771 switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
772 @intToEnum(os.windows.ws2_32.WinsockError, 0) => break,
773 .WSATRY_AGAIN => return error.TemporaryNameServerFailure,
774 .WSANO_RECOVERY => return error.NameServerFailure,
775 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
776 .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
777 .WSAHOST_NOT_FOUND => return error.UnknownHostName,
778 .WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
779 .WSAEINVAL => unreachable,
780 .WSAESOCKTNOSUPPORT => unreachable,
781 .WSANOTINITIALISED => {
782 if (!first) return error.Unexpected;
783 first = false;
784 try os.windows.callWSAStartup();
785 continue;
786 },
787 else => |err| return os.windows.unexpectedWSAError(err),
788 }
789 }
790 defer ws2_32.freeaddrinfo(res);
791
792 const addr_count = blk: {
793 var count: usize = 0;
794 var it: ?*os.addrinfo = res;
795 while (it) |info| : (it = info.next) {
796 if (info.addr != null) {
797 count += 1;
798 }
799 }
800 break :blk count;
801 };
802 result.addrs = try arena.alloc(Address, addr_count);
803
804 var it: ?*os.addrinfo = res;
805 var i: usize = 0;
806 while (it) |info| : (it = info.next) {
807 const addr = info.addr orelse continue;
808 result.addrs[i] = Address.initPosix(@alignCast(4, addr));
809
810 if (info.canonname) |n| {
811 if (result.canon_name == null) {
812 result.canon_name = try arena.dupe(u8, mem.sliceTo(n, 0));
813 }
814 }
815 i += 1;
816 }
817
818 return result;
819 }
820
821 if (builtin.link_libc) {
750 const name_c = try std.cstr.addNullByte(allocator, name);822 const name_c = try std.cstr.addNullByte(allocator, name);
751 defer allocator.free(name_c);823 defer allocator.free(name_c);
752824
...@@ -765,19 +837,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A...@@ -765,19 +837,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
765 .next = null,837 .next = null,
766 };838 };
767 var res: *os.addrinfo = undefined;839 var res: *os.addrinfo = undefined;
768 const rc = sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);840 switch (sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
769 if (builtin.target.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) {
770 @intToEnum(os.windows.ws2_32.WinsockError, 0) => {},
771 .WSATRY_AGAIN => return error.TemporaryNameServerFailure,
772 .WSANO_RECOVERY => return error.NameServerFailure,
773 .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
774 .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory,
775 .WSAHOST_NOT_FOUND => return error.UnknownHostName,
776 .WSATYPE_NOT_FOUND => return error.ServiceUnavailable,
777 .WSAEINVAL => unreachable,
778 .WSAESOCKTNOSUPPORT => unreachable,
779 else => |err| return os.windows.unexpectedWSAError(err),
780 } else switch (rc) {
781 @intToEnum(sys.EAI, 0) => {},841 @intToEnum(sys.EAI, 0) => {},
782 .ADDRFAMILY => return error.HostLacksNetworkAddresses,842 .ADDRFAMILY => return error.HostLacksNetworkAddresses,
783 .AGAIN => return error.TemporaryNameServerFailure,843 .AGAIN => return error.TemporaryNameServerFailure,
...@@ -824,6 +884,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A...@@ -824,6 +884,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A
824884
825 return result;885 return result;
826 }886 }
887
827 if (builtin.target.os.tag == .linux) {888 if (builtin.target.os.tag == .linux) {
828 const flags = std.c.AI.NUMERICSERV;889 const flags = std.c.AI.NUMERICSERV;
829 const family = os.AF.UNSPEC;890 const family = os.AF.UNSPEC;
lib/std/os/windows.zig+19-15
...@@ -28,6 +28,7 @@ pub const user32 = @import("windows/user32.zig");...@@ -28,6 +28,7 @@ pub const user32 = @import("windows/user32.zig");
28pub const ws2_32 = @import("windows/ws2_32.zig");28pub const ws2_32 = @import("windows/ws2_32.zig");
29pub const gdi32 = @import("windows/gdi32.zig");29pub const gdi32 = @import("windows/gdi32.zig");
30pub const winmm = @import("windows/winmm.zig");30pub const winmm = @import("windows/winmm.zig");
31pub const crypt32 = @import("windows/crypt32.zig");
3132
32pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));33pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));
3334
...@@ -1295,6 +1296,23 @@ pub fn WSACleanup() !void {...@@ -1295,6 +1296,23 @@ pub fn WSACleanup() !void {
12951296
1296var wsa_startup_mutex: std.Thread.Mutex = .{};1297var wsa_startup_mutex: std.Thread.Mutex = .{};
12971298
1299pub fn callWSAStartup() !void {
1300 wsa_startup_mutex.lock();
1301 defer wsa_startup_mutex.unlock();
1302
1303 // Here we could use a flag to prevent multiple threads to prevent
1304 // multiple calls to WSAStartup, but it doesn't matter. We're globally
1305 // leaking the resource intentionally, and the mutex already prevents
1306 // data races within the WSAStartup function.
1307 _ = WSAStartup(2, 2) catch |err| switch (err) {
1308 error.SystemNotAvailable => return error.SystemResources,
1309 error.VersionNotSupported => return error.Unexpected,
1310 error.BlockingOperationInProgress => return error.Unexpected,
1311 error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
1312 error.Unexpected => return error.Unexpected,
1313 };
1314}
1315
1298/// Microsoft requires WSAStartup to be called to initialize, or else1316/// Microsoft requires WSAStartup to be called to initialize, or else
1299/// WSASocketW will return WSANOTINITIALISED.1317/// WSASocketW will return WSANOTINITIALISED.
1300/// Since this is a standard library, we do not have the luxury of1318/// Since this is a standard library, we do not have the luxury of
...@@ -1337,21 +1355,7 @@ pub fn WSASocketW(...@@ -1337,21 +1355,7 @@ pub fn WSASocketW(
1337 .WSANOTINITIALISED => {1355 .WSANOTINITIALISED => {
1338 if (!first) return error.Unexpected;1356 if (!first) return error.Unexpected;
1339 first = false;1357 first = false;
13401358 try callWSAStartup();
1341 wsa_startup_mutex.lock();
1342 defer wsa_startup_mutex.unlock();
1343
1344 // Here we could use a flag to prevent multiple threads to prevent
1345 // multiple calls to WSAStartup, but it doesn't matter. We're globally
1346 // leaking the resource intentionally, and the mutex already prevents
1347 // data races within the WSAStartup function.
1348 _ = WSAStartup(2, 2) catch |err| switch (err) {
1349 error.SystemNotAvailable => return error.SystemResources,
1350 error.VersionNotSupported => return error.Unexpected,
1351 error.BlockingOperationInProgress => return error.Unexpected,
1352 error.ProcessFdQuotaExceeded => return error.ProcessFdQuotaExceeded,
1353 error.Unexpected => return error.Unexpected,
1354 };
1355 continue;1359 continue;
1356 },1360 },
1357 else => |err| return unexpectedWSAError(err),1361 else => |err| return unexpectedWSAError(err),
lib/std/os/windows/crypt32.zig created+32
...@@ -0,0 +1,32 @@
1const std = @import("../../std.zig");
2const windows = std.os.windows;
3const BOOL = windows.BOOL;
4const DWORD = windows.DWORD;
5const BYTE = windows.BYTE;
6const LPCWSTR = windows.LPCWSTR;
7const WINAPI = windows.WINAPI;
8
9pub const CERT_INFO = *opaque {};
10pub const HCERTSTORE = *opaque {};
11pub const CERT_CONTEXT = extern struct {
12 dwCertEncodingType: DWORD,
13 pbCertEncoded: [*]BYTE,
14 cbCertEncoded: DWORD,
15 pCertInfo: CERT_INFO,
16 hCertStore: HCERTSTORE,
17};
18
19pub extern "crypt32" fn CertOpenSystemStoreW(
20 _: ?*const anyopaque,
21 szSubsystemProtocol: LPCWSTR,
22) callconv(WINAPI) ?HCERTSTORE;
23
24pub extern "crypt32" fn CertCloseStore(
25 hCertStore: HCERTSTORE,
26 dwFlags: DWORD,
27) callconv(WINAPI) BOOL;
28
29pub extern "crypt32" fn CertEnumCertificatesInStore(
30 hCertStore: HCERTSTORE,
31 pPrevCertContext: ?*CERT_CONTEXT,
32) callconv(WINAPI) ?*CERT_CONTEXT;