| author | |
| committer | |
| log | 038ed32cffbb40d87d8634470e29df31b7699359 |
| tree | 7248b4e0c329644c16f0387e0af876a3f4572c04 |
| parent | 40e1fca34b2c0d2cde130fd17331a2935c473644 |
| signature |
4 files changed, 54 insertions(+), 43 deletions(-)
lib/std/crypto/Certificate.zig+21-11| ... | ... | @@ -371,7 +371,9 @@ test "Parsed.checkHostName" { |
| 371 | 371 | try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org")); |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | pub fn parse(cert: Certificate) !Parsed { | |
| 374 | pub const ParseError = der.Element.ParseElementError || ParseVersionError || ParseTimeError || ParseEnumError || ParseBitStringError; | |
| 375 | ||
| 376 | pub fn parse(cert: Certificate) ParseError!Parsed { | |
| 375 | 377 | const cert_bytes = cert.buffer; |
| 376 | 378 | const certificate = try der.Element.parse(cert_bytes, cert.index); |
| 377 | 379 | const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start); |
| ... | ... | @@ -514,14 +516,18 @@ pub fn contents(cert: Certificate, elem: der.Element) []const u8 { |
| 514 | 516 | return cert.buffer[elem.slice.start..elem.slice.end]; |
| 515 | 517 | } |
| 516 | 518 | |
| 519 | pub const ParseBitStringError = error{ CertificateFieldHasWrongDataType, CertificateHasInvalidBitString }; | |
| 520 | ||
| 517 | 521 | pub fn parseBitString(cert: Certificate, elem: der.Element) !der.Element.Slice { |
| 518 | 522 | if (elem.identifier.tag != .bitstring) return error.CertificateFieldHasWrongDataType; |
| 519 | 523 | if (cert.buffer[elem.slice.start] != 0) return error.CertificateHasInvalidBitString; |
| 520 | 524 | return .{ .start = elem.slice.start + 1, .end = elem.slice.end }; |
| 521 | 525 | } |
| 522 | 526 | |
| 527 | pub const ParseTimeError = error{ CertificateTimeInvalid, CertificateFieldHasWrongDataType }; | |
| 528 | ||
| 523 | 529 | /// Returns number of seconds since epoch. |
| 524 | pub fn parseTime(cert: Certificate, elem: der.Element) !u64 { | |
| 530 | pub fn parseTime(cert: Certificate, elem: der.Element) ParseTimeError!u64 { | |
| 525 | 531 | const bytes = cert.contents(elem); |
| 526 | 532 | switch (elem.identifier.tag) { |
| 527 | 533 | .utc_time => { |
| ... | ... | @@ -647,34 +653,38 @@ test parseYear4 { |
| 647 | 653 | try expectError(error.CertificateTimeInvalid, parseYear4("crap")); |
| 648 | 654 | } |
| 649 | 655 | |
| 650 | pub fn parseAlgorithm(bytes: []const u8, element: der.Element) !Algorithm { | |
| 656 | pub fn parseAlgorithm(bytes: []const u8, element: der.Element) ParseEnumError!Algorithm { | |
| 651 | 657 | return parseEnum(Algorithm, bytes, element); |
| 652 | 658 | } |
| 653 | 659 | |
| 654 | pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) !AlgorithmCategory { | |
| 660 | pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) ParseEnumError!AlgorithmCategory { | |
| 655 | 661 | return parseEnum(AlgorithmCategory, bytes, element); |
| 656 | 662 | } |
| 657 | 663 | |
| 658 | pub fn parseAttribute(bytes: []const u8, element: der.Element) !Attribute { | |
| 664 | pub fn parseAttribute(bytes: []const u8, element: der.Element) ParseEnumError!Attribute { | |
| 659 | 665 | return parseEnum(Attribute, bytes, element); |
| 660 | 666 | } |
| 661 | 667 | |
| 662 | pub fn parseNamedCurve(bytes: []const u8, element: der.Element) !NamedCurve { | |
| 668 | pub fn parseNamedCurve(bytes: []const u8, element: der.Element) ParseEnumError!NamedCurve { | |
| 663 | 669 | return parseEnum(NamedCurve, bytes, element); |
| 664 | 670 | } |
| 665 | 671 | |
| 666 | pub fn parseExtensionId(bytes: []const u8, element: der.Element) !ExtensionId { | |
| 672 | pub fn parseExtensionId(bytes: []const u8, element: der.Element) ParseEnumError!ExtensionId { | |
| 667 | 673 | return parseEnum(ExtensionId, bytes, element); |
| 668 | 674 | } |
| 669 | 675 | |
| 670 | fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E { | |
| 676 | pub const ParseEnumError = error{ CertificateFieldHasWrongDataType, CertificateHasUnrecognizedObjectId }; | |
| 677 | ||
| 678 | fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) ParseEnumError!E { | |
| 671 | 679 | if (element.identifier.tag != .object_identifier) |
| 672 | 680 | return error.CertificateFieldHasWrongDataType; |
| 673 | 681 | const oid_bytes = bytes[element.slice.start..element.slice.end]; |
| 674 | 682 | return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId; |
| 675 | 683 | } |
| 676 | 684 | |
| 677 | pub fn parseVersion(bytes: []const u8, version_elem: der.Element) !Version { | |
| 685 | pub const ParseVersionError = error{ UnsupportedCertificateVersion, CertificateFieldHasInvalidLength }; | |
| 686 | ||
| 687 | pub fn parseVersion(bytes: []const u8, version_elem: der.Element) ParseVersionError!Version { | |
| 678 | 688 | if (@bitCast(u8, version_elem.identifier) != 0xa0) |
| 679 | 689 | return .v1; |
| 680 | 690 | |
| ... | ... | @@ -861,9 +871,9 @@ pub const der = struct { |
| 861 | 871 | pub const empty: Slice = .{ .start = 0, .end = 0 }; |
| 862 | 872 | }; |
| 863 | 873 | |
| 864 | pub const ParseError = error{CertificateFieldHasInvalidLength}; | |
| 874 | pub const ParseElementError = error{CertificateFieldHasInvalidLength}; | |
| 865 | 875 | |
| 866 | pub fn parse(bytes: []const u8, index: u32) ParseError!Element { | |
| 876 | pub fn parse(bytes: []const u8, index: u32) ParseElementError!Element { | |
| 867 | 877 | var i = index; |
| 868 | 878 | const identifier = @bitCast(Identifier, bytes[i]); |
| 869 | 879 | i += 1; |
lib/std/crypto/Certificate/Bundle.zig+27-10| ... | ... | @@ -50,11 +50,13 @@ pub fn deinit(cb: *Bundle, gpa: Allocator) void { |
| 50 | 50 | cb.* = undefined; |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | pub const RescanError = RescanLinuxError || RescanMacError || RescanWindowsError; | |
| 54 | ||
| 53 | 55 | /// Clears the set of certificates and then scans the host operating system |
| 54 | 56 | /// file system standard locations for certificates. |
| 55 | 57 | /// For operating systems that do not have standard CA installations to be |
| 56 | 58 | /// found, this function clears the set of certificates. |
| 57 | pub fn rescan(cb: *Bundle, gpa: Allocator) !void { | |
| 59 | pub fn rescan(cb: *Bundle, gpa: Allocator) RescanError!void { | |
| 58 | 60 | switch (builtin.os.tag) { |
| 59 | 61 | .linux => return rescanLinux(cb, gpa), |
| 60 | 62 | .macos => return rescanMac(cb, gpa), |
| ... | ... | @@ -64,8 +66,11 @@ pub fn rescan(cb: *Bundle, gpa: Allocator) !void { |
| 64 | 66 | } |
| 65 | 67 | |
| 66 | 68 | pub const rescanMac = @import("Bundle/macos.zig").rescanMac; |
| 69 | pub const RescanMacError = @import("Bundle/macos.zig").RescanMacError; | |
| 70 | ||
| 71 | pub const RescanLinuxError = AddCertsFromFilePathError || AddCertsFromDirPathError; | |
| 67 | 72 | |
| 68 | pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void { | |
| 73 | pub fn rescanLinux(cb: *Bundle, gpa: Allocator) RescanLinuxError!void { | |
| 69 | 74 | // Possible certificate files; stop after finding one. |
| 70 | 75 | const cert_file_paths = [_][]const u8{ |
| 71 | 76 | "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. |
| ... | ... | @@ -107,7 +112,9 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void { |
| 107 | 112 | cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); |
| 108 | 113 | } |
| 109 | 114 | |
| 110 | pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void { | |
| 115 | pub const RescanWindowsError = Allocator.Error || ParseCertError || std.os.UnexpectedError || error{FileNotFound}; | |
| 116 | ||
| 117 | pub fn rescanWindows(cb: *Bundle, gpa: Allocator) RescanWindowsError!void { | |
| 111 | 118 | cb.bytes.clearRetainingCapacity(); |
| 112 | 119 | cb.map.clearRetainingCapacity(); |
| 113 | 120 | |
| ... | ... | @@ -132,12 +139,14 @@ pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void { |
| 132 | 139 | cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len); |
| 133 | 140 | } |
| 134 | 141 | |
| 142 | pub const AddCertsFromDirPathError = fs.File.OpenError || AddCertsFromDirError; | |
| 143 | ||
| 135 | 144 | pub fn addCertsFromDirPath( |
| 136 | 145 | cb: *Bundle, |
| 137 | 146 | gpa: Allocator, |
| 138 | 147 | dir: fs.Dir, |
| 139 | 148 | sub_dir_path: []const u8, |
| 140 | ) !void { | |
| 149 | ) AddCertsFromDirPathError!void { | |
| 141 | 150 | var iterable_dir = try dir.openIterableDir(sub_dir_path, .{}); |
| 142 | 151 | defer iterable_dir.close(); |
| 143 | 152 | return addCertsFromDir(cb, gpa, iterable_dir); |
| ... | ... | @@ -147,14 +156,16 @@ pub fn addCertsFromDirPathAbsolute( |
| 147 | 156 | cb: *Bundle, |
| 148 | 157 | gpa: Allocator, |
| 149 | 158 | abs_dir_path: []const u8, |
| 150 | ) !void { | |
| 159 | ) AddCertsFromDirPathError!void { | |
| 151 | 160 | assert(fs.path.isAbsolute(abs_dir_path)); |
| 152 | 161 | var iterable_dir = try fs.openIterableDirAbsolute(abs_dir_path, .{}); |
| 153 | 162 | defer iterable_dir.close(); |
| 154 | 163 | return addCertsFromDir(cb, gpa, iterable_dir); |
| 155 | 164 | } |
| 156 | 165 | |
| 157 | pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir) !void { | |
| 166 | pub const AddCertsFromDirError = AddCertsFromFilePathError; | |
| 167 | ||
| 168 | pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir) AddCertsFromDirError!void { | |
| 158 | 169 | var it = iterable_dir.iterate(); |
| 159 | 170 | while (try it.next()) |entry| { |
| 160 | 171 | switch (entry.kind) { |
| ... | ... | @@ -166,11 +177,13 @@ pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir |
| 166 | 177 | } |
| 167 | 178 | } |
| 168 | 179 | |
| 180 | pub const AddCertsFromFilePathError = fs.File.OpenError || AddCertsFromFileError; | |
| 181 | ||
| 169 | 182 | pub fn addCertsFromFilePathAbsolute( |
| 170 | 183 | cb: *Bundle, |
| 171 | 184 | gpa: Allocator, |
| 172 | 185 | abs_file_path: []const u8, |
| 173 | ) !void { | |
| 186 | ) AddCertsFromFilePathError!void { | |
| 174 | 187 | assert(fs.path.isAbsolute(abs_file_path)); |
| 175 | 188 | var file = try fs.openFileAbsolute(abs_file_path, .{}); |
| 176 | 189 | defer file.close(); |
| ... | ... | @@ -182,13 +195,15 @@ pub fn addCertsFromFilePath( |
| 182 | 195 | gpa: Allocator, |
| 183 | 196 | dir: fs.Dir, |
| 184 | 197 | sub_file_path: []const u8, |
| 185 | ) !void { | |
| 198 | ) AddCertsFromFilePathError!void { | |
| 186 | 199 | var file = try dir.openFile(sub_file_path, .{}); |
| 187 | 200 | defer file.close(); |
| 188 | 201 | return addCertsFromFile(cb, gpa, file); |
| 189 | 202 | } |
| 190 | 203 | |
| 191 | pub fn addCertsFromFile(cb: *Bundle, gpa: Allocator, file: fs.File) !void { | |
| 204 | pub const AddCertsFromFileError = Allocator.Error || fs.File.GetSeekPosError || fs.File.ReadError || ParseCertError || std.base64.Error || error{ CertificateAuthorityBundleTooBig, MissingEndCertificateMarker }; | |
| 205 | ||
| 206 | pub fn addCertsFromFile(cb: *Bundle, gpa: Allocator, file: fs.File) AddCertsFromFileError!void { | |
| 192 | 207 | const size = try file.getEndPos(); |
| 193 | 208 | |
| 194 | 209 | // We borrow `bytes` as a temporary buffer for the base64-encoded data. |
| ... | ... | @@ -222,7 +237,9 @@ pub fn addCertsFromFile(cb: *Bundle, gpa: Allocator, file: fs.File) !void { |
| 222 | 237 | } |
| 223 | 238 | } |
| 224 | 239 | |
| 225 | pub fn parseCert(cb: *Bundle, gpa: Allocator, decoded_start: u32, now_sec: i64) !void { | |
| 240 | pub const ParseCertError = Allocator.Error || Certificate.ParseError; | |
| 241 | ||
| 242 | pub fn parseCert(cb: *Bundle, gpa: Allocator, decoded_start: u32, now_sec: i64) ParseCertError!void { | |
| 226 | 243 | // Even though we could only partially parse the certificate to find |
| 227 | 244 | // the subject name, we pre-parse all of them to make sure and only |
| 228 | 245 | // include in the bundle ones that we know will parse. This way we can |
lib/std/crypto/Certificate/Bundle/macos.zig+3-1| ... | ... | @@ -5,7 +5,9 @@ const mem = std.mem; |
| 5 | 5 | const Allocator = std.mem.Allocator; |
| 6 | 6 | const Bundle = @import("../Bundle.zig"); |
| 7 | 7 | |
| 8 | pub fn rescanMac(cb: *Bundle, gpa: Allocator) !void { | |
| 8 | pub const RescanMacError = Allocator.Error || fs.File.OpenError || fs.File.ReadError || fs.File.SeekError || Bundle.ParseCertError || error{EndOfStream}; | |
| 9 | ||
| 10 | pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void { | |
| 9 | 11 | cb.bytes.clearRetainingCapacity(); |
| 10 | 12 | cb.map.clearRetainingCapacity(); |
| 11 | 13 |
lib/std/http/Client.zig+3-21| ... | ... | @@ -29,34 +29,16 @@ connection_pool: ConnectionPool = .{}, |
| 29 | 29 | last_error: ?ExtraError = null, |
| 30 | 30 | |
| 31 | 31 | pub const ExtraError = union(enum) { |
| 32 | fn impliedErrorSet(comptime f: anytype) type { | |
| 33 | const set = @typeInfo(@typeInfo(@TypeOf(f)).Fn.return_type.?).ErrorUnion.error_set; | |
| 34 | if (@typeName(set)[0] != '@') @compileError(@typeName(f) ++ " doesn't have an implied error set any more."); | |
| 35 | return set; | |
| 36 | } | |
| 37 | ||
| 38 | // There's apparently a dependency loop with using Client.DeflateDecompressor. | |
| 39 | const FakeTransferError = proto.HeadersParser.ReadError || error{ReadFailed}; | |
| 40 | const FakeTransferReader = std.io.Reader(void, FakeTransferError, fakeRead); | |
| 41 | fn fakeRead(ctx: void, buf: []u8) FakeTransferError!usize { | |
| 42 | _ = .{ buf, ctx }; | |
| 43 | return 0; | |
| 44 | } | |
| 45 | ||
| 46 | const FakeDeflateDecompressor = std.compress.zlib.ZlibStream(FakeTransferReader); | |
| 47 | const FakeGzipDecompressor = std.compress.gzip.Decompress(FakeTransferReader); | |
| 48 | const FakeZstdDecompressor = std.compress.zstd.DecompressStream(FakeTransferReader, .{}); | |
| 49 | ||
| 50 | 32 | pub const TcpConnectError = std.net.TcpConnectToHostError; |
| 51 | 33 | pub const TlsError = std.crypto.tls.Client.InitError(net.Stream); |
| 52 | 34 | pub const WriteError = BufferedConnection.WriteError; |
| 53 | 35 | pub const ReadError = BufferedConnection.ReadError || error{HttpChunkInvalid}; |
| 54 | pub const CaBundleError = impliedErrorSet(std.crypto.Certificate.Bundle.rescan); | |
| 36 | pub const CaBundleError = std.crypto.Certificate.Bundle.RescanError; | |
| 55 | 37 | |
| 56 | 38 | pub const ZlibInitError = error{ BadHeader, InvalidCompression, InvalidWindowSize, Unsupported, EndOfStream, OutOfMemory } || Request.TransferReadError; |
| 57 | 39 | pub const GzipInitError = error{ BadHeader, InvalidCompression, OutOfMemory, WrongChecksum, EndOfStream, StreamTooLong } || Request.TransferReadError; |
| 58 | // pub const DecompressError = Client.DeflateDecompressor.Error || Client.GzipDecompressor.Error || Client.ZstdDecompressor.Error; | |
| 59 | pub const DecompressError = FakeDeflateDecompressor.Error || FakeGzipDecompressor.Error || FakeZstdDecompressor.Error; | |
| 40 | // pub const DecompressError = Compression.DeflateDecompressor.Error || Compression.GzipDecompressor.Error || Compression.ZstdDecompressor.Error; | |
| 41 | pub const DecompressError = anyerror; // FIXME: the above line causes a false positive dependency loop | |
| 60 | 42 | |
| 61 | 43 | zlib_init: ZlibInitError, // error.CompressionInitializationFailed |
| 62 | 44 | gzip_init: GzipInitError, // error.CompressionInitializationFailed |