aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-23 16:15:36 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-23 16:15:36 -0700
commit1b9061989002467897fd25ac0284f50be67485d2 (patch)
tree678fa9c321d5fa8c9ab3c17f709cf17e5bf822f8
parent0ea34216de6452b1b1d4dcd8b2da9ba74ee60b26 (diff)
downloadbun-1b9061989002467897fd25ac0284f50be67485d2.tar.gz
bun-1b9061989002467897fd25ac0284f50be67485d2.tar.zst
bun-1b9061989002467897fd25ac0284f50be67485d2.zip
[internal] :scissors: dead code
-rw-r--r--src/ast/ast.ts153
-rw-r--r--src/bundler.zig1
-rw-r--r--src/deps/iguanaTLS/.gitattributes1
-rw-r--r--src/deps/iguanaTLS/.gitignore3
-rw-r--r--src/deps/iguanaTLS/.gitmodules0
-rw-r--r--src/deps/iguanaTLS/LICENSE21
-rw-r--r--src/deps/iguanaTLS/build.zig14
-rw-r--r--src/deps/iguanaTLS/src/asn1.zig631
-rw-r--r--src/deps/iguanaTLS/src/ciphersuites.zig446
-rw-r--r--src/deps/iguanaTLS/src/crypto.zig1016
-rw-r--r--src/deps/iguanaTLS/src/main.zig2216
-rw-r--r--src/deps/iguanaTLS/src/pcks1-1_5.zig209
-rw-r--r--src/deps/iguanaTLS/src/x509.zig1053
-rw-r--r--src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem20
-rw-r--r--src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem22
-rw-r--r--src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem23
-rw-r--r--src/deps/iguanaTLS/test/badssl.com-client.pem61
-rw-r--r--src/deps/iguanaTLS/test/github.derbin969 -> 0 bytes
-rw-r--r--src/deps/iguanaTLS/test/github.pem23
-rw-r--r--src/feature_flags.zig8
-rw-r--r--src/fs_impl.zig10
-rw-r--r--src/fs_impl_native.zig3
-rw-r--r--src/fs_impl_wasm.zig0
-rw-r--r--src/global_name_parser.zig0
-rw-r--r--src/hash_map_v2.zig1822
-rw-r--r--src/http_client.zig1
-rw-r--r--src/javascript/jsc/config.zig2
-rw-r--r--src/javascript/jsc/javascript.zig1
-rw-r--r--src/javascript/jsc/new.zig0
-rw-r--r--src/javascript/jsc/node_env_buf_map.zig151
-rw-r--r--src/linker.zig2
-rw-r--r--src/thread_safe_hash_map.zig58
32 files changed, 0 insertions, 7971 deletions
diff --git a/src/ast/ast.ts b/src/ast/ast.ts
deleted file mode 100644
index 2ab25644d..000000000
--- a/src/ast/ast.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-class BunASTNode {
- position = -1;
-}
-globalThis.BunASTNode = BunASTNode;
-// hint to JS engine to store it as a f64
-const NullPtrValue = Number.MAX_SAFE_INTEGER;
-const bindings = globalThis.BunASTBindings;
-
-const BunAST = {
- EArray: class EArray extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EUnary: class EUnary extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EBinary: class EBinary extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EClass: class EClass extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ENew: class ENew extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EFunction: class EFunction extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ECall: class ECall extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EDot: class EDot extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EIndex: class EIndex extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EArrow: class EArrow extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EIdentifier: class EIdentifier extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EImportIdentifier: class EImportIdentifier extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EPrivateIdentifier: class EPrivateIdentifier extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EJsxElement: class EJsxElement extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EObject: class EObject extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ESpread: class ESpread extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ETemplatePart: class ETemplatePart extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ETemplate: class ETemplate extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ERegExp: class ERegExp extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EAwait: class EAwait extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EYield: class EYield extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EIf: class EIf extends BunASTNode {
- no = NullPtrValue;
- yes = NullPtrValue;
- test = NullPtrValue;
- },
- ERequire: class ERequire extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EImport: class EImport extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EBoolean: class EBoolean extends BunASTNode {
- val = false;
- },
- ENumber: class ENumber extends BunASTNode {
- val = 0;
- },
- EBigInt: class EBigInt extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EString: class EString extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EMissing: class EMissing extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EThis: class EThis extends BunASTNode {},
- ESuper: class ESuper extends BunASTNode {
- #ptr = NullPtrValue;
- },
- ENull: class ENull extends BunASTNode {},
- EUndefined: class EUndefined extends BunASTNode {},
- ENewTarget: class ENewTarget extends BunASTNode {
- #ptr = NullPtrValue;
- },
- EImportMeta: class EImportMeta extends BunASTNode {},
- SImport: class SImport extends BunASTNode {
- #ptr = NullPtrValue;
- },
-};
-globalThis.BunAST = BunAST;
-const bunTags = [
- BunAST.EArray,
- BunAST.EUnary,
- BunAST.EBinary,
- BunAST.EClass,
- BunAST.ENew,
- BunAST.EFunction,
- BunAST.ECall,
- BunAST.EDot,
- BunAST.EIndex,
- BunAST.EArrow,
- BunAST.EIdentifier,
- BunAST.EImportIdentifier,
- BunAST.EPrivateIdentifier,
- BunAST.EJsxElement,
- BunAST.EObject,
- BunAST.ESpread,
- BunAST.ETemplatePart,
- BunAST.ETemplate,
- BunAST.ERegExp,
- BunAST.EAwait,
- BunAST.EYield,
- BunAST.EIf,
- BunAST.ERequire,
- BunAST.EImport,
- BunAST.EBoolean,
- BunAST.ENumber,
- BunAST.EBigInt,
- BunAST.EString,
- BunAST.EMissing,
- BunAST.EThis,
- BunAST.ESuper,
- BunAST.ENull,
- BunAST.EUndefined,
- BunAST.ENewTarget,
- BunAST.EImportMeta,
- BunAST.SImport,
-];
-globalThis.bunTags = bunTags;
-
diff --git a/src/bundler.zig b/src/bundler.zig
index 17c1ade2a..5ff273d75 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -18,7 +18,6 @@ const schema = @import("api/schema.zig");
const Api = schema.Api;
const _resolver = @import("./resolver/resolver.zig");
const sync = @import("sync.zig");
-const ThreadSafeHashMap = @import("./thread_safe_hash_map.zig");
const ImportRecord = @import("./import_record.zig").ImportRecord;
const allocators = @import("./allocators.zig");
const MimeType = @import("./http/mime_type.zig");
diff --git a/src/deps/iguanaTLS/.gitattributes b/src/deps/iguanaTLS/.gitattributes
deleted file mode 100644
index 0cb064aeb..000000000
--- a/src/deps/iguanaTLS/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.zig text=auto eol=lf
diff --git a/src/deps/iguanaTLS/.gitignore b/src/deps/iguanaTLS/.gitignore
deleted file mode 100644
index b78ba5f90..000000000
--- a/src/deps/iguanaTLS/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/zig-cache
-deps.zig
-gyro.lock
diff --git a/src/deps/iguanaTLS/.gitmodules b/src/deps/iguanaTLS/.gitmodules
deleted file mode 100644
index e69de29bb..000000000
--- a/src/deps/iguanaTLS/.gitmodules
+++ /dev/null
diff --git a/src/deps/iguanaTLS/LICENSE b/src/deps/iguanaTLS/LICENSE
deleted file mode 100644
index f830ca857..000000000
--- a/src/deps/iguanaTLS/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 Alexandros Naskos
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/src/deps/iguanaTLS/build.zig b/src/deps/iguanaTLS/build.zig
deleted file mode 100644
index 9aed4bf0d..000000000
--- a/src/deps/iguanaTLS/build.zig
+++ /dev/null
@@ -1,14 +0,0 @@
-const Builder = @import("std").build.Builder;
-
-pub fn build(b: *Builder) void {
- const mode = b.standardReleaseOptions();
- const lib = b.addStaticLibrary("iguanaTLS", "src/main.zig");
- lib.setBuildMode(mode);
- lib.install();
-
- var main_tests = b.addTest("src/main.zig");
- main_tests.setBuildMode(mode);
-
- const test_step = b.step("test", "Run library tests");
- test_step.dependOn(&main_tests.step);
-}
diff --git a/src/deps/iguanaTLS/src/asn1.zig b/src/deps/iguanaTLS/src/asn1.zig
deleted file mode 100644
index 8d43b38e9..000000000
--- a/src/deps/iguanaTLS/src/asn1.zig
+++ /dev/null
@@ -1,631 +0,0 @@
-const std = @import("std");
-const BigInt = std.math.big.int.Const;
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const ArenaAllocator = std.heap.ArenaAllocator;
-
-// zig fmt: off
-pub const Tag = enum(u8) {
- bool = 0x01,
- int = 0x02,
- bit_string = 0x03,
- octet_string = 0x04,
- @"null" = 0x05,
- object_identifier = 0x06,
- utf8_string = 0x0c,
- printable_string = 0x13,
- ia5_string = 0x16,
- utc_time = 0x17,
- bmp_string = 0x1e,
- sequence = 0x30,
- set = 0x31,
- // Bogus value
- context_specific = 0xff,
-};
-// zig fmt: on
-
-pub const ObjectIdentifier = struct {
- data: [16]u32,
- len: u8,
-};
-
-pub const BitString = struct {
- data: []const u8,
- bit_len: usize,
-};
-
-pub const Value = union(Tag) {
- bool: bool,
- int: BigInt,
- bit_string: BitString,
- octet_string: []const u8,
- @"null",
- // @TODO Make this []u32, owned?
- object_identifier: ObjectIdentifier,
- utf8_string: []const u8,
- printable_string: []const u8,
- ia5_string: []const u8,
- utc_time: []const u8,
- bmp_string: []const u16,
- sequence: []const @This(),
- set: []const @This(),
- context_specific: struct {
- child: *const Value,
- number: u8,
- },
-
- pub fn deinit(self: @This(), alloc: *Allocator) void {
- switch (self) {
- .int => |i| alloc.free(i.limbs),
- .bit_string => |bs| alloc.free(bs.data),
- .octet_string,
- .utf8_string,
- .printable_string,
- .ia5_string,
- .utc_time,
- => |s| alloc.free(s),
- .bmp_string => |s| alloc.free(s),
- .sequence, .set => |s| {
- for (s) |c| {
- c.deinit(alloc);
- }
- alloc.free(s);
- },
- .context_specific => |cs| {
- cs.child.deinit(alloc);
- alloc.destroy(cs.child);
- },
- else => {},
- }
- }
-
- fn formatInternal(
- self: Value,
- comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- indents: usize,
- writer: anytype,
- ) @TypeOf(writer).Error!void {
- try writer.writeByteNTimes(' ', indents);
- switch (self) {
- .bool => |b| try writer.print("BOOLEAN {}\n", .{b}),
- .int => |i| {
- try writer.writeAll("INTEGER ");
- try i.format(fmt, options, writer);
- try writer.writeByte('\n');
- },
- .bit_string => |bs| {
- try writer.print("BIT STRING ({} bits) ", .{bs.bit_len});
- const bits_to_show = std.math.min(8 * 3, bs.bit_len);
- const bytes = std.math.divCeil(usize, bits_to_show, 8) catch unreachable;
-
- var bit_idx: usize = 0;
- var byte_idx: usize = 0;
- while (byte_idx < bytes) : (byte_idx += 1) {
- const byte = bs.data[byte_idx];
- var cur_bit_idx: u3 = 0;
- while (bit_idx < bits_to_show) {
- const mask = @as(u8, 0x80) >> cur_bit_idx;
- try writer.print("{}", .{@boolToInt(byte & mask == mask)});
- cur_bit_idx += 1;
- bit_idx += 1;
- if (cur_bit_idx == 7)
- break;
- }
- }
- if (bits_to_show != bs.bit_len)
- try writer.writeAll("...");
- try writer.writeByte('\n');
- },
- .octet_string => |s| try writer.print("OCTET STRING ({} bytes) {X}\n", .{ s.len, s }),
- .@"null" => try writer.writeAll("NULL\n"),
- .object_identifier => |oid| {
- try writer.writeAll("OBJECT IDENTIFIER ");
- var i: u8 = 0;
- while (i < oid.len) : (i += 1) {
- if (i != 0) try writer.writeByte('.');
- try writer.print("{}", .{oid.data[i]});
- }
- try writer.writeByte('\n');
- },
- .utf8_string => |s| try writer.print("UTF8 STRING ({} bytes) {}\n", .{ s.len, s }),
- .printable_string => |s| try writer.print("PRINTABLE STRING ({} bytes) {}\n", .{ s.len, s }),
- .ia5_string => |s| try writer.print("IA5 STRING ({} bytes) {}\n", .{ s.len, s }),
- .utc_time => |s| try writer.print("UTC TIME {}\n", .{s}),
- .bmp_string => |s| try writer.print("BMP STRING ({} words) {}\n", .{
- s.len,
- @ptrCast([*]const u16, s.ptr)[0 .. s.len * 2],
- }),
- .sequence => |children| {
- try writer.print("SEQUENCE ({} elems)\n", .{children.len});
- for (children) |child| try child.formatInternal(fmt, options, indents + 2, writer);
- },
- .set => |children| {
- try writer.print("SET ({} elems)\n", .{children.len});
- for (children) |child| try child.formatInternal(fmt, options, indents + 2, writer);
- },
- .context_specific => |cs| {
- try writer.print("[{}]\n", .{cs.number});
- try cs.child.formatInternal(fmt, options, indents + 2, writer);
- },
- }
- }
-
- pub fn format(self: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
- try self.formatInternal(fmt, options, 0, writer);
- }
-};
-
-/// Distinguished encoding rules
-pub const der = struct {
- pub fn DecodeError(comptime Reader: type) type {
- return Reader.Error || error{
- OutOfMemory,
- EndOfStream,
- InvalidLength,
- InvalidTag,
- InvalidContainerLength,
- DoesNotMatchSchema,
- };
- }
-
- fn DERReaderState(comptime Reader: type) type {
- return struct {
- der_reader: Reader,
- length: usize,
- idx: usize = 0,
- };
- }
-
- fn DERReader(comptime Reader: type) type {
- const S = struct {
- pub fn read(state: *DERReaderState(Reader), buffer: []u8) DecodeError(Reader)!usize {
- const out_bytes = std.math.min(buffer.len, state.length - state.idx);
- const res = try state.der_reader.readAll(buffer[0..out_bytes]);
- state.idx += res;
- return res;
- }
- };
-
- return std.io.Reader(*DERReaderState(Reader), DecodeError(Reader), S.read);
- }
-
- pub fn parse_schema(
- schema: anytype,
- captures: anytype,
- der_reader: anytype,
- ) !void {
- const res = try parse_schema_tag_len_internal(null, null, schema, captures, der_reader);
- if (res != null) return error.DoesNotMatchSchema;
- }
-
- pub fn parse_schema_tag_len(
- existing_tag_byte: ?u8,
- existing_length: ?usize,
- schema: anytype,
- captures: anytype,
- der_reader: anytype,
- ) !void {
- const res = try parse_schema_tag_len_internal(
- existing_tag_byte,
- existing_length,
- schema,
- captures,
- der_reader,
- );
- if (res != null) return error.DoesNotMatchSchema;
- }
-
- const TagLength = struct {
- tag: u8,
- length: usize,
- };
-
- pub fn parse_schema_tag_len_internal(
- existing_tag_byte: ?u8,
- existing_length: ?usize,
- schema: anytype,
- captures: anytype,
- der_reader: anytype,
- ) !?TagLength {
- const Reader = @TypeOf(der_reader);
-
- const isEnumLit = comptime std.meta.trait.is(.EnumLiteral);
- comptime var tag_idx = 0;
-
- const has_capture = comptime isEnumLit(@TypeOf(schema[tag_idx])) and schema[tag_idx] == .capture;
- if (has_capture) tag_idx += 2;
-
- const is_optional = comptime isEnumLit(@TypeOf(schema[tag_idx])) and schema[tag_idx] == .optional;
- if (is_optional) tag_idx += 1;
-
- const tag_literal = schema[tag_idx];
- comptime std.debug.assert(isEnumLit(@TypeOf(tag_literal)));
-
- const tag_byte = existing_tag_byte orelse (der_reader.readByte() catch |err| switch (err) {
- error.EndOfStream => return if (is_optional) null else error.EndOfStream,
- else => |e| return e,
- });
-
- const length = existing_length orelse try parse_length(der_reader);
- if (tag_literal == .sequence_of) {
- if (tag_byte != @enumToInt(Tag.sequence)) {
- if (is_optional) return TagLength{ .tag = tag_byte, .length = length };
- return error.InvalidTag;
- }
-
- var curr_tag_length: ?TagLength = null;
- const sub_schema = schema[tag_idx + 1];
- while (true) {
- if (curr_tag_length == null) {
- curr_tag_length = .{
- .tag = der_reader.readByte() catch |err| switch (err) {
- error.EndOfStream => {
- curr_tag_length = null;
- break;
- },
- else => |e| return e,
- },
- .length = try parse_length(der_reader),
- };
- }
-
- curr_tag_length = parse_schema_tag_len_internal(
- curr_tag_length.?.tag,
- curr_tag_length.?.length,
- sub_schema,
- captures,
- der_reader,
- ) catch |err| switch (err) {
- error.DoesNotMatchSchema => break,
- else => |e| return e,
- };
- }
- return curr_tag_length;
- } else if (tag_literal == .any) {
- if (!has_capture) {
- try der_reader.skipBytes(length, .{});
- return null;
- }
-
- var reader_state = DERReaderState(Reader){
- .der_reader = der_reader,
- .idx = 0,
- .length = length,
- };
- var reader = DERReader(@TypeOf(der_reader)){ .context = &reader_state };
- const capture_context = captures[schema[1] * 2];
- const capture_action = captures[schema[1] * 2 + 1];
- try capture_action(capture_context, tag_byte, length, reader);
-
- // Skip remaining bytes
- try der_reader.skipBytes(reader_state.length - reader_state.idx, .{});
- return null;
- } else if (tag_literal == .context_specific) {
- const cs_number = schema[tag_idx + 1];
- if (tag_byte & 0xC0 == 0x80 and tag_byte - 0xa0 == cs_number) {
- if (!has_capture) {
- if (schema.len > tag_idx + 2) {
- return try parse_schema_tag_len_internal(null, null, schema[tag_idx + 2], captures, der_reader);
- }
-
- try der_reader.skipBytes(length, .{});
- return null;
- }
-
- var reader_state = DERReaderState(Reader){
- .der_reader = der_reader,
- .idx = 0,
- .length = length,
- };
- var reader = DERReader(Reader){ .context = &reader_state };
- const capture_context = captures[schema[1] * 2];
- const capture_action = captures[schema[1] * 2 + 1];
- try capture_action(capture_context, tag_byte, length, reader);
-
- // Skip remaining bytes
- try der_reader.skipBytes(reader_state.length - reader_state.idx, .{});
- return null;
- } else if (is_optional)
- return TagLength{ .tag = tag_byte, .length = length }
- else
- return error.DoesNotMatchSchema;
- }
-
- const schema_tag: Tag = tag_literal;
- const actual_tag = std.meta.intToEnum(Tag, tag_byte) catch return error.InvalidTag;
- if (actual_tag != schema_tag) {
- if (is_optional) return TagLength{ .tag = tag_byte, .length = length };
- return error.DoesNotMatchSchema;
- }
-
- const single_seq = schema_tag == .sequence and schema.len == 1;
- if ((!has_capture and schema_tag != .sequence) or (!has_capture and single_seq)) {
- try der_reader.skipBytes(length, .{});
- return null;
- }
-
- if (has_capture) {
- var reader_state = DERReaderState(Reader){
- .der_reader = der_reader,
- .idx = 0,
- .length = length,
- };
- var reader = DERReader(Reader){ .context = &reader_state };
- const capture_context = captures[schema[1] * 2];
- const capture_action = captures[schema[1] * 2 + 1];
- try capture_action(capture_context, tag_byte, length, reader);
-
- // Skip remaining bytes
- try der_reader.skipBytes(reader_state.length - reader_state.idx, .{});
- return null;
- }
-
- var cur_tag_length: ?TagLength = null;
- const sub_schemas = schema[tag_idx + 1];
- comptime var i = 0;
- inline while (i < sub_schemas.len) : (i += 1) {
- const curr_tag = if (cur_tag_length) |tl| tl.tag else null;
- const curr_length = if (cur_tag_length) |tl| tl.length else null;
- cur_tag_length = try parse_schema_tag_len_internal(curr_tag, curr_length, sub_schemas[i], captures, der_reader);
- }
- return cur_tag_length;
- }
-
- pub const EncodedLength = struct {
- data: [@sizeOf(usize) + 1]u8,
- len: usize,
-
- pub fn slice(self: @This()) []const u8 {
- if (self.len == 1) return self.data[0..1];
- return self.data[0 .. 1 + self.len];
- }
- };
-
- pub fn encode_length(length: usize) EncodedLength {
- var enc = EncodedLength{ .data = undefined, .len = 0 };
- if (length < 128) {
- enc.data[0] = @truncate(u8, length);
- enc.len = 1;
- } else {
- const bytes_needed = @intCast(u8, std.math.divCeil(
- usize,
- std.math.log2_int_ceil(usize, length),
- 8,
- ) catch unreachable);
- enc.data[0] = bytes_needed | 0x80;
- mem.copy(
- u8,
- enc.data[1 .. bytes_needed + 1],
- mem.asBytes(&length)[0..bytes_needed],
- );
- if (std.builtin.target.cpu.arch.endian() != .Big) {
- mem.reverse(u8, enc.data[1 .. bytes_needed + 1]);
- }
- enc.len = bytes_needed;
- }
- return enc;
- }
-
- fn parse_int_internal(alloc: *Allocator, bytes_read: *usize, der_reader: anytype) !BigInt {
- const length = try parse_length_internal(bytes_read, der_reader);
- return try parse_int_with_length_internal(alloc, bytes_read, length, der_reader);
- }
-
- pub fn parse_int(alloc: *Allocator, der_reader: anytype) !BigInt {
- var bytes: usize = undefined;
- return try parse_int_internal(alloc, &bytes, der_reader);
- }
-
- pub fn parse_int_with_length(alloc: *Allocator, length: usize, der_reader: anytype) !BigInt {
- var read: usize = 0;
- return try parse_int_with_length_internal(alloc, &read, length, der_reader);
- }
-
- fn parse_int_with_length_internal(alloc: *Allocator, bytes_read: *usize, length: usize, der_reader: anytype) !BigInt {
- const first_byte = try der_reader.readByte();
- if (first_byte == 0x0 and length > 1) {
- // Positive number with highest bit set to 1 in the rest.
- const limb_count = std.math.divCeil(usize, length - 1, @sizeOf(usize)) catch unreachable;
- const limbs = try alloc.alloc(usize, limb_count);
- std.mem.set(usize, limbs, 0);
- errdefer alloc.free(limbs);
-
- var limb_ptr = @ptrCast([*]u8, limbs.ptr);
- try der_reader.readNoEof(limb_ptr[0 .. length - 1]);
- // We always reverse because the standard library big int expects little endian.
- mem.reverse(u8, limb_ptr[0 .. length - 1]);
-
- bytes_read.* += length;
- return BigInt{ .limbs = limbs, .positive = true };
- }
- std.debug.assert(length != 0);
- // Write first_byte
- // Twos complement
- const limb_count = std.math.divCeil(usize, length, @sizeOf(usize)) catch unreachable;
- const limbs = try alloc.alloc(usize, limb_count);
- std.mem.set(usize, limbs, 0);
- errdefer alloc.free(limbs);
-
- var limb_ptr = @ptrCast([*]u8, limbs.ptr);
- limb_ptr[0] = first_byte & ~@as(u8, 0x80);
- try der_reader.readNoEof(limb_ptr[1..length]);
-
- // We always reverse because the standard library big int expects little endian.
- mem.reverse(u8, limb_ptr[0..length]);
- bytes_read.* += length;
- return BigInt{ .limbs = limbs, .positive = (first_byte & 0x80) == 0x00 };
- }
-
- pub fn parse_length(der_reader: anytype) !usize {
- var bytes: usize = 0;
- return try parse_length_internal(&bytes, der_reader);
- }
-
- fn parse_length_internal(bytes_read: *usize, der_reader: anytype) !usize {
- const first_byte = try der_reader.readByte();
- bytes_read.* += 1;
- if (first_byte & 0x80 == 0x00) {
- // 1 byte value
- return first_byte;
- }
- const length = @truncate(u7, first_byte);
- if (length > @sizeOf(usize))
- @panic("DER length does not fit in usize");
-
- var res_buf = std.mem.zeroes([@sizeOf(usize)]u8);
- try der_reader.readNoEof(res_buf[0..length]);
- bytes_read.* += length;
-
- if (std.builtin.target.cpu.arch.endian() != .Big) {
- mem.reverse(u8, res_buf[0..length]);
- }
- return mem.bytesToValue(usize, &res_buf);
- }
-
- fn parse_value_with_tag_byte(
- tag_byte: u8,
- alloc: *Allocator,
- bytes_read: *usize,
- der_reader: anytype,
- ) DecodeError(@TypeOf(der_reader))!Value {
- const tag = std.meta.intToEnum(Tag, tag_byte) catch {
- // tag starts with '0b10...', this is the context specific class.
- if (tag_byte & 0xC0 == 0x80) {
- const length = try parse_length_internal(bytes_read, der_reader);
- var cur_read_bytes: usize = 0;
- var child = try alloc.create(Value);
- errdefer alloc.destroy(child);
-
- child.* = try parse_value_internal(alloc, &cur_read_bytes, der_reader);
- if (cur_read_bytes != length)
- return error.InvalidContainerLength;
- bytes_read.* += length;
- return Value{ .context_specific = .{ .child = child, .number = tag_byte - 0xa0 } };
- }
-
- return error.InvalidTag;
- };
- switch (tag) {
- .bool => {
- if ((try der_reader.readByte()) != 0x1)
- return error.InvalidLength;
- defer bytes_read.* += 2;
- return Value{ .bool = (try der_reader.readByte()) != 0x0 };
- },
- .int => return Value{ .int = try parse_int_internal(alloc, bytes_read, der_reader) },
- .bit_string => {
- const length = try parse_length_internal(bytes_read, der_reader);
- const unused_bits = try der_reader.readByte();
- std.debug.assert(unused_bits < 8);
- const bit_count = (length - 1) * 8 - unused_bits;
- const bit_memory = try alloc.alloc(u8, std.math.divCeil(usize, bit_count, 8) catch unreachable);
- errdefer alloc.free(bit_memory);
- try der_reader.readNoEof(bit_memory[0 .. length - 1]);
-
- bytes_read.* += length;
- return Value{ .bit_string = .{ .data = bit_memory, .bit_len = bit_count } };
- },
- .octet_string, .utf8_string, .printable_string, .utc_time, .ia5_string => {
- const length = try parse_length_internal(bytes_read, der_reader);
- const str_mem = try alloc.alloc(u8, length);
- try der_reader.readNoEof(str_mem);
- bytes_read.* += length;
- return @as(Value, switch (tag) {
- .octet_string => .{ .octet_string = str_mem },
- .utf8_string => .{ .utf8_string = str_mem },
- .printable_string => .{ .printable_string = str_mem },
- .utc_time => .{ .utc_time = str_mem },
- .ia5_string => .{ .ia5_string = str_mem },
- else => unreachable,
- });
- },
- .@"null" => {
- std.debug.assert((try parse_length_internal(bytes_read, der_reader)) == 0x00);
- return .@"null";
- },
- .object_identifier => {
- const length = try parse_length_internal(bytes_read, der_reader);
- const first_byte = try der_reader.readByte();
- var ret = Value{ .object_identifier = .{ .data = undefined, .len = 0 } };
- ret.object_identifier.data[0] = first_byte / 40;
- ret.object_identifier.data[1] = first_byte % 40;
-
- var out_idx: u8 = 2;
- var i: usize = 0;
- while (i < length - 1) {
- var current_value: u32 = 0;
- var current_byte = try der_reader.readByte();
- i += 1;
- while (current_byte & 0x80 == 0x80) : (i += 1) {
- // Increase the base of the previous bytes
- current_value *= 128;
- // Add the current byte in base 128
- current_value += @as(u32, current_byte & ~@as(u8, 0x80)) * 128;
- current_byte = try der_reader.readByte();
- } else {
- current_value += current_byte;
- }
- ret.object_identifier.data[out_idx] = current_value;
- out_idx += 1;
- }
- ret.object_identifier.len = out_idx;
- std.debug.assert(out_idx <= 16);
- bytes_read.* += length;
- return ret;
- },
- .bmp_string => {
- const length = try parse_length_internal(bytes_read, der_reader);
- const str_mem = try alloc.alloc(u16, @divExact(length, 2));
- errdefer alloc.free(str_mem);
-
- for (str_mem) |*wide_char| {
- wide_char.* = try der_reader.readIntBig(u16);
- }
- bytes_read.* += length;
- return Value{ .bmp_string = str_mem };
- },
- .sequence, .set => {
- const length = try parse_length_internal(bytes_read, der_reader);
- var cur_read_bytes: usize = 0;
- var arr = std.ArrayList(Value).init(alloc);
- errdefer arr.deinit();
-
- while (cur_read_bytes < length) {
- (try arr.addOne()).* = try parse_value_internal(alloc, &cur_read_bytes, der_reader);
- }
- if (cur_read_bytes != length)
- return error.InvalidContainerLength;
- bytes_read.* += length;
-
- return @as(Value, switch (tag) {
- .sequence => .{ .sequence = arr.toOwnedSlice() },
- .set => .{ .set = arr.toOwnedSlice() },
- else => unreachable,
- });
- },
- .context_specific => unreachable,
- }
- }
-
- fn parse_value_internal(alloc: *Allocator, bytes_read: *usize, der_reader: anytype) DecodeError(@TypeOf(der_reader))!Value {
- const tag_byte = try der_reader.readByte();
- bytes_read.* += 1;
- return try parse_value_with_tag_byte(tag_byte, alloc, bytes_read, der_reader);
- }
-
- pub fn parse_value(alloc: *Allocator, der_reader: anytype) DecodeError(@TypeOf(der_reader))!Value {
- var read: usize = 0;
- return try parse_value_internal(alloc, &read, der_reader);
- }
-};
-
-test "der.parse_value" {
- const github_der = @embedFile("../test/github.der");
- var fbs = std.io.fixedBufferStream(github_der);
-
- var arena = ArenaAllocator.init(std.testing.allocator);
- defer arena.deinit();
-
- _ = try der.parse_value(&arena.allocator, fbs.reader());
-}
diff --git a/src/deps/iguanaTLS/src/ciphersuites.zig b/src/deps/iguanaTLS/src/ciphersuites.zig
deleted file mode 100644
index 99f58edec..000000000
--- a/src/deps/iguanaTLS/src/ciphersuites.zig
+++ /dev/null
@@ -1,446 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-
-const crypto = @import("crypto.zig");
-const ChaCha20Stream = crypto.ChaCha20Stream;
-const Chacha20Poly1305 = std.crypto.aead.chacha_poly.ChaCha20Poly1305;
-const Poly1305 = std.crypto.onetimeauth.Poly1305;
-const Aes128Gcm = std.crypto.aead.aes_gcm.Aes128Gcm;
-
-const main = @import("main.zig");
-const RecordHeader = main.RecordHeader;
-
-pub const suites = struct {
- pub const ECDHE_RSA_Chacha20_Poly1305 = struct {
- pub const name = "ECDHE-RSA-CHACHA20-POLY1305";
- pub const tag = 0xCCA8;
- pub const key_exchange = .ecdhe;
- pub const hash = .sha256;
- pub const prefix_data_length = 0;
- pub const mac_length = 16;
-
- pub const Keys = struct {
- client_key: [32]u8,
- server_key: [32]u8,
- client_iv: [12]u8,
- server_iv: [12]u8,
- };
-
- pub const State = struct {
- mac: Poly1305,
- context: ChaCha20Stream.BlockVec,
- buf: [64]u8,
- };
-
- pub fn init_state(_: [0]u8, server_seq: u64, key_data: anytype, header: RecordHeader) State {
- const len = header.len() - 16;
- var nonce: [12]u8 = ([1]u8{0} ** 4) ++ ([1]u8{undefined} ** 8);
- mem.writeIntBig(u64, nonce[4..12], server_seq);
- for (nonce) |*n, i| {
- n.* ^= key_data.server_iv(@This())[i];
- }
-
- var additional_data: [13]u8 = undefined;
- mem.writeIntBig(u64, additional_data[0..8], server_seq);
- additional_data[8..11].* = header.data[0..3].*;
- mem.writeIntBig(u16, additional_data[11..13], len);
-
- var c: [4]u32 = undefined;
- c[0] = 1;
- c[1] = mem.readIntLittle(u32, nonce[0..4]);
- c[2] = mem.readIntLittle(u32, nonce[4..8]);
- c[3] = mem.readIntLittle(u32, nonce[8..12]);
- const server_key = crypto.keyToWords(key_data.server_key(@This()).*);
-
- return .{
- .mac = ChaCha20Stream.initPoly1305(key_data.server_key(@This()).*, nonce, additional_data),
- .context = ChaCha20Stream.initContext(server_key, c),
- .buf = undefined,
- };
- }
-
- pub fn decrypt_part(
- key_data: anytype,
- record_length: usize,
- idx: *usize,
- state: *State,
- encrypted: []const u8,
- out: []u8,
- ) void {
- _ = record_length;
-
- std.debug.assert(encrypted.len == out.len);
- ChaCha20Stream.chacha20Xor(
- out,
- encrypted,
- crypto.keyToWords(key_data.server_key(@This()).*),
- &state.context,
- idx,
- &state.buf,
- );
-
- state.mac.update(encrypted);
- }
-
- pub fn verify_mac(reader: anytype, record_length: usize, state: *State) !void {
- var poly1305_tag: [16]u8 = undefined;
- reader.readNoEof(&poly1305_tag) catch |err| switch (err) {
- error.EndOfStream => return error.ServerMalformedResponse,
- else => |e| return e,
- };
- try ChaCha20Stream.checkPoly1305(&state.mac, record_length, poly1305_tag);
- }
-
- pub fn raw_write(
- comptime buffer_size: usize,
- rand: *std.rand.Random,
- key_data: anytype,
- writer: anytype,
- prefix: [3]u8,
- seq: u64,
- buffer: []const u8,
- ) !void {
- _ = rand;
-
- std.debug.assert(buffer.len <= buffer_size);
- try writer.writeAll(&prefix);
- try writer.writeIntBig(u16, @intCast(u16, buffer.len + 16));
-
- var additional_data: [13]u8 = undefined;
- mem.writeIntBig(u64, additional_data[0..8], seq);
- additional_data[8..11].* = prefix;
- mem.writeIntBig(u16, additional_data[11..13], @intCast(u16, buffer.len));
-
- var encrypted_data: [buffer_size]u8 = undefined;
- var tag_data: [16]u8 = undefined;
-
- var nonce: [12]u8 = ([1]u8{0} ** 4) ++ ([1]u8{undefined} ** 8);
- mem.writeIntBig(u64, nonce[4..12], seq);
- for (nonce) |*n, i| {
- n.* ^= key_data.client_iv(@This())[i];
- }
-
- Chacha20Poly1305.encrypt(
- encrypted_data[0..buffer.len],
- &tag_data,
- buffer,
- &additional_data,
- nonce,
- key_data.client_key(@This()).*,
- );
- try writer.writeAll(encrypted_data[0..buffer.len]);
- try writer.writeAll(&tag_data);
- }
-
- pub fn check_verify_message(
- key_data: anytype,
- length: usize,
- reader: anytype,
- verify_message: [16]u8,
- ) !bool {
- if (length != 32)
- return false;
-
- var msg_in: [32]u8 = undefined;
- try reader.readNoEof(&msg_in);
-
- const additional_data: [13]u8 = ([1]u8{0} ** 8) ++ [5]u8{ 0x16, 0x03, 0x03, 0x00, 0x10 };
- var decrypted: [16]u8 = undefined;
- Chacha20Poly1305.decrypt(
- &decrypted,
- msg_in[0..16],
- msg_in[16..].*,
- &additional_data,
- key_data.server_iv(@This()).*,
- key_data.server_key(@This()).*,
- ) catch return false;
-
- return mem.eql(u8, &decrypted, &verify_message);
- }
- };
-
- pub const ECDHE_RSA_AES128_GCM_SHA256 = struct {
- pub const name = "ECDHE-RSA-AES128-GCM-SHA256";
- pub const tag = 0xC02F;
- pub const key_exchange = .ecdhe;
- pub const hash = .sha256;
- pub const prefix_data_length = 8;
- pub const mac_length = 16;
-
- pub const Keys = struct {
- client_key: [16]u8,
- server_key: [16]u8,
- client_iv: [4]u8,
- server_iv: [4]u8,
- };
-
- const Aes = std.crypto.core.aes.Aes128;
- pub const State = struct {
- aes: @typeInfo(@TypeOf(Aes.initEnc)).Fn.return_type.?,
- counterInt: u128,
- };
-
- pub fn init_state(prefix_data: [8]u8, server_seq: u64, key_data: anytype, header: RecordHeader) State {
- _ = server_seq;
- _ = header;
-
- var iv: [12]u8 = undefined;
- iv[0..4].* = key_data.server_iv(@This()).*;
- iv[4..].* = prefix_data;
-
- var j: [16]u8 = undefined;
- mem.copy(u8, j[0..12], iv[0..]);
- mem.writeIntBig(u32, j[12..][0..4], 2);
-
- return .{
- .aes = Aes.initEnc(key_data.server_key(@This()).*),
- .counterInt = mem.readInt(u128, &j, .Big),
- };
- }
-
- pub fn decrypt_part(
- key_data: anytype,
- record_length: usize,
- idx: *usize,
- state: *State,
- encrypted: []const u8,
- out: []u8,
- ) void {
- _ = key_data;
- _ = record_length;
-
- std.debug.assert(encrypted.len == out.len);
-
- crypto.ctr(
- @TypeOf(state.aes),
- state.aes,
- out,
- encrypted,
- &state.counterInt,
- idx,
- .Big,
- );
- }
-
- pub fn verify_mac(reader: anytype, record_length: usize, state: *State) !void {
- _ = state;
- _ = record_length;
- // @TODO Implement this
- reader.skipBytes(16, .{}) catch |err| switch (err) {
- error.EndOfStream => return error.ServerMalformedResponse,
- else => |e| return e,
- };
- }
-
- pub fn check_verify_message(
- key_data: anytype,
- length: usize,
- reader: anytype,
- verify_message: [16]u8,
- ) !bool {
- if (length != 40)
- return false;
-
- var iv: [12]u8 = undefined;
- iv[0..4].* = key_data.server_iv(@This()).*;
- try reader.readNoEof(iv[4..12]);
-
- var msg_in: [32]u8 = undefined;
- try reader.readNoEof(&msg_in);
-
- const additional_data: [13]u8 = ([1]u8{0} ** 8) ++ [5]u8{ 0x16, 0x03, 0x03, 0x00, 0x10 };
- var decrypted: [16]u8 = undefined;
- Aes128Gcm.decrypt(
- &decrypted,
- msg_in[0..16],
- msg_in[16..].*,
- &additional_data,
- iv,
- key_data.server_key(@This()).*,
- ) catch return false;
-
- return mem.eql(u8, &decrypted, &verify_message);
- }
-
- pub fn raw_write(
- comptime buffer_size: usize,
- rand: *std.rand.Random,
- key_data: anytype,
- writer: anytype,
- prefix: [3]u8,
- seq: u64,
- buffer: []const u8,
- ) !void {
- std.debug.assert(buffer.len <= buffer_size);
- var iv: [12]u8 = undefined;
- iv[0..4].* = key_data.client_iv(@This()).*;
- rand.bytes(iv[4..12]);
-
- var additional_data: [13]u8 = undefined;
- mem.writeIntBig(u64, additional_data[0..8], seq);
- additional_data[8..11].* = prefix;
- mem.writeIntBig(u16, additional_data[11..13], @intCast(u16, buffer.len));
-
- try writer.writeAll(&prefix);
- try writer.writeIntBig(u16, @intCast(u16, buffer.len + 24));
- try writer.writeAll(iv[4..12]);
-
- var encrypted_data: [buffer_size]u8 = undefined;
- var tag_data: [16]u8 = undefined;
-
- Aes128Gcm.encrypt(
- encrypted_data[0..buffer.len],
- &tag_data,
- buffer,
- &additional_data,
- iv,
- key_data.client_key(@This()).*,
- );
- try writer.writeAll(encrypted_data[0..buffer.len]);
- try writer.writeAll(&tag_data);
- }
- };
-
- pub const all = &[_]type{ ECDHE_RSA_Chacha20_Poly1305, ECDHE_RSA_AES128_GCM_SHA256 };
-};
-
-fn key_field_width(comptime T: type, comptime field: anytype) ?usize {
- if (!@hasField(T, @tagName(field)))
- return null;
-
- const field_info = std.meta.fieldInfo(T, field);
- if (!comptime std.meta.trait.is(.Array)(field_info.field_type) or std.meta.Elem(field_info.field_type) != u8)
- @compileError("Field '" ++ field ++ "' of type '" ++ @typeName(T) ++ "' should be an array of u8.");
-
- return @typeInfo(field_info.field_type).Array.len;
-}
-
-pub fn key_data_size(comptime ciphersuites: anytype) usize {
- var max: usize = 0;
- for (ciphersuites) |cs| {
- const curr = (key_field_width(cs.Keys, .client_mac) orelse 0) +
- (key_field_width(cs.Keys, .server_mac) orelse 0) +
- key_field_width(cs.Keys, .client_key).? +
- key_field_width(cs.Keys, .server_key).? +
- key_field_width(cs.Keys, .client_iv).? +
- key_field_width(cs.Keys, .server_iv).?;
- if (curr > max)
- max = curr;
- }
- return max;
-}
-
-pub fn KeyData(comptime ciphersuites: anytype) type {
- return struct {
- data: [key_data_size(ciphersuites)]u8,
-
- pub fn client_mac(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .client_mac) orelse 0]u8 {
- return self.data[0..comptime (key_field_width(cs.Keys, .client_mac) orelse 0)];
- }
-
- pub fn server_mac(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .server_mac) orelse 0]u8 {
- const start = key_field_width(cs.Keys, .client_mac) orelse 0;
- return self.data[start..][0..comptime (key_field_width(cs.Keys, .server_mac) orelse 0)];
- }
-
- pub fn client_key(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .client_key).?]u8 {
- const start = (key_field_width(cs.Keys, .client_mac) orelse 0) +
- (key_field_width(cs.Keys, .server_mac) orelse 0);
- return self.data[start..][0..comptime key_field_width(cs.Keys, .client_key).?];
- }
-
- pub fn server_key(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .server_key).?]u8 {
- const start = (key_field_width(cs.Keys, .client_mac) orelse 0) +
- (key_field_width(cs.Keys, .server_mac) orelse 0) +
- key_field_width(cs.Keys, .client_key).?;
- return self.data[start..][0..comptime key_field_width(cs.Keys, .server_key).?];
- }
-
- pub fn client_iv(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .client_iv).?]u8 {
- const start = (key_field_width(cs.Keys, .client_mac) orelse 0) +
- (key_field_width(cs.Keys, .server_mac) orelse 0) +
- key_field_width(cs.Keys, .client_key).? +
- key_field_width(cs.Keys, .server_key).?;
- return self.data[start..][0..comptime key_field_width(cs.Keys, .client_iv).?];
- }
-
- pub fn server_iv(self: *@This(), comptime cs: type) *[key_field_width(cs.Keys, .server_iv).?]u8 {
- const start = (key_field_width(cs.Keys, .client_mac) orelse 0) +
- (key_field_width(cs.Keys, .server_mac) orelse 0) +
- key_field_width(cs.Keys, .client_key).? +
- key_field_width(cs.Keys, .server_key).? +
- key_field_width(cs.Keys, .client_iv).?;
- return self.data[start..][0..comptime key_field_width(cs.Keys, .server_iv).?];
- }
- };
-}
-
-pub fn key_expansion(
- comptime ciphersuites: anytype,
- tag: u16,
- context: anytype,
- comptime next_32_bytes: anytype,
-) KeyData(ciphersuites) {
- var res: KeyData(ciphersuites) = undefined;
- inline for (ciphersuites) |cs| {
- if (cs.tag == tag) {
- var chunk: [32]u8 = undefined;
- next_32_bytes(context, 0, &chunk);
- comptime var chunk_idx = 1;
- comptime var data_cursor = 0;
- comptime var chunk_cursor = 0;
-
- const fields = .{
- .client_mac, .server_mac,
- .client_key, .server_key,
- .client_iv, .server_iv,
- };
- inline for (fields) |field| {
- if (chunk_cursor == 32) {
- next_32_bytes(context, chunk_idx, &chunk);
- chunk_idx += 1;
- chunk_cursor = 0;
- }
-
- const field_width = comptime (key_field_width(cs.Keys, field) orelse 0);
- const first_read = comptime std.math.min(32 - chunk_cursor, field_width);
- const second_read = field_width - first_read;
-
- res.data[data_cursor..][0..first_read].* = chunk[chunk_cursor..][0..first_read].*;
- data_cursor += first_read;
- chunk_cursor += first_read;
-
- if (second_read != 0) {
- next_32_bytes(context, chunk_idx, &chunk);
- chunk_idx += 1;
- res.data[data_cursor..][0..second_read].* = chunk[chunk_cursor..][0..second_read].*;
- data_cursor += second_read;
- chunk_cursor = second_read;
- comptime std.debug.assert(chunk_cursor != 32);
- }
- }
-
- return res;
- }
- }
- unreachable;
-}
-
-pub fn InRecordState(comptime ciphersuites: anytype) type {
- var fields: [ciphersuites.len]std.builtin.TypeInfo.UnionField = undefined;
- for (ciphersuites) |cs, i| {
- fields[i] = .{
- .name = cs.name,
- .field_type = cs.State,
- .alignment = if (@sizeOf(cs.State) > 0) @alignOf(cs.State) else 0,
- };
- }
- return @Type(.{
- .Union = .{
- .layout = .Extern,
- .tag_type = null,
- .fields = &fields,
- .decls = &[0]std.builtin.TypeInfo.Declaration{},
- },
- });
-}
diff --git a/src/deps/iguanaTLS/src/crypto.zig b/src/deps/iguanaTLS/src/crypto.zig
deleted file mode 100644
index 304c6d284..000000000
--- a/src/deps/iguanaTLS/src/crypto.zig
+++ /dev/null
@@ -1,1016 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-
-const Poly1305 = std.crypto.onetimeauth.Poly1305;
-const Chacha20IETF = std.crypto.stream.chacha.ChaCha20IETF;
-
-// TODO See stdlib, this is a modified non vectorized implementation
-pub const ChaCha20Stream = struct {
- const math = std.math;
- pub const BlockVec = [16]u32;
-
- pub fn initContext(key: [8]u32, d: [4]u32) BlockVec {
- const c = "expand 32-byte k";
- const constant_le = comptime [4]u32{
- mem.readIntLittle(u32, c[0..4]),
- mem.readIntLittle(u32, c[4..8]),
- mem.readIntLittle(u32, c[8..12]),
- mem.readIntLittle(u32, c[12..16]),
- };
- return BlockVec{
- constant_le[0], constant_le[1], constant_le[2], constant_le[3],
- key[0], key[1], key[2], key[3],
- key[4], key[5], key[6], key[7],
- d[0], d[1], d[2], d[3],
- };
- }
-
- const QuarterRound = struct {
- a: usize,
- b: usize,
- c: usize,
- d: usize,
- };
-
- fn Rp(a: usize, b: usize, c: usize, d: usize) QuarterRound {
- return QuarterRound{
- .a = a,
- .b = b,
- .c = c,
- .d = d,
- };
- }
-
- inline fn chacha20Core(x: *BlockVec, input: BlockVec) void {
- x.* = input;
-
- const rounds = comptime [_]QuarterRound{
- Rp(0, 4, 8, 12),
- Rp(1, 5, 9, 13),
- Rp(2, 6, 10, 14),
- Rp(3, 7, 11, 15),
- Rp(0, 5, 10, 15),
- Rp(1, 6, 11, 12),
- Rp(2, 7, 8, 13),
- Rp(3, 4, 9, 14),
- };
-
- comptime var j: usize = 0;
- inline while (j < 20) : (j += 2) {
- inline for (rounds) |r| {
- x[r.a] +%= x[r.b];
- x[r.d] = math.rotl(u32, x[r.d] ^ x[r.a], @as(u32, 16));
- x[r.c] +%= x[r.d];
- x[r.b] = math.rotl(u32, x[r.b] ^ x[r.c], @as(u32, 12));
- x[r.a] +%= x[r.b];
- x[r.d] = math.rotl(u32, x[r.d] ^ x[r.a], @as(u32, 8));
- x[r.c] +%= x[r.d];
- x[r.b] = math.rotl(u32, x[r.b] ^ x[r.c], @as(u32, 7));
- }
- }
- }
-
- inline fn hashToBytes(out: *[64]u8, x: BlockVec) void {
- var i: usize = 0;
- while (i < 4) : (i += 1) {
- mem.writeIntLittle(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0]);
- mem.writeIntLittle(u32, out[16 * i + 4 ..][0..4], x[i * 4 + 1]);
- mem.writeIntLittle(u32, out[16 * i + 8 ..][0..4], x[i * 4 + 2]);
- mem.writeIntLittle(u32, out[16 * i + 12 ..][0..4], x[i * 4 + 3]);
- }
- }
-
- inline fn contextFeedback(x: *BlockVec, ctx: BlockVec) void {
- var i: usize = 0;
- while (i < 16) : (i += 1) {
- x[i] +%= ctx[i];
- }
- }
-
- pub fn initPoly1305(key: [32]u8, nonce: [12]u8, ad: [13]u8) Poly1305 {
- var polyKey = [_]u8{0} ** 32;
- Chacha20IETF.xor(&polyKey, &polyKey, 0, key, nonce);
- var mac = Poly1305.init(&polyKey);
- mac.update(&ad);
- // Pad to 16 bytes from ad
- mac.update(&.{ 0, 0, 0 });
- return mac;
- }
-
- /// Call after `mac` has been updated with the whole message
- pub fn checkPoly1305(mac: *Poly1305, len: usize, tag: [16]u8) !void {
- if (len % 16 != 0) {
- const zeros = [_]u8{0} ** 16;
- const padding = 16 - (len % 16);
- mac.update(zeros[0..padding]);
- }
- var lens: [16]u8 = undefined;
- mem.writeIntLittle(u64, lens[0..8], 13);
- mem.writeIntLittle(u64, lens[8..16], len);
- mac.update(lens[0..]);
- var computedTag: [16]u8 = undefined;
- mac.final(computedTag[0..]);
-
- var acc: u8 = 0;
- for (computedTag) |_, i| {
- acc |= computedTag[i] ^ tag[i];
- }
- if (acc != 0) {
- return error.AuthenticationFailed;
- }
- }
-
- // TODO: Optimize this
- pub fn chacha20Xor(out: []u8, in: []const u8, key: [8]u32, ctx: *BlockVec, idx: *usize, buf: *[64]u8) void {
- _ = key;
-
- var x: BlockVec = undefined;
-
- var i: usize = 0;
- while (i < in.len) {
- if (idx.* % 64 == 0) {
- if (idx.* != 0) {
- ctx.*[12] += 1;
- }
- chacha20Core(x[0..], ctx.*);
- contextFeedback(&x, ctx.*);
- hashToBytes(buf, x);
- }
-
- out[i] = in[i] ^ buf[idx.* % 64];
-
- i += 1;
- idx.* += 1;
- }
- }
-};
-
-pub fn keyToWords(key: [32]u8) [8]u32 {
- var k: [8]u32 = undefined;
- var i: usize = 0;
- while (i < 8) : (i += 1) {
- k[i] = mem.readIntLittle(u32, key[i * 4 ..][0..4]);
- }
- return k;
-}
-
-// See std.crypto.core.modes.ctr
-/// This mode creates a key stream by encrypting an incrementing counter using a block cipher, and adding it to the source material.
-pub fn ctr(
- comptime BlockCipher: anytype,
- block_cipher: BlockCipher,
- dst: []u8,
- src: []const u8,
- counterInt: *u128,
- idx: *usize,
- endian: std.builtin.Endian,
-) void {
- std.debug.assert(dst.len >= src.len);
- const block_length = BlockCipher.block_length;
- var cur_idx: usize = 0;
-
- const offset = idx.* % block_length;
- if (offset != 0) {
- const part_len = std.math.min(block_length - offset, src.len);
-
- var counter: [BlockCipher.block_length]u8 = undefined;
- mem.writeInt(u128, &counter, counterInt.*, endian);
- var pad = [_]u8{0} ** block_length;
- mem.copy(u8, pad[offset..], src[0..part_len]);
- block_cipher.xor(&pad, &pad, counter);
- mem.copy(u8, dst[0..part_len], pad[offset..][0..part_len]);
- cur_idx += part_len;
- idx.* += part_len;
- if (idx.* % block_length == 0)
- counterInt.* += 1;
- }
-
- const start_idx = cur_idx;
- const remaining = src.len - cur_idx;
- cur_idx = 0;
-
- const parallel_count = BlockCipher.block.parallel.optimal_parallel_blocks;
- const wide_block_length = parallel_count * 16;
- if (remaining >= wide_block_length) {
- var counters: [parallel_count * 16]u8 = undefined;
- while (cur_idx + wide_block_length <= remaining) : (cur_idx += wide_block_length) {
- comptime var j = 0;
- inline while (j < parallel_count) : (j += 1) {
- mem.writeInt(u128, counters[j * 16 .. j * 16 + 16], counterInt.*, endian);
- counterInt.* +%= 1;
- }
- block_cipher.xorWide(parallel_count, dst[start_idx..][cur_idx .. cur_idx + wide_block_length][0..wide_block_length], src[start_idx..][cur_idx .. cur_idx + wide_block_length][0..wide_block_length], counters);
- idx.* += wide_block_length;
- }
- }
- while (cur_idx + block_length <= remaining) : (cur_idx += block_length) {
- var counter: [BlockCipher.block_length]u8 = undefined;
- mem.writeInt(u128, &counter, counterInt.*, endian);
- counterInt.* +%= 1;
- block_cipher.xor(dst[start_idx..][cur_idx .. cur_idx + block_length][0..block_length], src[start_idx..][cur_idx .. cur_idx + block_length][0..block_length], counter);
- idx.* += block_length;
- }
- if (cur_idx < remaining) {
- std.debug.assert(idx.* % block_length == 0);
- var counter: [BlockCipher.block_length]u8 = undefined;
- mem.writeInt(u128, &counter, counterInt.*, endian);
-
- var pad = [_]u8{0} ** block_length;
- mem.copy(u8, &pad, src[start_idx..][cur_idx..]);
- block_cipher.xor(&pad, &pad, counter);
- mem.copy(u8, dst[start_idx..][cur_idx..], pad[0 .. remaining - cur_idx]);
-
- idx.* += remaining - cur_idx;
- if (idx.* % block_length == 0)
- counterInt.* +%= 1;
- }
-}
-
-// Ported from BearSSL's ec_prime_i31 engine
-pub const ecc = struct {
- pub const SECP384R1 = struct {
- pub const point_len = 96;
-
- const order = [point_len / 2]u8{
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
- 0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
- 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73,
- };
-
- const P = [_]u32{
- 0x0000018C, 0x7FFFFFFF, 0x00000001, 0x00000000,
- 0x7FFFFFF8, 0x7FFFFFEF, 0x7FFFFFFF, 0x7FFFFFFF,
- 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
- 0x7FFFFFFF, 0x00000FFF,
- };
- const R2 = [_]u32{
- 0x0000018C, 0x00000000, 0x00000080, 0x7FFFFE00,
- 0x000001FF, 0x00000800, 0x00000000, 0x7FFFE000,
- 0x00001FFF, 0x00008000, 0x00008000, 0x00000000,
- 0x00000000, 0x00000000,
- };
- const B = [_]u32{
- 0x0000018C, 0x6E666840, 0x070D0392, 0x5D810231,
- 0x7651D50C, 0x17E218D6, 0x1B192002, 0x44EFE441,
- 0x3A524E2B, 0x2719BA5F, 0x41F02209, 0x36C5643E,
- 0x5813EFFE, 0x000008A5,
- };
-
- const base_point = [point_len]u8{
- 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37,
- 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74,
- 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98,
- 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38,
- 0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C,
- 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7,
- 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F,
- 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29,
- 0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C,
- 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0,
- 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D,
- 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F,
- };
-
- comptime {
- std.debug.assert((P[0] - (P[0] >> 5) + 7) >> 2 == point_len + 1);
- }
- };
-
- pub const SECP256R1 = struct {
- pub const point_len = 64;
-
- const order = [point_len / 2]u8{
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
- 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51,
- };
-
- const P = [_]u32{
- 0x00000108, 0x7FFFFFFF,
- 0x7FFFFFFF, 0x7FFFFFFF,
- 0x00000007, 0x00000000,
- 0x00000000, 0x00000040,
- 0x7FFFFF80, 0x000000FF,
- };
- const R2 = [_]u32{
- 0x00000108, 0x00014000,
- 0x00018000, 0x00000000,
- 0x7FF40000, 0x7FEFFFFF,
- 0x7FF7FFFF, 0x7FAFFFFF,
- 0x005FFFFF, 0x00000000,
- };
- const B = [_]u32{
- 0x00000108, 0x6FEE1803,
- 0x6229C4BD, 0x21B139BE,
- 0x327150AA, 0x3567802E,
- 0x3F7212ED, 0x012E4355,
- 0x782DD38D, 0x0000000E,
- };
-
- const base_point = [point_len]u8{
- 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
- 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
- 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
- 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
- 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
- 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
- 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
- 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5,
- };
-
- comptime {
- std.debug.assert((P[0] - (P[0] >> 5) + 7) >> 2 == point_len + 1);
- }
- };
-
- fn jacobian_len(comptime Curve: type) usize {
- return @divTrunc(Curve.order.len * 8 + 61, 31);
- }
-
- fn Jacobian(comptime Curve: type) type {
- return [3][jacobian_len(Curve)]u32;
- }
-
- fn zero_jacobian(comptime Curve: type) Jacobian(Curve) {
- var result = std.mem.zeroes(Jacobian(Curve));
- result[0][0] = Curve.P[0];
- result[1][0] = Curve.P[0];
- result[2][0] = Curve.P[0];
- return result;
- }
-
- pub fn scalarmult(
- comptime Curve: type,
- point: [Curve.point_len]u8,
- k: []const u8,
- ) ![Curve.point_len]u8 {
- var P: Jacobian(Curve) = undefined;
- var res: u32 = decode_to_jacobian(Curve, &P, point);
- point_mul(Curve, &P, k);
- var out: [Curve.point_len]u8 = undefined;
- encode_from_jacobian(Curve, &out, P);
- if (res == 0)
- return error.MultiplicationFailed;
- return out;
- }
-
- pub fn KeyPair(comptime Curve: type) type {
- return struct {
- public_key: [Curve.point_len]u8,
- secret_key: [Curve.point_len / 2]u8,
- };
- }
-
- pub fn make_key_pair(comptime Curve: type, rand_bytes: [Curve.point_len / 2]u8) KeyPair(Curve) {
- var key_bytes = rand_bytes;
- comptime var mask: u8 = 0xFF;
- comptime {
- while (mask >= Curve.order[0]) {
- mask >>= 1;
- }
- }
- key_bytes[0] &= mask;
- key_bytes[Curve.point_len / 2 - 1] |= 0x01;
-
- return .{
- .secret_key = key_bytes,
- .public_key = scalarmult(Curve, Curve.base_point, &key_bytes) catch unreachable,
- };
- }
-
- fn jacobian_with_one_set(comptime Curve: type, comptime fields: [2][jacobian_len(Curve)]u32) Jacobian(Curve) {
- const plen = comptime (Curve.P[0] + 63) >> 5;
- return fields ++ [1][jacobian_len(Curve)]u32{
- [2]u32{ Curve.P[0], 1 } ++ ([1]u32{0} ** (plen - 2)),
- };
- }
-
- fn encode_from_jacobian(comptime Curve: type, point: *[Curve.point_len]u8, P: Jacobian(Curve)) void {
- var Q = P;
- const T = comptime jacobian_with_one_set(Curve, [2][jacobian_len(Curve)]u32{ undefined, undefined });
- _ = run_code(Curve, &Q, T, &code.affine);
- encode_jacobian_part(point[0 .. Curve.point_len / 2], &Q[0]);
- encode_jacobian_part(point[Curve.point_len / 2 ..], &Q[1]);
- }
-
- fn point_mul(comptime Curve: type, P: *Jacobian(Curve), x: []const u8) void {
- var P2 = P.*;
- point_double(Curve, &P2);
- var P3 = P.*;
- point_add(Curve, &P3, P2);
- var Q = zero_jacobian(Curve);
- var qz: u32 = 1;
- var xlen = x.len;
- var xidx: usize = 0;
- while (xlen > 0) : ({
- xlen -= 1;
- xidx += 1;
- }) {
- var k: u3 = 6;
- while (true) : (k -= 2) {
- point_double(Curve, &Q);
- point_double(Curve, &Q);
- var T = P.*;
- var U = Q;
- const bits = @as(u32, x[xidx] >> k) & 3;
- const bnz = NEQ(bits, 0);
- CCOPY(EQ(bits, 2), mem.asBytes(&T), mem.asBytes(&P2));
- CCOPY(EQ(bits, 3), mem.asBytes(&T), mem.asBytes(&P3));
- point_add(Curve, &U, T);
- CCOPY(bnz & qz, mem.asBytes(&Q), mem.asBytes(&T));
- CCOPY(bnz & ~qz, mem.asBytes(&Q), mem.asBytes(&U));
- qz &= ~bnz;
-
- if (k == 0)
- break;
- }
- }
- P.* = Q;
- }
-
- inline fn point_double(comptime Curve: type, P: *Jacobian(Curve)) void {
- _ = run_code(Curve, P, P.*, &code.double);
- }
- inline fn point_add(comptime Curve: type, P1: *Jacobian(Curve), P2: Jacobian(Curve)) void {
- _ = run_code(Curve, P1, P2, &code._add);
- }
-
- fn decode_to_jacobian(
- comptime Curve: type,
- out: *Jacobian(Curve),
- point: [Curve.point_len]u8,
- ) u32 {
- out.* = zero_jacobian(Curve);
- var result = decode_mod(Curve, &out.*[0], point[0 .. Curve.point_len / 2].*);
- result &= decode_mod(Curve, &out.*[1], point[Curve.point_len / 2 ..].*);
-
- const zlen = comptime ((Curve.P[0] + 63) >> 5);
- comptime std.debug.assert(zlen == @typeInfo(@TypeOf(Curve.R2)).Array.len);
- comptime std.debug.assert(zlen == @typeInfo(@TypeOf(Curve.B)).Array.len);
-
- const Q = comptime jacobian_with_one_set(Curve, [2][jacobian_len(Curve)]u32{ Curve.R2, Curve.B });
- result &= ~run_code(Curve, out, Q, &code.check);
- return result;
- }
-
- const code = struct {
- const P1x = 0;
- const P1y = 1;
- const P1z = 2;
- const P2x = 3;
- const P2y = 4;
- const P2z = 5;
- const Px = 0;
- const Py = 1;
- const Pz = 2;
- const t1 = 6;
- const t2 = 7;
- const t3 = 8;
- const t4 = 9;
- const t5 = 10;
- const t6 = 11;
- const t7 = 12;
- const t8 = 3;
- const t9 = 4;
- const t10 = 5;
- fn MSET(comptime d: u16, comptime a: u16) u16 {
- return 0x0000 + (d << 8) + (a << 4);
- }
- fn MADD(comptime d: u16, comptime a: u16) u16 {
- return 0x1000 + (d << 8) + (a << 4);
- }
- fn MSUB(comptime d: u16, comptime a: u16) u16 {
- return 0x2000 + (d << 8) + (a << 4);
- }
- fn MMUL(comptime d: u16, comptime a: u16, comptime b: u16) u16 {
- return 0x3000 + (d << 8) + (a << 4) + b;
- }
- fn MINV(comptime d: u16, comptime a: u16, comptime b: u16) u16 {
- return 0x4000 + (d << 8) + (a << 4) + b;
- }
- fn MTZ(comptime d: u16) u16 {
- return 0x5000 + (d << 8);
- }
- const ENDCODE = 0;
-
- const check = [_]u16{
- // Convert x and y to Montgomery representation.
- MMUL(t1, P1x, P2x),
- MMUL(t2, P1y, P2x),
- MSET(P1x, t1),
- MSET(P1y, t2),
- // Compute x^3 in t1.
- MMUL(t2, P1x, P1x),
- MMUL(t1, P1x, t2),
- // Subtract 3*x from t1.
- MSUB(t1, P1x),
- MSUB(t1, P1x),
- MSUB(t1, P1x),
- // Add b.
- MADD(t1, P2y),
- // Compute y^2 in t2.
- MMUL(t2, P1y, P1y),
- // Compare y^2 with x^3 - 3*x + b; they must match.
- MSUB(t1, t2),
- MTZ(t1),
- // Set z to 1 (in Montgomery representation).
- MMUL(P1z, P2x, P2z),
- ENDCODE,
- };
- const double = [_]u16{
- // Compute z^2 (in t1).
- MMUL(t1, Pz, Pz),
- // Compute x-z^2 (in t2) and then x+z^2 (in t1).
- MSET(t2, Px),
- MSUB(t2, t1),
- MADD(t1, Px),
- // Compute m = 3*(x+z^2)*(x-z^2) (in t1).
- MMUL(t3, t1, t2),
- MSET(t1, t3),
- MADD(t1, t3),
- MADD(t1, t3),
- // Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
- MMUL(t3, Py, Py),
- MADD(t3, t3),
- MMUL(t2, Px, t3),
- MADD(t2, t2),
- // Compute x' = m^2 - 2*s.
- MMUL(Px, t1, t1),
- MSUB(Px, t2),
- MSUB(Px, t2),
- // Compute z' = 2*y*z.
- MMUL(t4, Py, Pz),
- MSET(Pz, t4),
- MADD(Pz, t4),
- // Compute y' = m*(s - x') - 8*y^4. Note that we already have
- // 2*y^2 in t3.
- MSUB(t2, Px),
- MMUL(Py, t1, t2),
- MMUL(t4, t3, t3),
- MSUB(Py, t4),
- MSUB(Py, t4),
- ENDCODE,
- };
- const _add = [_]u16{
- // Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
- MMUL(t3, P2z, P2z),
- MMUL(t1, P1x, t3),
- MMUL(t4, P2z, t3),
- MMUL(t3, P1y, t4),
- // Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
- MMUL(t4, P1z, P1z),
- MMUL(t2, P2x, t4),
- MMUL(t5, P1z, t4),
- MMUL(t4, P2y, t5),
- //Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
- MSUB(t2, t1),
- MSUB(t4, t3),
- // Report cases where r = 0 through the returned flag.
- MTZ(t4),
- // Compute u1*h^2 (in t6) and h^3 (in t5).
- MMUL(t7, t2, t2),
- MMUL(t6, t1, t7),
- MMUL(t5, t7, t2),
- // Compute x3 = r^2 - h^3 - 2*u1*h^2.
- // t1 and t7 can be used as scratch registers.
- MMUL(P1x, t4, t4),
- MSUB(P1x, t5),
- MSUB(P1x, t6),
- MSUB(P1x, t6),
- //Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
- MSUB(t6, P1x),
- MMUL(P1y, t4, t6),
- MMUL(t1, t5, t3),
- MSUB(P1y, t1),
- //Compute z3 = h*z1*z2.
- MMUL(t1, P1z, P2z),
- MMUL(P1z, t1, t2),
- ENDCODE,
- };
- const affine = [_]u16{
- // Save z*R in t1.
- MSET(t1, P1z),
- // Compute z^3 in t2.
- MMUL(t2, P1z, P1z),
- MMUL(t3, P1z, t2),
- MMUL(t2, t3, P2z),
- // Invert to (1/z^3) in t2.
- MINV(t2, t3, t4),
- // Compute y.
- MSET(t3, P1y),
- MMUL(P1y, t2, t3),
- // Compute (1/z^2) in t3.
- MMUL(t3, t2, t1),
- // Compute x.
- MSET(t2, P1x),
- MMUL(P1x, t2, t3),
- ENDCODE,
- };
- };
-
- fn decode_mod(
- comptime Curve: type,
- x: *[jacobian_len(Curve)]u32,
- src: [Curve.point_len / 2]u8,
- ) u32 {
- const mlen = comptime ((Curve.P[0] + 31) >> 5);
- const tlen = comptime std.math.max(mlen << 2, Curve.point_len / 2) + 4;
-
- var r: u32 = 0;
- var pass: usize = 0;
- while (pass < 2) : (pass += 1) {
- var v: usize = 1;
- var acc: u32 = 0;
- var acc_len: u32 = 0;
-
- var u: usize = 0;
- while (u < tlen) : (u += 1) {
- const b = if (u < Curve.point_len / 2)
- @as(u32, src[Curve.point_len / 2 - 1 - u])
- else
- 0;
- acc |= b << @truncate(u5, acc_len);
- acc_len += 8;
- if (acc_len >= 31) {
- const xw = acc & 0x7FFFFFFF;
- acc_len -= 31;
- acc = b >> @truncate(u5, 8 - acc_len);
- if (v <= mlen) {
- if (pass != 0) {
- x[v] = r & xw;
- } else {
- const cc = @bitCast(u32, CMP(xw, Curve.P[v]));
- r = MUX(EQ(cc, 0), r, cc);
- }
- } else if (pass == 0) {
- r = MUX(EQ(xw, 0), r, 1);
- }
- v += 1;
- }
- }
- r >>= 1;
- r |= (r << 1);
- }
- x[0] = Curve.P[0];
- return r & 1;
- }
-
- fn run_code(
- comptime Curve: type,
- P1: *Jacobian(Curve),
- P2: Jacobian(Curve),
- comptime Code: []const u16,
- ) u32 {
- const jaclen = comptime jacobian_len(Curve);
-
- var t: [13][jaclen]u32 = undefined;
- var result: u32 = 1;
-
- t[0..3].* = P1.*;
- t[3..6].* = P2;
-
- comptime var u: usize = 0;
- inline while (true) : (u += 1) {
- comptime var op = Code[u];
- if (op == 0)
- break;
- const d = comptime (op >> 8) & 0x0F;
- const a = comptime (op >> 4) & 0x0F;
- const b = comptime op & 0x0F;
- op >>= 12;
-
- switch (op) {
- 0 => t[d] = t[a],
- 1 => {
- var ctl = add(&t[d], &t[a], 1);
- ctl |= NOT(sub(&t[d], &Curve.P, 0));
- _ = sub(&t[d], &Curve.P, ctl);
- },
- 2 => _ = add(&t[d], &Curve.P, sub(&t[d], &t[a], 1)),
- 3 => montymul(&t[d], &t[a], &t[b], &Curve.P, 1),
- 4 => {
- var tp: [Curve.point_len / 2]u8 = undefined;
- encode_jacobian_part(&tp, &Curve.P);
- tp[Curve.point_len / 2 - 1] -= 2;
- modpow(Curve, &t[d], tp, 1, &t[a], &t[b]);
- },
- else => result &= ~iszero(&t[d]),
- }
- }
- P1.* = t[0..3].*;
- return result;
- }
-
- inline fn MUL31(x: u32, y: u32) u64 {
- return @as(u64, x) * @as(u64, y);
- }
-
- inline fn MUL31_lo(x: u32, y: u32) u32 {
- return (x *% y) & 0x7FFFFFFF;
- }
-
- inline fn MUX(ctl: u32, x: u32, y: u32) u32 {
- return y ^ (@bitCast(u32, -@bitCast(i32, ctl)) & (x ^ y));
- }
- inline fn NOT(ctl: u32) u32 {
- return ctl ^ 1;
- }
- inline fn NEQ(x: u32, y: u32) u32 {
- const q = x ^ y;
- return (q | @bitCast(u32, -@bitCast(i32, q))) >> 31;
- }
- inline fn EQ(x: u32, y: u32) u32 {
- const q = x ^ y;
- return NOT((q | @bitCast(u32, -@bitCast(i32, q))) >> 31);
- }
- inline fn CMP(x: u32, y: u32) i32 {
- return @bitCast(i32, GT(x, y)) | -@bitCast(i32, GT(y, x));
- }
- inline fn GT(x: u32, y: u32) u32 {
- const z = y -% x;
- return (z ^ ((x ^ y) & (x ^ z))) >> 31;
- }
- inline fn LT(x: u32, y: u32) u32 {
- return GT(y, x);
- }
- inline fn GE(x: u32, y: u32) u32 {
- return NOT(GT(y, x));
- }
-
- fn CCOPY(ctl: u32, dst: []u8, src: []const u8) void {
- for (src) |s, i| {
- dst[i] = @truncate(u8, MUX(ctl, s, dst[i]));
- }
- }
-
- inline fn set_zero(out: [*]u32, bit_len: u32) void {
- out[0] = bit_len;
- mem.set(u32, (out + 1)[0 .. (bit_len + 31) >> 5], 0);
- }
-
- fn divrem(_hi: u32, _lo: u32, d: u32, r: *u32) u32 {
- var hi = _hi;
- var lo = _lo;
- var q: u32 = 0;
- const ch = EQ(hi, d);
- hi = MUX(ch, 0, hi);
-
- var k: u5 = 31;
- while (k > 0) : (k -= 1) {
- const j = @truncate(u5, 32 - @as(u6, k));
- const w = (hi << j) | (lo >> k);
- const ctl = GE(w, d) | (hi >> k);
- const hi2 = (w -% d) >> j;
- const lo2 = lo -% (d << k);
- hi = MUX(ctl, hi2, hi);
- lo = MUX(ctl, lo2, lo);
- q |= ctl << k;
- }
- const cf = GE(lo, d) | hi;
- q |= cf;
- r.* = MUX(cf, lo -% d, lo);
- return q;
- }
-
- inline fn div(hi: u32, lo: u32, d: u32) u32 {
- var r: u32 = undefined;
- return divrem(hi, lo, d, &r);
- }
-
- fn muladd_small(x: [*]u32, z: u32, m: [*]const u32) void {
- var a0: u32 = undefined;
- var a1: u32 = undefined;
- var b0: u32 = undefined;
- const mblr = @intCast(u5, m[0] & 31);
- const mlen = (m[0] + 31) >> 5;
- const hi = x[mlen];
- if (mblr == 0) {
- a0 = x[mlen];
- mem.copyBackwards(u32, (x + 2)[0 .. mlen - 1], (x + 1)[0 .. mlen - 1]);
- x[1] = z;
- a1 = x[mlen];
- b0 = m[mlen];
- } else {
- a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) & 0x7FFFFFFF;
- mem.copyBackwards(u32, (x + 2)[0 .. mlen - 1], (x + 1)[0 .. mlen - 1]);
- x[1] = z;
- a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr)) & 0x7FFFFFFF;
- b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr)) & 0x7FFFFFFF;
- }
-
- const g = div(a0 >> 1, a1 | (a0 << 31), b0);
- const q = MUX(EQ(a0, b0), 0x7FFFFFFF, MUX(EQ(g, 0), 0, g -% 1));
-
- var cc: u32 = 0;
- var tb: u32 = 1;
- var u: usize = 1;
- while (u <= mlen) : (u += 1) {
- const mw = m[u];
- const zl = MUL31(mw, q) + cc;
- cc = @truncate(u32, zl >> 31);
- const zw = @truncate(u32, zl) & 0x7FFFFFFF;
- const xw = x[u];
- var nxw = xw -% zw;
- cc += nxw >> 31;
- nxw &= 0x7FFFFFFF;
- x[u] = nxw;
- tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
- }
-
- const over = GT(cc, hi);
- const under = ~over & (tb | LT(cc, hi));
- _ = add(x, m, over);
- _ = sub(x, m, under);
- }
-
- fn to_monty(x: [*]u32, m: [*]const u32) void {
- const mlen = (m[0] + 31) >> 5;
- var k = mlen;
- while (k > 0) : (k -= 1) {
- muladd_small(x, 0, m);
- }
- }
-
- fn modpow(
- comptime Curve: type,
- x: *[jacobian_len(Curve)]u32,
- e: [Curve.point_len / 2]u8,
- m0i: u32,
- t1: *[jacobian_len(Curve)]u32,
- t2: *[jacobian_len(Curve)]u32,
- ) void {
- t1.* = x.*;
- to_monty(t1, &Curve.P);
- set_zero(x, Curve.P[0]);
- x[1] = 1;
- const bitlen = comptime (Curve.point_len / 2) << 3;
- var k: usize = 0;
- while (k < bitlen) : (k += 1) {
- const ctl = (e[Curve.point_len / 2 - 1 - (k >> 3)] >> (@truncate(u3, k & 7))) & 1;
- montymul(t2, x, t1, &Curve.P, m0i);
- CCOPY(ctl, mem.asBytes(x), mem.asBytes(t2));
- montymul(t2, t1, t1, &Curve.P, m0i);
- t1.* = t2.*;
- }
- }
-
- fn encode_jacobian_part(dst: []u8, x: [*]const u32) void {
- const xlen = (x[0] + 31) >> 5;
-
- var buf = @ptrToInt(dst.ptr) + dst.len;
- var len: usize = dst.len;
- var k: usize = 1;
- var acc: u32 = 0;
- var acc_len: u5 = 0;
- while (len != 0) {
- const w = if (k <= xlen) x[k] else 0;
- k += 1;
- if (acc_len == 0) {
- acc = w;
- acc_len = 31;
- } else {
- const z = acc | (w << acc_len);
- acc_len -= 1;
- acc = w >> (31 - acc_len);
- if (len >= 4) {
- buf -= 4;
- len -= 4;
- mem.writeIntBig(u32, @intToPtr([*]u8, buf)[0..4], z);
- } else {
- switch (len) {
- 3 => {
- @intToPtr(*u8, buf - 3).* = @truncate(u8, z >> 16);
- @intToPtr(*u8, buf - 2).* = @truncate(u8, z >> 8);
- },
- 2 => @intToPtr(*u8, buf - 2).* = @truncate(u8, z >> 8),
- 1 => {},
- else => unreachable,
- }
- @intToPtr(*u8, buf - 1).* = @truncate(u8, z);
- return;
- }
- }
- }
- }
-
- fn montymul(
- out: [*]u32,
- x: [*]const u32,
- y: [*]const u32,
- m: [*]const u32,
- m0i: u32,
- ) void {
- const len = (m[0] + 31) >> 5;
- const len4 = len & ~@as(usize, 3);
- set_zero(out, m[0]);
- var dh: u32 = 0;
- var u: usize = 0;
- while (u < len) : (u += 1) {
- const xu = x[u + 1];
- const f = MUL31_lo(out[1] + MUL31_lo(x[u + 1], y[1]), m0i);
-
- var r: u64 = 0;
- var v: usize = 0;
- while (v < len4) : (v += 4) {
- comptime var j = 1;
- inline while (j <= 4) : (j += 1) {
- const z = out[v + j] +% MUL31(xu, y[v + j]) +% MUL31(f, m[v + j]) +% r;
- r = z >> 31;
- out[v + j - 1] = @truncate(u32, z) & 0x7FFFFFFF;
- }
- }
- while (v < len) : (v += 1) {
- const z = out[v + 1] +% MUL31(xu, y[v + 1]) +% MUL31(f, m[v + 1]) +% r;
- r = z >> 31;
- out[v] = @truncate(u32, z) & 0x7FFFFFFF;
- }
- dh += @truncate(u32, r);
- out[len] = dh & 0x7FFFFFFF;
- dh >>= 31;
- }
- out[0] = m[0];
- const ctl = NEQ(dh, 0) | NOT(sub(out, m, 0));
- _ = sub(out, m, ctl);
- }
-
- fn add(a: [*]u32, b: [*]const u32, ctl: u32) u32 {
- var u: usize = 1;
- var cc: u32 = 0;
- const m = (a[0] + 63) >> 5;
- while (u < m) : (u += 1) {
- const aw = a[u];
- const bw = b[u];
- const naw = aw +% bw +% cc;
- cc = naw >> 31;
- a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw);
- }
- return cc;
- }
-
- fn sub(a: [*]u32, b: [*]const u32, ctl: u32) u32 {
- var cc: u32 = 0;
- const m = (a[0] + 63) >> 5;
- var u: usize = 1;
- while (u < m) : (u += 1) {
- const aw = a[u];
- const bw = b[u];
- const naw = aw -% bw -% cc;
- cc = naw >> 31;
- a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw);
- }
- return cc;
- }
-
- fn iszero(arr: [*]const u32) u32 {
- const mlen = (arr[0] + 63) >> 5;
- var z: u32 = 0;
- var u: usize = mlen - 1;
- while (u > 0) : (u -= 1) {
- z |= arr[u];
- }
- return ~(z | @bitCast(u32, -@bitCast(i32, z))) >> 31;
- }
-};
-
-test "elliptic curve functions with secp384r1 curve" {
- {
- // Decode to Jacobian then encode again with no operations
- var P: ecc.Jacobian(ecc.SECP384R1) = undefined;
- _ = ecc.decode_to_jacobian(ecc.SECP384R1, &P, ecc.SECP384R1.base_point);
- var out: [96]u8 = undefined;
- ecc.encode_from_jacobian(ecc.SECP384R1, &out, P);
- try std.testing.expectEqual(ecc.SECP384R1.base_point, out);
-
- // Multiply by one, check that the result is still the base point
- mem.set(u8, &out, 0);
- ecc.point_mul(ecc.SECP384R1, &P, &[1]u8{1});
- ecc.encode_from_jacobian(ecc.SECP384R1, &out, P);
- try std.testing.expectEqual(ecc.SECP384R1.base_point, out);
- }
-
- {
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- // Derive a shared secret from a Diffie-Hellman key exchange
- var seed: [48]u8 = undefined;
- rand.bytes(&seed);
- const kp1 = ecc.make_key_pair(ecc.SECP384R1, seed);
- rand.bytes(&seed);
- const kp2 = ecc.make_key_pair(ecc.SECP384R1, seed);
-
- const shared1 = try ecc.scalarmult(ecc.SECP384R1, kp1.public_key, &kp2.secret_key);
- const shared2 = try ecc.scalarmult(ecc.SECP384R1, kp2.public_key, &kp1.secret_key);
- try std.testing.expectEqual(shared1, shared2);
- }
-
- // @TODO Add tests with known points.
-}
diff --git a/src/deps/iguanaTLS/src/main.zig b/src/deps/iguanaTLS/src/main.zig
deleted file mode 100644
index 6937e19b2..000000000
--- a/src/deps/iguanaTLS/src/main.zig
+++ /dev/null
@@ -1,2216 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const Sha224 = std.crypto.hash.sha2.Sha224;
-const Sha384 = std.crypto.hash.sha2.Sha384;
-const Sha512 = std.crypto.hash.sha2.Sha512;
-const Sha256 = std.crypto.hash.sha2.Sha256;
-const Hmac256 = std.crypto.auth.hmac.sha2.HmacSha256;
-
-pub const asn1 = @import("asn1.zig");
-pub const x509 = @import("x509.zig");
-pub const crypto = @import("crypto.zig");
-
-const ciphers = @import("ciphersuites.zig");
-pub const ciphersuites = ciphers.suites;
-
-pub const @"pcks1v1.5" = @import("pcks1-1_5.zig");
-
-comptime {
- std.testing.refAllDecls(x509);
- std.testing.refAllDecls(asn1);
- std.testing.refAllDecls(crypto);
-}
-
-fn handshake_record_length(reader: anytype) !usize {
- return try record_length(0x16, reader);
-}
-
-pub const RecordHeader = struct {
- data: [5]u8,
-
- pub inline fn tag(self: @This()) u8 {
- return self.data[0];
- }
-
- pub inline fn len(self: @This()) u16 {
- return mem.readIntSliceBig(u16, self.data[3..]);
- }
-};
-
-pub fn record_header(reader: anytype) !RecordHeader {
- var header: [5]u8 = undefined;
- try reader.readNoEof(&header);
-
- if (!mem.eql(u8, header[1..3], "\x03\x03") and !mem.eql(u8, header[1..3], "\x03\x01"))
- return error.ServerInvalidVersion;
-
- return RecordHeader{
- .data = header,
- };
-}
-
-pub fn record_length(t: u8, reader: anytype) !usize {
- try check_record_type(t, reader);
- var header: [4]u8 = undefined;
- try reader.readNoEof(&header);
- if (!mem.eql(u8, header[0..2], "\x03\x03") and !mem.eql(u8, header[0..2], "\x03\x01"))
- return error.ServerInvalidVersion;
- return mem.readIntSliceBig(u16, header[2..4]);
-}
-
-pub const ServerAlert = error{
- AlertCloseNotify,
- AlertUnexpectedMessage,
- AlertBadRecordMAC,
- AlertDecryptionFailed,
- AlertRecordOverflow,
- AlertDecompressionFailure,
- AlertHandshakeFailure,
- AlertNoCertificate,
- AlertBadCertificate,
- AlertUnsupportedCertificate,
- AlertCertificateRevoked,
- AlertCertificateExpired,
- AlertCertificateUnknown,
- AlertIllegalParameter,
- AlertUnknownCA,
- AlertAccessDenied,
- AlertDecodeError,
- AlertDecryptError,
- AlertExportRestriction,
- AlertProtocolVersion,
- AlertInsufficientSecurity,
- AlertInternalError,
- AlertUserCanceled,
- AlertNoRenegotiation,
- AlertUnsupportedExtension,
-};
-
-fn check_record_type(
- expected: u8,
- reader: anytype,
-) (@TypeOf(reader).Error || ServerAlert || error{ ServerMalformedResponse, EndOfStream })!void {
- const record_type = try reader.readByte();
- // Alert
- if (record_type == 0x15) {
- // Skip SSL version, length of record
- try reader.skipBytes(4, .{});
-
- const severity = try reader.readByte();
- _ = severity;
- const err_num = try reader.readByte();
- return alert_byte_to_error(err_num);
- }
- if (record_type != expected)
- return error.ServerMalformedResponse;
-}
-
-pub fn alert_byte_to_error(b: u8) (ServerAlert || error{ServerMalformedResponse}) {
- return switch (b) {
- 0 => error.AlertCloseNotify,
- 10 => error.AlertUnexpectedMessage,
- 20 => error.AlertBadRecordMAC,
- 21 => error.AlertDecryptionFailed,
- 22 => error.AlertRecordOverflow,
- 30 => error.AlertDecompressionFailure,
- 40 => error.AlertHandshakeFailure,
- 41 => error.AlertNoCertificate,
- 42 => error.AlertBadCertificate,
- 43 => error.AlertUnsupportedCertificate,
- 44 => error.AlertCertificateRevoked,
- 45 => error.AlertCertificateExpired,
- 46 => error.AlertCertificateUnknown,
- 47 => error.AlertIllegalParameter,
- 48 => error.AlertUnknownCA,
- 49 => error.AlertAccessDenied,
- 50 => error.AlertDecodeError,
- 51 => error.AlertDecryptError,
- 60 => error.AlertExportRestriction,
- 70 => error.AlertProtocolVersion,
- 71 => error.AlertInsufficientSecurity,
- 80 => error.AlertInternalError,
- 90 => error.AlertUserCanceled,
- 100 => error.AlertNoRenegotiation,
- 110 => error.AlertUnsupportedExtension,
- else => error.ServerMalformedResponse,
- };
-}
-
-// TODO: Now that we keep all the hashes, check the ciphersuite for the hash
-// type used and use it where necessary instead of hardcoding sha256
-const HashSet = struct {
- sha224: Sha224,
- sha256: Sha256,
- sha384: Sha384,
- sha512: Sha512,
-
- fn update(self: *@This(), buf: []const u8) void {
- self.sha224.update(buf);
- self.sha256.update(buf);
- self.sha384.update(buf);
- self.sha512.update(buf);
- }
-};
-
-fn HashingReader(comptime Reader: anytype) type {
- const State = struct {
- hash_set: *HashSet,
- reader: Reader,
- };
- const S = struct {
- pub fn read(state: State, buffer: []u8) Reader.Error!usize {
- const amt = try state.reader.read(buffer);
- if (amt != 0) {
- state.hash_set.update(buffer[0..amt]);
- }
- return amt;
- }
- };
- return std.io.Reader(State, Reader.Error, S.read);
-}
-
-fn make_hashing_reader(hash_set: *HashSet, reader: anytype) HashingReader(@TypeOf(reader)) {
- return .{ .context = .{ .hash_set = hash_set, .reader = reader } };
-}
-
-fn HashingWriter(comptime Writer: anytype) type {
- const State = struct {
- hash_set: *HashSet,
- writer: Writer,
- };
- const S = struct {
- pub fn write(state: State, buffer: []const u8) Writer.Error!usize {
- const amt = try state.writer.write(buffer);
- if (amt != 0) {
- state.hash_set.update(buffer[0..amt]);
- }
- return amt;
- }
- };
- return std.io.Writer(State, Writer.Error, S.write);
-}
-
-fn make_hashing_writer(hash_set: *HashSet, writer: anytype) HashingWriter(@TypeOf(writer)) {
- return .{ .context = .{ .hash_set = hash_set, .writer = writer } };
-}
-
-fn CertificateReaderState(comptime Reader: type) type {
- return struct {
- reader: Reader,
- length: usize,
- idx: usize = 0,
- };
-}
-
-fn CertificateReader(comptime Reader: type) type {
- const S = struct {
- pub fn read(state: *CertificateReaderState(Reader), buffer: []u8) Reader.Error!usize {
- const out_bytes = std.math.min(buffer.len, state.length - state.idx);
- const res = try state.reader.readAll(buffer[0..out_bytes]);
- state.idx += res;
- return res;
- }
- };
-
- return std.io.Reader(*CertificateReaderState(Reader), Reader.Error, S.read);
-}
-
-pub const CertificateVerifier = union(enum) {
- none,
- function: anytype,
- default,
-};
-
-pub fn CertificateVerifierReader(comptime Reader: type) type {
- return CertificateReader(HashingReader(Reader));
-}
-
-pub fn ClientConnectError(
- comptime verifier: CertificateVerifier,
- comptime Reader: type,
- comptime Writer: type,
- comptime has_client_certs: bool,
-) type {
- const Additional = error{
- ServerInvalidVersion,
- ServerMalformedResponse,
- EndOfStream,
- ServerInvalidCipherSuite,
- ServerInvalidCompressionMethod,
- ServerInvalidRenegotiationData,
- ServerInvalidECPointCompression,
- ServerInvalidProtocol,
- ServerInvalidExtension,
- ServerInvalidCurve,
- ServerInvalidSignature,
- ServerInvalidSignatureAlgorithm,
- ServerAuthenticationFailed,
- ServerInvalidVerifyData,
- PreMasterGenerationFailed,
- OutOfMemory,
- };
- const err_msg = "Certificate verifier function cannot be generic, use CertificateVerifierReader to get the reader argument type";
- return Reader.Error || Writer.Error || ServerAlert || Additional || switch (verifier) {
- .none => error{},
- .function => |f| @typeInfo(@typeInfo(@TypeOf(f)).Fn.return_type orelse
- @compileError(err_msg)).ErrorUnion.error_set || error{CertificateVerificationFailed},
- .default => error{CertificateVerificationFailed},
- } || (if (has_client_certs) error{ClientCertificateVerifyFailed} else error{});
-}
-
-// See http://howardhinnant.github.io/date_algorithms.html
-// Timestamp in seconds, only supports A.D. dates
-fn unix_timestamp_from_civil_date(year: u16, month: u8, day: u8) i64 {
- var y: i64 = year;
- if (month <= 2) y -= 1;
- const era = @divTrunc(y, 400);
- const yoe = y - era * 400; // [0, 399]
- const doy = @divTrunc((153 * (month + (if (month > 2) @as(i64, -3) else 9)) + 2), 5) + day - 1; // [0, 365]
- const doe = yoe * 365 + @divTrunc(yoe, 4) - @divTrunc(yoe, 100) + doy; // [0, 146096]
- return (era * 146097 + doe - 719468) * 86400;
-}
-
-fn read_der_utc_timestamp(reader: anytype) !i64 {
- var buf: [17]u8 = undefined;
-
- const tag = try reader.readByte();
- if (tag != 0x17)
- return error.CertificateVerificationFailed;
- const len = try asn1.der.parse_length(reader);
- if (len > 17)
- return error.CertificateVerificationFailed;
-
- try reader.readNoEof(buf[0..len]);
- const year = std.fmt.parseUnsigned(u16, buf[0..2], 10) catch
- return error.CertificateVerificationFailed;
- const month = std.fmt.parseUnsigned(u8, buf[2..4], 10) catch
- return error.CertificateVerificationFailed;
- const day = std.fmt.parseUnsigned(u8, buf[4..6], 10) catch
- return error.CertificateVerificationFailed;
-
- var time = unix_timestamp_from_civil_date(2000 + year, month, day);
- time += (std.fmt.parseUnsigned(i64, buf[6..8], 10) catch
- return error.CertificateVerificationFailed) * 3600;
- time += (std.fmt.parseUnsigned(i64, buf[8..10], 10) catch
- return error.CertificateVerificationFailed) * 60;
-
- if (buf[len - 1] == 'Z') {
- if (len == 13) {
- time += std.fmt.parseUnsigned(u8, buf[10..12], 10) catch
- return error.CertificateVerificationFailed;
- } else if (len != 11) {
- return error.CertificateVerificationFailed;
- }
- } else {
- if (len == 15) {
- if (buf[10] != '+' and buf[10] != '-')
- return error.CertificateVerificationFailed;
-
- var additional = (std.fmt.parseUnsigned(i64, buf[11..13], 10) catch
- return error.CertificateVerificationFailed) * 3600;
- additional += (std.fmt.parseUnsigned(i64, buf[13..15], 10) catch
- return error.CertificateVerificationFailed) * 60;
-
- time += if (buf[10] == '+') -additional else additional;
- } else if (len == 17) {
- if (buf[12] != '+' and buf[12] != '-')
- return error.CertificateVerificationFailed;
- time += std.fmt.parseUnsigned(u8, buf[10..12], 10) catch
- return error.CertificateVerificationFailed;
-
- var additional = (std.fmt.parseUnsigned(i64, buf[13..15], 10) catch
- return error.CertificateVerificationFailed) * 3600;
- additional += (std.fmt.parseUnsigned(i64, buf[15..17], 10) catch
- return error.CertificateVerificationFailed) * 60;
-
- time += if (buf[12] == '+') -additional else additional;
- } else return error.CertificateVerificationFailed;
- }
- return time;
-}
-
-fn check_cert_timestamp(time: i64, tag_byte: u8, length: usize, reader: anytype) !void {
- _ = tag_byte;
- _ = length;
- if (time < (try read_der_utc_timestamp(reader)))
- return error.CertificateVerificationFailed;
- if (time > (try read_der_utc_timestamp(reader)))
- return error.CertificateVerificationFailed;
-}
-
-fn add_dn_field(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = length;
- _ = tag;
-
- const seq_tag = try reader.readByte();
- if (seq_tag != 0x30)
- return error.CertificateVerificationFailed;
- const seq_length = try asn1.der.parse_length(reader);
- _ = seq_length;
-
- const oid_tag = try reader.readByte();
- if (oid_tag != 0x06)
- return error.CertificateVerificationFailed;
-
- const oid_length = try asn1.der.parse_length(reader);
- if (oid_length == 3 and (try reader.isBytes("\x55\x04\x03"))) {
- // Common name
- const common_name_tag = try reader.readByte();
- if (common_name_tag != 0x04 and common_name_tag != 0x0c and common_name_tag != 0x13 and common_name_tag != 0x16)
- return error.CertificateVerificationFailed;
- const common_name_len = try asn1.der.parse_length(reader);
- state.list.items[state.list.items.len - 1].common_name = state.fbs.buffer[state.fbs.pos .. state.fbs.pos + common_name_len];
- }
-}
-
-fn add_cert_subject_dn(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- state.list.items[state.list.items.len - 1].dn = state.fbs.buffer[state.fbs.pos .. state.fbs.pos + length];
- const schema = .{
- .sequence_of,
- .{
- .capture, 0, .set,
- },
- };
- const captures = .{
- state, add_dn_field,
- };
- try asn1.der.parse_schema_tag_len(tag, length, schema, captures, reader);
-}
-
-fn add_cert_public_key(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- state.list.items[state.list.items.len - 1].public_key = x509.parse_public_key(
- state.allocator,
- reader,
- ) catch |err| switch (err) {
- error.MalformedDER => return error.CertificateVerificationFailed,
- else => |e| return e,
- };
-}
-
-fn add_cert_extensions(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const schema = .{
- .sequence_of,
- .{ .capture, 0, .sequence },
- };
- const captures = .{
- state, add_cert_extension,
- };
-
- try asn1.der.parse_schema(schema, captures, reader);
-}
-
-fn add_cert_extension(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const start = state.fbs.pos;
-
- // The happy path is allocation free
- // TODO: add a preflight check to mandate a specific tag
- const object_id = try asn1.der.parse_value(state.allocator, reader);
- defer object_id.deinit(state.allocator);
- if (object_id != .object_identifier) return error.DoesNotMatchSchema;
- if (object_id.object_identifier.len != 4)
- return;
-
- const data = object_id.object_identifier.data;
- // Prefix == id-ce
- if (data[0] != 2 or data[1] != 5 or data[2] != 29)
- return;
-
- switch (data[3]) {
- 17 => {
- const san_tag = try reader.readByte();
- if (san_tag != @enumToInt(asn1.Tag.octet_string)) return error.DoesNotMatchSchema;
-
- const san_length = try asn1.der.parse_length(reader);
- _ = san_length;
-
- const body_tag = try reader.readByte();
- if (body_tag != @enumToInt(asn1.Tag.sequence)) return error.DoesNotMatchSchema;
-
- const body_length = try asn1.der.parse_length(reader);
- const total_read = state.fbs.pos - start;
- if (total_read + body_length > length) return error.DoesNotMatchSchema;
-
- state.list.items[state.list.items.len - 1].raw_subject_alternative_name = state.fbs.buffer[state.fbs.pos .. state.fbs.pos + body_length];
-
- // Validate to make sure this is iterable later
- const ref = state.fbs.pos;
- while (state.fbs.pos - ref < body_length) {
- const choice = try reader.readByte();
- if (choice < 0x80) return error.DoesNotMatchSchema;
-
- const chunk_length = try asn1.der.parse_length(reader);
- _ = try reader.skipBytes(chunk_length, .{});
- }
- },
- else => {},
- }
-}
-
-fn add_server_cert(state: *VerifierCaptureState, tag_byte: u8, length: usize, reader: anytype) !void {
- const is_ca = state.list.items.len != 0;
-
- // TODO: Some way to get tag + length buffer directly in the capture callback?
- const encoded_length = asn1.der.encode_length(length).slice();
- // This is not errdefered since default_cert_verifier call takes care of cleaning up all the certificate data.
- // Same for the signature.data
- const cert_bytes = try state.allocator.alloc(u8, length + 1 + encoded_length.len);
- cert_bytes[0] = tag_byte;
- mem.copy(u8, cert_bytes[1 .. 1 + encoded_length.len], encoded_length);
-
- try reader.readNoEof(cert_bytes[1 + encoded_length.len ..]);
- (try state.list.addOne(state.allocator)).* = .{
- .is_ca = is_ca,
- .bytes = cert_bytes,
- .dn = undefined,
- .common_name = &[0]u8{},
- .raw_subject_alternative_name = &[0]u8{},
- .public_key = x509.PublicKey.empty,
- .signature = asn1.BitString{ .data = &[0]u8{}, .bit_len = 0 },
- .signature_algorithm = undefined,
- };
-
- const schema = .{
- .sequence,
- .{
- .{ .context_specific, 0 }, // version
- .{.int}, // serialNumber
- .{.sequence}, // signature
- .{.sequence}, // issuer
- .{ .capture, 0, .sequence }, // validity
- .{ .capture, 1, .sequence }, // subject
- .{ .capture, 2, .sequence }, // subjectPublicKeyInfo
- .{ .optional, .context_specific, 1 }, // issuerUniqueID
- .{ .optional, .context_specific, 2 }, // subjectUniqueID
- .{ .capture, 3, .optional, .context_specific, 3 }, // extensions
- },
- };
-
- const captures = .{
- std.time.timestamp(), check_cert_timestamp,
- state, add_cert_subject_dn,
- state, add_cert_public_key,
- state, add_cert_extensions,
- };
-
- var fbs = std.io.fixedBufferStream(@as([]const u8, cert_bytes[1 + encoded_length.len ..]));
- state.fbs = &fbs;
-
- asn1.der.parse_schema_tag_len(tag_byte, length, schema, captures, fbs.reader()) catch |err| switch (err) {
- error.InvalidLength,
- error.InvalidTag,
- error.InvalidContainerLength,
- error.DoesNotMatchSchema,
- => return error.CertificateVerificationFailed,
- else => |e| return e,
- };
-}
-
-fn set_signature_algorithm(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const cert = &state.list.items[state.list.items.len - 1];
- cert.signature_algorithm = (try x509.get_signature_algorithm(reader)) orelse return error.CertificateVerificationFailed;
-}
-
-fn set_signature_value(state: *VerifierCaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const unused_bits = try reader.readByte();
- const bit_count = (length - 1) * 8 - unused_bits;
- const signature_bytes = try state.allocator.alloc(u8, length - 1);
- errdefer state.allocator.free(signature_bytes);
- try reader.readNoEof(signature_bytes);
- state.list.items[state.list.items.len - 1].signature = .{
- .data = signature_bytes,
- .bit_len = bit_count,
- };
-}
-
-const ServerCertificate = struct {
- bytes: []const u8,
- dn: []const u8,
- common_name: []const u8,
- raw_subject_alternative_name: []const u8,
- public_key: x509.PublicKey,
- signature: asn1.BitString,
- signature_algorithm: x509.Certificate.SignatureAlgorithm,
- is_ca: bool,
-
- const GeneralName = enum(u5) {
- other_name = 0,
- rfc822_name = 1,
- dns_name = 2,
- x400_address = 3,
- directory_name = 4,
- edi_party_name = 5,
- uniform_resource_identifier = 6,
- ip_address = 7,
- registered_id = 8,
- };
-
- fn iterSAN(self: ServerCertificate, choice: GeneralName) NameIterator {
- return .{ .cert = self, .choice = choice };
- }
-
- const NameIterator = struct {
- cert: ServerCertificate,
- choice: GeneralName,
- pos: usize = 0,
-
- fn next(self: *NameIterator) ?[]const u8 {
- while (self.pos < self.cert.raw_subject_alternative_name.len) {
- const choice = self.cert.raw_subject_alternative_name[self.pos];
- std.debug.assert(choice >= 0x80);
- const len = self.cert.raw_subject_alternative_name[self.pos + 1];
- const start = self.pos + 2;
- const end = start + len;
- self.pos = end;
- if (@enumToInt(self.choice) == choice - 0x80) {
- return self.cert.raw_subject_alternative_name[start..end];
- }
- }
- return null;
- }
- };
-};
-
-const VerifierCaptureState = struct {
- list: std.ArrayListUnmanaged(ServerCertificate),
- allocator: *Allocator,
- // Used in `add_server_cert` to avoid an extra allocation
- fbs: *std.io.FixedBufferStream([]const u8),
-};
-
-// @TODO Move out of here
-const ReverseSplitIterator = struct {
- buffer: []const u8,
- index: ?usize,
- delimiter: []const u8,
-
- pub fn next(self: *ReverseSplitIterator) ?[]const u8 {
- const end = self.index orelse return null;
- const start = if (mem.lastIndexOfLinear(u8, self.buffer[0..end], self.delimiter)) |delim_start| blk: {
- self.index = delim_start;
- break :blk delim_start + self.delimiter.len;
- } else blk: {
- self.index = null;
- break :blk 0;
- };
- return self.buffer[start..end];
- }
-};
-
-fn reverse_split(buffer: []const u8, delimiter: []const u8) ReverseSplitIterator {
- std.debug.assert(delimiter.len != 0);
- return .{
- .index = buffer.len,
- .buffer = buffer,
- .delimiter = delimiter,
- };
-}
-
-fn cert_name_matches(cert_name: []const u8, hostname: []const u8) bool {
- var cert_name_split = reverse_split(cert_name, ".");
- var hostname_split = reverse_split(hostname, ".");
- while (true) {
- const cn_part = cert_name_split.next();
- const hn_part = hostname_split.next();
-
- if (cn_part) |cnp| {
- if (hn_part == null and cert_name_split.index == null and mem.eql(u8, cnp, "www"))
- return true
- else if (hn_part) |hnp| {
- if (mem.eql(u8, cnp, "*"))
- continue;
- if (!mem.eql(u8, cnp, hnp))
- return false;
- }
- } else return hn_part == null;
- }
-}
-
-pub fn default_cert_verifier(
- allocator: *mem.Allocator,
- reader: anytype,
- certs_bytes: usize,
- trusted_certificates: []const x509.Certificate,
- hostname: []const u8,
-) !x509.PublicKey {
- var capture_state = VerifierCaptureState{
- .list = try std.ArrayListUnmanaged(ServerCertificate).initCapacity(allocator, 3),
- .allocator = allocator,
- .fbs = undefined,
- };
- defer {
- for (capture_state.list.items) |cert| {
- cert.public_key.deinit(allocator);
- allocator.free(cert.bytes);
- allocator.free(cert.signature.data);
- }
- capture_state.list.deinit(allocator);
- }
-
- const schema = .{
- .sequence, .{
- // tbsCertificate
- .{ .capture, 0, .sequence },
- // signatureAlgorithm
- .{ .capture, 1, .sequence },
- // signatureValue
- .{ .capture, 2, .bit_string },
- },
- };
- const captures = .{
- &capture_state, add_server_cert,
- &capture_state, set_signature_algorithm,
- &capture_state, set_signature_value,
- };
-
- var bytes_read: u24 = 0;
- while (bytes_read < certs_bytes) {
- const cert_length = try reader.readIntBig(u24);
-
- asn1.der.parse_schema(schema, captures, reader) catch |err| switch (err) {
- error.InvalidLength,
- error.InvalidTag,
- error.InvalidContainerLength,
- error.DoesNotMatchSchema,
- => return error.CertificateVerificationFailed,
- else => |e| return e,
- };
-
- bytes_read += 3 + cert_length;
- }
- if (bytes_read != certs_bytes)
- return error.CertificateVerificationFailed;
-
- const chain = capture_state.list.items;
- if (chain.len == 0) return error.CertificateVerificationFailed;
- // Check if the hostname matches one of the leaf certificate's names
- name_matched: {
- if (cert_name_matches(chain[0].common_name, hostname)) {
- break :name_matched;
- }
-
- var iter = chain[0].iterSAN(.dns_name);
- while (iter.next()) |cert_name| {
- if (cert_name_matches(cert_name, hostname)) {
- break :name_matched;
- }
- }
-
- return error.CertificateVerificationFailed;
- }
-
- var i: usize = 0;
- while (i < chain.len - 1) : (i += 1) {
- if (!try @"pcks1v1.5".certificate_verify_signature(
- allocator,
- chain[i].signature_algorithm,
- chain[i].signature,
- chain[i].bytes,
- chain[i + 1].public_key,
- )) {
- return error.CertificateVerificationFailed;
- }
- }
-
- for (chain) |cert| {
- for (trusted_certificates) |trusted| {
- // Try to find an exact match to a trusted certificate
- if (cert.is_ca == trusted.is_ca and mem.eql(u8, cert.dn, trusted.dn) and
- cert.public_key.eql(trusted.public_key))
- {
- const key = chain[0].public_key;
- chain[0].public_key = x509.PublicKey.empty;
- return key;
- }
-
- if (!trusted.is_ca)
- continue;
-
- if (try @"pcks1v1.5".certificate_verify_signature(
- allocator,
- cert.signature_algorithm,
- cert.signature,
- cert.bytes,
- trusted.public_key,
- )) {
- const key = chain[0].public_key;
- chain[0].public_key = x509.PublicKey.empty;
- return key;
- }
- }
- }
- return error.CertificateVerificationFailed;
-}
-
-pub fn extract_cert_public_key(allocator: *Allocator, reader: anytype, length: usize) !x509.PublicKey {
- const CaptureState = struct {
- pub_key: x509.PublicKey,
- allocator: *Allocator,
- };
- var capture_state = CaptureState{
- .pub_key = undefined,
- .allocator = allocator,
- };
-
- const schema = .{
- .sequence, .{
- // tbsCertificate
- .{
- .sequence,
- .{
- .{ .context_specific, 0 }, // version
- .{.int}, // serialNumber
- .{.sequence}, // signature
- .{.sequence}, // issuer
- .{.sequence}, // validity
- .{.sequence}, // subject
- .{ .capture, 0, .sequence }, // subjectPublicKeyInfo
- .{ .optional, .context_specific, 1 }, // issuerUniqueID
- .{ .optional, .context_specific, 2 }, // subjectUniqueID
- .{ .optional, .context_specific, 3 }, // extensions
- },
- },
- // signatureAlgorithm
- .{.sequence},
- // signatureValue
- .{.bit_string},
- },
- };
- const captures = .{
- &capture_state, struct {
- fn f(state: *CaptureState, tag: u8, _length: usize, subreader: anytype) !void {
- _ = tag;
- _ = _length;
-
- state.pub_key = x509.parse_public_key(state.allocator, subreader) catch |err| switch (err) {
- error.MalformedDER => return error.ServerMalformedResponse,
- else => |e| return e,
- };
- }
- }.f,
- };
-
- const cert_length = try reader.readIntBig(u24);
- asn1.der.parse_schema(schema, captures, reader) catch |err| switch (err) {
- error.InvalidLength,
- error.InvalidTag,
- error.InvalidContainerLength,
- error.DoesNotMatchSchema,
- => return error.ServerMalformedResponse,
- else => |e| return e,
- };
- errdefer capture_state.pub_key.deinit(allocator);
-
- try reader.skipBytes(length - cert_length - 3, .{});
- return capture_state.pub_key;
-}
-
-pub const curves = struct {
- pub const x25519 = struct {
- pub const name = "x25519";
- const tag = 0x001D;
- const pub_key_len = 32;
- const Keys = std.crypto.dh.X25519.KeyPair;
-
- inline fn make_key_pair(rand: *std.rand.Random) Keys {
- while (true) {
- var seed: [32]u8 = undefined;
- rand.bytes(&seed);
- return std.crypto.dh.X25519.KeyPair.create(seed) catch continue;
- } else unreachable;
- }
-
- inline fn make_pre_master_secret(
- key_pair: Keys,
- pre_master_secret_buf: []u8,
- server_public_key: *const [32]u8,
- ) ![]const u8 {
- pre_master_secret_buf[0..32].* = std.crypto.dh.X25519.scalarmult(
- key_pair.secret_key,
- server_public_key.*,
- ) catch return error.PreMasterGenerationFailed;
- return pre_master_secret_buf[0..32];
- }
- };
-
- pub const secp384r1 = struct {
- pub const name = "secp384r1";
- const tag = 0x0018;
- const pub_key_len = 97;
- const Keys = crypto.ecc.KeyPair(crypto.ecc.SECP384R1);
-
- inline fn make_key_pair(rand: *std.rand.Random) Keys {
- var seed: [48]u8 = undefined;
- rand.bytes(&seed);
- return crypto.ecc.make_key_pair(crypto.ecc.SECP384R1, seed);
- }
-
- inline fn make_pre_master_secret(
- key_pair: Keys,
- pre_master_secret_buf: []u8,
- server_public_key: *const [97]u8,
- ) ![]const u8 {
- pre_master_secret_buf[0..96].* = crypto.ecc.scalarmult(
- crypto.ecc.SECP384R1,
- server_public_key[1..].*,
- &key_pair.secret_key,
- ) catch return error.PreMasterGenerationFailed;
- return pre_master_secret_buf[0..48];
- }
- };
-
- pub const secp256r1 = struct {
- pub const name = "secp256r1";
- const tag = 0x0017;
- const pub_key_len = 65;
- const Keys = crypto.ecc.KeyPair(crypto.ecc.SECP256R1);
-
- inline fn make_key_pair(rand: *std.rand.Random) Keys {
- var seed: [32]u8 = undefined;
- rand.bytes(&seed);
- return crypto.ecc.make_key_pair(crypto.ecc.SECP256R1, seed);
- }
-
- inline fn make_pre_master_secret(
- key_pair: Keys,
- pre_master_secret_buf: []u8,
- server_public_key: *const [65]u8,
- ) ![]const u8 {
- pre_master_secret_buf[0..64].* = crypto.ecc.scalarmult(
- crypto.ecc.SECP256R1,
- server_public_key[1..].*,
- &key_pair.secret_key,
- ) catch return error.PreMasterGenerationFailed;
- return pre_master_secret_buf[0..32];
- }
- };
-
- pub const all = &[_]type{ x25519, secp384r1, secp256r1 };
-
- fn max_pub_key_len(comptime list: anytype) usize {
- var max: usize = 0;
- for (list) |curve| {
- if (curve.pub_key_len > max)
- max = curve.pub_key_len;
- }
- return max;
- }
-
- fn max_pre_master_secret_len(comptime list: anytype) usize {
- var max: usize = 0;
- for (list) |curve| {
- const curr = @typeInfo(std.meta.fieldInfo(curve.Keys, .public_key).field_type).Array.len;
- if (curr > max)
- max = curr;
- }
- return max;
- }
-
- fn KeyPair(comptime list: anytype) type {
- var fields: [list.len]std.builtin.TypeInfo.UnionField = undefined;
- for (list) |curve, i| {
- fields[i] = .{
- .name = curve.name,
- .field_type = curve.Keys,
- .alignment = @alignOf(curve.Keys),
- };
- }
- return @Type(.{
- .Union = .{
- .layout = .Extern,
- .tag_type = null,
- .fields = &fields,
- .decls = &[0]std.builtin.TypeInfo.Declaration{},
- },
- });
- }
-
- inline fn make_key_pair(comptime list: anytype, curve_id: u16, rand: *std.rand.Random) KeyPair(list) {
- inline for (list) |curve| {
- if (curve.tag == curve_id) {
- return @unionInit(KeyPair(list), curve.name, curve.make_key_pair(rand));
- }
- }
- unreachable;
- }
-
- inline fn make_pre_master_secret(
- comptime list: anytype,
- curve_id: u16,
- key_pair: KeyPair(list),
- pre_master_secret_buf: *[max_pre_master_secret_len(list)]u8,
- server_public_key: [max_pub_key_len(list)]u8,
- ) ![]const u8 {
- inline for (list) |curve| {
- if (curve.tag == curve_id) {
- return try curve.make_pre_master_secret(
- @field(key_pair, curve.name),
- pre_master_secret_buf,
- server_public_key[0..curve.pub_key_len],
- );
- }
- }
- unreachable;
- }
-};
-
-pub fn client_connect(
- options: anytype,
- hostname: []const u8,
-) ClientConnectError(
- options.cert_verifier,
- @TypeOf(options.reader),
- @TypeOf(options.writer),
- @hasField(@TypeOf(options), "client_certificates"),
-)!Client(
- @TypeOf(options.reader),
- @TypeOf(options.writer),
- if (@hasField(@TypeOf(options), "ciphersuites"))
- options.ciphersuites
- else
- ciphersuites.all,
- @hasField(@TypeOf(options), "protocols"),
-) {
- const Options = @TypeOf(options);
- if (@TypeOf(options.cert_verifier) != CertificateVerifier and
- @TypeOf(options.cert_verifier) != @Type(.EnumLiteral))
- @compileError("cert_verifier should be of type CertificateVerifier");
-
- if (!@hasField(Options, "temp_allocator"))
- @compileError("Option tuple is missing field 'temp_allocator'");
- if (options.cert_verifier == .default) {
- if (!@hasField(Options, "trusted_certificates"))
- @compileError("Option tuple is missing field 'trusted_certificates' for .default cert_verifier");
- }
-
- const suites = if (!@hasField(Options, "ciphersuites"))
- ciphersuites.all
- else
- options.ciphersuites;
- if (suites.len == 0)
- @compileError("Must provide at least one ciphersuite type.");
-
- const curvelist = if (!@hasField(Options, "curves"))
- curves.all
- else
- options.curves;
- if (curvelist.len == 0)
- @compileError("Must provide at least one curve type.");
-
- const has_alpn = comptime @hasField(Options, "protocols");
- var handshake_record_hash_set = HashSet{
- .sha224 = Sha224.init(.{}),
- .sha256 = Sha256.init(.{}),
- .sha384 = Sha384.init(.{}),
- .sha512 = Sha512.init(.{}),
- };
- const reader = options.reader;
- const writer = options.writer;
- const hashing_reader = make_hashing_reader(&handshake_record_hash_set, reader);
- const hashing_writer = make_hashing_writer(&handshake_record_hash_set, writer);
-
- var client_random: [32]u8 = undefined;
- const rand = if (!@hasField(Options, "rand"))
- std.crypto.random
- else
- options.rand;
-
- rand.bytes(&client_random);
-
- var server_random: [32]u8 = undefined;
- const ciphersuite_bytes = 2 * suites.len + 2;
- const alpn_bytes = if (has_alpn) blk: {
- var sum: usize = 0;
- for (options.protocols) |proto| {
- sum += proto.len;
- }
- break :blk 6 + options.protocols.len + sum;
- } else 0;
- const curvelist_bytes = 2 * curvelist.len;
- var protocol: if (has_alpn) []const u8 else void = undefined;
- {
- const client_hello_start = comptime blk: {
- // TODO: We assume the compiler is running in a little endian system
- var starting_part: [46]u8 = [_]u8{
- // Record header: Handshake record type, protocol version, handshake size
- 0x16, 0x03, 0x01, undefined, undefined,
- // Handshake message type, bytes of client hello
- 0x01, undefined, undefined, undefined,
- // Client version (hardcoded to TLS 1.2 even for TLS 1.3)
- 0x03,
- 0x03,
- } ++ ([1]u8{undefined} ** 32) ++ [_]u8{
- // Session ID
- 0x00,
- } ++ mem.toBytes(@byteSwap(u16, ciphersuite_bytes));
- // using .* = mem.asBytes(...).* or mem.writeIntBig didn't work...
-
- // Same as above, couldnt achieve this with a single buffer.
- // TLS_EMPTY_RENEGOTIATION_INFO_SCSV
- var ciphersuite_buf: []const u8 = &[2]u8{ 0x00, 0x0f };
- for (suites) |cs| {
- // Also check for properties of the ciphersuites here
- if (cs.key_exchange != .ecdhe)
- @compileError("Non ECDHE key exchange is not supported yet.");
- if (cs.hash != .sha256)
- @compileError("Non SHA256 hash algorithm is not supported yet.");
-
- ciphersuite_buf = ciphersuite_buf ++ mem.toBytes(@byteSwap(u16, cs.tag));
- }
-
- var ending_part: [13]u8 = [_]u8{
- // Compression methods (no compression)
- 0x01, 0x00,
- // Extensions length
- undefined, undefined,
- // Extension: server name
- // id, length, length of entry
- 0x00, 0x00,
- undefined, undefined,
- undefined, undefined,
- // entry type, length of bytes
- 0x00, undefined,
- undefined,
- };
- break :blk starting_part ++ ciphersuite_buf ++ ending_part;
- };
-
- var msg_buf = client_hello_start.ptr[0..client_hello_start.len].*;
- mem.writeIntBig(u16, msg_buf[3..5], @intCast(u16, alpn_bytes + hostname.len + 0x55 + ciphersuite_bytes + curvelist_bytes));
- mem.writeIntBig(u24, msg_buf[6..9], @intCast(u24, alpn_bytes + hostname.len + 0x51 + ciphersuite_bytes + curvelist_bytes));
- mem.copy(u8, msg_buf[11..43], &client_random);
- mem.writeIntBig(u16, msg_buf[48 + ciphersuite_bytes ..][0..2], @intCast(u16, alpn_bytes + hostname.len + 0x28 + curvelist_bytes));
- mem.writeIntBig(u16, msg_buf[52 + ciphersuite_bytes ..][0..2], @intCast(u16, hostname.len + 5));
- mem.writeIntBig(u16, msg_buf[54 + ciphersuite_bytes ..][0..2], @intCast(u16, hostname.len + 3));
- mem.writeIntBig(u16, msg_buf[57 + ciphersuite_bytes ..][0..2], @intCast(u16, hostname.len));
- try writer.writeAll(msg_buf[0..5]);
- try hashing_writer.writeAll(msg_buf[5..]);
- }
- try hashing_writer.writeAll(hostname);
- if (has_alpn) {
- var msg_buf = [6]u8{ 0x00, 0x10, undefined, undefined, undefined, undefined };
- mem.writeIntBig(u16, msg_buf[2..4], @intCast(u16, alpn_bytes - 4));
- mem.writeIntBig(u16, msg_buf[4..6], @intCast(u16, alpn_bytes - 6));
- try hashing_writer.writeAll(&msg_buf);
- for (options.protocols) |proto| {
- try hashing_writer.writeByte(@intCast(u8, proto.len));
- try hashing_writer.writeAll(proto);
- }
- }
-
- // Extension: supported groups
- {
- var msg_buf = [6]u8{
- 0x00, 0x0A,
- undefined, undefined,
- undefined, undefined,
- };
-
- mem.writeIntBig(u16, msg_buf[2..4], @intCast(u16, curvelist_bytes + 2));
- mem.writeIntBig(u16, msg_buf[4..6], @intCast(u16, curvelist_bytes));
- try hashing_writer.writeAll(&msg_buf);
-
- inline for (curvelist) |curve| {
- try hashing_writer.writeIntBig(u16, curve.tag);
- }
- }
-
- try hashing_writer.writeAll(&[25]u8{
- // Extension: EC point formats => uncompressed point format
- 0x00, 0x0B, 0x00, 0x02, 0x01, 0x00,
- // Extension: Signature algorithms
- // RSA/PKCS1/SHA256, RSA/PKCS1/SHA512
- 0x00, 0x0D, 0x00, 0x06, 0x00, 0x04,
- 0x04, 0x01, 0x06, 0x01,
- // Extension: Renegotiation Info => new connection
- 0xFF, 0x01,
- 0x00, 0x01, 0x00,
- // Extension: SCT (signed certificate timestamp)
- 0x00, 0x12, 0x00,
- 0x00,
- });
-
- // Read server hello
- var ciphersuite: u16 = undefined;
- {
- const length = try handshake_record_length(reader);
- if (length < 44)
- return error.ServerMalformedResponse;
- {
- var hs_hdr_and_server_ver: [6]u8 = undefined;
- try hashing_reader.readNoEof(&hs_hdr_and_server_ver);
- if (hs_hdr_and_server_ver[0] != 0x02)
- return error.ServerMalformedResponse;
- if (!mem.eql(u8, hs_hdr_and_server_ver[4..6], "\x03\x03"))
- return error.ServerInvalidVersion;
- }
- try hashing_reader.readNoEof(&server_random);
-
- // Just skip the session id for now
- const sess_id_len = try hashing_reader.readByte();
- if (sess_id_len != 0)
- try hashing_reader.skipBytes(sess_id_len, .{});
-
- {
- ciphersuite = try hashing_reader.readIntBig(u16);
- var found = false;
- inline for (suites) |cs| {
- if (ciphersuite == cs.tag) {
- found = true;
- // TODO This segfaults stage1
- // break;
- }
- }
- if (!found)
- return error.ServerInvalidCipherSuite;
- }
-
- // Compression method
- if ((try hashing_reader.readByte()) != 0x00)
- return error.ServerInvalidCompressionMethod;
-
- const exts_length = try hashing_reader.readIntBig(u16);
- var ext_byte_idx: usize = 0;
- while (ext_byte_idx < exts_length) {
- var ext_tag: [2]u8 = undefined;
- try hashing_reader.readNoEof(&ext_tag);
-
- const ext_len = try hashing_reader.readIntBig(u16);
- ext_byte_idx += 4 + ext_len;
- if (ext_tag[0] == 0xFF and ext_tag[1] == 0x01) {
- // Renegotiation info
- const renegotiation_info = try hashing_reader.readByte();
- if (ext_len != 0x01 or renegotiation_info != 0x00)
- return error.ServerInvalidRenegotiationData;
- } else if (ext_tag[0] == 0x00 and ext_tag[1] == 0x00) {
- // Server name
- if (ext_len != 0)
- try hashing_reader.skipBytes(ext_len, .{});
- } else if (ext_tag[0] == 0x00 and ext_tag[1] == 0x0B) {
- const format_count = try hashing_reader.readByte();
- var found_uncompressed = false;
- var i: usize = 0;
- while (i < format_count) : (i += 1) {
- const byte = try hashing_reader.readByte();
- if (byte == 0x0)
- found_uncompressed = true;
- }
- if (!found_uncompressed)
- return error.ServerInvalidECPointCompression;
- } else if (has_alpn and ext_tag[0] == 0x00 and ext_tag[1] == 0x10) {
- const alpn_ext_len = try hashing_reader.readIntBig(u16);
- if (alpn_ext_len != ext_len - 2)
- return error.ServerMalformedResponse;
- const str_len = try hashing_reader.readByte();
- var buf: [256]u8 = undefined;
- try hashing_reader.readNoEof(buf[0..str_len]);
- const found = for (options.protocols) |proto| {
- if (mem.eql(u8, proto, buf[0..str_len])) {
- protocol = proto;
- break true;
- }
- } else false;
- if (!found)
- return error.ServerInvalidProtocol;
- try hashing_reader.skipBytes(alpn_ext_len - str_len - 1, .{});
- } else return error.ServerInvalidExtension;
- }
- if (ext_byte_idx != exts_length)
- return error.ServerMalformedResponse;
- }
- // Read server certificates
- var certificate_public_key: x509.PublicKey = undefined;
- {
- const length = try handshake_record_length(reader);
- _ = length;
- {
- var handshake_header: [4]u8 = undefined;
- try hashing_reader.readNoEof(&handshake_header);
- if (handshake_header[0] != 0x0b)
- return error.ServerMalformedResponse;
- }
- const certs_length = try hashing_reader.readIntBig(u24);
- const cert_verifier: CertificateVerifier = options.cert_verifier;
- switch (cert_verifier) {
- .none => certificate_public_key = try extract_cert_public_key(
- options.temp_allocator,
- hashing_reader,
- certs_length,
- ),
- .function => |f| {
- var reader_state = CertificateReaderState(@TypeOf(hashing_reader)){
- .reader = hashing_reader,
- .length = certs_length,
- };
- var cert_reader = CertificateReader(@TypeOf(hashing_reader)){ .context = &reader_state };
- certificate_public_key = try f(cert_reader);
- try hashing_reader.skipBytes(reader_state.length - reader_state.idx, .{});
- },
- .default => certificate_public_key = try default_cert_verifier(
- options.temp_allocator,
- hashing_reader,
- certs_length,
- options.trusted_certificates,
- hostname,
- ),
- }
- }
- errdefer certificate_public_key.deinit(options.temp_allocator);
- // Read server ephemeral public key
- var server_public_key_buf: [curves.max_pub_key_len(curvelist)]u8 = undefined;
- var curve_id: u16 = undefined;
- var curve_id_buf: [3]u8 = undefined;
- var pub_key_len: u8 = undefined;
- {
- const length = try handshake_record_length(reader);
- _ = length;
- {
- var handshake_header: [4]u8 = undefined;
- try hashing_reader.readNoEof(&handshake_header);
- if (handshake_header[0] != 0x0c)
- return error.ServerMalformedResponse;
-
- try hashing_reader.readNoEof(&curve_id_buf);
- if (curve_id_buf[0] != 0x03)
- return error.ServerMalformedResponse;
-
- curve_id = mem.readIntBig(u16, curve_id_buf[1..]);
- var found = false;
- inline for (curvelist) |curve| {
- if (curve.tag == curve_id) {
- found = true;
- // @TODO This break segfaults stage1
- // break;
- }
- }
- if (!found)
- return error.ServerInvalidCurve;
- }
-
- pub_key_len = try hashing_reader.readByte();
- inline for (curvelist) |curve| {
- if (curve.tag == curve_id) {
- if (curve.pub_key_len != pub_key_len)
- return error.ServerMalformedResponse;
- // @TODO This break segfaults stage1
- // break;
- }
- }
-
- try hashing_reader.readNoEof(server_public_key_buf[0..pub_key_len]);
- if (curve_id != curves.x25519.tag) {
- if (server_public_key_buf[0] != 0x04)
- return error.ServerMalformedResponse;
- }
-
- // Signed public key
- const signature_id = try hashing_reader.readIntBig(u16);
- const signature_len = try hashing_reader.readIntBig(u16);
-
- var hash_buf: [64]u8 = undefined;
- var hash: []const u8 = undefined;
- const signature_algoritm: x509.Certificate.SignatureAlgorithm = switch (signature_id) {
- // TODO: More
- // RSA/PKCS1/SHA256
- 0x0401 => block: {
- var sha256 = Sha256.init(.{});
- sha256.update(&client_random);
- sha256.update(&server_random);
- sha256.update(&curve_id_buf);
- sha256.update(&[1]u8{pub_key_len});
- sha256.update(server_public_key_buf[0..pub_key_len]);
- sha256.final(hash_buf[0..32]);
- hash = hash_buf[0..32];
- break :block .{ .signature = .rsa, .hash = .sha256 };
- },
- // RSA/PKCS1/SHA512
- 0x0601 => block: {
- var sha512 = Sha512.init(.{});
- sha512.update(&client_random);
- sha512.update(&server_random);
- sha512.update(&curve_id_buf);
- sha512.update(&[1]u8{pub_key_len});
- sha512.update(server_public_key_buf[0..pub_key_len]);
- sha512.final(hash_buf[0..64]);
- hash = hash_buf[0..64];
- break :block .{ .signature = .rsa, .hash = .sha512 };
- },
- else => return error.ServerInvalidSignatureAlgorithm,
- };
- const signature_bytes = try options.temp_allocator.alloc(u8, signature_len);
- defer options.temp_allocator.free(signature_bytes);
- try hashing_reader.readNoEof(signature_bytes);
-
- if (!try @"pcks1v1.5".verify_signature(
- options.temp_allocator,
- signature_algoritm,
- .{ .data = signature_bytes, .bit_len = signature_len * 8 },
- hash,
- certificate_public_key,
- ))
- return error.ServerInvalidSignature;
-
- certificate_public_key.deinit(options.temp_allocator);
- certificate_public_key = x509.PublicKey.empty;
- }
- var client_certificate: ?*const x509.ClientCertificateChain = null;
- {
- const length = try handshake_record_length(reader);
- const record_type = try hashing_reader.readByte();
- if (record_type == 14) {
- // Server hello done
- const is_bytes = try hashing_reader.isBytes("\x00\x00\x00");
- if (length != 4 or !is_bytes)
- return error.ServerMalformedResponse;
- } else if (record_type == 13) {
- // Certificate request
- const certificate_request_bytes = try hashing_reader.readIntBig(u24);
- const hello_done_in_same_record =
- if (length == certificate_request_bytes + 8)
- true
- else if (length != certificate_request_bytes)
- false
- else
- return error.ServerMalformedResponse;
- // TODO: For now, we are ignoring the certificate types, as they have been somewhat
- // superceded by the supported_signature_algorithms field
- const certificate_types_bytes = try hashing_reader.readByte();
- try hashing_reader.skipBytes(certificate_types_bytes, .{});
-
- var chosen_client_certificates = std.ArrayListUnmanaged(*const x509.ClientCertificateChain){};
- defer chosen_client_certificates.deinit(options.temp_allocator);
-
- const signature_algorithms_bytes = try hashing_reader.readIntBig(u16);
- if (@hasField(Options, "client_certificates")) {
- var i: usize = 0;
- while (i < signature_algorithms_bytes / 2) : (i += 1) {
- var signature_algorithm: [2]u8 = undefined;
- try hashing_reader.readNoEof(&signature_algorithm);
- for (options.client_certificates) |*cert_chain| {
- if (@enumToInt(cert_chain.signature_algorithm.hash) == signature_algorithm[0] and
- @enumToInt(cert_chain.signature_algorithm.signature) == signature_algorithm[1])
- {
- try chosen_client_certificates.append(options.temp_allocator, cert_chain);
- }
- }
- }
- } else {
- try hashing_reader.skipBytes(signature_algorithms_bytes, .{});
- }
-
- const certificate_authorities_bytes = try hashing_reader.readIntBig(u16);
- if (chosen_client_certificates.items.len == 0) {
- try hashing_reader.skipBytes(certificate_authorities_bytes, .{});
- } else {
- const dns_buf = try options.temp_allocator.alloc(u8, certificate_authorities_bytes);
- defer options.temp_allocator.free(dns_buf);
-
- try hashing_reader.readNoEof(dns_buf);
- var fbs = std.io.fixedBufferStream(dns_buf[2..]);
- var fbs_reader = fbs.reader();
-
- while (fbs.pos < fbs.buffer.len) {
- const start_idx = fbs.pos;
- const seq_tag = fbs_reader.readByte() catch return error.ServerMalformedResponse;
- if (seq_tag != 0x30)
- return error.ServerMalformedResponse;
-
- const seq_length = asn1.der.parse_length(fbs_reader) catch return error.ServerMalformedResponse;
- fbs_reader.skipBytes(seq_length, .{}) catch return error.ServerMalformedResponse;
-
- var i: usize = 0;
- while (i < chosen_client_certificates.items.len) {
- const cert = chosen_client_certificates.items[i];
- var cert_idx: usize = 0;
- while (cert_idx < cert.cert_len) : (cert_idx += 1) {
- if (mem.eql(u8, cert.cert_issuer_dns[cert_idx], fbs.buffer[start_idx..fbs.pos]))
- break;
- } else {
- _ = chosen_client_certificates.swapRemove(i);
- continue;
- }
- i += 1;
- }
- }
- if (fbs.pos != fbs.buffer.len)
- return error.ServerMalformedResponse;
- }
- // Server hello done
- if (!hello_done_in_same_record) {
- const hello_done_record_len = try handshake_record_length(reader);
- if (hello_done_record_len != 4)
- return error.ServerMalformedResponse;
- }
- const hello_record_type = try hashing_reader.readByte();
- if (hello_record_type != 14)
- return error.ServerMalformedResponse;
- const is_bytes = try hashing_reader.isBytes("\x00\x00\x00");
- if (!is_bytes)
- return error.ServerMalformedResponse;
-
- // Send the client certificate message
- try writer.writeAll(&[3]u8{ 0x16, 0x03, 0x03 });
- if (chosen_client_certificates.items.len != 0) {
- client_certificate = chosen_client_certificates.items[0];
-
- const certificate_count = client_certificate.?.cert_len;
- // 7 bytes for the record type tag (1), record length (3), certificate list length (3)
- // 3 bytes for each certificate length
- var total_len: u24 = 7 + 3 * @intCast(u24, certificate_count);
- var i: usize = 0;
- while (i < certificate_count) : (i += 1) {
- total_len += @intCast(u24, client_certificate.?.raw_certs[i].len);
- }
- try writer.writeIntBig(u16, @intCast(u16, total_len));
- var msg_buf: [7]u8 = [1]u8{0x0b} ++ ([1]u8{undefined} ** 6);
- mem.writeIntBig(u24, msg_buf[1..4], total_len - 4);
- mem.writeIntBig(u24, msg_buf[4..7], total_len - 7);
- try hashing_writer.writeAll(&msg_buf);
- i = 0;
- while (i < certificate_count) : (i += 1) {
- try hashing_writer.writeIntBig(u24, @intCast(u24, client_certificate.?.raw_certs[i].len));
- try hashing_writer.writeAll(client_certificate.?.raw_certs[i]);
- }
- } else {
- try writer.writeIntBig(u16, 7);
- try hashing_writer.writeAll(&[7]u8{ 0x0b, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 });
- }
- } else return error.ServerMalformedResponse;
- }
-
- // Generate keys for the session
- const client_key_pair = curves.make_key_pair(curvelist, curve_id, rand);
-
- // Client key exchange
- try writer.writeAll(&[3]u8{ 0x16, 0x03, 0x03 });
- try writer.writeIntBig(u16, pub_key_len + 5);
- try hashing_writer.writeAll(&[5]u8{ 0x10, 0x00, 0x00, pub_key_len + 1, pub_key_len });
-
- inline for (curvelist) |curve| {
- if (curve.tag == curve_id) {
- const actual_len = @typeInfo(std.meta.fieldInfo(curve.Keys, .public_key).field_type).Array.len;
- if (pub_key_len == actual_len + 1) {
- try hashing_writer.writeByte(0x04);
- } else {
- std.debug.assert(pub_key_len == actual_len);
- }
- try hashing_writer.writeAll(&@field(client_key_pair, curve.name).public_key);
- break;
- }
- }
-
- // If we have a client certificate, send a certificate verify message
- if (@hasField(Options, "client_certificates")) {
- if (client_certificate) |client_cert| {
- var current_hash_buf: [64]u8 = undefined;
- var current_hash: []const u8 = undefined;
- const hash_algo = client_cert.signature_algorithm.hash;
- // TODO: Making this a switch statement kills stage1
- if (hash_algo == .none or hash_algo == .md5 or hash_algo == .sha1)
- return error.ClientCertificateVerifyFailed
- else if (hash_algo == .sha224) {
- var hash_copy = handshake_record_hash_set.sha224;
- hash_copy.final(current_hash_buf[0..28]);
- current_hash = current_hash_buf[0..28];
- } else if (hash_algo == .sha256) {
- var hash_copy = handshake_record_hash_set.sha256;
- hash_copy.final(current_hash_buf[0..32]);
- current_hash = current_hash_buf[0..32];
- } else if (hash_algo == .sha384) {
- var hash_copy = handshake_record_hash_set.sha384;
- hash_copy.final(current_hash_buf[0..48]);
- current_hash = current_hash_buf[0..48];
- } else {
- var hash_copy = handshake_record_hash_set.sha512;
- hash_copy.final(&current_hash_buf);
- current_hash = &current_hash_buf;
- }
-
- const signed = (try @"pcks1v1.5".sign(
- options.temp_allocator,
- client_cert.signature_algorithm,
- current_hash,
- client_cert.private_key,
- )) orelse return error.ClientCertificateVerifyFailed;
- defer options.temp_allocator.free(signed);
-
- try writer.writeAll(&[3]u8{ 0x16, 0x03, 0x03 });
- try writer.writeIntBig(u16, @intCast(u16, signed.len + 8));
- var msg_buf: [8]u8 = [1]u8{0x0F} ++ ([1]u8{undefined} ** 7);
- mem.writeIntBig(u24, msg_buf[1..4], @intCast(u24, signed.len + 4));
- msg_buf[4] = @enumToInt(client_cert.signature_algorithm.hash);
- msg_buf[5] = @enumToInt(client_cert.signature_algorithm.signature);
- mem.writeIntBig(u16, msg_buf[6..8], @intCast(u16, signed.len));
- try hashing_writer.writeAll(&msg_buf);
- try hashing_writer.writeAll(signed);
- }
- }
-
- // Client encryption keys calculation for ECDHE_RSA cipher suites with SHA256 hash
- var master_secret: [48]u8 = undefined;
- var key_data: ciphers.KeyData(suites) = undefined;
- {
- var pre_master_secret_buf: [curves.max_pre_master_secret_len(curvelist)]u8 = undefined;
- const pre_master_secret = try curves.make_pre_master_secret(
- curvelist,
- curve_id,
- client_key_pair,
- &pre_master_secret_buf,
- server_public_key_buf,
- );
-
- const seed_len = 77; // extra len variable to workaround a bug
- var seed: [seed_len]u8 = undefined;
- seed[0..13].* = "master secret".*;
- seed[13..45].* = client_random;
- seed[45..77].* = server_random;
-
- var a1: [32 + seed.len]u8 = undefined;
- Hmac256.create(a1[0..32], &seed, pre_master_secret);
- var a2: [32 + seed.len]u8 = undefined;
- Hmac256.create(a2[0..32], a1[0..32], pre_master_secret);
-
- a1[32..].* = seed;
- a2[32..].* = seed;
-
- var p1: [32]u8 = undefined;
- Hmac256.create(&p1, &a1, pre_master_secret);
- var p2: [32]u8 = undefined;
- Hmac256.create(&p2, &a2, pre_master_secret);
-
- master_secret[0..32].* = p1;
- master_secret[32..48].* = p2[0..16].*;
-
- // Key expansion
- seed[0..13].* = "key expansion".*;
- seed[13..45].* = server_random;
- seed[45..77].* = client_random;
- a1[32..].* = seed;
- a2[32..].* = seed;
-
- const KeyExpansionState = struct {
- seed: *const [77]u8,
- a1: *[32 + seed_len]u8,
- a2: *[32 + seed_len]u8,
- master_secret: *const [48]u8,
- };
-
- const next_32_bytes = struct {
- inline fn f(
- state: *KeyExpansionState,
- comptime chunk_idx: comptime_int,
- chunk: *[32]u8,
- ) void {
- if (chunk_idx == 0) {
- Hmac256.create(state.a1[0..32], state.seed, state.master_secret);
- Hmac256.create(chunk, state.a1, state.master_secret);
- } else if (chunk_idx % 2 == 1) {
- Hmac256.create(state.a2[0..32], state.a1[0..32], state.master_secret);
- Hmac256.create(chunk, state.a2, state.master_secret);
- } else {
- Hmac256.create(state.a1[0..32], state.a2[0..32], state.master_secret);
- Hmac256.create(chunk, state.a1, state.master_secret);
- }
- }
- }.f;
- var state = KeyExpansionState{
- .seed = &seed,
- .a1 = &a1,
- .a2 = &a2,
- .master_secret = &master_secret,
- };
-
- key_data = ciphers.key_expansion(suites, ciphersuite, &state, next_32_bytes);
- }
-
- // Client change cipher spec and client handshake finished
- {
- try writer.writeAll(&[6]u8{
- // Client change cipher spec
- 0x14, 0x03, 0x03,
- 0x00, 0x01, 0x01,
- });
- // The message we need to encrypt is the following:
- // 0x14 0x00 0x00 0x0c
- // <12 bytes of verify_data>
- // seed = "client finished" + SHA256(all handshake messages)
- // a1 = HMAC-SHA256(key=MasterSecret, data=seed)
- // p1 = HMAC-SHA256(key=MasterSecret, data=a1 + seed)
- // verify_data = p1[0..12]
- var verify_message: [16]u8 = undefined;
- verify_message[0..4].* = "\x14\x00\x00\x0C".*;
- {
- var seed: [47]u8 = undefined;
- seed[0..15].* = "client finished".*;
- // We still need to update the hash one time, so we copy
- // to get the current digest here.
- var hash_copy = handshake_record_hash_set.sha256;
- hash_copy.final(seed[15..47]);
-
- var a1: [32 + seed.len]u8 = undefined;
- Hmac256.create(a1[0..32], &seed, &master_secret);
- a1[32..].* = seed;
- var p1: [32]u8 = undefined;
- Hmac256.create(&p1, &a1, &master_secret);
- verify_message[4..16].* = p1[0..12].*;
- }
- handshake_record_hash_set.update(&verify_message);
-
- inline for (suites) |cs| {
- if (cs.tag == ciphersuite) {
- try cs.raw_write(
- 256,
- rand,
- &key_data,
- writer,
- [3]u8{ 0x16, 0x03, 0x03 },
- 0,
- &verify_message,
- );
- }
- }
- }
-
- // Server change cipher spec
- {
- const length = try record_length(0x14, reader);
- const next_byte = try reader.readByte();
- if (length != 1 or next_byte != 0x01)
- return error.ServerMalformedResponse;
- }
- // Server handshake finished
- {
- const length = try handshake_record_length(reader);
-
- var verify_message: [16]u8 = undefined;
- verify_message[0..4].* = "\x14\x00\x00\x0C".*;
- {
- var seed: [47]u8 = undefined;
- seed[0..15].* = "server finished".*;
- handshake_record_hash_set.sha256.final(seed[15..47]);
- var a1: [32 + seed.len]u8 = undefined;
- Hmac256.create(a1[0..32], &seed, &master_secret);
- a1[32..].* = seed;
- var p1: [32]u8 = undefined;
- Hmac256.create(&p1, &a1, &master_secret);
- verify_message[4..16].* = p1[0..12].*;
- }
-
- inline for (suites) |cs| {
- if (cs.tag == ciphersuite) {
- if (!try cs.check_verify_message(&key_data, length, reader, verify_message))
- return error.ServerInvalidVerifyData;
- }
- }
- }
-
- return Client(@TypeOf(reader), @TypeOf(writer), suites, has_alpn){
- .ciphersuite = ciphersuite,
- .key_data = key_data,
- .rand = rand,
- .parent_reader = reader,
- .parent_writer = writer,
- .protocol = protocol,
- };
-}
-
-pub fn Client(
- comptime _Reader: type,
- comptime _Writer: type,
- comptime _ciphersuites: anytype,
- comptime has_protocol: bool,
-) type {
- return struct {
- const ReaderError = _Reader.Error || ServerAlert || error{ ServerMalformedResponse, ServerInvalidVersion, AuthenticationFailed };
- pub const Reader = std.io.Reader(*@This(), ReaderError, read);
- pub const Writer = std.io.Writer(*@This(), _Writer.Error, write);
-
- const InRecordState = ciphers.InRecordState(_ciphersuites);
- const ReadState = union(enum) {
- none,
- in_record: struct {
- record_length: usize,
- index: usize = 0,
- state: InRecordState,
- },
- };
-
- ciphersuite: u16,
- client_seq: u64 = 1,
- server_seq: u64 = 1,
- key_data: ciphers.KeyData(_ciphersuites),
- read_state: ReadState = .none,
- rand: *std.rand.Random,
-
- parent_reader: _Reader,
- parent_writer: _Writer,
-
- protocol: if (has_protocol) []const u8 else void,
-
- pub fn reader(self: *@This()) Reader {
- return .{ .context = self };
- }
-
- pub fn writer(self: *@This()) Writer {
- return .{ .context = self };
- }
-
- pub fn read(self: *@This(), buffer: []u8) ReaderError!usize {
- const buf_size = 1024;
-
- switch (self.read_state) {
- .none => {
- const header = record_header(self.parent_reader) catch |err| switch (err) {
- error.EndOfStream => return 0,
- else => |e| return e,
- };
-
- const len_overhead = inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- break cs.mac_length + cs.prefix_data_length;
- }
- } else unreachable;
-
- const rec_length = header.len();
- if (rec_length < len_overhead)
- return error.ServerMalformedResponse;
- const len = rec_length - len_overhead;
-
- if ((header.tag() != 0x17 and header.tag() != 0x15) or
- (header.tag() == 0x15 and len != 2))
- {
- return error.ServerMalformedResponse;
- }
-
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- var prefix_data: [cs.prefix_data_length]u8 = undefined;
- if (cs.prefix_data_length > 0) {
- self.parent_reader.readNoEof(&prefix_data) catch |err| switch (err) {
- error.EndOfStream => return error.ServerMalformedResponse,
- else => |e| return e,
- };
- }
- self.read_state = .{ .in_record = .{
- .record_length = len,
- .state = @unionInit(
- InRecordState,
- cs.name,
- cs.init_state(prefix_data, self.server_seq, &self.key_data, header),
- ),
- } };
- }
- }
-
- if (header.tag() == 0x15) {
- var encrypted: [2]u8 = undefined;
- self.parent_reader.readNoEof(&encrypted) catch |err| switch (err) {
- error.EndOfStream => return error.ServerMalformedResponse,
- else => |e| return e,
- };
-
- var result: [2]u8 = undefined;
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- // This decrypt call should always consume the whole record
- cs.decrypt_part(
- &self.key_data,
- self.read_state.in_record.record_length,
- &self.read_state.in_record.index,
- &@field(self.read_state.in_record.state, cs.name),
- &encrypted,
- &result,
- );
- std.debug.assert(self.read_state.in_record.index == self.read_state.in_record.record_length);
- try cs.verify_mac(
- self.parent_reader,
- self.read_state.in_record.record_length,
- &@field(self.read_state.in_record.state, cs.name),
- );
- }
- }
- self.read_state = .none;
- self.server_seq += 1;
- // CloseNotify
- if (result[1] == 0)
- return 0;
- return alert_byte_to_error(result[1]);
- } else if (header.tag() == 0x17) {
- const curr_bytes = std.math.min(std.math.min(len, buf_size), buffer.len);
- // Partially decrypt the data.
- var encrypted: [buf_size]u8 = undefined;
- const actually_read = try self.parent_reader.read(encrypted[0..curr_bytes]);
-
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- cs.decrypt_part(
- &self.key_data,
- self.read_state.in_record.record_length,
- &self.read_state.in_record.index,
- &@field(self.read_state.in_record.state, cs.name),
- encrypted[0..actually_read],
- buffer[0..actually_read],
- );
-
- if (self.read_state.in_record.index == self.read_state.in_record.record_length) {
- try cs.verify_mac(
- self.parent_reader,
- self.read_state.in_record.record_length,
- &@field(self.read_state.in_record.state, cs.name),
- );
- self.server_seq += 1;
- self.read_state = .none;
- }
- }
- }
- return actually_read;
- } else unreachable;
- },
- .in_record => |*in_record| {
- const curr_bytes = std.math.min(std.math.min(buf_size, buffer.len), in_record.record_length - in_record.index);
- // Partially decrypt the data.
- var encrypted: [buf_size]u8 = undefined;
- const actually_read = try self.parent_reader.read(encrypted[0..curr_bytes]);
-
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- cs.decrypt_part(
- &self.key_data,
- in_record.record_length,
- &in_record.index,
- &@field(in_record.state, cs.name),
- encrypted[0..actually_read],
- buffer[0..actually_read],
- );
-
- if (in_record.index == in_record.record_length) {
- try cs.verify_mac(
- self.parent_reader,
- in_record.record_length,
- &@field(in_record.state, cs.name),
- );
- self.server_seq += 1;
- self.read_state = .none;
- }
- }
- }
- return actually_read;
- },
- }
- }
-
- pub fn write(self: *@This(), buffer: []const u8) _Writer.Error!usize {
- if (buffer.len == 0) return 0;
-
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- // @TODO Make this buffer size configurable
- const curr_bytes = @truncate(u16, std.math.min(buffer.len, 1024));
- try cs.raw_write(
- 1024,
- self.rand,
- &self.key_data,
- self.parent_writer,
- [3]u8{ 0x17, 0x03, 0x03 },
- self.client_seq,
- buffer[0..curr_bytes],
- );
- self.client_seq += 1;
- return curr_bytes;
- }
- }
- unreachable;
- }
-
- pub fn close_notify(self: *@This()) !void {
- inline for (_ciphersuites) |cs| {
- if (self.ciphersuite == cs.tag) {
- try cs.raw_write(
- 1024,
- self.rand,
- &self.key_data,
- self.parent_writer,
- [3]u8{ 0x15, 0x03, 0x03 },
- self.client_seq,
- "\x01\x00",
- );
- self.client_seq += 1;
- return;
- }
- }
- unreachable;
- }
- };
-}
-
-test "HTTPS request on wikipedia main page" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "en.wikipedia.org", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertHighAssuranceEVRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- var client = try client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- .ciphersuites = .{ciphersuites.ECDHE_RSA_Chacha20_Poly1305},
- .protocols = &[_][]const u8{"http/1.1"},
- .curves = .{curves.x25519},
- }, "en.wikipedia.org");
- defer client.close_notify() catch {};
- try std.testing.expectEqualStrings("http/1.1", client.protocol);
- try client.writer().writeAll("GET /wiki/Main_Page HTTP/1.1\r\nHost: en.wikipedia.org\r\nAccept: */*\r\n\r\n");
-
- {
- const header = try client.reader().readUntilDelimiterAlloc(std.testing.allocator, '\n', std.math.maxInt(usize));
- try std.testing.expectEqualStrings("HTTP/1.1 200 OK", mem.trim(u8, header, &std.ascii.spaces));
- std.testing.allocator.free(header);
- }
-
- // Skip the rest of the headers expect for Content-Length
- var content_length: ?usize = null;
- hdr_loop: while (true) {
- const header = try client.reader().readUntilDelimiterAlloc(std.testing.allocator, '\n', std.math.maxInt(usize));
- defer std.testing.allocator.free(header);
-
- const hdr_contents = mem.trim(u8, header, &std.ascii.spaces);
- if (hdr_contents.len == 0) {
- break :hdr_loop;
- }
-
- if (mem.startsWith(u8, hdr_contents, "Content-Length: ")) {
- content_length = try std.fmt.parseUnsigned(usize, hdr_contents[16..], 10);
- }
- }
- try std.testing.expect(content_length != null);
- const html_contents = try std.testing.allocator.alloc(u8, content_length.?);
- defer std.testing.allocator.free(html_contents);
-
- try client.reader().readNoEof(html_contents);
-}
-
-test "HTTPS request on wikipedia alternate name" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "en.m.wikipedia.org", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertHighAssuranceEVRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- var client = try client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- .ciphersuites = .{ciphersuites.ECDHE_RSA_Chacha20_Poly1305},
- .protocols = &[_][]const u8{"http/1.1"},
- .curves = .{curves.x25519},
- }, "en.m.wikipedia.org");
- defer client.close_notify() catch {};
-}
-
-test "HTTPS request on twitch oath2 endpoint" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "id.twitch.tv", 443);
- defer sock.close();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- var client = try client_connect(.{
- .rand = rand,
- .temp_allocator = std.testing.allocator,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .none,
- .protocols = &[_][]const u8{"http/1.1"},
- }, "id.twitch.tv");
- try std.testing.expectEqualStrings("http/1.1", client.protocol);
- defer client.close_notify() catch {};
-
- try client.writer().writeAll("GET /oauth2/validate HTTP/1.1\r\nHost: id.twitch.tv\r\nAccept: */*\r\n\r\n");
- var content_length: ?usize = null;
- hdr_loop: while (true) {
- const header = try client.reader().readUntilDelimiterAlloc(std.testing.allocator, '\n', std.math.maxInt(usize));
- defer std.testing.allocator.free(header);
-
- const hdr_contents = mem.trim(u8, header, &std.ascii.spaces);
- if (hdr_contents.len == 0) {
- break :hdr_loop;
- }
-
- if (mem.startsWith(u8, hdr_contents, "Content-Length: ")) {
- content_length = try std.fmt.parseUnsigned(usize, hdr_contents[16..], 10);
- }
- }
- try std.testing.expect(content_length != null);
- const html_contents = try std.testing.allocator.alloc(u8, content_length.?);
- defer std.testing.allocator.free(html_contents);
-
- try client.reader().readNoEof(html_contents);
-}
-
-test "Connecting to expired.badssl.com returns an error" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "expired.badssl.com", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertGlobalRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- if (client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- }, "expired.badssl.com")) |_| {
- return error.ExpectedVerificationFailed;
- } else |err| {
- try std.testing.expect(err == error.CertificateVerificationFailed);
- }
-}
-
-test "Connecting to wrong.host.badssl.com returns an error" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "wrong.host.badssl.com", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertGlobalRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- if (client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- }, "wrong.host.badssl.com")) |_| {
- return error.ExpectedVerificationFailed;
- } else |err| {
- try std.testing.expect(err == error.CertificateVerificationFailed);
- }
-}
-
-test "Connecting to self-signed.badssl.com returns an error" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "self-signed.badssl.com", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertGlobalRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- if (client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- }, "self-signed.badssl.com")) |_| {
- return error.ExpectedVerificationFailed;
- } else |err| {
- try std.testing.expect(err == error.CertificateVerificationFailed);
- }
-}
-
-test "Connecting to client.badssl.com with a client certificate" {
- const sock = try std.net.tcpConnectToHost(std.testing.allocator, "client.badssl.com", 443);
- defer sock.close();
-
- var fbs = std.io.fixedBufferStream(@embedFile("../test/DigiCertGlobalRootCA.crt.pem"));
- var trusted_chain = try x509.CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer trusted_chain.deinit();
-
- // @TODO Remove this once std.crypto.rand works in .evented mode
- var rand = blk: {
- var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
- try std.os.getrandom(&seed);
- break :blk &std.rand.DefaultCsprng.init(seed).random;
- };
-
- var client_cert = try x509.ClientCertificateChain.from_pem(
- std.testing.allocator,
- std.io.fixedBufferStream(@embedFile("../test/badssl.com-client.pem")).reader(),
- );
- defer client_cert.deinit(std.testing.allocator);
-
- var client = try client_connect(.{
- .rand = rand,
- .reader = sock.reader(),
- .writer = sock.writer(),
- .cert_verifier = .default,
- .temp_allocator = std.testing.allocator,
- .trusted_certificates = trusted_chain.data.items,
- .client_certificates = &[1]x509.ClientCertificateChain{client_cert},
- }, "client.badssl.com");
- defer client.close_notify() catch {};
-
- try client.writer().writeAll("GET / HTTP/1.1\r\nHost: client.badssl.com\r\nAccept: */*\r\n\r\n");
-
- const line = try client.reader().readUntilDelimiterAlloc(std.testing.allocator, '\n', std.math.maxInt(usize));
- defer std.testing.allocator.free(line);
- try std.testing.expectEqualStrings("HTTP/1.1 200 OK\r", line);
-}
diff --git a/src/deps/iguanaTLS/src/pcks1-1_5.zig b/src/deps/iguanaTLS/src/pcks1-1_5.zig
deleted file mode 100644
index 32183a2d7..000000000
--- a/src/deps/iguanaTLS/src/pcks1-1_5.zig
+++ /dev/null
@@ -1,209 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const Sha224 = std.crypto.hash.sha2.Sha224;
-const Sha384 = std.crypto.hash.sha2.Sha384;
-const Sha512 = std.crypto.hash.sha2.Sha512;
-const Sha256 = std.crypto.hash.sha2.Sha256;
-
-const x509 = @import("x509.zig");
-const SignatureAlgorithm = x509.Certificate.SignatureAlgorithm;
-const asn1 = @import("asn1.zig");
-
-fn rsa_perform(
- allocator: *Allocator,
- modulus: std.math.big.int.Const,
- exponent: std.math.big.int.Const,
- base: []const u8,
-) !?std.math.big.int.Managed {
- // @TODO Better algorithm, make it faster.
- const curr_base_limbs = try allocator.alloc(
- usize,
- std.math.divCeil(usize, base.len, @sizeOf(usize)) catch unreachable,
- );
- const curr_base_limb_bytes = @ptrCast([*]u8, curr_base_limbs)[0..base.len];
- mem.copy(u8, curr_base_limb_bytes, base);
- mem.reverse(u8, curr_base_limb_bytes);
- var curr_base = (std.math.big.int.Mutable{
- .limbs = curr_base_limbs,
- .positive = true,
- .len = curr_base_limbs.len,
- }).toManaged(allocator);
- defer curr_base.deinit();
-
- var curr_exponent = try exponent.toManaged(allocator);
- defer curr_exponent.deinit();
- var result = try std.math.big.int.Managed.initSet(allocator, @as(usize, 1));
-
- // encrypted = signature ^ key.exponent MOD key.modulus
- while (curr_exponent.toConst().orderAgainstScalar(0) == .gt) {
- if (curr_exponent.isOdd()) {
- try result.ensureMulCapacity(result.toConst(), curr_base.toConst());
- try result.mul(result.toConst(), curr_base.toConst());
- try llmod(&result, modulus);
- }
- try curr_base.sqr(curr_base.toConst());
- try llmod(&curr_base, modulus);
- try curr_exponent.shiftRight(curr_exponent, 1);
- }
-
- if (result.limbs.len * @sizeOf(usize) < base.len)
- return null;
- return result;
-}
-
-// res = res mod N
-fn llmod(res: *std.math.big.int.Managed, n: std.math.big.int.Const) !void {
- var temp = try std.math.big.int.Managed.init(res.allocator);
- defer temp.deinit();
- try temp.divTrunc(res, res.toConst(), n);
-}
-
-pub fn algorithm_prefix(signature_algorithm: SignatureAlgorithm) ?[]const u8 {
- return switch (signature_algorithm.hash) {
- .none, .md5, .sha1 => null,
- .sha224 => &[_]u8{
- 0x30, 0x2d, 0x30, 0x0d, 0x06,
- 0x09, 0x60, 0x86, 0x48, 0x01,
- 0x65, 0x03, 0x04, 0x02, 0x04,
- 0x05, 0x00, 0x04, 0x1c,
- },
- .sha256 => &[_]u8{
- 0x30, 0x31, 0x30, 0x0d, 0x06,
- 0x09, 0x60, 0x86, 0x48, 0x01,
- 0x65, 0x03, 0x04, 0x02, 0x01,
- 0x05, 0x00, 0x04, 0x20,
- },
- .sha384 => &[_]u8{
- 0x30, 0x41, 0x30, 0x0d, 0x06,
- 0x09, 0x60, 0x86, 0x48, 0x01,
- 0x65, 0x03, 0x04, 0x02, 0x02,
- 0x05, 0x00, 0x04, 0x30,
- },
- .sha512 => &[_]u8{
- 0x30, 0x51, 0x30, 0x0d, 0x06,
- 0x09, 0x60, 0x86, 0x48, 0x01,
- 0x65, 0x03, 0x04, 0x02, 0x03,
- 0x05, 0x00, 0x04, 0x40,
- },
- };
-}
-
-pub fn sign(
- allocator: *Allocator,
- signature_algorithm: SignatureAlgorithm,
- hash: []const u8,
- private_key: x509.PrivateKey,
-) !?[]const u8 {
- // @TODO ECDSA signatures
- if (signature_algorithm.signature != .rsa or private_key != .rsa)
- return null;
-
- const signature_length = private_key.rsa.modulus.len * @sizeOf(usize);
- var sig_buf = try allocator.alloc(u8, signature_length);
- defer allocator.free(sig_buf);
- const prefix = algorithm_prefix(signature_algorithm) orelse return null;
- const first_prefix_idx = sig_buf.len - hash.len - prefix.len;
- const first_hash_idx = sig_buf.len - hash.len;
-
- // EM = 0x00 || 0x01 || PS || 0x00 || T
- sig_buf[0] = 0;
- sig_buf[1] = 1;
- mem.set(u8, sig_buf[2 .. first_prefix_idx - 1], 0xff);
- sig_buf[first_prefix_idx - 1] = 0;
- mem.copy(u8, sig_buf[first_prefix_idx..first_hash_idx], prefix);
- mem.copy(u8, sig_buf[first_hash_idx..], hash);
-
- const modulus = std.math.big.int.Const{ .limbs = private_key.rsa.modulus, .positive = true };
- const exponent = std.math.big.int.Const{ .limbs = private_key.rsa.exponent, .positive = true };
-
- var rsa_result = (try rsa_perform(allocator, modulus, exponent, sig_buf)) orelse return null;
- if (rsa_result.limbs.len * @sizeOf(usize) < signature_length) {
- rsa_result.deinit();
- return null;
- }
-
- const enc_buf = @ptrCast([*]u8, rsa_result.limbs.ptr)[0..signature_length];
- mem.reverse(u8, enc_buf);
- return allocator.resize(
- enc_buf.ptr[0 .. rsa_result.limbs.len * @sizeOf(usize)],
- signature_length,
- ) catch unreachable;
-}
-
-pub fn verify_signature(
- allocator: *Allocator,
- signature_algorithm: SignatureAlgorithm,
- signature: asn1.BitString,
- hash: []const u8,
- public_key: x509.PublicKey,
-) !bool {
- // @TODO ECDSA algorithms
- if (public_key != .rsa or signature_algorithm.signature != .rsa) return false;
- const prefix = algorithm_prefix(signature_algorithm) orelse return false;
-
- // RSA hash verification with PKCS 1 V1_5 padding
- const modulus = std.math.big.int.Const{ .limbs = public_key.rsa.modulus, .positive = true };
- const exponent = std.math.big.int.Const{ .limbs = public_key.rsa.exponent, .positive = true };
- if (modulus.bitCountAbs() != signature.bit_len)
- return false;
-
- var rsa_result = (try rsa_perform(allocator, modulus, exponent, signature.data)) orelse return false;
- defer rsa_result.deinit();
-
- if (rsa_result.limbs.len * @sizeOf(usize) < signature.data.len)
- return false;
-
- const enc_buf = @ptrCast([*]u8, rsa_result.limbs.ptr)[0..signature.data.len];
- mem.reverse(u8, enc_buf);
-
- if (enc_buf[0] != 0x00 or enc_buf[1] != 0x01)
- return false;
- if (!mem.endsWith(u8, enc_buf, hash))
- return false;
- if (!mem.endsWith(u8, enc_buf[0 .. enc_buf.len - hash.len], prefix))
- return false;
- if (enc_buf[enc_buf.len - hash.len - prefix.len - 1] != 0x00)
- return false;
- for (enc_buf[2 .. enc_buf.len - hash.len - prefix.len - 1]) |c| {
- if (c != 0xff) return false;
- }
-
- return true;
-}
-
-pub fn certificate_verify_signature(
- allocator: *Allocator,
- signature_algorithm: x509.Certificate.SignatureAlgorithm,
- signature: asn1.BitString,
- bytes: []const u8,
- public_key: x509.PublicKey,
-) !bool {
- // @TODO ECDSA algorithms
- if (public_key != .rsa or signature_algorithm.signature != .rsa) return false;
-
- var hash_buf: [64]u8 = undefined;
- var hash: []u8 = undefined;
-
- switch (signature_algorithm.hash) {
- // Deprecated hash algos
- .none, .md5, .sha1 => return false,
- .sha224 => {
- Sha224.hash(bytes, hash_buf[0..28], .{});
- hash = hash_buf[0..28];
- },
- .sha256 => {
- Sha256.hash(bytes, hash_buf[0..32], .{});
- hash = hash_buf[0..32];
- },
- .sha384 => {
- Sha384.hash(bytes, hash_buf[0..48], .{});
- hash = hash_buf[0..48];
- },
- .sha512 => {
- Sha512.hash(bytes, hash_buf[0..64], .{});
- hash = &hash_buf;
- },
- }
- return try verify_signature(allocator, signature_algorithm, signature, hash, public_key);
-}
diff --git a/src/deps/iguanaTLS/src/x509.zig b/src/deps/iguanaTLS/src/x509.zig
deleted file mode 100644
index 06f8fc258..000000000
--- a/src/deps/iguanaTLS/src/x509.zig
+++ /dev/null
@@ -1,1053 +0,0 @@
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-const mem = std.mem;
-const trait = std.meta.trait;
-
-const asn1 = @import("asn1.zig");
-
-// zig fmt: off
-// http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
-pub const CurveId = enum {
- sect163k1, sect163r1, sect163r2, sect193r1,
- sect193r2, sect233k1, sect233r1, sect239k1,
- sect283k1, sect283r1, sect409k1, sect409r1,
- sect571k1, sect571r1, secp160k1, secp160r1,
- secp160r2, secp192k1, secp192r1, secp224k1,
- secp224r1, secp256k1, secp256r1, secp384r1,
- secp521r1,brainpoolP256r1, brainpoolP384r1,
- brainpoolP512r1, curve25519, curve448,
-};
-// zig fmt: on
-
-pub const PublicKey = union(enum) {
- pub const empty = PublicKey{ .ec = .{ .id = undefined, .curve_point = &[0]u8{} } };
-
- /// RSA public key
- rsa: struct {
- //Positive std.math.big.int.Const numbers.
- modulus: []const usize,
- exponent: []const usize,
- },
- /// Elliptic curve public key
- ec: struct {
- id: CurveId,
- /// Public curve point (uncompressed format)
- curve_point: []const u8,
- },
-
- pub fn deinit(self: @This(), alloc: *Allocator) void {
- switch (self) {
- .rsa => |rsa| {
- alloc.free(rsa.modulus);
- alloc.free(rsa.exponent);
- },
- .ec => |ec| alloc.free(ec.curve_point),
- }
- }
-
- pub fn eql(self: @This(), other: @This()) bool {
- if (@as(std.meta.Tag(@This()), self) != @as(std.meta.Tag(@This()), other))
- return false;
- switch (self) {
- .rsa => |mod_exp| return mem.eql(usize, mod_exp.exponent, other.rsa.exponent) and
- mem.eql(usize, mod_exp.modulus, other.rsa.modulus),
- .ec => |ec| return ec.id == other.ec.id and mem.eql(u8, ec.curve_point, other.ec.curve_point),
- }
- }
-};
-
-pub const PrivateKey = PublicKey;
-
-pub fn parse_public_key(allocator: *Allocator, reader: anytype) !PublicKey {
- if ((try reader.readByte()) != 0x30)
- return error.MalformedDER;
- const seq_len = try asn1.der.parse_length(reader);
- _ = seq_len;
-
- if ((try reader.readByte()) != 0x06)
- return error.MalformedDER;
- const oid_bytes = try asn1.der.parse_length(reader);
- if (oid_bytes == 9) {
- // @TODO This fails in async if merged with the if
- if (!try reader.isBytes(&[9]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1 }))
- return error.MalformedDER;
- // OID is 1.2.840.113549.1.1.1
- // RSA key
- // Skip past the NULL
- const null_byte = try reader.readByte();
- if (null_byte != 0x05)
- return error.MalformedDER;
- const null_len = try asn1.der.parse_length(reader);
- if (null_len != 0x00)
- return error.MalformedDER;
- {
- // BitString next!
- if ((try reader.readByte()) != 0x03)
- return error.MalformedDER;
- _ = try asn1.der.parse_length(reader);
- const bit_string_unused_bits = try reader.readByte();
- if (bit_string_unused_bits != 0)
- return error.MalformedDER;
-
- if ((try reader.readByte()) != 0x30)
- return error.MalformedDER;
- _ = try asn1.der.parse_length(reader);
-
- // Modulus
- if ((try reader.readByte()) != 0x02)
- return error.MalformedDER;
- const modulus = try asn1.der.parse_int(allocator, reader);
- errdefer allocator.free(modulus.limbs);
- if (!modulus.positive) return error.MalformedDER;
- // Exponent
- if ((try reader.readByte()) != 0x02)
- return error.MalformedDER;
- const exponent = try asn1.der.parse_int(allocator, reader);
- errdefer allocator.free(exponent.limbs);
- if (!exponent.positive) return error.MalformedDER;
- return PublicKey{
- .rsa = .{
- .modulus = modulus.limbs,
- .exponent = exponent.limbs,
- },
- };
- }
- } else if (oid_bytes == 7) {
- // @TODO This fails in async if merged with the if
- if (!try reader.isBytes(&[7]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }))
- return error.MalformedDER;
- // OID is 1.2.840.10045.2.1
- // Elliptical curve
- // We only support named curves, for which the parameter field is an OID.
- const oid_tag = try reader.readByte();
- if (oid_tag != 0x06)
- return error.MalformedDER;
- const curve_oid_bytes = try asn1.der.parse_length(reader);
-
- var key: PublicKey = undefined;
- if (curve_oid_bytes == 5) {
- if (!try reader.isBytes(&[4]u8{ 0x2B, 0x81, 0x04, 0x00 }))
- return error.MalformedDER;
- // 1.3.132.0.{34, 35}
- const last_byte = try reader.readByte();
- if (last_byte == 0x22)
- key = .{ .ec = .{ .id = .secp384r1, .curve_point = undefined } }
- else if (last_byte == 0x23)
- key = .{ .ec = .{ .id = .secp521r1, .curve_point = undefined } }
- else
- return error.MalformedDER;
- } else if (curve_oid_bytes == 8) {
- if (!try reader.isBytes(&[8]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x3, 0x1, 0x7 }))
- return error.MalformedDER;
- key = .{ .ec = .{ .id = .secp256r1, .curve_point = undefined } };
- } else {
- return error.MalformedDER;
- }
-
- if ((try reader.readByte()) != 0x03)
- return error.MalformedDER;
- const byte_len = try asn1.der.parse_length(reader);
- const unused_bits = try reader.readByte();
- const bit_count = (byte_len - 1) * 8 - unused_bits;
- if (bit_count % 8 != 0)
- return error.MalformedDER;
- const bit_memory = try allocator.alloc(u8, std.math.divCeil(usize, bit_count, 8) catch unreachable);
- errdefer allocator.free(bit_memory);
- try reader.readNoEof(bit_memory[0 .. byte_len - 1]);
-
- key.ec.curve_point = bit_memory;
- return key;
- }
- return error.MalformedDER;
-}
-
-pub fn DecodeDERError(comptime Reader: type) type {
- return Reader.Error || error{
- MalformedPEM,
- MalformedDER,
- EndOfStream,
- OutOfMemory,
- };
-}
-
-pub const Certificate = struct {
- pub const SignatureAlgorithm = struct {
- hash: enum(u8) {
- none = 0,
- md5 = 1,
- sha1 = 2,
- sha224 = 3,
- sha256 = 4,
- sha384 = 5,
- sha512 = 6,
- },
- signature: enum(u8) {
- anonymous = 0,
- rsa = 1,
- dsa = 2,
- ecdsa = 3,
- },
- };
-
- /// Subject distinguished name
- dn: []const u8,
- /// A "CA" anchor is deemed fit to verify signatures on certificates.
- /// A "non-CA" anchor is accepted only for direct trust (server's certificate
- /// name and key match the anchor).
- is_ca: bool = false,
- public_key: PublicKey,
-
- const CaptureState = struct {
- self: *Certificate,
- allocator: *Allocator,
- dn_allocated: bool = false,
- pk_allocated: bool = false,
- };
-
- fn initSubjectDn(state: *CaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
-
- const dn_mem = try state.allocator.alloc(u8, length);
- errdefer state.allocator.free(dn_mem);
- try reader.readNoEof(dn_mem);
- state.self.dn = dn_mem;
- state.dn_allocated = true;
- }
-
- fn processExtension(state: *CaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const object_id = try asn1.der.parse_value(state.allocator, reader);
- defer object_id.deinit(state.allocator);
- if (object_id != .object_identifier) return error.DoesNotMatchSchema;
- if (object_id.object_identifier.len != 4)
- return;
-
- const data = object_id.object_identifier.data;
- // Basic constraints extension
- if (data[0] != 2 or data[1] != 5 or data[2] != 29 or data[3] != 19)
- return;
-
- const basic_constraints = try asn1.der.parse_value(state.allocator, reader);
- defer basic_constraints.deinit(state.allocator);
-
- switch (basic_constraints) {
- .bool => state.self.is_ca = true,
- .octet_string => |s| {
- if (s.len != 5 or s[0] != 0x30 or s[1] != 0x03 or s[2] != 0x01 or s[3] != 0x01)
- return error.DoesNotMatchSchema;
- state.self.is_ca = s[4] != 0x00;
- },
- else => return error.DoesNotMatchSchema,
- }
- }
-
- fn initExtensions(state: *CaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- const schema = .{
- .sequence_of,
- .{ .capture, 0, .sequence },
- };
- const captures = .{
- state, processExtension,
- };
- try asn1.der.parse_schema(schema, captures, reader);
- }
-
- fn initPublicKeyInfo(state: *CaptureState, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- state.self.public_key = try parse_public_key(state.allocator, reader);
- state.pk_allocated = true;
- }
-
- /// Initialize a trusted anchor from distinguished encoding rules (DER) encoded data
- pub fn create(allocator: *Allocator, der_reader: anytype) DecodeDERError(@TypeOf(der_reader))!@This() {
- var self: @This() = undefined;
- self.is_ca = false;
- // https://tools.ietf.org/html/rfc5280#page-117
- const schema = .{
- .sequence, .{
- // tbsCertificate
- .{
- .sequence,
- .{
- .{ .context_specific, 0 }, // version
- .{.int}, // serialNumber
- .{.sequence}, // signature
- .{.sequence}, // issuer
- .{.sequence}, // validity,
- .{ .capture, 0, .sequence }, // subject
- .{ .capture, 1, .sequence }, // subjectPublicKeyInfo
- .{ .optional, .context_specific, 1 }, // issuerUniqueID
- .{ .optional, .context_specific, 2 }, // subjectUniqueID
- .{ .capture, 2, .optional, .context_specific, 3 }, // extensions
- },
- },
- // signatureAlgorithm
- .{.sequence},
- // signatureValue
- .{.bit_string},
- },
- };
-
- var capture_state = CaptureState{
- .self = &self,
- .allocator = allocator,
- };
- const captures = .{
- &capture_state, initSubjectDn,
- &capture_state, initPublicKeyInfo,
- &capture_state, initExtensions,
- };
-
- errdefer {
- if (capture_state.dn_allocated)
- allocator.free(self.dn);
- if (capture_state.pk_allocated)
- self.public_key.deinit(allocator);
- }
-
- asn1.der.parse_schema(schema, captures, der_reader) catch |err| switch (err) {
- error.InvalidLength,
- error.InvalidTag,
- error.InvalidContainerLength,
- error.DoesNotMatchSchema,
- => return error.MalformedDER,
- else => |e| return e,
- };
- return self;
- }
-
- pub fn deinit(self: @This(), alloc: *Allocator) void {
- alloc.free(self.dn);
- self.public_key.deinit(alloc);
- }
-
- pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
- _ = fmt;
- _ = options;
-
- try writer.print(
- \\CERTIFICATE
- \\-----------
- \\IS CA: {}
- \\Subject distinguished name (encoded):
- \\{X}
- \\Public key:
- \\
- , .{ self.is_ca, self.dn });
-
- switch (self.public_key) {
- .rsa => |mod_exp| {
- const modulus = std.math.big.int.Const{ .positive = true, .limbs = mod_exp.modulus };
- const exponent = std.math.big.int.Const{ .positive = true, .limbs = mod_exp.exponent };
- try writer.print(
- \\RSA
- \\modulus: {}
- \\exponent: {}
- \\
- , .{
- modulus,
- exponent,
- });
- },
- .ec => |ec| {
- try writer.print(
- \\EC (Curve: {})
- \\point: {}
- \\
- , .{
- ec.id,
- ec.curve_point,
- });
- },
- }
-
- try writer.writeAll(
- \\-----------
- \\
- );
- }
-};
-
-pub const CertificateChain = struct {
- data: std.ArrayList(Certificate),
-
- pub fn from_pem(allocator: *Allocator, pem_reader: anytype) DecodeDERError(@TypeOf(pem_reader))!@This() {
- var self = @This(){ .data = std.ArrayList(Certificate).init(allocator) };
- errdefer self.deinit();
-
- var it = pemCertificateIterator(pem_reader);
- while (try it.next()) |cert_reader| {
- var buffered = std.io.bufferedReader(cert_reader);
- const anchor = try Certificate.create(allocator, buffered.reader());
- errdefer anchor.deinit(allocator);
- try self.data.append(anchor);
- }
- return self;
- }
-
- pub fn deinit(self: @This()) void {
- const alloc = self.data.allocator;
- for (self.data.items) |ta| ta.deinit(alloc);
- self.data.deinit();
- }
-};
-
-pub fn get_signature_algorithm(
- reader: anytype,
-) (@TypeOf(reader).Error || error{EndOfStream})!?Certificate.SignatureAlgorithm {
- const oid_tag = try reader.readByte();
- if (oid_tag != 0x06)
- return null;
-
- const oid_length = try asn1.der.parse_length(reader);
- if (oid_length == 9) {
- var oid_bytes: [9]u8 = undefined;
- try reader.readNoEof(&oid_bytes);
-
- if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 })) {
- // TODO: Is hash actually none here?
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .none };
- } else if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 })) {
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .md5 };
- } else if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 })) {
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .sha1 };
- } else if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B })) {
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .sha256 };
- } else if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C })) {
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .sha384 };
- } else if (mem.eql(u8, &oid_bytes, &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D })) {
- return Certificate.SignatureAlgorithm{ .signature = .rsa, .hash = .sha512 };
- } else {
- return null;
- }
- return;
- } else if (oid_length == 10) {
- // TODO
- // ECDSA + <Hash> algorithms
- }
- return null;
-}
-
-pub const ClientCertificateChain = struct {
- /// Number of certificates in the chain
- cert_len: usize,
- /// Contains the raw data of each certificate in the certificate chain
- raw_certs: [*]const []const u8,
- /// Issuer distinguished name in DER format of each certificate in the certificate chain
- /// issuer_dn[N] is a dubslice of raw[N]
- cert_issuer_dns: [*]const []const u8,
- signature_algorithm: Certificate.SignatureAlgorithm,
- private_key: PrivateKey,
-
- // TODO: Encrypted private keys, non-RSA private keys
- pub fn from_pem(allocator: *Allocator, pem_reader: anytype) !@This() {
- var it = PEMSectionIterator(@TypeOf(pem_reader), .{
- .section_names = &.{
- "X.509 CERTIFICATE",
- "CERTIFICATE",
- "RSA PRIVATE KEY",
- },
- .skip_irrelevant_lines = true,
- }){ .reader = pem_reader };
-
- var raw_certs = std.ArrayListUnmanaged([]const u8){};
- var cert_issuer_dns = std.ArrayList([]const u8).init(allocator);
- errdefer {
- for (raw_certs.items) |bytes| {
- allocator.free(bytes);
- }
- raw_certs.deinit(allocator);
- cert_issuer_dns.deinit();
- }
-
- var signature_algorithm: Certificate.SignatureAlgorithm = undefined;
- var private_key: ?PrivateKey = null;
- errdefer if (private_key) |pk| {
- pk.deinit(allocator);
- };
-
- while (try it.next()) |state_and_reader| {
- switch (state_and_reader.state) {
- .@"X.509 CERTIFICATE", .@"CERTIFICATE" => {
- const cert_bytes = try state_and_reader.reader.readAllAlloc(allocator, std.math.maxInt(usize));
- errdefer allocator.free(cert_bytes);
- try raw_certs.append(allocator, cert_bytes);
-
- const schema = .{
- .sequence, .{
- // tbsCertificate
- .{
- .sequence,
- .{
- .{ .context_specific, 0 }, // version
- .{.int}, // serialNumber
- .{.sequence}, // signature
- .{ .capture, 0, .sequence }, // issuer
- .{.sequence}, // validity
- .{.sequence}, // subject
- .{.sequence}, // subjectPublicKeyInfo
- .{ .optional, .context_specific, 1 }, // issuerUniqueID
- .{ .optional, .context_specific, 2 }, // subjectUniqueID
- .{ .optional, .context_specific, 3 }, // extensions
- },
- },
- // signatureAlgorithm
- .{ .capture, 1, .sequence },
- // signatureValue
- .{.bit_string},
- },
- };
-
- var fbs = std.io.fixedBufferStream(cert_bytes);
- const state = .{
- .fbs = &fbs,
- .dns = &cert_issuer_dns,
- .signature_algorithm = &signature_algorithm,
- };
-
- const captures = .{
- state,
- struct {
- fn capture(_state: anytype, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = reader;
-
- // TODO: Some way to get tag + length buffer directly in the capture callback?
- const encoded_length = asn1.der.encode_length(length).slice();
- const pos = _state.fbs.pos;
- const dn = _state.fbs.buffer[pos - encoded_length.len - 1 .. pos + length];
- try _state.dns.append(dn);
- }
- }.capture,
- state,
- struct {
- fn capture(_state: anytype, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
- _ = length;
-
- if (_state.dns.items.len == 1)
- _state.signature_algorithm.* = (try get_signature_algorithm(reader)) orelse
- return error.InvalidSignatureAlgorithm;
- }
- }.capture,
- };
-
- asn1.der.parse_schema(schema, captures, fbs.reader()) catch |err| switch (err) {
- error.DoesNotMatchSchema,
- error.EndOfStream,
- error.InvalidTag,
- error.InvalidLength,
- error.InvalidSignatureAlgorithm,
- error.InvalidContainerLength,
- => return error.InvalidCertificate,
- error.OutOfMemory => return error.OutOfMemory,
- };
- },
- .@"RSA PRIVATE KEY" => {
- if (private_key != null)
- return error.MultiplePrivateKeys;
-
- const schema = .{
- .sequence, .{
- .{.int}, // version
- .{ .capture, 0, .int }, //modulus
- .{.int}, //publicExponent
- .{ .capture, 1, .int }, //privateExponent
- .{.int}, // prime1
- .{.int}, //prime2
- .{.int}, //exponent1
- .{.int}, //exponent2
- .{.int}, //coefficient
- .{ .optional, .any }, //otherPrimeInfos
- },
- };
-
- private_key = .{ .rsa = undefined };
- const state = .{
- .modulus = &private_key.?.rsa.modulus,
- .exponent = &private_key.?.rsa.exponent,
- .allocator = allocator,
- };
-
- const captures = .{
- state,
- struct {
- fn capture(_state: anytype, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
-
- _state.modulus.* = (try asn1.der.parse_int_with_length(
- _state.allocator,
- length,
- reader,
- )).limbs;
- }
- }.capture,
- state,
- struct {
- fn capture(_state: anytype, tag: u8, length: usize, reader: anytype) !void {
- _ = tag;
-
- _state.exponent.* = (try asn1.der.parse_int_with_length(
- _state.allocator,
- length,
- reader,
- )).limbs;
- }
- }.capture,
- };
-
- asn1.der.parse_schema(schema, captures, state_and_reader.reader) catch |err| switch (err) {
- error.DoesNotMatchSchema,
- error.EndOfStream,
- error.InvalidTag,
- error.InvalidLength,
- error.InvalidContainerLength,
- => return error.InvalidPrivateKey,
- error.OutOfMemory => return error.OutOfMemory,
- error.MalformedPEM => return error.MalformedPEM,
- };
- },
- .none, .other => unreachable,
- }
- }
- if (private_key == null)
- return error.NoPrivateKey;
-
- std.debug.assert(cert_issuer_dns.items.len == raw_certs.items.len);
- return @This(){
- .cert_len = raw_certs.items.len,
- .raw_certs = raw_certs.toOwnedSlice(allocator).ptr,
- .cert_issuer_dns = cert_issuer_dns.toOwnedSlice().ptr,
- .signature_algorithm = signature_algorithm,
- .private_key = private_key.?,
- };
- }
-
- pub fn deinit(self: *@This(), allocator: *Allocator) void {
- for (self.raw_certs[0..self.cert_len]) |cert_bytes| {
- allocator.free(cert_bytes);
- }
- allocator.free(self.raw_certs[0..self.cert_len]);
- allocator.free(self.cert_issuer_dns[0..self.cert_len]);
- self.private_key.deinit(allocator);
- }
-};
-
-fn PEMSectionReader(comptime Reader: type, comptime options: PEMSectionIteratorOptions) type {
- const Error = Reader.Error || error{MalformedPEM};
- const read = struct {
- fn f(it: *PEMSectionIterator(Reader, options), buf: []u8) Error!usize {
- var out_idx: usize = 0;
- if (it.waiting_chars_len > 0) {
- const rest_written = std.math.min(it.waiting_chars_len, buf.len);
- while (out_idx < rest_written) : (out_idx += 1) {
- buf[out_idx] = it.waiting_chars[out_idx];
- }
-
- it.waiting_chars_len -= rest_written;
- if (it.waiting_chars_len != 0) {
- std.mem.copy(u8, it.waiting_chars[0..], it.waiting_chars[rest_written..]);
- }
-
- if (out_idx == buf.len) {
- return out_idx;
- }
- }
- if (it.state == .none)
- return out_idx;
-
- var base64_buf: [4]u8 = undefined;
- var base64_idx: usize = 0;
- while (true) {
- const byte = it.reader.readByte() catch |err| switch (err) {
- error.EndOfStream => return out_idx,
- else => |e| return e,
- };
-
- if (byte == '-') {
- if (it.reader.isBytes("----END ") catch |err| switch (err) {
- error.EndOfStream => return error.MalformedPEM,
- else => |e| return e,
- }) {
- try it.reader.skipUntilDelimiterOrEof('\n');
- it.state = .none;
- return out_idx;
- } else return error.MalformedPEM;
- } else if (byte == '\r') {
- if ((it.reader.readByte() catch |err| switch (err) {
- error.EndOfStream => return error.MalformedPEM,
- else => |e| return e,
- }) != '\n')
- return error.MalformedPEM;
- continue;
- } else if (byte == '\n')
- continue;
-
- base64_buf[base64_idx] = byte;
- base64_idx += 1;
- if (base64_idx == base64_buf.len) {
- base64_idx = 0;
-
- const out_len = std.base64.standard_decoder.calcSizeForSlice(&base64_buf) catch
- return error.MalformedPEM;
-
- const rest_chars = if (out_len > buf.len - out_idx)
- out_len - (buf.len - out_idx)
- else
- 0;
- const buf_chars = out_len - rest_chars;
-
- var res_buffer: [3]u8 = undefined;
- std.base64.standard_decoder.decode(res_buffer[0..out_len], &base64_buf) catch
- return error.MalformedPEM;
-
- var i: u3 = 0;
- while (i < buf_chars) : (i += 1) {
- buf[out_idx] = res_buffer[i];
- out_idx += 1;
- }
-
- if (rest_chars > 0) {
- mem.copy(u8, &it.waiting_chars, res_buffer[i..]);
- it.waiting_chars_len = @intCast(u2, rest_chars);
- }
- if (out_idx == buf.len)
- return out_idx;
- }
- }
- }
- }.f;
-
- return std.io.Reader(
- *PEMSectionIterator(Reader, options),
- Error,
- read,
- );
-}
-
-const PEMSectionIteratorOptions = struct {
- section_names: []const []const u8,
- skip_irrelevant_lines: bool = false,
-};
-
-fn PEMSectionIterator(comptime Reader: type, comptime options: PEMSectionIteratorOptions) type {
- var biggest_name_len = 0;
-
- var fields: [options.section_names.len + 2]std.builtin.TypeInfo.EnumField = undefined;
- fields[0] = .{ .name = "none", .value = 0 };
- fields[1] = .{ .name = "other", .value = 1 };
- for (fields[2..]) |*field, idx| {
- field.name = options.section_names[idx];
- field.value = @as(u8, idx + 2);
- if (field.name.len > biggest_name_len)
- biggest_name_len = field.name.len;
- }
-
- const StateEnum = @Type(.{
- .Enum = .{
- .layout = .Auto,
- .tag_type = u8,
- .fields = &fields,
- .decls = &.{},
- .is_exhaustive = true,
- },
- });
-
- const _biggest_name_len = biggest_name_len;
-
- return struct {
- pub const SectionReader = PEMSectionReader(Reader, options);
- pub const StateAndName = struct {
- state: StateEnum,
- reader: SectionReader,
- };
- pub const NextError = SectionReader.Error || error{EndOfStream};
-
- reader: Reader,
- // Internal state for the iterator and the current reader.
- state: StateEnum = .none,
- waiting_chars: [4]u8 = undefined,
- waiting_chars_len: u2 = 0,
-
- // TODO More verification, this will accept lots of invalid PEM
- // TODO Simplify code
- pub fn next(self: *@This()) NextError!?StateAndName {
- self.waiting_chars_len = 0;
- outer_loop: while (true) {
- const byte = self.reader.readByte() catch |err| switch (err) {
- error.EndOfStream => if (self.state == .none)
- return null
- else
- return error.EndOfStream,
- else => |e| return e,
- };
-
- switch (self.state) {
- .none => switch (byte) {
- '#' => {
- try self.reader.skipUntilDelimiterOrEof('\n');
- continue;
- },
- '\r', '\n', ' ', '\t' => continue,
- '-' => {
- if (try self.reader.isBytes("----BEGIN ")) {
- var name_char_idx: usize = 0;
- var name_buf: [_biggest_name_len]u8 = undefined;
-
- while (true) {
- const next_byte = try self.reader.readByte();
- switch (next_byte) {
- '-' => {
- try self.reader.skipUntilDelimiterOrEof('\n');
- const name = name_buf[0..name_char_idx];
- for (options.section_names) |sec_name, idx| {
- if (mem.eql(u8, sec_name, name)) {
- self.state = @intToEnum(StateEnum, @intCast(u8, idx + 2));
- return StateAndName{
- .reader = .{ .context = self },
- .state = self.state,
- };
- }
- }
- self.state = .other;
- continue :outer_loop;
- },
- '\n' => return error.MalformedPEM,
- else => {
- if (name_char_idx == _biggest_name_len) {
- try self.reader.skipUntilDelimiterOrEof('\n');
- self.state = .other;
- continue :outer_loop;
- }
- name_buf[name_char_idx] = next_byte;
- name_char_idx += 1;
- },
- }
- }
- } else return error.MalformedPEM;
- },
- else => {
- if (options.skip_irrelevant_lines) {
- try self.reader.skipUntilDelimiterOrEof('\n');
- continue;
- } else {
- return error.MalformedPEM;
- }
- },
- },
- else => switch (byte) {
- '#' => {
- try self.reader.skipUntilDelimiterOrEof('\n');
- continue;
- },
- '\r', '\n', ' ', '\t' => continue,
- '-' => {
- if (try self.reader.isBytes("----END ")) {
- try self.reader.skipUntilDelimiterOrEof('\n');
- self.state = .none;
- continue;
- } else return error.MalformedPEM;
- },
- // TODO: Make sure the character is base64
- else => continue,
- },
- }
- }
- }
- };
-}
-
-fn PEMCertificateIterator(comptime Reader: type) type {
- const SectionIterator = PEMSectionIterator(Reader, .{
- .section_names = &.{ "X.509 CERTIFICATE", "CERTIFICATE" },
- });
-
- return struct {
- pub const SectionReader = SectionIterator.SectionReader;
- pub const NextError = SectionReader.Error || error{EndOfStream};
-
- section_it: SectionIterator,
-
- pub fn next(self: *@This()) NextError!?SectionReader {
- return ((try self.section_it.next()) orelse return null).reader;
- }
- };
-}
-
-/// Iterator of io.Reader that each decode one certificate from the PEM reader.
-/// Readers do not have to be fully consumed until end of stream, but they must be
-/// read from in order.
-/// Iterator.SectionReader is the type of the io.Reader, Iterator.NextError is the error
-/// set of the next() function.
-pub fn pemCertificateIterator(reader: anytype) PEMCertificateIterator(@TypeOf(reader)) {
- return .{ .section_it = .{ .reader = reader } };
-}
-
-pub const NameElement = struct {
- // Encoded OID without tag
- oid: asn1.ObjectIdentifier,
- // Destination buffer
- buf: []u8,
- status: enum {
- not_found,
- found,
- errored,
- },
-};
-
-const github_pem = @embedFile("../test/github.pem");
-const github_der = @embedFile("../test/github.der");
-
-fn expected_pem_certificate_chain(bytes: []const u8, certs: []const []const u8) !void {
- var fbs = std.io.fixedBufferStream(bytes);
-
- var it = pemCertificateIterator(fbs.reader());
- var idx: usize = 0;
- while (try it.next()) |cert_reader| : (idx += 1) {
- const result_bytes = try cert_reader.readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
- defer std.testing.allocator.free(result_bytes);
- try std.testing.expectEqualSlices(u8, certs[idx], result_bytes);
- }
- if (idx != certs.len) {
- std.debug.panic("Read {} certificates, wanted {}", .{ idx, certs.len });
- }
- try std.testing.expect((try it.next()) == null);
-}
-
-fn expected_pem_certificate(bytes: []const u8, cert_bytes: []const u8) !void {
- try expected_pem_certificate_chain(bytes, &[1][]const u8{cert_bytes});
-}
-
-test "pemCertificateIterator" {
- try expected_pem_certificate(github_pem, github_der);
- try expected_pem_certificate(
- \\-----BEGIN BOGUS-----
- \\-----END BOGUS-----
- \\
- ++
- github_pem,
- github_der,
- );
-
- try expected_pem_certificate_chain(
- github_pem ++
- \\
- \\-----BEGIN BOGUS-----
- \\-----END BOGUS-----
- \\
- ++ github_pem,
- &[2][]const u8{ github_der, github_der },
- );
-
- try expected_pem_certificate_chain(
- \\-----BEGIN BOGUS-----
- \\-----END BOGUS-----
- \\
- ,
- &[0][]const u8{},
- );
-
- // Try reading byte by byte from a cert reader
- {
- var fbs = std.io.fixedBufferStream(github_pem ++ "\n# Some comment\n" ++ github_pem);
- var it = pemCertificateIterator(fbs.reader());
- // Read a couple of bytes from the first reader, then skip to the next
- {
- const first_reader = (try it.next()) orelse return error.NoCertificate;
- var first_few: [8]u8 = undefined;
- const bytes = try first_reader.readAll(&first_few);
- try std.testing.expectEqual(first_few.len, bytes);
- try std.testing.expectEqualSlices(u8, github_der[0..bytes], &first_few);
- }
-
- const next_reader = (try it.next()) orelse return error.NoCertificate;
- var idx: usize = 0;
- while (true) : (idx += 1) {
- const byte = next_reader.readByte() catch |err| switch (err) {
- error.EndOfStream => break,
- else => |e| return e,
- };
- if (github_der[idx] != byte) {
- std.debug.panic("index {}: expected 0x{X}, found 0x{X}", .{ idx, github_der[idx], byte });
- }
- }
- try std.testing.expectEqual(github_der.len, idx);
- try std.testing.expect((try it.next()) == null);
- }
-}
-
-test "CertificateChain" {
- var fbs = std.io.fixedBufferStream(github_pem ++
- \\
- \\# Hellenic Academic and Research Institutions RootCA 2011
- \\-----BEGIN CERTIFICATE-----
- \\MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
- \\RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
- \\dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p
- \\YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw
- \\NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK
- \\EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl
- \\cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
- \\c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB
- \\BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz
- \\dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ
- \\fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns
- \\bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD
- \\75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP
- \\FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV
- \\HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp
- \\5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu
- \\b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA
- \\A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p
- \\6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
- \\TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7
- \\dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
- \\Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
- \\l7WdmplNsDz4SgCbZN2fOUvRJ9e4
- \\-----END CERTIFICATE-----
- \\
- \\# ePKI Root Certification Authority
- \\-----BEGIN CERTIFICATE-----
- \\MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
- \\MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
- \\ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
- \\Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
- \\IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
- \\SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
- \\AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
- \\SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
- \\ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
- \\DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
- \\TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
- \\fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
- \\sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
- \\WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
- \\nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
- \\dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
- \\NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
- \\AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
- \\MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
- \\ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
- \\uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
- \\PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
- \\JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
- \\gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
- \\j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
- \\5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
- \\o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
- \\/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
- \\Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
- \\W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
- \\hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
- \\-----END CERTIFICATE-----
- );
- const chain = try CertificateChain.from_pem(std.testing.allocator, fbs.reader());
- defer chain.deinit();
-}
diff --git a/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem b/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem
deleted file mode 100644
index ea08d57a2..000000000
--- a/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
-PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
-Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
-rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
-OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
-xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
-7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
-aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
-SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
-ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
-AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
-R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
-JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
-Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
------END CERTIFICATE-----
diff --git a/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem b/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem
deleted file mode 100644
index fd4341df2..000000000
--- a/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem
+++ /dev/null
@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
-QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
-b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
-CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
-nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
-43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
-T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
-gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
-TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
-DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
-hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
-06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
-PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
-YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
diff --git a/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem b/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem
deleted file mode 100644
index 9e6810ab7..000000000
--- a/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
diff --git a/src/deps/iguanaTLS/test/badssl.com-client.pem b/src/deps/iguanaTLS/test/badssl.com-client.pem
deleted file mode 100644
index 16a2d1ad9..000000000
--- a/src/deps/iguanaTLS/test/badssl.com-client.pem
+++ /dev/null
@@ -1,61 +0,0 @@
-Bag Attributes
- localKeyID: 41 C3 6C 33 C7 E3 36 DD EA 4A 1F C0 B7 23 B8 E6 9C DC D8 0F
-subject=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Certificate
-
-issuer=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Root Certificate Authority
-
------BEGIN CERTIFICATE-----
-MIIEqDCCApCgAwIBAgIUK5Ns4y2CzosB/ZoFlaxjZqoBTIIwDQYJKoZIhvcNAQEL
-BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
-DVNhbiBGcmFuY2lzY28xDzANBgNVBAoMBkJhZFNTTDExMC8GA1UEAwwoQmFkU1NM
-IENsaWVudCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTExMjcwMDE5
-NTdaFw0yMTExMjYwMDE5NTdaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
-Zm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wx
-IjAgBgNVBAMMGUJhZFNTTCBDbGllbnQgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDHN18R6x5Oz+u6SOXLoxIscz5GHR6cDcCLgyPa
-x2XfXHdJs+h6fTy61WGM+aXEhR2SIwbj5997s34m0MsbvkJrFmn0LHK1fuTLCihE
-EmxGdCGZA9xrwxFYAkEjP7D8v7cAWRMipYF/JP7VU7xNUo+QSkZ0sOi9k6bNkABK
-L3+yP6PqAzsBoKIN5lN/YRLrppsDmk6nrRDo4R3CD+8JQl9quEoOmL22Pc/qpOjL
-1jgOIFSE5y3gwbzDlfCYoAL5V+by1vu0yJShTTK8oo5wvphcFfEHaQ9w5jFg2htd
-q99UER3BKuNDuL+zejqGQZCWb0Xsk8S5WBuX8l3Brrg5giqNAgMBAAGjLTArMAkG
-A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMAsGA1UdDwQEAwIF4DANBgkqhkiG
-9w0BAQsFAAOCAgEAZBauLzFSOijkDadcippr9C6laHebb0oRS54xAV70E9k5GxfR
-/E2EMuQ8X+miRUMXxKquffcDsSxzo2ac0flw94hDx3B6vJIYvsQx9Lzo95Im0DdT
-DkHFXhTlv2kjQwFVnEsWYwyGpHMTjanvNkO7sBP9p1bN1qTE3QAeyMZNKWJk5xPl
-U298ERar6tl3Z2Cl8mO6yLhrq4ba6iPGw08SENxzuAJW+n8r0rq7EU+bMg5spgT1
-CxExzG8Bb0f98ZXMklpYFogkcuH4OUOFyRodotrotm3iRbuvZNk0Zz7N5n1oLTPl
-bGPMwBcqaGXvK62NlaRkwjnbkPM4MYvREM0bbAgZD2GHyANBTso8bdWvhLvmoSjs
-FSqJUJp17AZ0x/ELWZd69v2zKW9UdPmw0evyVR19elh/7dmtF6wbewc4N4jxQnTq
-IItuhIWKWB9edgJz65uZ9ubQWjXoa+9CuWcV/1KxuKCbLHdZXiboLrKm4S1WmMYW
-d0sJm95H9mJzcLyhLF7iX2kK6K9ug1y02YCVXBC9WGZc2x6GMS7lDkXSkJFy3EWh
-CmfxkmFGwOgwKt3Jd1pF9ftcSEMhu4WcMgxi9vZr9OdkJLxmk033sVKI/hnkPaHw
-g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4=
------END CERTIFICATE-----
-
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAxzdfEeseTs/rukjly6MSLHM+Rh0enA3Ai4Mj2sdl31x3SbPo
-en08utVhjPmlxIUdkiMG4+ffe7N+JtDLG75CaxZp9CxytX7kywooRBJsRnQhmQPc
-a8MRWAJBIz+w/L+3AFkTIqWBfyT+1VO8TVKPkEpGdLDovZOmzZAASi9/sj+j6gM7
-AaCiDeZTf2ES66abA5pOp60Q6OEdwg/vCUJfarhKDpi9tj3P6qToy9Y4DiBUhOct
-4MG8w5XwmKAC+Vfm8tb7tMiUoU0yvKKOcL6YXBXxB2kPcOYxYNobXavfVBEdwSrj
-Q7i/s3o6hkGQlm9F7JPEuVgbl/Jdwa64OYIqjQIDAQABAoIBAFUQf7fW/YoJnk5c
-8kKRzyDL1Lt7k6Zu+NiZlqXEnutRQF5oQ8yJzXS5yH25296eOJI+AqMuT28ypZtN
-bGzcQOAZIgTxNcnp9Sf9nlPyyekLjY0Y6PXaxX0e+VFj0N8bvbiYUGNq6HCyC15r
-8uvRZRvnm04YfEj20zLTWkxTG+OwJ6ZNha1vfq8z7MG5JTsZbP0g7e/LrEb3wI7J
-Zu9yHQUzq23HhfhpmLN/0l89YLtOaS8WNq4QvKYgZapw/0G1wWoWW4Y2/UpAxZ9r
-cqTBWSpCSCCgyWjiNhPbSJWfe/9J2bcanITLcvCLlPWGAHy1wpo9iBH57y7S+7YS
-3yi7lgECgYEA8lwaRIChc38tmtQCNPtai/7uVDdeJe0uv8Jsg04FTF8KMYcD0V1g
-+T7rUPA+rTHwv8uAGLdzl4NW5Qryw18rDY+UivnaZkEdEsnlo3fc8MSQF78dDHCX
-nwmHfOmBnBoSbLl+W5ByHkJRHOnX+8qKq9ePNFUMf/hZNYuma9BCFBUCgYEA0m2p
-VDn12YdhFUUBIH91aD5cQIsBhkHFU4vqW4zBt6TsJpFciWbrBrTeRzeDou59aIsn
-zGBrLMykOY+EwwRku9KTVM4U791Z/NFbH89GqyUaicb4or+BXw5rGF8DmzSsDo0f
-ixJ9TVD5DmDi3c9ZQ7ljrtdSxPdA8kOoYPFsApkCgYEA08uZSPQAI6aoe/16UEK4
-Rk9qhz47kHlNuVZ27ehoyOzlQ5Lxyy0HacmKaxkILOLPuUxljTQEWAv3DAIdVI7+
-WMN41Fq0eVe9yIWXoNtGwUGFirsA77YVSm5RcN++3GQMZedUfUAl+juKFvJkRS4j
-MTkXdGw+mDa3/wsjTGSa2mECgYABO6NCWxSVsbVf6oeXKSgG9FaWCjp4DuqZErjM
-0IZSDSVVFIT2SSQXZffncuvSiJMziZ0yFV6LZKeRrsWYXu44K4Oxe4Oj5Cgi0xc1
-mIFRf2YoaIIMchLP+8Wk3ummfyiC7VDB/9m8Gj1bWDX8FrrvKqbq31gcz1YSFVNn
-PgLkAQKBgFzG8NdL8os55YcjBcOZMUs5QTKiQSyZM0Abab17k9JaqsU0jQtzeFsY
-FTiwh2uh6l4gdO/dGC/P0Vrp7F05NnO7oE4T+ojDzVQMnFpCBeL7x08GfUQkphEG
-m0Wqhhi8/24Sy934t5Txgkfoltg8ahkx934WjP6WWRnSAu+cf+vW
------END RSA PRIVATE KEY-----
diff --git a/src/deps/iguanaTLS/test/github.der b/src/deps/iguanaTLS/test/github.der
deleted file mode 100644
index dae019650..000000000
--- a/src/deps/iguanaTLS/test/github.der
+++ /dev/null
Binary files differ
diff --git a/src/deps/iguanaTLS/test/github.pem b/src/deps/iguanaTLS/test/github.pem
deleted file mode 100644
index 4b1bc66be..000000000
--- a/src/deps/iguanaTLS/test/github.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
diff --git a/src/feature_flags.zig b/src/feature_flags.zig
index 1772cfb77..e25171b46 100644
--- a/src/feature_flags.zig
+++ b/src/feature_flags.zig
@@ -48,14 +48,6 @@ pub const bundle_dynamic_import = true;
pub const allow_json_single_quotes = true;
pub const react_specific_warnings = true;
-// Disabled due to concurrency bug I don't have time to fix right now.
-// I suspect it's like 3 undefined memory issues.
-// This was the command I ran to reproduce it:
-// for i in (seq 1000)
-// command ../../build/debug/macos-x86_64/bun --use=./nexty2 --new-jsb > /dev/null
-// end
-// It only happens 1 out of every N times, probably like 50.
-pub const parallel_bun = false;
pub const CSSInJSImportBehavior = enum {
// When you import a .css file and you reference the import in JavaScript
diff --git a/src/fs_impl.zig b/src/fs_impl.zig
deleted file mode 100644
index 312d67171..000000000
--- a/src/fs_impl.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-const std = @import("std");
-usingnamespace @import("flags.zig");
-
-pub const FS = comptime {
- if (isWASM) {
- return @import("fs_impl_wasm.zig");
- } else {
- return @import("fs_impl_native.zig");
- }
-};
diff --git a/src/fs_impl_native.zig b/src/fs_impl_native.zig
deleted file mode 100644
index c9fb6bef2..000000000
--- a/src/fs_impl_native.zig
+++ /dev/null
@@ -1,3 +0,0 @@
-const std = @import("std");
-
-const fs = std.fs;
diff --git a/src/fs_impl_wasm.zig b/src/fs_impl_wasm.zig
deleted file mode 100644
index e69de29bb..000000000
--- a/src/fs_impl_wasm.zig
+++ /dev/null
diff --git a/src/global_name_parser.zig b/src/global_name_parser.zig
deleted file mode 100644
index e69de29bb..000000000
--- a/src/global_name_parser.zig
+++ /dev/null
diff --git a/src/hash_map_v2.zig b/src/hash_map_v2.zig
deleted file mode 100644
index e0b84fcd5..000000000
--- a/src/hash_map_v2.zig
+++ /dev/null
@@ -1,1822 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright (c) 2015-2021 Zig Contributors
-// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
-// The MIT license requires this copyright notice to be included in all copies
-// and substantial portions of the software.
-const std = @import("std");
-const assert = debug.assert;
-const autoHash = std.hash.autoHash;
-const debug = std.debug;
-const warn = debug.warn;
-const math = std.math;
-const mem = std.mem;
-const meta = std.meta;
-const trait = meta.trait;
-const Allocator = mem.Allocator;
-const Wyhash = std.hash.Wyhash;
-
-/// Finds the max of three numbers
-pub fn math_max3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) {
- return std.math.max(x, std.math.max(y, z));
-}
-
-pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K) u64) {
- comptime {
- assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated
- if (K == []const u8) {
- @compileError("std.auto_hash.autoHash does not allow slices here (" ++
- @typeName(K) ++
- ") because the intent is unclear. " ++
- "Consider using std.StringHashMap for hashing the contents of []const u8. " ++
- "Alternatively, consider using std.auto_hash.hash or providing your own hash function instead.");
- }
- }
-
- return struct {
- fn hash(ctx: Context, key: K) u64 {
- if (comptime trait.hasUniqueRepresentation(K)) {
- return Wyhash.hash(0, std.mem.asBytes(&key));
- } else {
- var hasher = Wyhash.init(0);
- autoHash(&hasher, key);
- return hasher.final();
- }
- }
- }.hash;
-}
-
-pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K) bool) {
- return struct {
- fn eql(ctx: Context, a: K, b: K) bool {
- if (comptime @typeInfo(K) == .Struct and @hasDecl(K, "eql")) {
- return a.eql(b);
- }
-
- return meta.eql(a, b);
- }
- }.eql;
-}
-
-pub fn AutoHashMap(comptime K: type, comptime V: type) type {
- return HashMap(K, V, AutoContext(K), default_max_load_percentage);
-}
-
-pub fn AutoHashMapUnmanaged(comptime K: type, comptime V: type) type {
- return HashMapUnmanaged(K, V, AutoContext(K), default_max_load_percentage);
-}
-
-pub fn AutoContext(comptime K: type) type {
- return struct {
- pub const hash = getAutoHashFn(K, @This());
- pub const eql = getAutoEqlFn(K, @This());
- };
-}
-
-/// Builtin hashmap for strings as keys.
-/// Key memory is managed by the caller. Keys and values
-/// will not automatically be freed.
-pub fn StringHashMap(comptime V: type) type {
- return HashMap([]const u8, V, StringContext, default_max_load_percentage);
-}
-
-/// Key memory is managed by the caller. Keys and values
-/// will not automatically be freed.
-pub fn StringHashMapUnmanaged(comptime V: type) type {
- return HashMapUnmanaged([]const u8, V, StringContext, default_max_load_percentage);
-}
-
-pub const StringContext = struct {
- pub fn hash(self: @This(), s: []const u8) u64 {
- return hashString(s);
- }
- pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
- return eqlString(a, b);
- }
-};
-
-pub fn eqlString(a: []const u8, b: []const u8) bool {
- return mem.eql(u8, a, b);
-}
-
-pub fn hashString(s: []const u8) u64 {
- return std.hash.Wyhash.hash(0, s);
-}
-
-/// Deprecated use `default_max_load_percentage`
-pub const DefaultMaxLoadPercentage = default_max_load_percentage;
-
-pub const default_max_load_percentage = 80;
-
-/// This function issues a compile error with a helpful message if there
-/// is a problem with the provided context type. A context must have the following
-/// member functions:
-/// - hash(self, PseudoKey) Hash
-/// - eql(self, PseudoKey, Key) bool
-/// If you are passing a context to a *Adapted function, PseudoKey is the type
-/// of the key parameter. Otherwise, when creating a HashMap or HashMapUnmanaged
-/// type, PseudoKey = Key = K.
-pub fn verifyContext(comptime RawContext: type, comptime PseudoKey: type, comptime Key: type, comptime Hash: type) void {
- comptime {
- var allow_const_ptr = false;
- var allow_mutable_ptr = false;
- // Context is the actual namespace type. RawContext may be a pointer to Context.
- var Context = RawContext;
- // Make sure the context is a namespace type which may have member functions
- switch (@typeInfo(Context)) {
- .Struct, .Union => {},
- // Special-case .Opaque for a better error message
- .Opaque => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context) ++ " because it is opaque. Use a pointer instead."),
- .Pointer => |ptr| {
- if (ptr.size != .One) {
- @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context) ++ " because it is not a single pointer.");
- }
- Context = ptr.child;
- allow_const_ptr = true;
- allow_mutable_ptr = !ptr.is_const;
- switch (@typeInfo(Context)) {
- .Struct, .Union, .Opaque => {},
- else => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context)),
- }
- },
- else => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context)),
- }
-
- // Keep track of multiple errors so we can report them all.
- var errors: []const u8 = "";
-
- // Put common errors here, they will only be evaluated
- // if the error is actually triggered.
- const lazy = struct {
- const prefix = "\n ";
- const deep_prefix = prefix ++ " ";
- const hash_signature = "fn (self, " ++ @typeName(PseudoKey) ++ ") " ++ @typeName(Hash);
- const eql_signature = "fn (self, " ++ @typeName(PseudoKey) ++ ", " ++ @typeName(Key) ++ ") bool";
- const err_invalid_hash_signature = prefix ++ @typeName(Context) ++ ".hash must be " ++ hash_signature ++
- deep_prefix ++ "but is actually " ++ @typeName(@TypeOf(Context.hash));
- const err_invalid_eql_signature = prefix ++ @typeName(Context) ++ ".eql must be " ++ eql_signature ++
- deep_prefix ++ "but is actually " ++ @typeName(@TypeOf(Context.eql));
- };
-
- // Verify Context.hash(self, PseudoKey) => Hash
- if (@hasDecl(Context, "hash")) {
- const hash = Context.hash;
- const info = @typeInfo(@TypeOf(hash));
- if (info == .Fn) {
- const func = info.Fn;
- if (func.args.len != 2) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- } else {
- var emitted_signature = false;
- if (func.args[0].arg_type) |Self| {
- if (Self == Context) {
- // pass, this is always fine.
- } else if (Self == *const Context) {
- if (!allow_const_ptr) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value.";
- }
- } else if (Self == *Context) {
- if (!allow_mutable_ptr) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- emitted_signature = true;
- }
- if (!allow_const_ptr) {
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value.";
- } else {
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ " or " ++ @typeName(*const Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be non-const because it is passed by const pointer.";
- }
- }
- } else {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context);
- if (allow_const_ptr) {
- errors = errors ++ " or " ++ @typeName(*const Context);
- if (allow_mutable_ptr) {
- errors = errors ++ " or " ++ @typeName(*Context);
- }
- }
- errors = errors ++ ", but is " ++ @typeName(Self);
- }
- }
- if (func.args[1].arg_type != null and func.args[1].arg_type.? != PseudoKey) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "Second parameter must be " ++ @typeName(PseudoKey) ++ ", but is " ++ @typeName(func.args[1].arg_type.?);
- }
- if (func.return_type != null and func.return_type.? != Hash) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_hash_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "Return type must be " ++ @typeName(Hash) ++ ", but was " ++ @typeName(func.return_type.?);
- }
- // If any of these are generic (null), we cannot verify them.
- // The call sites check the return type, but cannot check the
- // parameters. This may cause compile errors with generic hash/eql functions.
- }
- } else {
- errors = errors ++ lazy.err_invalid_hash_signature;
- }
- } else {
- errors = errors ++ lazy.prefix ++ @typeName(Context) ++ " must declare a hash function with signature " ++ lazy.hash_signature;
- }
-
- // Verify Context.eql(self, PseudoKey, Key) => bool
- if (@hasDecl(Context, "eql")) {
- const eql = Context.eql;
- const info = @typeInfo(@TypeOf(eql));
- if (info == .Fn) {
- const func = info.Fn;
- if (func.args.len != 3) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- } else {
- var emitted_signature = false;
- if (func.args[0].arg_type) |Self| {
- if (Self == Context) {
- // pass, this is always fine.
- } else if (Self == *const Context) {
- if (!allow_const_ptr) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value.";
- }
- } else if (Self == *Context) {
- if (!allow_mutable_ptr) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- if (!allow_const_ptr) {
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value.";
- } else {
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ " or " ++ @typeName(*const Context) ++ ", but is " ++ @typeName(Self);
- errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be non-const because it is passed by const pointer.";
- }
- }
- } else {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context);
- if (allow_const_ptr) {
- errors = errors ++ " or " ++ @typeName(*const Context);
- if (allow_mutable_ptr) {
- errors = errors ++ " or " ++ @typeName(*Context);
- }
- }
- errors = errors ++ ", but is " ++ @typeName(Self);
- }
- }
- if (func.args[1].arg_type.? != PseudoKey) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "Second parameter must be " ++ @typeName(PseudoKey) ++ ", but is " ++ @typeName(func.args[1].arg_type.?);
- }
- if (func.args[2].arg_type.? != Key) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "Third parameter must be " ++ @typeName(Key) ++ ", but is " ++ @typeName(func.args[2].arg_type.?);
- }
- if (func.return_type.? != bool) {
- if (!emitted_signature) {
- errors = errors ++ lazy.err_invalid_eql_signature;
- emitted_signature = true;
- }
- errors = errors ++ lazy.deep_prefix ++ "Return type must be bool, but was " ++ @typeName(func.return_type.?);
- }
- // If any of these are generic (null), we cannot verify them.
- // The call sites check the return type, but cannot check the
- // parameters. This may cause compile errors with generic hash/eql functions.
- }
- } else {
- errors = errors ++ lazy.err_invalid_eql_signature;
- }
- } else {
- errors = errors ++ lazy.prefix ++ @typeName(Context) ++ " must declare a eql function with signature " ++ lazy.eql_signature;
- }
-
- if (errors.len != 0) {
- // errors begins with a newline (from lazy.prefix)
- @compileError("Problems found with hash context type " ++ @typeName(Context) ++ ":" ++ errors);
- }
- }
-}
-
-/// General purpose hash table.
-/// No order is guaranteed and any modification invalidates live iterators.
-/// It provides fast operations (lookup, insertion, deletion) with quite high
-/// load factors (up to 80% by default) for a low memory usage.
-/// For a hash map that can be initialized directly that does not store an Allocator
-/// field, see `HashMapUnmanaged`.
-/// If iterating over the table entries is a strong usecase and needs to be fast,
-/// prefer the alternative `std.ArrayHashMap`.
-/// Context must be a struct type with two member functions:
-/// hash(self, K) u64
-/// eql(self, K, K) bool
-/// Adapted variants of many functions are provided. These variants
-/// take a pseudo key instead of a key. Their context must have the functions:
-/// hash(self, PseudoKey) u64
-/// eql(self, PseudoKey, K) bool
-pub fn HashMap(
- comptime K: type,
- comptime V: type,
- comptime Context: type,
- comptime max_load_percentage: u64,
-) type {
- comptime verifyContext(Context, K, K, u64);
- return struct {
- unmanaged: Unmanaged,
- allocator: *Allocator,
- ctx: Context,
-
- /// The type of the unmanaged hash map underlying this wrapper
- pub const Unmanaged = HashMapUnmanaged(K, V, Context, max_load_percentage);
- /// An entry, containing pointers to a key and value stored in the map
- pub const Entry = Unmanaged.Entry;
- /// A copy of a key and value which are no longer in the map
- pub const KV = Unmanaged.KV;
- /// The integer type that is the result of hashing
- pub const Hash = Unmanaged.Hash;
- /// The iterator type returned by iterator()
- pub const Iterator = Unmanaged.Iterator;
- /// The integer type used to store the size of the map
- pub const Size = Unmanaged.Size;
- /// The type returned from getOrPut and variants
- pub const GetOrPutResult = Unmanaged.GetOrPutResult;
-
- const Self = @This();
-
- /// Create a managed hash map with an empty context.
- /// If the context is not zero-sized, you must use
- /// initContext(allocator, ctx) instead.
- pub fn init(allocator: *Allocator) Self {
- if (@sizeOf(Context) != 0) {
- @compileError("Context must be specified! Call initContext(allocator, ctx) instead.");
- }
- return .{
- .unmanaged = .{},
- .allocator = allocator,
- .ctx = undefined, // ctx is zero-sized so this is safe.
- };
- }
-
- /// Create a managed hash map with a context
- pub fn initContext(allocator: *Allocator, ctx: Context) Self {
- return .{
- .unmanaged = .{},
- .allocator = allocator,
- .ctx = ctx,
- };
- }
-
- /// Release the backing array and invalidate this map.
- /// This does *not* deinit keys, values, or the context!
- /// If your keys or values need to be released, ensure
- /// that that is done before calling this function.
- pub fn deinit(self: *Self) void {
- self.unmanaged.deinit(self.allocator);
- self.* = undefined;
- }
-
- /// Empty the map, but keep the backing allocation for future use.
- /// This does *not* free keys or values! Be sure to
- /// release them if they need deinitialization before
- /// calling this function.
- pub fn clearRetainingCapacity(self: *Self) void {
- return self.unmanaged.clearRetainingCapacity();
- }
-
- /// Empty the map and release the backing allocation.
- /// This does *not* free keys or values! Be sure to
- /// release them if they need deinitialization before
- /// calling this function.
- pub fn clearAndFree(self: *Self) void {
- return self.unmanaged.clearAndFree(self.allocator);
- }
-
- /// Return the number of items in the map.
- pub fn count(self: Self) Size {
- return self.unmanaged.count();
- }
-
- /// Create an iterator over the entries in the map.
- /// The iterator is invalidated if the map is modified.
- pub fn iterator(self: *const Self) Iterator {
- return self.unmanaged.iterator();
- }
-
- /// If key exists this function cannot fail.
- /// If there is an existing item with `key`, then the result
- /// `Entry` pointers point to it, and found_existing is true.
- /// Otherwise, puts a new item with undefined value, and
- /// the `Entry` pointers point to it. Caller should then initialize
- /// the value (but not the key).
- pub fn getOrPut(self: *Self, key: K) !GetOrPutResult {
- return self.unmanaged.getOrPutContext(self.allocator, key, self.ctx);
- }
-
- /// If key exists this function cannot fail.
- /// If there is an existing item with `key`, then the result
- /// `Entry` pointers point to it, and found_existing is true.
- /// Otherwise, puts a new item with undefined key and value, and
- /// the `Entry` pointers point to it. Caller must then initialize
- /// the key and value.
- pub fn getOrPutAdapted(self: *Self, key: anytype, ctx: anytype) !GetOrPutResult {
- return self.unmanaged.getOrPutContextAdapted(self.allocator, key, ctx, self.ctx);
- }
-
- /// If there is an existing item with `key`, then the result
- /// `Entry` pointers point to it, and found_existing is true.
- /// Otherwise, puts a new item with undefined value, and
- /// the `Entry` pointers point to it. Caller should then initialize
- /// the value (but not the key).
- /// If a new entry needs to be stored, this function asserts there
- /// is enough capacity to store it.
- pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult {
- return self.unmanaged.getOrPutAssumeCapacityContext(key, self.ctx);
- }
-
- /// If there is an existing item with `key`, then the result
- /// `Entry` pointers point to it, and found_existing is true.
- /// Otherwise, puts a new item with undefined value, and
- /// the `Entry` pointers point to it. Caller must then initialize
- /// the key and value.
- /// If a new entry needs to be stored, this function asserts there
- /// is enough capacity to store it.
- pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult {
- return self.unmanaged.getOrPutAssumeCapacityAdapted(self.allocator, key, ctx);
- }
-
- pub fn getOrPutValue(self: *Self, key: K, value: V) !Entry {
- return self.unmanaged.getOrPutValueContext(self.allocator, key, value, self.ctx);
- }
-
- /// Increases capacity, guaranteeing that insertions up until the
- /// `expected_count` will not cause an allocation, and therefore cannot fail.
- pub fn ensureCapacity(self: *Self, expected_count: Size) !void {
- return self.unmanaged.ensureCapacityContext(self.allocator, expected_count, self.ctx);
- }
-
- /// Returns the number of total elements which may be present before it is
- /// no longer guaranteed that no allocations will be performed.
- pub fn capacity(self: *Self) Size {
- return self.unmanaged.capacity();
- }
-
- /// Clobbers any existing data. To detect if a put would clobber
- /// existing data, see `getOrPut`.
- pub fn put(self: *Self, key: K, value: V) !void {
- return self.unmanaged.putContext(self.allocator, key, value, self.ctx);
- }
-
- /// Inserts a key-value pair into the hash map, asserting that no previous
- /// entry with the same key is already present
- pub fn putNoClobber(self: *Self, key: K, value: V) !void {
- return self.unmanaged.putNoClobberContext(self.allocator, key, value, self.ctx);
- }
-
- /// Asserts there is enough capacity to store the new key-value pair.
- /// Clobbers any existing data. To detect if a put would clobber
- /// existing data, see `getOrPutAssumeCapacity`.
- pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
- return self.unmanaged.putAssumeCapacityContext(key, value, self.ctx);
- }
-
- /// Asserts there is enough capacity to store the new key-value pair.
- /// Asserts that it does not clobber any existing data.
- /// To detect if a put would clobber existing data, see `getOrPutAssumeCapacity`.
- pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {
- return self.unmanaged.putAssumeCapacityNoClobberContext(key, value, self.ctx);
- }
-
- /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
- pub fn fetchPut(self: *Self, key: K, value: V) !?KV {
- return self.unmanaged.fetchPutContext(self.allocator, key, value, self.ctx);
- }
-
- /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
- /// If insertion happuns, asserts there is enough capacity without allocating.
- pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?KV {
- return self.unmanaged.fetchPutAssumeCapacityContext(key, value, self.ctx);
- }
-
- /// Removes a value from the map and returns the removed kv pair.
- pub fn fetchRemove(self: *Self, key: K) ?KV {
- return self.unmanaged.fetchRemoveContext(key, self.ctx);
- }
-
- pub fn fetchRemoveAdapted(self: *Self, key: anytype, ctx: anytype) ?KV {
- return self.unmanaged.fetchRemoveAdapted(key, ctx);
- }
-
- /// Finds the value associated with a key in the map
- pub fn get(self: Self, key: K) ?*V {
- return self.unmanaged.getContext(key, self.ctx);
- }
-
- pub fn getAdapted(self: Self, key: anytype, ctx: anytype) ?*V {
- return self.unmanaged.getAdapted(key, ctx);
- }
-
- /// Finds the key and value associated with a key in the map
- pub fn getEntry(self: Self, key: K) ?Entry {
- return self.unmanaged.getEntryContext(key, self.ctx);
- }
-
- pub fn getEntryAdapted(self: Self, key: anytype, ctx: anytype) ?Entry {
- return self.unmanaged.getEntryAdapted(key, ctx);
- }
-
- /// Check if the map contains a key
- pub fn contains(self: Self, key: K) bool {
- return self.unmanaged.containsContext(key, self.ctx);
- }
-
- pub fn containsAdapted(self: Self, key: anytype, ctx: anytype) bool {
- return self.unmanaged.containsAdapted(key, ctx);
- }
-
- /// If there is an `Entry` with a matching key, it is deleted from
- /// the hash map, and then returned from this function.
- pub fn remove(self: *Self, key: K) bool {
- return self.unmanaged.removeContext(key, self.ctx);
- }
-
- pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool {
- return self.unmanaged.removeAdapted(key, ctx);
- }
-
- /// Creates a copy of this map, using the same allocator
- pub fn clone(self: Self) !Self {
- var other = try self.unmanaged.cloneContext(self.allocator, self.ctx);
- return other.promoteContext(self.allocator, self.ctx);
- }
-
- /// Creates a copy of this map, using a specified allocator
- pub fn cloneWithAllocator(self: Self, new_allocator: *Allocator) !Self {
- var other = try self.unmanaged.cloneContext(new_allocator, self.ctx);
- return other.promoteContext(new_allocator, self.ctx);
- }
-
- /// Creates a copy of this map, using a specified context
- pub fn cloneWithContext(self: Self, new_ctx: anytype) !HashMap(K, V, @TypeOf(new_ctx), max_load_percentage) {
- var other = try self.unmanaged.cloneContext(self.allocator, new_ctx);
- return other.promoteContext(self.allocator, new_ctx);
- }
-
- /// Creates a copy of this map, using a specified allocator and context
- pub fn cloneWithAllocatorAndContext(new_allocator: *Allocator, new_ctx: anytype) !HashMap(K, V, @TypeOf(new_ctx), max_load_percentage) {
- var other = try self.unmanaged.cloneContext(new_allocator, new_ctx);
- return other.promoteContext(new_allocator, new_ctx);
- }
- };
-}
-
-/// A HashMap based on open addressing and linear probing.
-/// A lookup or modification typically occurs only 2 cache misses.
-/// No order is guaranteed and any modification invalidates live iterators.
-/// It achieves good performance with quite high load factors (by default,
-/// grow is triggered at 80% full) and only one byte of overhead per element.
-/// The struct itself is only 16 bytes for a small footprint. This comes at
-/// the price of handling size with u32, which should be reasonnable enough
-/// for almost all uses.
-/// Deletions are achieved with tombstones.
-pub fn HashMapUnmanaged(
- comptime K: type,
- comptime V: type,
- comptime Context: type,
- comptime max_load_percentage: u64,
-) type {
- if (max_load_percentage <= 0 or max_load_percentage >= 100)
- @compileError("max_load_percentage must be between 0 and 100.");
- comptime verifyContext(Context, K, K, u64);
-
- return struct {
- const Self = @This();
-
- // This is actually a midway pointer to the single buffer containing
- // a `Header` field, the `Metadata`s and `Entry`s.
- // At `-@sizeOf(Header)` is the Header field.
- // At `sizeOf(Metadata) * capacity + offset`, which is pointed to by
- // self.header().entries, is the array of entries.
- // This means that the hashmap only holds one live allocation, to
- // reduce memory fragmentation and struct size.
- /// Pointer to the metadata.
- metadata: ?[*]Metadata = null,
-
- /// Current number of elements in the hashmap.
- size: Size = 0,
-
- // Having a countdown to grow reduces the number of instructions to
- // execute when determining if the hashmap has enough capacity already.
- /// Number of available slots before a grow is needed to satisfy the
- /// `max_load_percentage`.
- available: Size = 0,
-
- // This is purely empirical and not a /very smart magic constantâ„¢/.
- /// Capacity of the first grow when bootstrapping the hashmap.
- const minimal_capacity = 8;
-
- // This hashmap is specially designed for sizes that fit in a u32.
- pub const Size = u32;
-
- // u64 hashes guarantee us that the fingerprint bits will never be used
- // to compute the index of a slot, maximizing the use of entropy.
- pub const Hash = u64;
-
- pub const Entry = struct {
- key: *K,
- value: *V,
- };
-
- pub const KV = struct {
- key: K,
- value: V,
- };
-
- const Header = packed struct {
- values: [*]V,
- keys: [*]K,
- capacity: Size,
- };
-
- /// Metadata for a slot. It can be in three states: empty, used or
- /// tombstone. Tombstones indicate that an entry was previously used,
- /// they are a simple way to handle removal.
- /// To this state, we add 6 bits from the slot's key hash. These are
- /// used as a fast way to disambiguate between entries without
- /// having to use the equality function. If two fingerprints are
- /// different, we know that we don't have to compare the keys at all.
- /// The 6 bits are the highest ones from a 64 bit hash. This way, not
- /// only we use the `log2(capacity)` lowest bits from the hash to determine
- /// a slot index, but we use 6 more bits to quickly resolve collisions
- /// when multiple elements with different hashes end up wanting to be in / the same slot.
- /// Not using the equality function means we don't have to read into
- /// the entries array, avoiding a likely cache miss.
- const Metadata = packed struct {
- const FingerPrint = u6;
-
- used: u1 = 0,
- tombstone: u1 = 0,
- fingerprint: FingerPrint = 0,
-
- pub fn isUsed(self: Metadata) bool {
- return self.used == 1;
- }
-
- pub fn isTombstone(self: Metadata) bool {
- return self.tombstone == 1;
- }
-
- pub fn takeFingerprint(hash: Hash) FingerPrint {
- const hash_bits = @typeInfo(Hash).Int.bits;
- const fp_bits = @typeInfo(FingerPrint).Int.bits;
- return @truncate(FingerPrint, hash >> (hash_bits - fp_bits));
- }
-
- pub fn fill(self: *Metadata, fp: FingerPrint) void {
- self.used = 1;
- self.tombstone = 0;
- self.fingerprint = fp;
- }
-
- pub fn remove(self: *Metadata) void {
- self.used = 0;
- self.tombstone = 1;
- self.fingerprint = 0;
- }
- };
-
- comptime {
- assert(@sizeOf(Metadata) == 1);
- assert(@alignOf(Metadata) == 1);
- }
-
- pub const Iterator = struct {
- hm: *const Self,
- index: Size = 0,
-
- pub fn next(it: *Iterator) ?Entry {
- assert(it.index <= it.hm.capacity());
- if (it.hm.size == 0) return null;
-
- const cap = it.hm.capacity();
- const end = it.hm.metadata.? + cap;
- var metadata = it.hm.metadata.? + it.index;
-
- while (metadata != end) : ({
- metadata += 1;
- it.index += 1;
- }) {
- if (metadata[0].isUsed()) {
- const key = &it.hm.keys()[it.index];
- const value = &it.hm.values()[it.index];
- it.index += 1;
- return Entry{ .key = key, .value = value };
- }
- }
-
- return null;
- }
- };
-
- pub const GetOrPutResult = struct {
- entry: Entry,
- found_existing: bool,
- };
-
- pub const Managed = HashMap(K, V, Context, max_load_percentage);
-
- pub fn promote(self: Self, allocator: *Allocator) Managed {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call promoteContext instead.");
- return promoteContext(self, allocator, undefined);
- }
-
- pub fn promoteContext(self: Self, allocator: *Allocator, ctx: Context) Managed {
- return .{
- .unmanaged = self,
- .allocator = allocator,
- .ctx = ctx,
- };
- }
-
- fn isUnderMaxLoadPercentage(size: Size, cap: Size) bool {
- return size * 100 < max_load_percentage * cap;
- }
-
- pub fn deinit(self: *Self, allocator: *Allocator) void {
- self.deallocate(allocator);
- self.* = undefined;
- }
-
- fn capacityForSize(size: Size) Size {
- var new_cap = @truncate(u32, (@as(u64, size) * 100) / max_load_percentage + 1);
- new_cap = math.ceilPowerOfTwo(u32, new_cap) catch unreachable;
- return new_cap;
- }
-
- pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_size: Size) !void {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureCapacityContext instead.");
- return ensureCapacityContext(self, allocator, new_size, undefined);
- }
-
- pub fn ensureCapacityContext(self: *Self, allocator: *Allocator, new_size: Size, ctx: Context) !void {
- if (new_size > self.size)
- try self.growIfNeeded(allocator, new_size - self.size, ctx);
- }
-
- pub fn clearRetainingCapacity(self: *Self) void {
- if (self.metadata) |_| {
- self.initMetadatas();
- self.size = 0;
- self.available = @truncate(u32, (self.capacity() * max_load_percentage) / 100);
- }
- }
-
- pub fn clearAndFree(self: *Self, allocator: *Allocator) void {
- self.deallocate(allocator);
- self.size = 0;
- self.available = 0;
- }
-
- pub fn count(self: *const Self) Size {
- return self.size;
- }
-
- fn header(self: *const Self) *Header {
- return @ptrCast(*Header, @ptrCast([*]Header, self.metadata.?) - 1);
- }
-
- fn keys(self: *const Self) [*]K {
- return self.header().keys;
- }
-
- fn values(self: *const Self) [*]V {
- return self.header().values;
- }
-
- pub fn capacity(self: *const Self) Size {
- if (self.metadata == null) return 0;
-
- return self.header().capacity;
- }
-
- pub fn iterator(self: *const Self) Iterator {
- return .{ .hm = self };
- }
-
- pub fn putNoClobber(self: *Self, allocator: *Allocator, key: K, value: V) !void {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead.");
- return self.putNoClobberContext(allocator, key, value, undefined);
- }
-
- /// Insert an entry in the map. Assumes it is not already present.
- pub fn putNoClobberContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !void {
- assert(!self.containsContext(key, ctx));
- try self.growIfNeeded(allocator, 1, ctx);
-
- self.putAssumeCapacityNoClobberContext(key, value, ctx);
- }
-
- /// Asserts there is enough capacity to store the new key-value pair.
- /// Clobbers any existing data. To detect if a put would clobber
- /// existing data, see `getOrPutAssumeCapacity`.
- pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putAssumeCapacityContext instead.");
- return self.putAssumeCapacityContext(key, value, undefined);
- }
-
- pub fn putAssumeCapacityContext(self: *Self, key: K, value: V, ctx: Context) void {
- const gop = self.getOrPutAssumeCapacityContext(key, ctx);
- gop.entry.value.* = value;
- }
-
- pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putAssumeCapacityNoClobberContext instead.");
- return self.putAssumeCapacityNoClobberContext(key, value, undefined);
- }
-
- /// Insert an entry in the map. Assumes it is not already present,
- /// and that no allocation is needed.
- pub fn putAssumeCapacityNoClobberContext(self: *Self, key: K, value: V, ctx: Context) void {
- assert(!self.containsContext(key, ctx));
-
- const hash = ctx.hash(key);
- const mask = self.capacity() - 1;
- var idx = @truncate(usize, hash & mask);
-
- var metadata = self.metadata.? + idx;
- while (metadata[0].isUsed()) {
- idx = (idx + 1) & mask;
- metadata = self.metadata.? + idx;
- }
-
- if (!metadata[0].isTombstone()) {
- assert(self.available > 0);
- self.available -= 1;
- }
-
- const fingerprint = Metadata.takeFingerprint(hash);
- metadata[0].fill(fingerprint);
- self.keys()[idx] = key;
- self.values()[idx] = value;
-
- self.size += 1;
- }
-
- /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
- pub fn fetchPut(self: *Self, allocator: *Allocator, key: K, value: V) !?KV {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead.");
- return self.fetchPutContext(allocator, key, value, undefined);
- }
-
- pub fn fetchPutContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !?KV {
- const gop = try self.getOrPutContext(allocator, key, ctx);
- var result: ?KV = null;
- if (gop.found_existing) {
- result = KV{
- .key = gop.entry.key.*,
- .value = gop.entry.value.*,
- };
- }
- gop.entry.value.* = value;
- return result;
- }
-
- /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
- /// If insertion happens, asserts there is enough capacity without allocating.
- pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?KV {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutAssumeCapacityContext instead.");
- return self.fetchPutAssumeCapacityContext(allocator, key, value, undefined);
- }
-
- pub fn fetchPutAssumeCapacityContext(self: *Self, key: K, value: V, ctx: Context) ?KV {
- const gop = self.getOrPutAssumeCapacityContext(key, ctx);
- var result: ?KV = null;
- if (gop.found_existing) {
- result = KV{
- .key = gop.entry.key.*,
- .value = gop.entry.value.*,
- };
- }
- gop.entry.value.* = value;
- return result;
- }
-
- /// If there is an `Entry` with a matching key, it is deleted from
- /// the hash map, and then returned from this function.
- pub fn fetchRemove(self: *Self, key: K) ?KV {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchRemoveContext instead.");
- return self.fetchRemoveContext(allocator, key, value, undefined);
- }
-
- pub fn fetchRemoveContext(self: *Self, key: K, ctx: Context) ?KV {
- return self.fetchRemoveAdapted(key, ctx);
- }
-
- pub fn fetchRemoveAdapted(self: *Self, key: anytype, ctx: anytype) ?KV {
- if (self.getIndex(key, ctx)) |idx| {
- const old_key = &self.keys()[idx];
- const old_val = &self.values()[idx];
- const result = KV{
- .key = old_key.*,
- .value = old_val.*,
- };
- self.metadata.?[idx].remove();
- old_key.* = undefined;
- old_val.* = undefined;
- self.size -= 1;
- return result;
- }
-
- return null;
- }
-
- /// Find the index containing the data for the given key.
- /// Whether this function returns null is almost always
- /// branched on after this function returns, and this function
- /// returns null/not null from separate code paths. We
- /// want the optimizer to remove that branch and instead directly
- /// fuse the basic blocks after the branch to the basic blocks
- /// from this function. To encourage that, this function is
- /// marked as inline.
- inline fn getIndex(self: Self, key: anytype, ctx: anytype) ?usize {
- comptime verifyContext(@TypeOf(ctx), @TypeOf(key), K, Hash);
-
- if (self.size == 0) {
- return null;
- }
-
- // If you get a compile error on this line, it means that your generic hash
- // function is invalid for these parameters.
- const hash = ctx.hash(key);
- // verifyContext can't verify the return type of generic hash functions,
- // so we need to double-check it here.
- if (@TypeOf(hash) != Hash) {
- @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic hash function that returns the wrong type! " ++ @typeName(Hash) ++ " was expected, but found " ++ @typeName(@TypeOf(hash)));
- }
- const mask = self.capacity() - 1;
- const fingerprint = Metadata.takeFingerprint(hash);
- var idx = @truncate(usize, hash & mask);
-
- var metadata = self.metadata.? + idx;
- while (metadata[0].isUsed() or metadata[0].isTombstone()) {
- if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) {
- const test_key = &self.keys()[idx];
- // If you get a compile error on this line, it means that your generic eql
- // function is invalid for these parameters.
- const eql = ctx.eql(key, test_key.*);
- // verifyContext can't verify the return type of generic eql functions,
- // so we need to double-check it here.
- if (@TypeOf(eql) != bool) {
- @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic eql function that returns the wrong type! bool was expected, but found " ++ @typeName(@TypeOf(eql)));
- }
- if (eql) {
- return idx;
- }
- }
-
- idx = (idx + 1) & mask;
- metadata = self.metadata.? + idx;
- }
-
- return null;
- }
-
- pub fn getEntry(self: Self, key: K) ?Entry {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getEntryContext instead.");
- return self.getEntryContext(key, undefined);
- }
-
- pub fn getEntryContext(self: Self, key: K, ctx: Context) ?Entry {
- return self.getEntryAdapted(key, ctx);
- }
-
- pub fn getEntryAdapted(self: Self, key: anytype, ctx: anytype) ?Entry {
- if (self.getIndex(key, ctx)) |idx| {
- return Entry{
- .key = &self.keys()[idx],
- .value = &self.values()[idx],
- };
- }
- return null;
- }
-
- /// Insert an entry if the associated key is not already present, otherwise update preexisting value.
- pub fn put(self: *Self, allocator: *Allocator, key: K, v: Value) !void {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead.");
- return self.putContext(allocator, key, value, undefined);
- }
-
- pub fn putContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !void {
- const result = try self.getOrPutContext(allocator, key, ctx);
- result.entry.value.* = value;
- }
-
- /// Get an optional pointer to the value associated with key, if present.
- pub fn get(self: Self, key: K, ctx: Context) ?*V {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getContext instead.");
- return self.getContext(key, undefined);
- }
-
- pub fn getContext(self: Self, key: K, ctx: Context) ?*V {
- return self.getAdapted(key, ctx);
- }
-
- /// Get an optional pointer to the value associated with key, if present.
- pub fn getAdapted(self: Self, key: anytype, ctx: anytype) ?*V {
- if (self.getIndex(key, ctx)) |idx| {
- return &self.values()[idx];
- }
- return null;
- }
-
- pub fn getOrPut(self: *Self, allocator: *Allocator, key: K) !GetOrPutResult {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead.");
- return self.getOrPutContext(allocator, key, undefined);
- }
-
- pub fn getOrPutContext(self: *Self, allocator: *Allocator, key: K, ctx: Context) !GetOrPutResult {
- const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx);
- if (!gop.found_existing) {
- gop.entry.key.* = key;
- }
- return gop;
- }
-
- pub fn getOrPutAdapted(self: *Self, allocator: *Allocator, key: anytype, key_ctx: anytype) !GetOrPutResult {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead.");
- return self.getOrPutContextAdapted(allocator, key, key_ctx, undefined);
- }
-
- pub fn getOrPutContextAdapted(self: *Self, allocator: *Allocator, key: anytype, key_ctx: anytype, ctx: Context) !GetOrPutResult {
- self.growIfNeeded(allocator, 1, ctx) catch |err| {
- // If allocation fails, try to do the lookup anyway.
- // If we find an existing item, we can return it.
- // Otherwise return the error, we could not add another.
- const index = self.getIndex(key, key_ctx) orelse return err;
- return GetOrPutResult{
- .entry = .{
- .key = &self.keys()[index],
- .value = &self.values()[index],
- },
- .found_existing = true,
- };
- };
- return self.getOrPutAssumeCapacityAdapted(key, key_ctx);
- }
-
- pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutAssumeCapacityContext instead.");
- return self.getOrPutAssumeCapacityContext(key, undefined);
- }
-
- pub fn getOrPutAssumeCapacityContext(self: *Self, key: K, ctx: Context) GetOrPutResult {
- const result = self.getOrPutAssumeCapacityAdapted(key, ctx);
- if (!result.found_existing) {
- result.entry.key.* = key;
- }
- return result;
- }
-
- pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult {
- comptime verifyContext(@TypeOf(ctx), @TypeOf(key), K, Hash);
-
- // If you get a compile error on this line, it means that your generic hash
- // function is invalid for these parameters.
- const hash = ctx.hash(key);
- // verifyContext can't verify the return type of generic hash functions,
- // so we need to double-check it here.
- if (@TypeOf(hash) != Hash) {
- @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic hash function that returns the wrong type! " ++ @typeName(Hash) ++ " was expected, but found " ++ @typeName(@TypeOf(hash)));
- }
- const mask = self.capacity() - 1;
- const fingerprint = Metadata.takeFingerprint(hash);
- var idx = @truncate(usize, hash & mask);
-
- var first_tombstone_idx: usize = self.capacity(); // invalid index
- var metadata = self.metadata.? + idx;
- while (metadata[0].isUsed() or metadata[0].isTombstone()) {
- if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) {
- const test_key = &self.keys()[idx];
- // If you get a compile error on this line, it means that your generic eql
- // function is invalid for these parameters.
- const eql = ctx.eql(key, test_key.*);
- // verifyContext can't verify the return type of generic eql functions,
- // so we need to double-check it here.
- if (@TypeOf(eql) != bool) {
- @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic eql function that returns the wrong type! bool was expected, but found " ++ @typeName(@TypeOf(eql)));
- }
- if (eql) {
- return GetOrPutResult{ .entry = .{
- .key = test_key,
- .value = &self.values()[idx],
- }, .found_existing = true };
- }
- } else if (first_tombstone_idx == self.capacity() and metadata[0].isTombstone()) {
- first_tombstone_idx = idx;
- }
-
- idx = (idx + 1) & mask;
- metadata = self.metadata.? + idx;
- }
-
- if (first_tombstone_idx < self.capacity()) {
- // Cheap try to lower probing lengths after deletions. Recycle a tombstone.
- idx = first_tombstone_idx;
- metadata = self.metadata.? + idx;
- } else {
- // We're using a slot previously free.
- self.available -= 1;
- }
-
- metadata[0].fill(fingerprint);
- const new_key = &self.keys()[idx];
- const new_value = &self.values()[idx];
- new_key.* = key;
- new_value.* = undefined;
- self.size += 1;
-
- return GetOrPutResult{ .entry = .{
- .key = new_key,
- .value = new_value,
- }, .found_existing = false };
- }
-
- pub fn getOrPutValue(self: *Self, allocator: *Allocator, key: K, value: V) !Entry {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead.");
- return self.getOrPutValueContext(allocator, key, value, undefined);
- }
-
- pub fn getOrPutValueContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !Entry {
- const res = try self.getOrPutAdapted(allocator, key, ctx);
- if (!res.found_existing) {
- res.entry.key.* = key;
- res.entry.value.* = value;
- }
- return res.entry;
- }
-
- /// Return true if there is a value associated with key in the map.
- pub fn contains(self: *const Self, key: K) bool {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call containsContext instead.");
- return self.containsContext(key, undefined);
- }
-
- pub fn containsContext(self: *const Self, key: K, ctx: Context) bool {
- return self.containsAdapted(key, ctx);
- }
-
- pub fn containsAdapted(self: *const Self, key: anytype, ctx: anytype) bool {
- return self.getIndex(key, ctx) != null;
- }
-
- /// If there is an `Entry` with a matching key, it is deleted from
- /// the hash map, and this function returns true. Otherwise this
- /// function returns false.
- pub fn remove(self: *Self, key: K) bool {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call removeContext instead.");
- return self.removeContext(key, undefined);
- }
-
- pub fn removeContext(self: *Self, key: K, ctx: Context) bool {
- return self.removeAdapted(key, ctx);
- }
-
- pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool {
- if (self.getIndex(key, ctx)) |idx| {
- self.metadata.?[idx].remove();
- self.keys()[idx] = undefined;
- self.values()[idx] = undefined;
- self.size -= 1;
- return true;
- }
-
- return false;
- }
-
- fn initMetadatas(self: *Self) void {
- @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity());
- }
-
- // This counts the number of occupied slots, used + tombstones, which is
- // what has to stay under the max_load_percentage of capacity.
- fn load(self: *const Self) Size {
- const max_load = (self.capacity() * max_load_percentage) / 100;
- assert(max_load >= self.available);
- return @truncate(Size, max_load - self.available);
- }
-
- fn growIfNeeded(self: *Self, allocator: *Allocator, new_count: Size, ctx: Context) !void {
- if (new_count > self.available) {
- try self.grow(allocator, capacityForSize(self.load() + new_count), ctx);
- }
- }
-
- pub fn clone(self: Self, allocator: *Allocator) !Self {
- if (@sizeOf(Context) != 0)
- @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead.");
- return self.cloneContext(key, @as(Context, undefined));
- }
-
- pub fn cloneContext(self: Self, allocator: *Allocator, new_ctx: anytype) !HashMapUnmanaged(K, V, @TypeOf(new_ctx), max_load_percentage) {
- var other = HashMapUnmanaged(K, V, @TypeOf(new_ctx), max_load_percentage){};
- if (self.size == 0)
- return other;
-
- const new_cap = capacityForSize(self.size);
- try other.allocate(allocator, new_cap);
- other.initMetadatas();
- other.available = @truncate(u32, (new_cap * max_load_percentage) / 100);
-
- var i: Size = 0;
- var metadata = self.metadata.?;
- var keys_ptr = self.keys();
- var values_ptr = self.values();
- while (i < self.capacity()) : (i += 1) {
- if (metadata[i].isUsed()) {
- other.putAssumeCapacityNoClobberContext(keys_ptr[i], values_ptr[i], new_ctx);
- if (other.size == self.size)
- break;
- }
- }
-
- return other;
- }
-
- fn grow(self: *Self, allocator: *Allocator, new_capacity: Size, ctx: Context) !void {
- @setCold(true);
- const new_cap = std.math.max(new_capacity, minimal_capacity);
- assert(new_cap > self.capacity());
- assert(std.math.isPowerOfTwo(new_cap));
-
- var map = Self{};
- defer map.deinit(allocator);
- try map.allocate(allocator, new_cap);
- map.initMetadatas();
- map.available = @truncate(u32, (new_cap * max_load_percentage) / 100);
-
- if (self.size != 0) {
- const old_capacity = self.capacity();
- var i: Size = 0;
- var metadata = self.metadata.?;
- var keys_ptr = self.keys();
- var values_ptr = self.values();
- while (i < old_capacity) : (i += 1) {
- if (metadata[i].isUsed()) {
- map.putAssumeCapacityNoClobberContext(keys_ptr[i], values_ptr[i], ctx);
- if (map.size == self.size)
- break;
- }
- }
- }
-
- self.size = 0;
- std.mem.swap(Self, self, &map);
- }
-
- fn allocate(self: *Self, allocator: *Allocator, new_capacity: Size) !void {
- const header_align = @alignOf(Header);
- const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K);
- const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V);
- const max_align = comptime math_max3(header_align, key_align, val_align);
-
- const meta_size = @sizeOf(Header) + new_capacity * @sizeOf(Metadata);
- comptime assert(@alignOf(Metadata) == 1);
-
- const keys_start = std.mem.alignForward(meta_size, key_align);
- const keys_end = keys_start + new_capacity * @sizeOf(K);
-
- const vals_start = std.mem.alignForward(keys_end, val_align);
- const vals_end = vals_start + new_capacity * @sizeOf(V);
-
- const total_size = std.mem.alignForward(vals_end, max_align);
-
- const slice = try allocator.alignedAlloc(u8, max_align, total_size);
- const ptr = @ptrToInt(slice.ptr);
-
- const metadata = ptr + @sizeOf(Header);
-
- const hdr = @intToPtr(*Header, ptr);
- if (@sizeOf([*]V) != 0) {
- hdr.values = @intToPtr([*]V, ptr + vals_start);
- }
- if (@sizeOf([*]K) != 0) {
- hdr.keys = @intToPtr([*]K, ptr + keys_start);
- }
- hdr.capacity = new_capacity;
- self.metadata = @intToPtr([*]Metadata, metadata);
- }
-
- fn deallocate(self: *Self, allocator: *Allocator) void {
- if (self.metadata == null) return;
-
- const header_align = @alignOf(Header);
- const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K);
- const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V);
- const max_align = comptime math_max3(header_align, key_align, val_align);
-
- const cap = self.capacity();
- const meta_size = @sizeOf(Header) + cap * @sizeOf(Metadata);
- comptime assert(@alignOf(Metadata) == 1);
-
- const keys_start = std.mem.alignForward(meta_size, key_align);
- const keys_end = keys_start + cap * @sizeOf(K);
-
- const vals_start = std.mem.alignForward(keys_end, val_align);
- const vals_end = vals_start + cap * @sizeOf(V);
-
- const total_size = std.mem.alignForward(vals_end, max_align);
-
- const slice = @intToPtr([*]align(max_align) u8, @ptrToInt(self.header()))[0..total_size];
- allocator.free(slice);
-
- self.metadata = null;
- self.available = 0;
- }
- };
-}
-
-const testing = std.testing;
-const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
-
-test "std.hash_map basic usage" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- const count = 5;
- var i: u32 = 0;
- var total: u32 = 0;
- while (i < count) : (i += 1) {
- try map.put(i, i);
- total += i;
- }
-
- var sum: u32 = 0;
- var it = map.iterator();
- while (it.next()) |kv| {
- sum += kv.key.*;
- }
- try expectEqual(total, sum);
-
- i = 0;
- sum = 0;
- while (i < count) : (i += 1) {
- try expectEqual(i, map.get(i).?.*);
- sum += map.get(i).?.*;
- }
- try expectEqual(total, sum);
-}
-
-test "std.hash_map ensureCapacity" {
- var map = AutoHashMap(i32, i32).init(std.testing.allocator);
- defer map.deinit();
-
- try map.ensureCapacity(20);
- const initial_capacity = map.capacity();
- try testing.expect(initial_capacity >= 20);
- var i: i32 = 0;
- while (i < 20) : (i += 1) {
- try testing.expect(map.fetchPutAssumeCapacity(i, i + 10) == null);
- }
- // shouldn't resize from putAssumeCapacity
- try testing.expect(initial_capacity == map.capacity());
-}
-
-test "std.hash_map ensureCapacity with tombstones" {
- var map = AutoHashMap(i32, i32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: i32 = 0;
- while (i < 100) : (i += 1) {
- try map.ensureCapacity(@intCast(u32, map.count() + 1));
- map.putAssumeCapacity(i, i);
- // Remove to create tombstones that still count as load in the hashmap.
- _ = map.remove(i);
- }
-}
-
-test "std.hash_map clearRetainingCapacity" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- map.clearRetainingCapacity();
-
- try map.put(1, 1);
- try expectEqual(map.get(1).?.*, 1);
- try expectEqual(map.count(), 1);
-
- map.clearRetainingCapacity();
- map.putAssumeCapacity(1, 1);
- try expectEqual(map.get(1).?.*, 1);
- try expectEqual(map.count(), 1);
-
- const cap = map.capacity();
- try expect(cap > 0);
-
- map.clearRetainingCapacity();
- map.clearRetainingCapacity();
- try expectEqual(map.count(), 0);
- try expectEqual(map.capacity(), cap);
- try expect(!map.contains(1));
-}
-
-test "std.hash_map grow" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- const growTo = 12456;
-
- var i: u32 = 0;
- while (i < growTo) : (i += 1) {
- try map.put(i, i);
- }
- try expectEqual(map.count(), growTo);
-
- i = 0;
- var it = map.iterator();
- while (it.next()) |kv| {
- try expectEqual(kv.key.*, kv.value.*);
- i += 1;
- }
- try expectEqual(i, growTo);
-
- i = 0;
- while (i < growTo) : (i += 1) {
- try expectEqual(map.get(i).?.*, i);
- }
-}
-
-test "std.hash_map clone" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var a = try map.clone();
- defer a.deinit();
-
- try expectEqual(a.count(), 0);
-
- try a.put(1, 1);
- try a.put(2, 2);
- try a.put(3, 3);
-
- var b = try a.clone();
- defer b.deinit();
-
- try expectEqual(b.count(), 3);
- try expectEqual(b.get(1).?.*, 1);
- try expectEqual(b.get(2).?.*, 2);
- try expectEqual(b.get(3).?.*, 3);
-}
-
-test "std.hash_map ensureCapacity with existing elements" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- try map.put(0, 0);
- try expectEqual(map.count(), 1);
- try expectEqual(map.capacity(), @TypeOf(map).Unmanaged.minimal_capacity);
-
- try map.ensureCapacity(65);
- try expectEqual(map.count(), 1);
- try expectEqual(map.capacity(), 128);
-}
-
-test "std.hash_map ensureCapacity satisfies max load factor" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- try map.ensureCapacity(127);
- try expectEqual(map.capacity(), 256);
-}
-
-test "std.hash_map remove" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: u32 = 0;
- while (i < 16) : (i += 1) {
- try map.put(i, i);
- }
-
- i = 0;
- while (i < 16) : (i += 1) {
- if (i % 3 == 0) {
- _ = map.remove(i);
- }
- }
- try expectEqual(map.count(), 10);
- var it = map.iterator();
- while (it.next()) |kv| {
- try expectEqual(kv.key.*, kv.value.*);
- try expect(kv.key.* % 3 != 0);
- }
-
- i = 0;
- while (i < 16) : (i += 1) {
- if (i % 3 == 0) {
- try expect(!map.contains(i));
- } else {
- try expectEqual(map.get(i).?.*, i);
- }
- }
-}
-
-test "std.hash_map reverse removes" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: u32 = 0;
- while (i < 16) : (i += 1) {
- try map.putNoClobber(i, i);
- }
-
- i = 16;
- while (i > 0) : (i -= 1) {
- _ = map.remove(i - 1);
- try expect(!map.contains(i - 1));
- var j: u32 = 0;
- while (j < i - 1) : (j += 1) {
- try expectEqual(map.get(j).?.*, j);
- }
- }
-
- try expectEqual(map.count(), 0);
-}
-
-test "std.hash_map multiple removes on same metadata" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: u32 = 0;
- while (i < 16) : (i += 1) {
- try map.put(i, i);
- }
-
- _ = map.remove(7);
- _ = map.remove(15);
- _ = map.remove(14);
- _ = map.remove(13);
- try expect(!map.contains(7));
- try expect(!map.contains(15));
- try expect(!map.contains(14));
- try expect(!map.contains(13));
-
- i = 0;
- while (i < 13) : (i += 1) {
- if (i == 7) {
- try expect(!map.contains(i));
- } else {
- try expectEqual(map.get(i).?.*, i);
- }
- }
-
- try map.put(15, 15);
- try map.put(13, 13);
- try map.put(14, 14);
- try map.put(7, 7);
- i = 0;
- while (i < 16) : (i += 1) {
- try expectEqual(map.get(i).?.*, i);
- }
-}
-
-test "std.hash_map put and remove loop in random order" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var keys = std.ArrayList(u32).init(std.testing.allocator);
- defer keys.deinit();
-
- const size = 32;
- const iterations = 100;
-
- var i: u32 = 0;
- while (i < size) : (i += 1) {
- try keys.append(i);
- }
- var rng = std.rand.DefaultPrng.init(0);
-
- while (i < iterations) : (i += 1) {
- std.rand.Random.shuffle(&rng.random, u32, keys.items);
-
- for (keys.items) |key| {
- try map.put(key, key);
- }
- try expectEqual(map.count(), size);
-
- for (keys.items) |key| {
- _ = map.remove(key);
- }
- try expectEqual(map.count(), 0);
- }
-}
-
-test "std.hash_map remove one million elements in random order" {
- const Map = AutoHashMap(u32, u32);
- const n = 1000 * 1000;
- var map = Map.init(std.heap.page_allocator);
- defer map.deinit();
-
- var keys = std.ArrayList(u32).init(std.heap.page_allocator);
- defer keys.deinit();
-
- var i: u32 = 0;
- while (i < n) : (i += 1) {
- keys.append(i) catch unreachable;
- }
-
- var rng = std.rand.DefaultPrng.init(0);
- std.rand.Random.shuffle(&rng.random, u32, keys.items);
-
- for (keys.items) |key| {
- map.put(key, key) catch unreachable;
- }
-
- std.rand.Random.shuffle(&rng.random, u32, keys.items);
- i = 0;
- while (i < n) : (i += 1) {
- const key = keys.items[i];
- _ = map.remove(key);
- }
-}
-
-test "std.hash_map put" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: u32 = 0;
- while (i < 16) : (i += 1) {
- try map.put(i, i);
- }
-
- i = 0;
- while (i < 16) : (i += 1) {
- try expectEqual(map.get(i).?.*, i);
- }
-
- i = 0;
- while (i < 16) : (i += 1) {
- try map.put(i, i * 16 + 1);
- }
-
- i = 0;
- while (i < 16) : (i += 1) {
- try expectEqual(map.get(i).?.*, i * 16 + 1);
- }
-}
-
-test "std.hash_map putAssumeCapacity" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- try map.ensureCapacity(20);
- var i: u32 = 0;
- while (i < 20) : (i += 1) {
- map.putAssumeCapacityNoClobber(i, i);
- }
-
- i = 0;
- var sum = i;
- while (i < 20) : (i += 1) {
- sum += map.get(i).?.*;
- }
- try expectEqual(sum, 190);
-
- i = 0;
- while (i < 20) : (i += 1) {
- map.putAssumeCapacity(i, 1);
- }
-
- i = 0;
- sum = i;
- while (i < 20) : (i += 1) {
- sum += map.get(i).?.*;
- }
- try expectEqual(sum, 20);
-}
-
-test "std.hash_map getOrPut" {
- var map = AutoHashMap(u32, u32).init(std.testing.allocator);
- defer map.deinit();
-
- var i: u32 = 0;
- while (i < 10) : (i += 1) {
- try map.put(i * 2, 2);
- }
-
- i = 0;
- while (i < 20) : (i += 1) {
- var n = try map.getOrPutValue(i, 1);
- }
-
- i = 0;
- var sum = i;
- while (i < 20) : (i += 1) {
- sum += map.get(i).?.*;
- }
-
- try expectEqual(sum, 30);
-}
-
-test "std.hash_map basic hash map usage" {
- var map = AutoHashMap(i32, i32).init(std.testing.allocator);
- defer map.deinit();
-
- try testing.expect((try map.fetchPut(1, 11)) == null);
- try testing.expect((try map.fetchPut(2, 22)) == null);
- try testing.expect((try map.fetchPut(3, 33)) == null);
- try testing.expect((try map.fetchPut(4, 44)) == null);
-
- try map.putNoClobber(5, 55);
- try testing.expect((try map.fetchPut(5, 66)).?.value == 55);
- try testing.expect((try map.fetchPut(5, 55)).?.value == 66);
-
- const gop1 = try map.getOrPut(5);
- try testing.expect(gop1.found_existing == true);
- try testing.expect(gop1.entry.value.* == 55);
- gop1.entry.value.* = 77;
- try testing.expect(map.getEntry(5).?.value.* == 77);
-
- const gop2 = try map.getOrPut(99);
- try testing.expect(gop2.found_existing == false);
- gop2.entry.value.* = 42;
- try testing.expect(map.getEntry(99).?.value.* == 42);
-
- const gop3 = try map.getOrPutValue(5, 5);
- try testing.expect(gop3.value.* == 77);
-
- const gop4 = try map.getOrPutValue(100, 41);
- try testing.expect(gop4.value.* == 41);
-
- try testing.expect(map.contains(2));
- try testing.expect(map.getEntry(2).?.value.* == 22);
- try testing.expect(map.get(2).?.* == 22);
-
- const rmv1 = map.fetchRemove(2);
- try testing.expect(rmv1.?.key == 2);
- try testing.expect(rmv1.?.value == 22);
- try testing.expect(map.fetchRemove(2) == null);
- try testing.expect(map.remove(2) == false);
- try testing.expect(map.getEntry(2) == null);
- try testing.expect(map.get(2) == null);
-
- try testing.expect(map.remove(3) == true);
-}
-
-test "std.hash_map clone" {
- var original = AutoHashMap(i32, i32).init(std.testing.allocator);
- defer original.deinit();
-
- var i: u8 = 0;
- while (i < 10) : (i += 1) {
- try original.putNoClobber(i, i * 10);
- }
-
- var copy = try original.clone();
- defer copy.deinit();
-
- i = 0;
- while (i < 10) : (i += 1) {
- try testing.expect(copy.get(i).?.* == i * 10);
- }
-}
diff --git a/src/http_client.zig b/src/http_client.zig
index 65660c03b..834bc9215 100644
--- a/src/http_client.zig
+++ b/src/http_client.zig
@@ -6,7 +6,6 @@ const std = @import("std");
const Headers = @import("./javascript/jsc/webcore/response.zig").Headers;
const URL = @import("./query_string_map.zig").URL;
const Method = @import("./http/method.zig").Method;
-const iguanaTLS = @import("./deps/iguanaTLS/src/main.zig");
const Api = @import("./api/schema.zig").Api;
const Lock = @import("./lock.zig").Lock;
const HTTPClient = @This();
diff --git a/src/javascript/jsc/config.zig b/src/javascript/jsc/config.zig
index 2f91e433d..1356bc8eb 100644
--- a/src/javascript/jsc/config.zig
+++ b/src/javascript/jsc/config.zig
@@ -13,8 +13,6 @@ const js_printer = @import("../../js_printer.zig");
const hash_map = @import("../../hash_map.zig");
const http = @import("../../http.zig");
-usingnamespace @import("./node_env_buf_map.zig");
-
pub const DefaultBunDefines = struct {
pub const Keys = struct {
const window = "window";
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 4a6498a2b..124237c04 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -17,7 +17,6 @@ const hash_map = @import("../../hash_map.zig");
const http = @import("../../http.zig");
const ImportKind = ast.ImportKind;
const Analytics = @import("../../analytics/analytics_thread.zig");
-usingnamespace @import("./node_env_buf_map.zig");
usingnamespace @import("./base.zig");
usingnamespace @import("./webcore/response.zig");
usingnamespace @import("./config.zig");
diff --git a/src/javascript/jsc/new.zig b/src/javascript/jsc/new.zig
deleted file mode 100644
index e69de29bb..000000000
--- a/src/javascript/jsc/new.zig
+++ /dev/null
diff --git a/src/javascript/jsc/node_env_buf_map.zig b/src/javascript/jsc/node_env_buf_map.zig
deleted file mode 100644
index 73bc025b6..000000000
--- a/src/javascript/jsc/node_env_buf_map.zig
+++ /dev/null
@@ -1,151 +0,0 @@
-const std = @import("std");
-usingnamespace @import("../../global.zig");
-
-// This makes it so we get the defines already formatted from the user's environment with the "process.env." prefix set
-// This also normalizes quoting
-// Currently, it truncates any environment variables to a max of 1024 bytes
-pub const NodeEnvBufMap = struct {
- backing: std.BufMap,
- pub fn init(allocator: *std.mem.Allocator) NodeEnvBufMap {
- return NodeEnvBufMap{ .backing = std.BufMap.init(allocator) };
- }
- pub fn get(this: *const NodeEnvBufMap, key: string) ?string {
- return this.backing.get(key);
- }
- pub threadlocal var bufkeybuf: [4096]u8 = undefined;
- pub threadlocal var bufkeybuf_first = true;
-
- pub fn iterator(this: *NodeEnvBufMap) @typeInfo(@TypeOf(std.BufMap.iterator)).Fn.return_type.? {
- return this.backing.iterator();
- }
-
- pub fn put(this: *NodeEnvBufMap, key: string, value: anytype) !void {
- if (value.len == 0) {
- return;
- }
-
- if (bufkeybuf_first) {
- std.mem.copy(u8, &bufkeybuf, "process.env.");
- bufkeybuf_first = false;
- }
- std.mem.copy(u8, bufkeybuf["process.env.".len..], key);
- var key_slice = bufkeybuf[0 .. key.len + "process.env.".len];
- var value_slice = value;
- if (value_slice.len > 0) {
- const max_value_slice_len = std.math.min(value.len, bufkeybuf.len - key_slice.len);
- if (key_slice.len < bufkeybuf.len and value_slice[0] != '"' and value_slice[value.len - 1] != '"') {
- value_slice = bufkeybuf[key_slice.len..];
- if (value_slice.len > 0) {
- value_slice = value_slice[0 .. max_value_slice_len + 2];
- value_slice[0] = '"';
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- value_slice[value_slice.len - 1] = '"';
- } else {
- value_slice.len = 0;
- }
- } else if (value_slice[0] != '"') {
- value_slice[0] = '"';
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- } else if (value_slice[value.len - 1] != '"') {
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- value_slice[value_slice.len - 1] = '"';
- }
- }
-
- return this.backing.put(key_slice, value_slice);
- }
-
- pub fn count(this: *const NodeEnvBufMap) usize {
- return this.backing.count();
- }
-
- pub fn deinit(this: *NodeEnvBufMap) void {
- this.backing.deinit();
- }
-};
-
-pub fn getNodeEnvMap(allocator: *std.mem.Allocator) !NodeEnvBufMap {
- var result = NodeEnvBufMap.init(allocator);
- errdefer result.deinit();
- const builtin = std.builtin;
- if (builtin.os.tag == .windows) {
- const ptr = os.windows.peb().ProcessParameters.Environment;
-
- var i: usize = 0;
- while (ptr[i] != 0) {
- const key_start = i;
-
- while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
- const key_w = ptr[key_start..i];
- const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
- errdefer allocator.free(key);
-
- if (ptr[i] == '=') i += 1;
-
- const value_start = i;
- while (ptr[i] != 0) : (i += 1) {}
- const value_w = ptr[value_start..i];
- const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
- errdefer allocator.free(value);
-
- i += 1; // skip over null byte
-
- try result.putMove(key, value);
- }
- return result;
- } else if (builtin.os.tag == .wasi) {
- var environ_count: usize = undefined;
- var environ_buf_size: usize = undefined;
-
- const environ_sizes_get_ret = os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
- if (environ_sizes_get_ret != os.wasi.ESUCCESS) {
- return os.unexpectedErrno(environ_sizes_get_ret);
- }
-
- var environ = try allocator.alloc([*:0]u8, environ_count);
- defer allocator.free(environ);
- var environ_buf = try allocator.alloc(u8, environ_buf_size);
- defer allocator.free(environ_buf);
-
- const environ_get_ret = os.wasi.environ_get(environ.ptr, environ_buf.ptr);
- if (environ_get_ret != os.wasi.ESUCCESS) {
- return os.unexpectedErrno(environ_get_ret);
- }
-
- for (environ) |env| {
- const pair = mem.spanZ(env);
- var parts = mem.split(pair, "=");
- const key = parts.next().?;
- const value = parts.next().?;
- try result.put(key, value);
- }
- return result;
- } else if (builtin.link_libc) {
- var ptr = std.c.environ;
- while (ptr.*) |line| : (ptr += 1) {
- var line_i: usize = 0;
- while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
- const key = line[0..line_i];
-
- var end_i: usize = line_i;
- while (line[end_i] != 0) : (end_i += 1) {}
- const value = line[line_i + 1 .. end_i];
-
- try result.put(key, value);
- }
- return result;
- } else {
- for (os.environ) |line| {
- var line_i: usize = 0;
- while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
- const key = line[0..line_i];
-
- var end_i: usize = line_i;
- while (line[end_i] != 0) : (end_i += 1) {}
- const value = line[line_i + 1 .. end_i];
-
- try result.put(key, value);
- }
- return result;
- }
-}
diff --git a/src/linker.zig b/src/linker.zig
index 10f611a81..b031952b2 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -15,8 +15,6 @@ const Fs = @import("fs.zig");
const Api = @import("api/schema.zig").Api;
const Resolver = @import("./resolver/resolver.zig");
const sync = @import("sync.zig");
-const ThreadPool = sync.ThreadPool;
-const ThreadSafeHashMap = @import("./thread_safe_hash_map.zig");
const _import_record = @import("./import_record.zig");
const ImportRecord = _import_record.ImportRecord;
const ImportKind = _import_record.ImportKind;
diff --git a/src/thread_safe_hash_map.zig b/src/thread_safe_hash_map.zig
deleted file mode 100644
index 5c3a8cf51..000000000
--- a/src/thread_safe_hash_map.zig
+++ /dev/null
@@ -1,58 +0,0 @@
-const std = @import("std");
-const sync = @import("sync.zig");
-usingnamespace @import("global.zig");
-const hash_map = @import("hash_map.zig");
-
-pub fn ThreadSafeStringHashMap(comptime Value: type) type {
- const HashMapType = hash_map.StringHashMap(Value);
- return struct {
- backing: HashMapType,
- lock: sync.RwLock,
- pub const HashMap = @This();
-
- pub fn init(allocator: *std.mem.Allocator) !*HashMap {
- var self = try allocator.create(HashMap);
- self.* = HashMap{ .backing = HashMapType.init(allocator), .lock = sync.RwLock.init() };
-
- return self;
- }
-
- pub fn get(self: *HashMap, key: string) ?Value {
- self.lock.lockShared();
- defer self.lock.unlockShared();
- return self.backing.get(key);
- }
-
- pub fn getHash(key: string) u64 {
- return HashMapType.getHash(key);
- }
-
- pub fn contains(self: *HashMap, str: string) bool {
- self.lock.lockShared();
- defer self.lock.unlockShared();
- return self.backing.contains(str);
- }
-
- pub fn containsHash(self: *HashMap, hash: u64) bool {
- self.lock.lockShared();
- defer self.lock.unlockShared();
- return self.backing.contains(str);
- }
-
- pub fn deinit(self: *HashMap, allocator: *std.mem.Allocator) void {
- self.backing.deinit();
- }
-
- pub fn put(self: *HashMap, key: string, value: Value) !void {
- self.lock.lock();
- defer self.lock.unlock();
- try self.backing.put(key, value);
- }
-
- pub fn putWithHash(self: *HashMap, key: string, hash: u64, value: Value) !void {
- self.lock.lock();
- defer self.lock.unlock();
- try self.backing.put(key, value);
- }
- };
-}