Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 101 additions & 22 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ pub fn build(b: *std.Build) !void {
"-fno-sanitize=undefined",
};

const openssl = b.option(bool, "enable-openssl", "Use OpenSSL instead of MbedTLS") orelse false;

if (target.result.os.tag == .windows) {
if (openssl) {
std.log.err("OpenSSL option unsupported on Windows", .{});
return;
}

lib.linkSystemLibrary("winhttp");
lib.linkSystemLibrary("rpcrt4");
lib.linkSystemLibrary("crypt32");
Expand All @@ -61,20 +68,37 @@ pub fn build(b: *std.Build) !void {
lib.addWin32ResourceFile(.{ .file = libgit_src.path("src/libgit2/git2.rc") });
lib.addCSourceFiles(.{ .root = libgit_root, .files = &util_win32_sources, .flags = &flags });
} else {
// mbedTLS https and SHA backend
lib.linkSystemLibrary("mbedtls");
lib.linkSystemLibrary("mbedcrypto");
lib.linkSystemLibrary("mbedx509");
features.addValues(.{
.GIT_HTTPS = 1,
.GIT_MBEDTLS = 1,
.GIT_SHA1_MBEDTLS = 1,
.GIT_SHA256_MBEDTLS = 1,

.GIT_USE_FUTIMENS = 1,
.GIT_IO_POLL = 1,
.GIT_IO_SELECT = 1,
});
if (openssl) {
// OpenSSL backend
const openssl_dep = b.dependency("openssl", .{});
const openssl_lib = openssl_dep.artifact("openssl");
lib.linkLibrary(openssl_lib);
features.addValues(.{
.GIT_HTTPS = 1,
.GIT_OPENSSL = 1,
.GIT_SHA1_OPENSSL = 1,
.GIT_SHA256_OPENSSL = 1,

.GIT_USE_FUTIMENS = 1,
.GIT_IO_POLL = 1,
.GIT_IO_SELECT = 1,
});
} else {
// mbedTLS https and SHA backend
lib.linkSystemLibrary("mbedtls");
lib.linkSystemLibrary("mbedcrypto");
lib.linkSystemLibrary("mbedx509");
features.addValues(.{
.GIT_HTTPS = 1,
.GIT_MBEDTLS = 1,
.GIT_SHA1_MBEDTLS = 1,
.GIT_SHA256_MBEDTLS = 1,

.GIT_USE_FUTIMENS = 1,
.GIT_IO_POLL = 1,
.GIT_IO_SELECT = 1,
});
}

// ntlmclient
{
Expand All @@ -85,15 +109,30 @@ pub fn build(b: *std.Build) !void {
.link_libc = true,
});
ntlm.addIncludePath(libgit_src.path("deps/ntlmclient"));
if (openssl) addOpenSSLHeaders(ntlm);

const ntlm_cflags = .{
"-Wno-implicit-fallthrough",
"-DNTLM_STATIC=1",
"-DUNICODE_BUILTIN=1",
if (openssl)
"-DCRYPT_OPENSSL"
else
"-DCRYPT_MBEDTLS",
};
ntlm.addCSourceFiles(.{
.root = libgit_root,
.files = &ntlm_sources,
.flags = &.{
"-Wno-implicit-fallthrough",
"-DNTLM_STATIC=1",
"-DUNICODE_BUILTIN=1",
"-DCRYPT_MBEDTLS",
.flags = &ntlm_cflags,
});
ntlm.addCSourceFiles(.{
.root = libgit_root,
.files = if (openssl) &.{
"deps/ntlmclient/crypt_openssl.c",
} else &.{
"deps/ntlmclient/crypt_mbedtls.c",
},
.flags = &ntlm_cflags,
});

lib.linkLibrary(ntlm);
Expand All @@ -106,6 +145,15 @@ pub fn build(b: *std.Build) !void {
.files = &util_unix_sources,
.flags = &flags,
});
lib.addCSourceFiles(.{
.root = libgit_root,
.files = if (openssl) &.{
"src/util/hash/openssl.c",
} else &.{
"src/util/hash/mbedtls.c",
},
.flags = &flags,
});
}

if (b.option(bool, "enable-ssh", "Enable SSH support") orelse false) {
Expand Down Expand Up @@ -249,6 +297,7 @@ pub fn build(b: *std.Build) !void {
cli.addIncludePath(libgit_src.path("include"));
cli.addIncludePath(libgit_src.path("src/util"));
cli.addIncludePath(libgit_src.path("src/cli"));
if (openssl) addOpenSSLHeaders(cli);

if (target.result.os.tag == .windows)
cli.addCSourceFiles(.{ .root = libgit_root, .files = &cli_win32_sources })
Expand Down Expand Up @@ -293,6 +342,7 @@ pub fn build(b: *std.Build) !void {
});

exe.addIncludePath(libgit_src.path("include"));
if (openssl) addOpenSSLHeaders(exe);
exe.linkLibrary(lib);

// independent install step so you can easily access the binary
Expand All @@ -304,6 +354,38 @@ pub fn build(b: *std.Build) !void {
example_run.step.dependOn(&examples_install.step);
examples_step.dependOn(&example_run.step);
}

const tests_step = b.step("run-tests", "Tests");
{
const tests = b.addTest(.{
.root_source_file = b.path("tests/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});

const fixture = b.addOptions();
fixture.addOptionPath("resources", libgit_src.path("tests/resources"));

tests.root_module.addOptions("fixture", fixture);

tests.addConfigHeader(features);
tests.addIncludePath(libgit_src.path("include"));
tests.addIncludePath(libgit_src.path("src/util"));
if (openssl) addOpenSSLHeaders(tests);

tests.linkLibrary(lib);

const tests_run = b.addRunArtifact(tests);
tests_step.dependOn(&tests_run.step);
}
}

fn addOpenSSLHeaders(compile: *std.Build.Step.Compile) void {
const b = compile.step.owner;
const openssl_dep = b.dependency("openssl", .{});
const openssl_lib = openssl_dep.artifact("openssl");
compile.addIncludePath(openssl_lib.getEmittedIncludeTree());
}

const libgit_sources = [_][]const u8{
Expand Down Expand Up @@ -478,8 +560,6 @@ const util_unix_sources = [_][]const u8{
"src/util/unix/map.c",
"src/util/unix/process.c",
"src/util/unix/realpath.c",

"src/util/hash/mbedtls.c",
};

const util_win32_sources = [_][]const u8{
Expand Down Expand Up @@ -555,7 +635,6 @@ const xdiff_sources = [_][]const u8{

const ntlm_sources = [_][]const u8{
"deps/ntlmclient/crypt_builtin_md4.c",
"deps/ntlmclient/crypt_mbedtls.c",
"deps/ntlmclient/ntlm.c",
"deps/ntlmclient/unicode_builtin.c",
"deps/ntlmclient/util.c",
Expand Down
6 changes: 5 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
.libgit2 = .{
.url = "https://github.com/libgit2/libgit2/archive/refs/tags/v1.8.1.tar.gz",
.hash = "12208db692747f305b79ecfb3ac69e691d0b9584383ec4bcb0eb07b62b73de77b1cf",
}
},
.openssl = .{
.url = "https://github.com/allyourcodebase/openssl/archive/refs/tags/3.3.1-1.tar.gz",
.hash = "12207c40cefa38fe90e4230dfba2e5c76b37e1ee36602512cad8ff0501f892002a65",
},
},
.paths = .{
"build.zig",
Expand Down
3 changes: 3 additions & 0 deletions tests/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test {
_ = @import("sha.zig");
}
114 changes: 114 additions & 0 deletions tests/sha.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const std = @import("std");
const testing = std.testing;

const c = @cImport({
@cInclude("hash.h");
});

const fixture = @import("fixture");

fn calcHashFile(
allocator: std.mem.Allocator,
filename: []const u8,
comptime algorithm: c.git_hash_algorithm_t,
) ![]u8 {
const file = try std.fs.openFileAbsolute(
filename,
.{},
);
defer file.close();

const size: usize = switch (algorithm) {
c.GIT_HASH_ALGORITHM_SHA1 => c.GIT_HASH_SHA1_SIZE,
c.GIT_HASH_ALGORITHM_SHA256 => c.GIT_HASH_SHA256_SIZE,
else => unreachable,
};
const actual = try allocator.alloc(u8, size);

var r: c_int = undefined;
var ctx: c.git_hash_ctx = undefined;
r = c.git_hash_ctx_init(&ctx, algorithm);
if (r != 0) return error.Unexpected;
defer c.git_hash_ctx_cleanup(&ctx);

const reader = file.reader();
while (true) {
var buf: [2048]u8 = undefined;
const len = try reader.read(&buf);
if (len == 0) break;
r = c.git_hash_update(&ctx, &buf, len);
if (r != 0) return error.Unexpected;
}

r = c.git_hash_final(actual.ptr, &ctx);
if (r != 0) return error.Unexpected;

return actual;
}

test "sha1" {
const expect = [c.GIT_HASH_SHA1_SIZE]u8{
0x4e, 0x72, 0x67, 0x9e, 0x3e, 0xa4, 0xd0, 0x4e,
0x0c, 0x64, 0x2f, 0x02, 0x9e, 0x61, 0xeb, 0x80,
0x56, 0xc7, 0xed, 0x94,
};
const actual = try calcHashFile(
testing.allocator,
fixture.resources ++ "/sha1/hello_c",
c.GIT_HASH_ALGORITHM_SHA1,
);
defer testing.allocator.free(actual);

try testing.expectEqualSlices(u8, &expect, actual);
}

test "sha256 empty" {
const expect = [c.GIT_HASH_SHA256_SIZE]u8{
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
};
const actual = try calcHashFile(
testing.allocator,
fixture.resources ++ "/sha1/empty",
c.GIT_HASH_ALGORITHM_SHA256,
);
defer testing.allocator.free(actual);

try testing.expectEqualSlices(u8, &expect, actual);
}

test "sha256 hello" {
const expect = [c.GIT_HASH_SHA256_SIZE]u8{
0xaa, 0x32, 0x7f, 0xae, 0x5c, 0x91, 0x58, 0x3a,
0x4f, 0xb6, 0x54, 0xcc, 0xb6, 0xc2, 0xb1, 0x0c,
0x77, 0xd7, 0x49, 0xc9, 0x91, 0x2a, 0x8d, 0x6b,
0x47, 0x26, 0x13, 0xc0, 0xa0, 0x4b, 0x4d, 0xad,
};
const actual = try calcHashFile(
testing.allocator,
fixture.resources ++ "/sha1/hello_c",
c.GIT_HASH_ALGORITHM_SHA256,
);
defer testing.allocator.free(actual);

try testing.expectEqualSlices(u8, &expect, actual);
}

test "sha256 pdf" {
const expect = [c.GIT_HASH_SHA256_SIZE]u8{
0x2b, 0xb7, 0x87, 0xa7, 0x3e, 0x37, 0x35, 0x2f,
0x92, 0x38, 0x3a, 0xbe, 0x7e, 0x29, 0x02, 0x93,
0x6d, 0x10, 0x59, 0xad, 0x9f, 0x1b, 0xa6, 0xda,
0xaa, 0x9c, 0x1e, 0x58, 0xee, 0x69, 0x70, 0xd0,
};
const actual = try calcHashFile(
testing.allocator,
fixture.resources ++ "/sha1/shattered-1.pdf",
c.GIT_HASH_ALGORITHM_SHA256,
);
defer testing.allocator.free(actual);

try testing.expectEqualSlices(u8, &expect, actual);
}