| author | |
| committer | |
| log | f4b4e570d87c53d31cb4bee27b0468bdc8b826ae |
| tree | 2b8af517d767df8cddc6476e1adc30f88f3e99e0 |
| parent | d56a65a8c4609a740eee43fd7073c2485c87c2c6 |
| parent | d35d086ae6206b706c9116d0376cabbdf6a25650 |
| signature |
windows root certificate scanning5 files changed, 208 insertions(+), 34 deletions(-)
lib/std/crypto/Certificate.zig+49-2| ... | ... | @@ -15,6 +15,8 @@ pub const Algorithm = enum { |
| 15 | 15 | ecdsa_with_SHA256, |
| 16 | 16 | ecdsa_with_SHA384, |
| 17 | 17 | ecdsa_with_SHA512, |
| 18 | md2WithRSAEncryption, | |
| 19 | md5WithRSAEncryption, | |
| 18 | 20 | |
| 19 | 21 | pub const map = std.ComptimeStringMap(Algorithm, .{ |
| 20 | 22 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption }, |
| ... | ... | @@ -26,6 +28,8 @@ pub const Algorithm = enum { |
| 26 | 28 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }, .ecdsa_with_SHA256 }, |
| 27 | 29 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 }, .ecdsa_with_SHA384 }, |
| 28 | 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 | }); |
| 30 | 34 | |
| 31 | 35 | pub fn Hash(comptime algorithm: Algorithm) type { |
| ... | ... | @@ -35,6 +39,8 @@ pub const Algorithm = enum { |
| 35 | 39 | .ecdsa_with_SHA256, .sha256WithRSAEncryption => crypto.hash.sha2.Sha256, |
| 36 | 40 | .ecdsa_with_SHA384, .sha384WithRSAEncryption => crypto.hash.sha2.Sha384, |
| 37 | 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 | 61 | countryName, |
| 56 | 62 | localityName, |
| 57 | 63 | stateOrProvinceName, |
| 64 | streetAddress, | |
| 58 | 65 | organizationName, |
| 59 | 66 | organizationalUnitName, |
| 67 | postalCode, | |
| 60 | 68 | organizationIdentifier, |
| 61 | 69 | pkcs9_emailAddress, |
| 70 | domainComponent, | |
| 62 | 71 | |
| 63 | 72 | pub const map = std.ComptimeStringMap(Attribute, .{ |
| 64 | 73 | .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName }, |
| ... | ... | @@ -66,19 +75,24 @@ pub const Attribute = enum { |
| 66 | 75 | .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName }, |
| 67 | 76 | .{ &[_]u8{ 0x55, 0x04, 0x07 }, .localityName }, |
| 68 | 77 | .{ &[_]u8{ 0x55, 0x04, 0x08 }, .stateOrProvinceName }, |
| 78 | .{ &[_]u8{ 0x55, 0x04, 0x09 }, .streetAddress }, | |
| 69 | 79 | .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName }, |
| 70 | 80 | .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName }, |
| 81 | .{ &[_]u8{ 0x55, 0x04, 0x11 }, .postalCode }, | |
| 71 | 82 | .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier }, |
| 72 | 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 | }; |
| 75 | 87 | |
| 76 | 88 | pub const NamedCurve = enum { |
| 77 | 89 | secp384r1, |
| 90 | secp521r1, | |
| 78 | 91 | X9_62_prime256v1, |
| 79 | 92 | |
| 80 | 93 | pub const map = std.ComptimeStringMap(NamedCurve, .{ |
| 81 | 94 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 }, |
| 95 | .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 }, | |
| 82 | 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 | 107 | crl_number, |
| 94 | 108 | certificate_policies, |
| 95 | 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, | |
| 96 | 120 | |
| 97 | 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 | 125 | .{ &[_]u8{ 0x55, 0x1D, 0x0E }, .subject_key_identifier }, |
| 99 | 126 | .{ &[_]u8{ 0x55, 0x1D, 0x0F }, .key_usage }, |
| 127 | .{ &[_]u8{ 0x55, 0x1D, 0x0A }, .basic_constraints }, | |
| 100 | 128 | .{ &[_]u8{ 0x55, 0x1D, 0x10 }, .private_key_usage_period }, |
| 101 | 129 | .{ &[_]u8{ 0x55, 0x1D, 0x11 }, .subject_alt_name }, |
| 102 | 130 | .{ &[_]u8{ 0x55, 0x1D, 0x12 }, .issuer_alt_name }, |
| 103 | 131 | .{ &[_]u8{ 0x55, 0x1D, 0x13 }, .basic_constraints }, |
| 104 | 132 | .{ &[_]u8{ 0x55, 0x1D, 0x14 }, .crl_number }, |
| 133 | .{ &[_]u8{ 0x55, 0x1D, 0x1F }, .crl_distribution_points }, | |
| 105 | 134 | .{ &[_]u8{ 0x55, 0x1D, 0x20 }, .certificate_policies }, |
| 106 | 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 | }; |
| 109 | 146 | |
| ... | ... | @@ -238,6 +275,10 @@ pub const Parsed = struct { |
| 238 | 275 | parsed_issuer.pub_key_algo, |
| 239 | 276 | parsed_issuer.pubKey(), |
| 240 | 277 | ), |
| 278 | ||
| 279 | .md2WithRSAEncryption, .md5WithRSAEncryption => { | |
| 280 | return error.CertificateSignatureAlgorithmUnsupported; | |
| 281 | }, | |
| 241 | 282 | } |
| 242 | 283 | } |
| 243 | 284 | |
| ... | ... | @@ -354,13 +395,16 @@ pub fn parse(cert: Certificate) !Parsed { |
| 354 | 395 | var atav_i = atav.slice.start; |
| 355 | 396 | while (atav_i < atav.slice.end) { |
| 356 | 397 | const ty_elem = try der.Element.parse(cert_bytes, atav_i); |
| 357 | const ty = try parseAttribute(cert_bytes, ty_elem); | |
| 358 | 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 | 404 | switch (ty) { |
| 360 | 405 | .commonName => common_name = val.slice, |
| 361 | 406 | else => {}, |
| 362 | 407 | } |
| 363 | atav_i = val.slice.end; | |
| 364 | 408 | } |
| 365 | 409 | rdn_i = atav.slice.end; |
| 366 | 410 | } |
| ... | ... | @@ -712,6 +756,9 @@ fn verify_ecdsa( |
| 712 | 756 | }; |
| 713 | 757 | |
| 714 | 758 | switch (sig_named_curve) { |
| 759 | .secp521r1 => { | |
| 760 | return error.CertificateSignatureNamedCurveUnsupported; | |
| 761 | }, | |
| 715 | 762 | .secp384r1 => { |
| 716 | 763 | const P = crypto.ecc.P384; |
| 717 | 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 | 57 | pub fn rescan(cb: *Bundle, gpa: Allocator) !void { |
| 58 | 58 | switch (builtin.os.tag) { |
| 59 | 59 | .linux => return rescanLinux(cb, gpa), |
| 60 | .windows => { | |
| 61 | // TODO | |
| 62 | }, | |
| 63 | 60 | .macos => return rescanMac(cb, gpa), |
| 61 | .windows => return rescanWindows(cb, gpa), | |
| 64 | 62 | else => {}, |
| 65 | 63 | } |
| 66 | 64 | } |
| ... | ... | @@ -109,6 +107,38 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void { |
| 109 | 107 | cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); |
| 110 | 108 | } |
| 111 | 109 | |
| 110 | pub 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 | ||
| 112 | 142 | pub fn addCertsFromDirPath( |
| 113 | 143 | cb: *Bundle, |
| 114 | 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 | 746 | const arena = result.arena.allocator(); |
| 747 | 747 | errdefer result.deinit(); |
| 748 | 748 | |
| 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 | 822 | const name_c = try std.cstr.addNullByte(allocator, name); |
| 751 | 823 | defer allocator.free(name_c); |
| 752 | 824 | |
| ... | ... | @@ -765,19 +837,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A |
| 765 | 837 | .next = null, |
| 766 | 838 | }; |
| 767 | 839 | var res: *os.addrinfo = undefined; |
| 768 | const rc = 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) { | |
| 840 | switch (sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) { | |
| 781 | 841 | @intToEnum(sys.EAI, 0) => {}, |
| 782 | 842 | .ADDRFAMILY => return error.HostLacksNetworkAddresses, |
| 783 | 843 | .AGAIN => return error.TemporaryNameServerFailure, |
| ... | ... | @@ -824,6 +884,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) !*A |
| 824 | 884 | |
| 825 | 885 | return result; |
| 826 | 886 | } |
| 887 | ||
| 827 | 888 | if (builtin.target.os.tag == .linux) { |
| 828 | 889 | const flags = std.c.AI.NUMERICSERV; |
| 829 | 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 | 28 | pub const ws2_32 = @import("windows/ws2_32.zig"); |
| 29 | 29 | pub const gdi32 = @import("windows/gdi32.zig"); |
| 30 | 30 | pub const winmm = @import("windows/winmm.zig"); |
| 31 | pub const crypt32 = @import("windows/crypt32.zig"); | |
| 31 | 32 | |
| 32 | 33 | pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize)); |
| 33 | 34 | |
| ... | ... | @@ -1295,6 +1296,23 @@ pub fn WSACleanup() !void { |
| 1295 | 1296 | |
| 1296 | 1297 | var wsa_startup_mutex: std.Thread.Mutex = .{}; |
| 1297 | 1298 | |
| 1299 | pub 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 | 1316 | /// Microsoft requires WSAStartup to be called to initialize, or else |
| 1299 | 1317 | /// WSASocketW will return WSANOTINITIALISED. |
| 1300 | 1318 | /// Since this is a standard library, we do not have the luxury of |
| ... | ... | @@ -1337,21 +1355,7 @@ pub fn WSASocketW( |
| 1337 | 1355 | .WSANOTINITIALISED => { |
| 1338 | 1356 | if (!first) return error.Unexpected; |
| 1339 | 1357 | first = false; |
| 1340 | ||
| 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 | }; | |
| 1358 | try callWSAStartup(); | |
| 1355 | 1359 | continue; |
| 1356 | 1360 | }, |
| 1357 | 1361 | else => |err| return unexpectedWSAError(err), |
lib/std/os/windows/crypt32.zig created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | const std = @import("../../std.zig"); | |
| 2 | const windows = std.os.windows; | |
| 3 | const BOOL = windows.BOOL; | |
| 4 | const DWORD = windows.DWORD; | |
| 5 | const BYTE = windows.BYTE; | |
| 6 | const LPCWSTR = windows.LPCWSTR; | |
| 7 | const WINAPI = windows.WINAPI; | |
| 8 | ||
| 9 | pub const CERT_INFO = *opaque {}; | |
| 10 | pub const HCERTSTORE = *opaque {}; | |
| 11 | pub const CERT_CONTEXT = extern struct { | |
| 12 | dwCertEncodingType: DWORD, | |
| 13 | pbCertEncoded: [*]BYTE, | |
| 14 | cbCertEncoded: DWORD, | |
| 15 | pCertInfo: CERT_INFO, | |
| 16 | hCertStore: HCERTSTORE, | |
| 17 | }; | |
| 18 | ||
| 19 | pub extern "crypt32" fn CertOpenSystemStoreW( | |
| 20 | _: ?*const anyopaque, | |
| 21 | szSubsystemProtocol: LPCWSTR, | |
| 22 | ) callconv(WINAPI) ?HCERTSTORE; | |
| 23 | ||
| 24 | pub extern "crypt32" fn CertCloseStore( | |
| 25 | hCertStore: HCERTSTORE, | |
| 26 | dwFlags: DWORD, | |
| 27 | ) callconv(WINAPI) BOOL; | |
| 28 | ||
| 29 | pub extern "crypt32" fn CertEnumCertificatesInStore( | |
| 30 | hCertStore: HCERTSTORE, | |
| 31 | pPrevCertContext: ?*CERT_CONTEXT, | |
| 32 | ) callconv(WINAPI) ?*CERT_CONTEXT; |