authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-27 22:59:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:57:15-07:00
logceb211e65fe6bfe864b1150d08cd5e0383f6c2c2
tree291bbfb58a68c60d1c36a7d58af9961ea40570ba
parent5bbedb63cf43297bcb6ff1dca12affafebc9c09e

std.crypto.tls.Client: handle key_update message


2 files changed, 64 insertions(+), 4 deletions(-)

lib/std/crypto/tls.zig+8
......@@ -227,6 +227,12 @@ pub const CertificateType = enum(u8) {
227227 _,
228228};
229229
230pub const KeyUpdateRequest = enum(u8) {
231 update_not_requested = 0,
232 update_requested = 1,
233 _,
234};
235
230236pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type) type {
231237 return struct {
232238 pub const AEAD = AeadType;
......@@ -261,6 +267,8 @@ pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type) type
261267 pub const Hmac = crypto.auth.hmac.Hmac(Hash);
262268 pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);
263269
270 client_secret: [Hash.digest_length]u8,
271 server_secret: [Hash.digest_length]u8,
264272 client_key: [AEAD.key_length]u8,
265273 server_key: [AEAD.key_length]u8,
266274 client_iv: [AEAD.nonce_length]u8,
lib/std/crypto/tls/Client.zig+56-4
......@@ -24,7 +24,7 @@ read_seq: u64,
2424write_seq: u64,
2525/// The size is enough to contain exactly one TLSCiphertext record.
2626partially_read_buffer: [tls.max_ciphertext_record_len]u8,
27/// The number of partially read bytes inside `partiall_read_buffer`.
27/// The number of partially read bytes inside `partially_read_buffer`.
2828partially_read_len: u15,
2929eof: bool,
3030
......@@ -584,6 +584,8 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
584584 // std.fmt.fmtSliceHexLower(&server_secret),
585585 //});
586586 break :c @unionInit(ApplicationCipher, @tagName(tag), .{
587 .client_secret = client_secret,
588 .server_secret = server_secret,
587589 .client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length),
588590 .server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length),
589591 .client_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length),
......@@ -669,7 +671,7 @@ pub fn write(c: *Client, stream: net.Stream, bytes: []const u8) !usize {
669671 ciphertext_end += auth_tag.len;
670672 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
671673 const operand: V = pad ++ @bitCast([8]u8, big(c.write_seq));
672 c.write_seq += 1;
674 c.write_seq += 1; // TODO send key_update on overflow
673675 const nonce = @as(V, p.client_iv) ^ operand;
674676 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, p.client_key);
675677 //std.debug.print("seq: {d} nonce: {} client_key: {} client_iv: {} ad: {} auth_tag: {}\nserver_key: {} server_iv: {}\n", .{
......@@ -789,7 +791,8 @@ pub fn read(c: *Client, stream: net.Stream, buffer: []u8) !usize {
789791 },
790792 };
791793
792 const inner_ct = @intToEnum(ContentType, buffer[out + cleartext_len - 1]);
794 const cleartext = buffer[out..][0..cleartext_len];
795 const inner_ct = @intToEnum(ContentType, cleartext[cleartext.len - 1]);
793796 switch (inner_ct) {
794797 .alert => {
795798 const level = @intToEnum(tls.AlertLevel, buffer[out]);
......@@ -802,7 +805,56 @@ pub fn read(c: *Client, stream: net.Stream, buffer: []u8) !usize {
802805 return error.TlsAlert;
803806 },
804807 .handshake => {
805 std.debug.print("the server wants to keep shaking hands\n", .{});
808 var ct_i: usize = 0;
809 while (true) {
810 const handshake_type = cleartext[ct_i];
811 ct_i += 1;
812 const handshake_len = mem.readIntBig(u24, cleartext[ct_i..][0..3]);
813 ct_i += 3;
814 const next_handshake_i = ct_i + handshake_len;
815 if (next_handshake_i > cleartext.len - 1)
816 return error.TlsBadLength;
817 const handshake = cleartext[ct_i..next_handshake_i];
818 switch (handshake_type) {
819 @enumToInt(HandshakeType.new_session_ticket) => {
820 std.debug.print("server sent a new session ticket\n", .{});
821 },
822 @enumToInt(HandshakeType.key_update) => {
823 switch (c.application_cipher) {
824 inline else => |*p| {
825 const P = @TypeOf(p.*);
826 const server_secret = hkdfExpandLabel(P.Hkdf, p.server_secret, "traffic upd", "", P.Hash.digest_length);
827 p.server_secret = server_secret;
828 p.server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length);
829 p.server_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length);
830 },
831 }
832 c.read_seq = 0;
833
834 switch (@intToEnum(tls.KeyUpdateRequest, handshake[0])) {
835 .update_requested => {
836 switch (c.application_cipher) {
837 inline else => |*p| {
838 const P = @TypeOf(p.*);
839 const client_secret = hkdfExpandLabel(P.Hkdf, p.client_secret, "traffic upd", "", P.Hash.digest_length);
840 p.client_secret = client_secret;
841 p.client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length);
842 p.client_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length);
843 },
844 }
845 c.write_seq = 0;
846 },
847 .update_not_requested => {},
848 _ => return error.TlsIllegalParameter,
849 }
850 },
851 else => {
852 return error.TlsUnexpectedMessage;
853 },
854 }
855 ct_i = next_handshake_i;
856 if (ct_i >= cleartext.len - 1) break;
857 }
806858 },
807859 .application_data => {
808860 out += cleartext_len - 1;