authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-16 02:14:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:57:15-07:00
logb97fc43baac9498799f3520ee860e5026e8dcb53
treeb7af862417bb3e8650e6a59866715f3c5d60b313
parent40a85506b2e6a97af9c06bdcd001b6fd84cc549a

std.crypto.Tls: client is working against some servers


2 files changed, 122 insertions(+), 54 deletions(-)

lib/std/crypto/Tls.zig+101-52
...@@ -9,12 +9,14 @@ application_cipher: ApplicationCipher,...@@ -9,12 +9,14 @@ application_cipher: ApplicationCipher,
9read_seq: u64,9read_seq: u64,
10write_seq: u64,10write_seq: u64,
11/// The size is enough to contain exactly one TLSCiphertext record.11/// The size is enough to contain exactly one TLSCiphertext record.
12partially_read_buffer: [max_ciphertext_len + ciphertext_record_header_len]u8,12partially_read_buffer: [max_ciphertext_record_len]u8,
13/// The number of partially read bytes inside `partiall_read_buffer`.13/// The number of partially read bytes inside `partiall_read_buffer`.
14partially_read_len: u15,14partially_read_len: u15,
15eof: bool,
1516
16pub const ciphertext_record_header_len = 5;17pub const ciphertext_record_header_len = 5;
17pub const max_ciphertext_len = (1 << 14) + 256;18pub const max_ciphertext_len = (1 << 14) + 256;
19pub const max_ciphertext_record_len = max_ciphertext_len + ciphertext_record_header_len;
1820
19pub const ProtocolVersion = enum(u16) {21pub const ProtocolVersion = enum(u16) {
20 tls_1_2 = 0x0303,22 tls_1_2 = 0x0303,
...@@ -416,7 +418,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -416,7 +418,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
416418
417 var cipher_params: CipherParams = undefined;419 var cipher_params: CipherParams = undefined;
418420
419 var handshake_buf: [4000]u8 = undefined;421 var handshake_buf: [8000]u8 = undefined;
420 var len: usize = 0;422 var len: usize = 0;
421 var i: usize = i: {423 var i: usize = i: {
422 const plaintext = handshake_buf[0..5];424 const plaintext = handshake_buf[0..5];
...@@ -554,8 +556,8 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -554,8 +556,8 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
554 // std.fmt.fmtSliceHexLower(&hello_hash),556 // std.fmt.fmtSliceHexLower(&hello_hash),
555 // std.fmt.fmtSliceHexLower(&early_secret),557 // std.fmt.fmtSliceHexLower(&early_secret),
556 // std.fmt.fmtSliceHexLower(&empty_hash),558 // std.fmt.fmtSliceHexLower(&empty_hash),
557 // std.fmt.fmtSliceHexLower(&derived_secret),559 // std.fmt.fmtSliceHexLower(&hs_derived_secret),
558 // std.fmt.fmtSliceHexLower(&handshake_secret),560 // std.fmt.fmtSliceHexLower(&p.handshake_secret),
559 // std.fmt.fmtSliceHexLower(&client_secret),561 // std.fmt.fmtSliceHexLower(&client_secret),
560 // std.fmt.fmtSliceHexLower(&server_secret),562 // std.fmt.fmtSliceHexLower(&server_secret),
561 //});563 //});
...@@ -582,7 +584,9 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -582,7 +584,9 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
582 const end_hdr = i + 5;584 const end_hdr = i + 5;
583 if (end_hdr > handshake_buf.len) return error.TlsRecordOverflow;585 if (end_hdr > handshake_buf.len) return error.TlsRecordOverflow;
584 if (end_hdr > len) {586 if (end_hdr > len) {
587 std.debug.print("read len={d} atleast={d}\n", .{ len, end_hdr - len });
585 len += try stream.readAtLeast(handshake_buf[len..], end_hdr - len);588 len += try stream.readAtLeast(handshake_buf[len..], end_hdr - len);
589 std.debug.print("new len: {d} bytes\n", .{len});
586 if (end_hdr > len) return error.EndOfStream;590 if (end_hdr > len) return error.EndOfStream;
587 }591 }
588 const ct = @intToEnum(ContentType, handshake_buf[i]);592 const ct = @intToEnum(ContentType, handshake_buf[i]);
...@@ -593,9 +597,12 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -593,9 +597,12 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
593 const record_size = mem.readIntBig(u16, handshake_buf[i..][0..2]);597 const record_size = mem.readIntBig(u16, handshake_buf[i..][0..2]);
594 i += 2;598 i += 2;
595 const end = i + record_size;599 const end = i + record_size;
600 std.debug.print("ct={any} record_size={d} end={d}\n", .{ ct, record_size, end });
596 if (end > handshake_buf.len) return error.TlsRecordOverflow;601 if (end > handshake_buf.len) return error.TlsRecordOverflow;
597 if (end > len) {602 if (end > len) {
603 std.debug.print("read len={d} atleast={d}\n", .{ len, end - len });
598 len += try stream.readAtLeast(handshake_buf[len..], end - len);604 len += try stream.readAtLeast(handshake_buf[len..], end - len);
605 std.debug.print("new len: {d} bytes\n", .{len});
599 if (end > len) return error.EndOfStream;606 if (end > len) return error.EndOfStream;
600 }607 }
601 switch (ct) {608 switch (ct) {
...@@ -604,7 +611,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -604,7 +611,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
604 if (handshake_buf[i] != 0x01) return error.TlsUnexpectedMessage;611 if (handshake_buf[i] != 0x01) return error.TlsUnexpectedMessage;
605 },612 },
606 .application_data => {613 .application_data => {
607 var cleartext_buf: [1000]u8 = undefined;614 var cleartext_buf: [8000]u8 = undefined;
608 const cleartext = switch (cipher_params) {615 const cleartext = switch (cipher_params) {
609 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| c: {616 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| c: {
610 const P = @TypeOf(p.*);617 const P = @TypeOf(p.*);
...@@ -637,17 +644,18 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -637,17 +644,18 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
637 };644 };
638645
639 const inner_ct = cleartext[cleartext.len - 1];646 const inner_ct = cleartext[cleartext.len - 1];
647 std.debug.print("inner_ct={any}\n", .{@intToEnum(ContentType, inner_ct)});
640 switch (inner_ct) {648 switch (inner_ct) {
641 @enumToInt(ContentType.handshake) => {649 @enumToInt(ContentType.handshake) => {
642 const handshake_len = mem.readIntBig(u24, cleartext[1..4]);650 const handshake_len = mem.readIntBig(u24, cleartext[1..4]);
643 if (4 + handshake_len != cleartext.len - 1) return error.TlsBadLength;651 if (4 + handshake_len > cleartext.len - 1) return error.TlsBadLength;
652 std.debug.print("handshake type: {any} size: {d}\n", .{ @intToEnum(HandshakeType, cleartext[0]), handshake_len });
644 switch (cleartext[0]) {653 switch (cleartext[0]) {
645 @enumToInt(HandshakeType.encrypted_extensions) => {654 @enumToInt(HandshakeType.encrypted_extensions) => {
646 const ext_size = mem.readIntBig(u16, cleartext[4..6]);655 const ext_size = mem.readIntBig(u16, cleartext[4..6]);
647 if (ext_size != 0) {656 std.debug.print("{d} bytes of encrypted extensions\n", .{
648 @panic("TODO handle encrypted extensions");657 ext_size,
649 }658 });
650 std.debug.print("empty encrypted extensions\n", .{});
651 },659 },
652 @enumToInt(HandshakeType.certificate) => {660 @enumToInt(HandshakeType.certificate) => {
653 std.debug.print("cool certificate bro\n", .{});661 std.debug.print("cool certificate bro\n", .{});
...@@ -688,22 +696,18 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -688,22 +696,18 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
688 const nonce = p.client_handshake_iv;696 const nonce = p.client_handshake_iv;
689 P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, p.client_handshake_key);697 P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, p.client_handshake_key);
690698
691 {699 //const both_msgs = client_change_cipher_spec_msg ++ finished_msg;
692 var iovecs = [_]std.os.iovec_const{700 _ = client_change_cipher_spec_msg;
693 .{701 const both_msgs = finished_msg;
694 .iov_base = &client_change_cipher_spec_msg,702 try stream.writeAll(&both_msgs);
695 .iov_len = client_change_cipher_spec_msg.len,
696 },
697 .{
698 .iov_base = &finished_msg,
699 .iov_len = finished_msg.len,
700 },
701 };
702 try stream.writevAll(&iovecs);
703 }
704703
705 const client_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);704 const client_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);
706 const server_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "s ap traffic", &handshake_hash, P.Hash.digest_length);705 const server_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "s ap traffic", &handshake_hash, P.Hash.digest_length);
706 //std.debug.print("master_secret={}\nclient_secret={}\nserver_secret={}\n", .{
707 // std.fmt.fmtSliceHexLower(&p.master_secret),
708 // std.fmt.fmtSliceHexLower(&client_secret),
709 // std.fmt.fmtSliceHexLower(&server_secret),
710 //});
707 break :c @unionInit(ApplicationCipher, @tagName(tag), .{711 break :c @unionInit(ApplicationCipher, @tagName(tag), .{
708 .client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length),712 .client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length),
709 .server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length),713 .server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length),
...@@ -721,12 +725,14 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -721,12 +725,14 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
721 @panic("TODO");725 @panic("TODO");
722 },726 },
723 };727 };
728 std.debug.print("remaining bytes: {d}\n", .{len - end});
724 return .{729 return .{
725 .application_cipher = app_cipher,730 .application_cipher = app_cipher,
726 .read_seq = read_seq,731 .read_seq = 0,
727 .write_seq = 1,732 .write_seq = 0,
728 .partially_read_buffer = undefined,733 .partially_read_buffer = undefined,
729 .partially_read_len = 0,734 .partially_read_len = 0,
735 .eof = false,
730 };736 };
731 },737 },
732 else => {738 else => {
...@@ -753,49 +759,67 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {...@@ -753,49 +759,67 @@ pub fn init(stream: net.Stream, host: []const u8) !Tls {
753}759}
754760
755pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {761pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {
756 var ciphertext_buf: [max_ciphertext_len * 4]u8 = undefined;762 var ciphertext_buf: [max_ciphertext_record_len * 4]u8 = undefined;
763 // Due to the trailing inner content type byte in the ciphertext, we need
764 // an additional buffer for storing the cleartext into before encrypting.
765 var cleartext_buf: [max_ciphertext_len]u8 = undefined;
757 var iovecs_buf: [5]std.os.iovec_const = undefined;766 var iovecs_buf: [5]std.os.iovec_const = undefined;
758 var ciphertext_end: usize = 0;767 var ciphertext_end: usize = 0;
759 var iovec_end: usize = 0;768 var iovec_end: usize = 0;
760 var bytes_i: usize = 0;769 var bytes_i: usize = 0;
761 switch (tls.application_cipher) {770 // How many bytes are taken up by overhead per record.
762 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| {771 const overhead_len: usize = switch (tls.application_cipher) {
772 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| l: {
763 const P = @TypeOf(p.*);773 const P = @TypeOf(p.*);
764 const V = @Vector(P.AEAD.nonce_length, u8);774 const V = @Vector(P.AEAD.nonce_length, u8);
775 const overhead_len = ciphertext_record_header_len + P.AEAD.tag_length + 1;
765 while (true) {776 while (true) {
766 const ciphertext_len = @intCast(u16, @min(777 const encrypted_content_len = @intCast(u16, @min(
767 @min(bytes.len - bytes_i, max_ciphertext_len),778 @min(bytes.len - bytes_i, max_ciphertext_len - 1),
768 ciphertext_buf.len - 5 - P.AEAD.tag_length - ciphertext_end,779 ciphertext_buf.len -
780 ciphertext_record_header_len - P.AEAD.tag_length - ciphertext_end - 1,
769 ));781 ));
770 if (ciphertext_len == 0) return bytes_i;782 if (encrypted_content_len == 0) break :l overhead_len;
771783
772 const wrapped_len = ciphertext_len + P.AEAD.tag_length;784 mem.copy(u8, &cleartext_buf, bytes[bytes_i..][0..encrypted_content_len]);
773 const record = ciphertext_buf[ciphertext_end..][0 .. 5 + wrapped_len];785 cleartext_buf[encrypted_content_len] = @enumToInt(ContentType.application_data);
786 bytes_i += encrypted_content_len;
787 const ciphertext_len = encrypted_content_len + 1;
788 const cleartext = cleartext_buf[0..ciphertext_len];
774789
775 const ad = record[0..5];790 const record_start = ciphertext_end;
776 ciphertext_end += 5;791 const ad = ciphertext_buf[ciphertext_end..][0..5];
792 ad.* =
793 [_]u8{@enumToInt(ContentType.application_data)} ++
794 int2(@enumToInt(ProtocolVersion.tls_1_2)) ++
795 int2(ciphertext_len + P.AEAD.tag_length);
796 ciphertext_end += ad.len;
777 const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];797 const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];
778 ciphertext_end += ciphertext_len;798 ciphertext_end += ciphertext_len;
779 const auth_tag = ciphertext_buf[ciphertext_end..][0..P.AEAD.tag_length];799 const auth_tag = ciphertext_buf[ciphertext_end..][0..P.AEAD.tag_length];
780 ciphertext_end += P.AEAD.tag_length;800 ciphertext_end += auth_tag.len;
781 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);801 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
782 const operand: V = pad ++ @bitCast([8]u8, big(tls.write_seq));802 const operand: V = pad ++ @bitCast([8]u8, big(tls.write_seq));
783 tls.write_seq += 1;803 tls.write_seq += 1;
784 const nonce: [P.AEAD.nonce_length]u8 = @as(V, p.client_iv) ^ operand;804 const nonce: [P.AEAD.nonce_length]u8 = @as(V, p.client_iv) ^ operand;
785 ad.* =
786 [_]u8{@enumToInt(ContentType.application_data)} ++
787 int2(@enumToInt(ProtocolVersion.tls_1_2)) ++
788 int2(wrapped_len);
789 const cleartext = bytes[bytes_i..ciphertext.len];
790 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, p.client_key);805 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, p.client_key);
791806 //std.debug.print("seq: {d} nonce: {} client_key: {} client_iv: {} ad: {} auth_tag: {}\nserver_key: {} server_iv: {}", .{
807 // tls.write_seq - 1,
808 // std.fmt.fmtSliceHexLower(&nonce),
809 // std.fmt.fmtSliceHexLower(&p.client_key),
810 // std.fmt.fmtSliceHexLower(&p.client_iv),
811 // std.fmt.fmtSliceHexLower(ad),
812 // std.fmt.fmtSliceHexLower(auth_tag),
813 // std.fmt.fmtSliceHexLower(&p.server_key),
814 // std.fmt.fmtSliceHexLower(&p.server_iv),
815 //});
816
817 const record = ciphertext_buf[record_start..ciphertext_end];
792 iovecs_buf[iovec_end] = .{818 iovecs_buf[iovec_end] = .{
793 .iov_base = record.ptr,819 .iov_base = record.ptr,
794 .iov_len = record.len,820 .iov_len = record.len,
795 };821 };
796 iovec_end += 1;822 iovec_end += 1;
797
798 bytes_i += ciphertext_len;
799 }823 }
800 },824 },
801 .TLS_CHACHA20_POLY1305_SHA256 => {825 .TLS_CHACHA20_POLY1305_SHA256 => {
...@@ -807,7 +831,7 @@ pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {...@@ -807,7 +831,7 @@ pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {
807 .TLS_AES_128_CCM_8_SHA256 => {831 .TLS_AES_128_CCM_8_SHA256 => {
808 @panic("TODO");832 @panic("TODO");
809 },833 },
810 }834 };
811835
812 // Ideally we would call writev exactly once here, however, we must ensure836 // Ideally we would call writev exactly once here, however, we must ensure
813 // that we don't return with a record partially written.837 // that we don't return with a record partially written.
...@@ -815,9 +839,10 @@ pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {...@@ -815,9 +839,10 @@ pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize {
815 var total_amt: usize = 0;839 var total_amt: usize = 0;
816 while (true) {840 while (true) {
817 var amt = try stream.writev(iovecs_buf[i..iovec_end]);841 var amt = try stream.writev(iovecs_buf[i..iovec_end]);
818 total_amt += amt;
819 while (amt >= iovecs_buf[i].iov_len) {842 while (amt >= iovecs_buf[i].iov_len) {
820 amt -= iovecs_buf[i].iov_len;843 const encrypted_amt = iovecs_buf[i].iov_len;
844 total_amt += encrypted_amt - overhead_len;
845 amt -= encrypted_amt;
821 i += 1;846 i += 1;
822 // Rely on the property that iovecs delineate records, meaning that847 // Rely on the property that iovecs delineate records, meaning that
823 // if amt equals zero here, we have fortunately found ourselves848 // if amt equals zero here, we have fortunately found ourselves
...@@ -849,11 +874,17 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {...@@ -849,11 +874,17 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {
849 const wanted_read_len = buf_cap * (max_ciphertext_len + ciphertext_record_header_len);874 const wanted_read_len = buf_cap * (max_ciphertext_len + ciphertext_record_header_len);
850 const actual_read_len = try stream.read(in_buf[prev_len..@min(wanted_read_len, in_buf.len)]);875 const actual_read_len = try stream.read(in_buf[prev_len..@min(wanted_read_len, in_buf.len)]);
851 const frag = in_buf[0 .. prev_len + actual_read_len];876 const frag = in_buf[0 .. prev_len + actual_read_len];
877 if (frag.len == 0) {
878 tls.eof = true;
879 return 0;
880 }
881 std.debug.print("actual_read_len={d} frag.len={d}\n", .{ actual_read_len, frag.len });
852 var in: usize = 0;882 var in: usize = 0;
853 var out: usize = 0;883 var out: usize = 0;
854884
855 while (true) {885 while (true) {
856 if (in + ciphertext_record_header_len > frag.len) {886 if (in + ciphertext_record_header_len > frag.len) {
887 std.debug.print("in={d} frag.len={d}\n", .{ in, frag.len });
857 return finishRead(tls, frag, in, out);888 return finishRead(tls, frag, in, out);
858 }889 }
859 const ct = @intToEnum(ContentType, frag[in]);890 const ct = @intToEnum(ContentType, frag[in]);
...@@ -866,6 +897,7 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {...@@ -866,6 +897,7 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {
866 const end = in + record_size;897 const end = in + record_size;
867 if (end > frag.len) {898 if (end > frag.len) {
868 if (record_size > max_ciphertext_len) return error.TlsRecordOverflow;899 if (record_size > max_ciphertext_len) return error.TlsRecordOverflow;
900 std.debug.print("end={d} frag.len={d}\n", .{ end, frag.len });
869 return finishRead(tls, frag, in, out);901 return finishRead(tls, frag, in, out);
870 }902 }
871 switch (ct) {903 switch (ct) {
...@@ -877,6 +909,7 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {...@@ -877,6 +909,7 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {
877 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| c: {909 inline .TLS_AES_128_GCM_SHA256, .TLS_AES_256_GCM_SHA384 => |*p| c: {
878 const P = @TypeOf(p.*);910 const P = @TypeOf(p.*);
879 const V = @Vector(P.AEAD.nonce_length, u8);911 const V = @Vector(P.AEAD.nonce_length, u8);
912 const ad = frag[in - 5 ..][0..5];
880 const ciphertext_len = record_size - P.AEAD.tag_length;913 const ciphertext_len = record_size - P.AEAD.tag_length;
881 const ciphertext = frag[in..][0..ciphertext_len];914 const ciphertext = frag[in..][0..ciphertext_len];
882 in += ciphertext_len;915 in += ciphertext_len;
...@@ -886,7 +919,12 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {...@@ -886,7 +919,12 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {
886 const operand: V = pad ++ @bitCast([8]u8, big(tls.read_seq));919 const operand: V = pad ++ @bitCast([8]u8, big(tls.read_seq));
887 tls.read_seq += 1;920 tls.read_seq += 1;
888 const nonce: [P.AEAD.nonce_length]u8 = @as(V, p.server_iv) ^ operand;921 const nonce: [P.AEAD.nonce_length]u8 = @as(V, p.server_iv) ^ operand;
889 const ad = frag[0..ciphertext_record_header_len];922 //std.debug.print("seq: {d} nonce: {} server_key: {} server_iv: {}\n", .{
923 // tls.read_seq - 1,
924 // std.fmt.fmtSliceHexLower(&nonce),
925 // std.fmt.fmtSliceHexLower(&p.server_key),
926 // std.fmt.fmtSliceHexLower(&p.server_iv),
927 //});
890 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_key) catch928 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_key) catch
891 return error.TlsBadRecordMac;929 return error.TlsBadRecordMac;
892 break :c cleartext.len;930 break :c cleartext.len;
...@@ -902,15 +940,26 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {...@@ -902,15 +940,26 @@ pub fn read(tls: *Tls, stream: net.Stream, buffer: []u8) !usize {
902 },940 },
903 };941 };
904942
905 const inner_ct = buffer[out + cleartext_len - 1];943 const inner_ct = @intToEnum(ContentType, buffer[out + cleartext_len - 1]);
906 switch (inner_ct) {944 switch (inner_ct) {
907 @enumToInt(ContentType.handshake) => {945 .alert => {
946 const level = @intToEnum(AlertLevel, buffer[out]);
947 const desc = @intToEnum(AlertDescription, buffer[out + 1]);
948 if (desc == .close_notify) {
949 tls.eof = true;
950 return out;
951 }
952 std.debug.print("alert: {s} {s}\n", .{ @tagName(level), @tagName(desc) });
953 return error.TlsAlert;
954 },
955 .handshake => {
908 std.debug.print("the server wants to keep shaking hands\n", .{});956 std.debug.print("the server wants to keep shaking hands\n", .{});
909 },957 },
910 @enumToInt(ContentType.application_data) => {958 .application_data => {
911 out += cleartext_len - 1;959 out += cleartext_len - 1;
912 },960 },
913 else => {961 else => {
962 std.debug.print("inner content type: {d}\n", .{inner_ct});
914 return error.TlsUnexpectedMessage;963 return error.TlsUnexpectedMessage;
915 },964 },
916 }965 }
lib/std/http/Client.zig+21-2
...@@ -62,6 +62,25 @@ pub const Request = struct {...@@ -62,6 +62,25 @@ pub const Request = struct {
62 .https => return req.tls.read(req.stream, buffer),62 .https => return req.tls.read(req.stream, buffer),
63 }63 }
64 }64 }
65
66 pub fn readAll(req: *Request, buffer: []u8) !usize {
67 return readAtLeast(req, buffer, buffer.len);
68 }
69
70 pub fn readAtLeast(req: *Request, buffer: []u8, len: usize) !usize {
71 var index: usize = 0;
72 while (index < len) {
73 const amt = try req.read(buffer[index..]);
74 if (amt == 0) {
75 switch (req.protocol) {
76 .http => break,
77 .https => if (req.tls.eof) break,
78 }
79 }
80 index += amt;
81 }
82 return index;
83 }
65};84};
6685
67pub fn deinit(client: *Client) void {86pub fn deinit(client: *Client) void {
...@@ -92,7 +111,7 @@ pub fn request(client: *Client, options: Request.Options) !Request {...@@ -92,7 +111,7 @@ pub fn request(client: *Client, options: Request.Options) !Request {
92 @tagName(options.method).len +111 @tagName(options.method).len +
93 1 +112 1 +
94 options.path.len +113 options.path.len +
95 " HTTP/2\r\nHost: ".len +114 " HTTP/1.1\r\nHost: ".len +
96 options.host.len +115 options.host.len +
97 "\r\nUpgrade-Insecure-Requests: 1\r\n".len +116 "\r\nUpgrade-Insecure-Requests: 1\r\n".len +
98 client.headers.items.len +117 client.headers.items.len +
...@@ -101,7 +120,7 @@ pub fn request(client: *Client, options: Request.Options) !Request {...@@ -101,7 +120,7 @@ pub fn request(client: *Client, options: Request.Options) !Request {
101 req.headers.appendSliceAssumeCapacity(@tagName(options.method));120 req.headers.appendSliceAssumeCapacity(@tagName(options.method));
102 req.headers.appendSliceAssumeCapacity(" ");121 req.headers.appendSliceAssumeCapacity(" ");
103 req.headers.appendSliceAssumeCapacity(options.path);122 req.headers.appendSliceAssumeCapacity(options.path);
104 req.headers.appendSliceAssumeCapacity(" HTTP/2\r\nHost: ");123 req.headers.appendSliceAssumeCapacity(" HTTP/1.1\r\nHost: ");
105 req.headers.appendSliceAssumeCapacity(options.host);124 req.headers.appendSliceAssumeCapacity(options.host);
106 switch (options.protocol) {125 switch (options.protocol) {
107 .https => req.headers.appendSliceAssumeCapacity("\r\nUpgrade-Insecure-Requests: 1\r\n"),126 .https => req.headers.appendSliceAssumeCapacity("\r\nUpgrade-Insecure-Requests: 1\r\n"),