From be42b070866fe6520bc5cac62fd10b9462515b52 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Wed, 19 Jan 2022 21:17:44 -0800 Subject: [PATCH] add tls trust chain for AWS --- Amazon_Root_CA_1.pem | 20 ++++++++++++++++++++ build.zig | 1 + src/aws.zig | 9 ++++++--- src/aws_http.zig | 24 ++++++++++++++++++------ src/main.zig | 2 +- 5 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Amazon_Root_CA_1.pem diff --git a/Amazon_Root_CA_1.pem b/Amazon_Root_CA_1.pem new file mode 100644 index 0000000..a6f3e92 --- /dev/null +++ b/Amazon_Root_CA_1.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- diff --git a/build.zig b/build.zig index 94abbd5..f6a8322 100644 --- a/build.zig +++ b/build.zig @@ -53,6 +53,7 @@ pub fn build(b: *Builder) !void { // so we'll have to keep that in sync with upstream // const zfetch = @import("libs/zfetch/build.zig"); exe.addPackage(getZfetchPackage(b, "libs/zfetch") catch unreachable); + exe.addPackagePath("iguanaTLS", "libs/zfetch/libs/iguanaTLS/src/main.zig"); const run_cmd = exe.run(); run_cmd.step.dependOn(b.getInstallStep()); diff --git a/src/aws.zig b/src/aws.zig index c46824b..114a83f 100644 --- a/src/aws.zig +++ b/src/aws.zig @@ -25,16 +25,19 @@ pub const services = servicemodel.services; /// This will give you a constant with service data for sts, ec2, s3 and ddb only pub const Services = servicemodel.Services; +pub const ClientOptions = struct { + trust_pem: ?[]const u8 = awshttp.default_root_ca, +}; pub const Client = struct { allocator: std.mem.Allocator, aws_http: awshttp.AwsHttp, const Self = @This(); - pub fn init(allocator: std.mem.Allocator) Self { - return .{ + pub fn init(allocator: std.mem.Allocator, options: ClientOptions) !Self { + return Self{ .allocator = allocator, - .aws_http = awshttp.AwsHttp.init(allocator), + .aws_http = try awshttp.AwsHttp.init(allocator, options.trust_pem), }; } pub fn deinit(self: *Client) void { diff --git a/src/aws_http.zig b/src/aws_http.zig index bd3fa39..419d61e 100644 --- a/src/aws_http.zig +++ b/src/aws_http.zig @@ -12,6 +12,7 @@ const base = @import("aws_http_base.zig"); const signing = @import("aws_signing.zig"); const credentials = @import("aws_credentials.zig"); const zfetch = @import("zfetch"); +const tls = @import("iguanaTLS"); const CN_NORTH_1_HASH = std.hash_map.hashString("cn-north-1"); const CN_NORTHWEST_1_HASH = std.hash_map.hashString("cn-northwest-1"); @@ -20,6 +21,10 @@ const US_ISOB_EAST_1_HASH = std.hash_map.hashString("us-isob-east-1"); const log = std.log.scoped(.awshttp); +const amazon_root_ca_1 = @embedFile("../Amazon_Root_CA_1.pem"); + +pub const default_root_ca = amazon_root_ca_1; + pub const AwsError = error{ AddHeaderError, AlpnError, @@ -57,20 +62,29 @@ const EndPoint = struct { self.allocator.free(self.uri); } }; - pub const AwsHttp = struct { allocator: std.mem.Allocator, + trust_chain: ?tls.x509.CertificateChain, const Self = @This(); - pub fn init(allocator: std.mem.Allocator) Self { - return .{ + /// Recommend usage is init(allocator, awshttp.default_root_ca) + /// Passing null for root_pem will result in no TLS verification + pub fn init(allocator: std.mem.Allocator, root_pem: ?[]const u8) !Self { + var trust_chain: ?tls.x509.CertificateChain = null; + if (root_pem) |p| { + var fbs = std.io.fixedBufferStream(p); + trust_chain = try tls.x509.CertificateChain.from_pem(allocator, fbs.reader()); + } + return Self{ .allocator = allocator, + .trust_chain = trust_chain, // .credentialsProvider = // creds provider could be useful }; } pub fn deinit(self: *AwsHttp) void { + if (self.trust_chain) |c| c.deinit(); _ = self; log.debug("Deinit complete", .{}); } @@ -160,7 +174,7 @@ pub const AwsHttp = struct { const url = try std.fmt.allocPrint(self.allocator, "{s}{s}", .{ endpoint.uri, request.path }); defer self.allocator.free(url); log.debug("Request url: {s}", .{url}); - var req = try zfetch.Request.init(self.allocator, url, null); + var req = try zfetch.Request.init(self.allocator, url, self.trust_chain); defer req.deinit(); const method = std.meta.stringToEnum(zfetch.Method, request_cp.method).?; @@ -182,8 +196,6 @@ pub const AwsHttp = struct { content_length = std.fmt.parseInt(usize, h.value, 10) catch 0; } const reader = req.reader(); - // TODO: Get content length and use that to allocate the buffer - // Content length can be missing, and why would we trust it anyway var buf: [65535]u8 = undefined; var resp_payload = try std.ArrayList(u8).initCapacity(self.allocator, content_length); defer resp_payload.deinit(); diff --git a/src/main.zig b/src/main.zig index 8de5e0f..aa36d52 100644 --- a/src/main.zig +++ b/src/main.zig @@ -71,7 +71,7 @@ pub fn main() anyerror!void { } std.log.info("Start\n", .{}); - var client = aws.Client.init(allocator); + var client = try aws.Client.init(allocator, .{}); const options = aws.Options{ .region = "us-west-2", .client = client,