Commit 038ed32cff
Changed files (4)
lib
std
crypto
Certificate
Bundle
http
lib/std/crypto/Certificate/Bundle/macos.zig
@@ -5,7 +5,9 @@ const mem = std.mem;
const Allocator = std.mem.Allocator;
const Bundle = @import("../Bundle.zig");
-pub fn rescanMac(cb: *Bundle, gpa: Allocator) !void {
+pub const RescanMacError = Allocator.Error || fs.File.OpenError || fs.File.ReadError || fs.File.SeekError || Bundle.ParseCertError || error{EndOfStream};
+
+pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void {
cb.bytes.clearRetainingCapacity();
cb.map.clearRetainingCapacity();
lib/std/crypto/Certificate/Bundle.zig
@@ -50,11 +50,13 @@ pub fn deinit(cb: *Bundle, gpa: Allocator) void {
cb.* = undefined;
}
+pub const RescanError = RescanLinuxError || RescanMacError || RescanWindowsError;
+
/// Clears the set of certificates and then scans the host operating system
/// file system standard locations for certificates.
/// For operating systems that do not have standard CA installations to be
/// found, this function clears the set of certificates.
-pub fn rescan(cb: *Bundle, gpa: Allocator) !void {
+pub fn rescan(cb: *Bundle, gpa: Allocator) RescanError!void {
switch (builtin.os.tag) {
.linux => return rescanLinux(cb, gpa),
.macos => return rescanMac(cb, gpa),
@@ -64,8 +66,11 @@ pub fn rescan(cb: *Bundle, gpa: Allocator) !void {
}
pub const rescanMac = @import("Bundle/macos.zig").rescanMac;
+pub const RescanMacError = @import("Bundle/macos.zig").RescanMacError;
+
+pub const RescanLinuxError = AddCertsFromFilePathError || AddCertsFromDirPathError;
-pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void {
+pub fn rescanLinux(cb: *Bundle, gpa: Allocator) RescanLinuxError!void {
// Possible certificate files; stop after finding one.
const cert_file_paths = [_][]const u8{
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
@@ -107,7 +112,9 @@ pub fn rescanLinux(cb: *Bundle, gpa: Allocator) !void {
cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
}
-pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void {
+pub const RescanWindowsError = Allocator.Error || ParseCertError || std.os.UnexpectedError || error{FileNotFound};
+
+pub fn rescanWindows(cb: *Bundle, gpa: Allocator) RescanWindowsError!void {
cb.bytes.clearRetainingCapacity();
cb.map.clearRetainingCapacity();
@@ -132,12 +139,14 @@ pub fn rescanWindows(cb: *Bundle, gpa: Allocator) !void {
cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
}
+pub const AddCertsFromDirPathError = fs.File.OpenError || AddCertsFromDirError;
+
pub fn addCertsFromDirPath(
cb: *Bundle,
gpa: Allocator,
dir: fs.Dir,
sub_dir_path: []const u8,
-) !void {
+) AddCertsFromDirPathError!void {
var iterable_dir = try dir.openIterableDir(sub_dir_path, .{});
defer iterable_dir.close();
return addCertsFromDir(cb, gpa, iterable_dir);
@@ -147,14 +156,16 @@ pub fn addCertsFromDirPathAbsolute(
cb: *Bundle,
gpa: Allocator,
abs_dir_path: []const u8,
-) !void {
+) AddCertsFromDirPathError!void {
assert(fs.path.isAbsolute(abs_dir_path));
var iterable_dir = try fs.openIterableDirAbsolute(abs_dir_path, .{});
defer iterable_dir.close();
return addCertsFromDir(cb, gpa, iterable_dir);
}
-pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir) !void {
+pub const AddCertsFromDirError = AddCertsFromFilePathError;
+
+pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir) AddCertsFromDirError!void {
var it = iterable_dir.iterate();
while (try it.next()) |entry| {
switch (entry.kind) {
@@ -166,11 +177,13 @@ pub fn addCertsFromDir(cb: *Bundle, gpa: Allocator, iterable_dir: fs.IterableDir
}
}
+pub const AddCertsFromFilePathError = fs.File.OpenError || AddCertsFromFileError;
+
pub fn addCertsFromFilePathAbsolute(
cb: *Bundle,
gpa: Allocator,
abs_file_path: []const u8,
-) !void {
+) AddCertsFromFilePathError!void {
assert(fs.path.isAbsolute(abs_file_path));
var file = try fs.openFileAbsolute(abs_file_path, .{});
defer file.close();
@@ -182,13 +195,15 @@ pub fn addCertsFromFilePath(
gpa: Allocator,
dir: fs.Dir,
sub_file_path: []const u8,
-) !void {
+) AddCertsFromFilePathError!void {
var file = try dir.openFile(sub_file_path, .{});
defer file.close();
return addCertsFromFile(cb, gpa, file);
}
-pub fn addCertsFromFile(cb: *Bundle, gpa: Allocator, file: fs.File) !void {
+pub const AddCertsFromFileError = Allocator.Error || fs.File.GetSeekPosError || fs.File.ReadError || ParseCertError || std.base64.Error || error{ CertificateAuthorityBundleTooBig, MissingEndCertificateMarker };
+
+pub fn addCertsFromFile(cb: *Bundle, gpa: Allocator, file: fs.File) AddCertsFromFileError!void {
const size = try file.getEndPos();
// 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 {
}
}
-pub fn parseCert(cb: *Bundle, gpa: Allocator, decoded_start: u32, now_sec: i64) !void {
+pub const ParseCertError = Allocator.Error || Certificate.ParseError;
+
+pub fn parseCert(cb: *Bundle, gpa: Allocator, decoded_start: u32, now_sec: i64) ParseCertError!void {
// Even though we could only partially parse the certificate to find
// the subject name, we pre-parse all of them to make sure and only
// include in the bundle ones that we know will parse. This way we can
lib/std/crypto/Certificate.zig
@@ -371,7 +371,9 @@ test "Parsed.checkHostName" {
try expectEqual(false, Parsed.checkHostName("lang.org", "zig*.org"));
}
-pub fn parse(cert: Certificate) !Parsed {
+pub const ParseError = der.Element.ParseElementError || ParseVersionError || ParseTimeError || ParseEnumError || ParseBitStringError;
+
+pub fn parse(cert: Certificate) ParseError!Parsed {
const cert_bytes = cert.buffer;
const certificate = try der.Element.parse(cert_bytes, cert.index);
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 {
return cert.buffer[elem.slice.start..elem.slice.end];
}
+pub const ParseBitStringError = error{ CertificateFieldHasWrongDataType, CertificateHasInvalidBitString };
+
pub fn parseBitString(cert: Certificate, elem: der.Element) !der.Element.Slice {
if (elem.identifier.tag != .bitstring) return error.CertificateFieldHasWrongDataType;
if (cert.buffer[elem.slice.start] != 0) return error.CertificateHasInvalidBitString;
return .{ .start = elem.slice.start + 1, .end = elem.slice.end };
}
+pub const ParseTimeError = error{ CertificateTimeInvalid, CertificateFieldHasWrongDataType };
+
/// Returns number of seconds since epoch.
-pub fn parseTime(cert: Certificate, elem: der.Element) !u64 {
+pub fn parseTime(cert: Certificate, elem: der.Element) ParseTimeError!u64 {
const bytes = cert.contents(elem);
switch (elem.identifier.tag) {
.utc_time => {
@@ -647,34 +653,38 @@ test parseYear4 {
try expectError(error.CertificateTimeInvalid, parseYear4("crap"));
}
-pub fn parseAlgorithm(bytes: []const u8, element: der.Element) !Algorithm {
+pub fn parseAlgorithm(bytes: []const u8, element: der.Element) ParseEnumError!Algorithm {
return parseEnum(Algorithm, bytes, element);
}
-pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) !AlgorithmCategory {
+pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) ParseEnumError!AlgorithmCategory {
return parseEnum(AlgorithmCategory, bytes, element);
}
-pub fn parseAttribute(bytes: []const u8, element: der.Element) !Attribute {
+pub fn parseAttribute(bytes: []const u8, element: der.Element) ParseEnumError!Attribute {
return parseEnum(Attribute, bytes, element);
}
-pub fn parseNamedCurve(bytes: []const u8, element: der.Element) !NamedCurve {
+pub fn parseNamedCurve(bytes: []const u8, element: der.Element) ParseEnumError!NamedCurve {
return parseEnum(NamedCurve, bytes, element);
}
-pub fn parseExtensionId(bytes: []const u8, element: der.Element) !ExtensionId {
+pub fn parseExtensionId(bytes: []const u8, element: der.Element) ParseEnumError!ExtensionId {
return parseEnum(ExtensionId, bytes, element);
}
-fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E {
+pub const ParseEnumError = error{ CertificateFieldHasWrongDataType, CertificateHasUnrecognizedObjectId };
+
+fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) ParseEnumError!E {
if (element.identifier.tag != .object_identifier)
return error.CertificateFieldHasWrongDataType;
const oid_bytes = bytes[element.slice.start..element.slice.end];
return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId;
}
-pub fn parseVersion(bytes: []const u8, version_elem: der.Element) !Version {
+pub const ParseVersionError = error{ UnsupportedCertificateVersion, CertificateFieldHasInvalidLength };
+
+pub fn parseVersion(bytes: []const u8, version_elem: der.Element) ParseVersionError!Version {
if (@bitCast(u8, version_elem.identifier) != 0xa0)
return .v1;
@@ -861,9 +871,9 @@ pub const der = struct {
pub const empty: Slice = .{ .start = 0, .end = 0 };
};
- pub const ParseError = error{CertificateFieldHasInvalidLength};
+ pub const ParseElementError = error{CertificateFieldHasInvalidLength};
- pub fn parse(bytes: []const u8, index: u32) ParseError!Element {
+ pub fn parse(bytes: []const u8, index: u32) ParseElementError!Element {
var i = index;
const identifier = @bitCast(Identifier, bytes[i]);
i += 1;
lib/std/http/Client.zig
@@ -29,34 +29,16 @@ connection_pool: ConnectionPool = .{},
last_error: ?ExtraError = null,
pub const ExtraError = union(enum) {
- fn impliedErrorSet(comptime f: anytype) type {
- const set = @typeInfo(@typeInfo(@TypeOf(f)).Fn.return_type.?).ErrorUnion.error_set;
- if (@typeName(set)[0] != '@') @compileError(@typeName(f) ++ " doesn't have an implied error set any more.");
- return set;
- }
-
- // There's apparently a dependency loop with using Client.DeflateDecompressor.
- const FakeTransferError = proto.HeadersParser.ReadError || error{ReadFailed};
- const FakeTransferReader = std.io.Reader(void, FakeTransferError, fakeRead);
- fn fakeRead(ctx: void, buf: []u8) FakeTransferError!usize {
- _ = .{ buf, ctx };
- return 0;
- }
-
- const FakeDeflateDecompressor = std.compress.zlib.ZlibStream(FakeTransferReader);
- const FakeGzipDecompressor = std.compress.gzip.Decompress(FakeTransferReader);
- const FakeZstdDecompressor = std.compress.zstd.DecompressStream(FakeTransferReader, .{});
-
pub const TcpConnectError = std.net.TcpConnectToHostError;
pub const TlsError = std.crypto.tls.Client.InitError(net.Stream);
pub const WriteError = BufferedConnection.WriteError;
pub const ReadError = BufferedConnection.ReadError || error{HttpChunkInvalid};
- pub const CaBundleError = impliedErrorSet(std.crypto.Certificate.Bundle.rescan);
+ pub const CaBundleError = std.crypto.Certificate.Bundle.RescanError;
pub const ZlibInitError = error{ BadHeader, InvalidCompression, InvalidWindowSize, Unsupported, EndOfStream, OutOfMemory } || Request.TransferReadError;
pub const GzipInitError = error{ BadHeader, InvalidCompression, OutOfMemory, WrongChecksum, EndOfStream, StreamTooLong } || Request.TransferReadError;
- // pub const DecompressError = Client.DeflateDecompressor.Error || Client.GzipDecompressor.Error || Client.ZstdDecompressor.Error;
- pub const DecompressError = FakeDeflateDecompressor.Error || FakeGzipDecompressor.Error || FakeZstdDecompressor.Error;
+ // pub const DecompressError = Compression.DeflateDecompressor.Error || Compression.GzipDecompressor.Error || Compression.ZstdDecompressor.Error;
+ pub const DecompressError = anyerror; // FIXME: the above line causes a false positive dependency loop
zlib_init: ZlibInitError, // error.CompressionInitializationFailed
gzip_init: GzipInitError, // error.CompressionInitializationFailed