| ... | @@ -536,7 +536,24 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8) | ... | @@ -536,7 +536,24 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8) |
| 536 | try sig.verify(verify_bytes, key); | 536 | try sig.verify(verify_bytes, key); |
| 537 | }, | 537 | }, |
| 538 | .rsa_pss_rsae_sha256 => { | 538 | .rsa_pss_rsae_sha256 => { |
| 539 | @panic("TODO signature scheme: rsa_pss_rsae_sha256"); | 539 | if (main_cert_pub_key_algo != .rsaEncryption) |
| | 540 | return error.TlsBadSignatureScheme; |
| | 541 | |
| | 542 | const Hash = crypto.hash.sha2.Sha256; |
| | 543 | const rsa = Certificate.rsa; |
| | 544 | const components = try rsa.PublicKey.parseDer(main_cert_pub_key); |
| | 545 | const exponent = components.exponent; |
| | 546 | const modulus = components.modulus; |
| | 547 | switch (modulus.len) { |
| | 548 | inline 128, 256, 512 => |modulus_len| { |
| | 549 | const key = try rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop); |
| | 550 | const sig = rsa.PSSSignature.fromBytes(modulus_len, encoded_sig); |
| | 551 | try rsa.PSSSignature.verify(modulus_len, sig, verify_bytes, key, Hash, rsa.poop); |
| | 552 | }, |
| | 553 | else => { |
| | 554 | return error.TlsBadRsaSignatureBitCount; |
| | 555 | }, |
| | 556 | } |
| 540 | }, | 557 | }, |
| 541 | else => { | 558 | else => { |
| 542 | //std.debug.print("signature scheme: {any}\n", .{ | 559 | //std.debug.print("signature scheme: {any}\n", .{ |
| ... | @@ -737,7 +754,7 @@ pub fn writeAll(c: *Client, stream: net.Stream, bytes: []const u8) !void { | ... | @@ -737,7 +754,7 @@ pub fn writeAll(c: *Client, stream: net.Stream, bytes: []const u8) !void { |
| 737 | } | 754 | } |
| 738 | | 755 | |
| 739 | pub fn eof(c: Client) bool { | 756 | pub fn eof(c: Client) bool { |
| 740 | return c.received_close_notify and c.partial_ciphertext_end == 0; | 757 | return c.received_close_notify and c.partial_ciphertext_idx >= c.partial_ciphertext_end; |
| 741 | } | 758 | } |
| 742 | | 759 | |
| 743 | /// Returns the number of bytes read, calling the underlying read function the | 760 | /// Returns the number of bytes read, calling the underlying read function the |
| ... | @@ -822,6 +839,10 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -822,6 +839,10 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 822 | c.partial_cleartext_idx = 0; | 839 | c.partial_cleartext_idx = 0; |
| 823 | c.partial_ciphertext_idx = 0; | 840 | c.partial_ciphertext_idx = 0; |
| 824 | c.partial_ciphertext_end = 0; | 841 | c.partial_ciphertext_end = 0; |
| | 842 | } else { |
| | 843 | std.debug.print("finished giving partial cleartext. {d} bytes ciphertext remain\n", .{ |
| | 844 | c.partial_ciphertext_end - c.partial_ciphertext_idx, |
| | 845 | }); |
| 825 | } | 846 | } |
| 826 | } | 847 | } |
| 827 | | 848 | |
| ... | @@ -866,8 +887,9 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -866,8 +887,9 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 866 | | 887 | |
| 867 | // There might be more bytes inside `in_stack_buffer` that need to be processed, | 888 | // There might be more bytes inside `in_stack_buffer` that need to be processed, |
| 868 | // but at least frag0 will have one complete ciphertext record. | 889 | // but at least frag0 will have one complete ciphertext record. |
| 869 | const frag0 = c.partially_read_buffer[0..@min(c.partially_read_buffer.len, actual_read_len)]; | 890 | const frag0_end = @min(c.partially_read_buffer.len, c.partial_ciphertext_end + actual_read_len); |
| 870 | var frag1 = in_stack_buffer[0 .. actual_read_len - frag0.len]; | 891 | const frag0 = c.partially_read_buffer[c.partial_ciphertext_idx..frag0_end]; |
| | 892 | var frag1 = in_stack_buffer[0..actual_read_len -| first_iov.len]; |
| 871 | // We need to decipher frag0 and frag1 but there may be a ciphertext record | 893 | // We need to decipher frag0 and frag1 but there may be a ciphertext record |
| 872 | // straddling the boundary. We can handle this with two memcpy() calls to | 894 | // straddling the boundary. We can handle this with two memcpy() calls to |
| 873 | // assemble the straddling record in between handling the two sides. | 895 | // assemble the straddling record in between handling the two sides. |
| ... | @@ -900,12 +922,14 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -900,12 +922,14 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 900 | const record_len = (record_len_byte_0 << 8) | record_len_byte_1; | 922 | const record_len = (record_len_byte_0 << 8) | record_len_byte_1; |
| 901 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; | 923 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; |
| 902 | | 924 | |
| 903 | const second_len = record_len + tls.ciphertext_record_header_len - first.len; | 925 | const full_record_len = record_len + tls.ciphertext_record_header_len; |
| | 926 | const second_len = full_record_len - first.len; |
| 904 | if (frag1.len < second_len) | 927 | if (frag1.len < second_len) |
| 905 | return finishRead2(c, first, frag1, vp.total); | 928 | return finishRead2(c, first, frag1, vp.total); |
| 906 | | 929 | |
| 907 | mem.copy(u8, frag[0..in], first); | 930 | mem.copy(u8, frag[0..in], first); |
| 908 | mem.copy(u8, frag[first.len..], frag1[0..second_len]); | 931 | mem.copy(u8, frag[first.len..], frag1[0..second_len]); |
| | 932 | frag = frag[0..full_record_len]; |
| 909 | frag1 = frag1[second_len..]; | 933 | frag1 = frag1[second_len..]; |
| 910 | in = 0; | 934 | in = 0; |
| 911 | continue; | 935 | continue; |
| ... | @@ -914,23 +938,35 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -914,23 +938,35 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 914 | in += 1; | 938 | in += 1; |
| 915 | const legacy_version = mem.readIntBig(u16, frag[in..][0..2]); | 939 | const legacy_version = mem.readIntBig(u16, frag[in..][0..2]); |
| 916 | in += 2; | 940 | in += 2; |
| 917 | _ = legacy_version; | 941 | //_ = legacy_version; |
| 918 | const record_len = mem.readIntBig(u16, frag[in..][0..2]); | 942 | const record_len = mem.readIntBig(u16, frag[in..][0..2]); |
| | 943 | std.debug.print("ct={any} legacy_version={x} record_len={d}\n", .{ |
| | 944 | ct, legacy_version, record_len, |
| | 945 | }); |
| 919 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; | 946 | if (record_len > max_ciphertext_len) return error.TlsRecordOverflow; |
| 920 | in += 2; | 947 | in += 2; |
| 921 | const end = in + record_len; | 948 | const end = in + record_len; |
| 922 | if (end > frag.len) { | 949 | if (end > frag.len) { |
| | 950 | // We need the record header on the next iteration of the loop. |
| | 951 | in -= tls.ciphertext_record_header_len; |
| | 952 | |
| 923 | if (frag.ptr == frag1.ptr) | 953 | if (frag.ptr == frag1.ptr) |
| 924 | return finishRead(c, frag, in, vp.total); | 954 | return finishRead(c, frag, in, vp.total); |
| 925 | | 955 | |
| 926 | // A record straddles the two fragments. Copy into the now-empty first fragment. | 956 | // A record straddles the two fragments. Copy into the now-empty first fragment. |
| 927 | const first = frag[in..]; | 957 | const first = frag[in..]; |
| 928 | const second_len = record_len + tls.ciphertext_record_header_len - first.len; | 958 | const full_record_len = record_len + tls.ciphertext_record_header_len; |
| 929 | if (frag1.len < second_len) | 959 | const second_len = full_record_len - first.len; |
| | 960 | if (frag1.len < second_len) { |
| | 961 | std.debug.print("end > frag.len finishRead2 end={d} frag.len={d}\n", .{ |
| | 962 | end, frag.len, |
| | 963 | }); |
| 930 | return finishRead2(c, first, frag1, vp.total); | 964 | return finishRead2(c, first, frag1, vp.total); |
| | 965 | } |
| 931 | | 966 | |
| 932 | mem.copy(u8, frag[0..in], first); | 967 | mem.copy(u8, frag[0..in], first); |
| 933 | mem.copy(u8, frag[first.len..], frag1[0..second_len]); | 968 | mem.copy(u8, frag[first.len..], frag1[0..second_len]); |
| | 969 | frag = frag[0..full_record_len]; |
| 934 | frag1 = frag1[second_len..]; | 970 | frag1 = frag1[second_len..]; |
| 935 | in = 0; | 971 | in = 0; |
| 936 | continue; | 972 | continue; |
| ... | @@ -991,9 +1027,11 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -991,9 +1027,11 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 991 | const handshake = cleartext[ct_i..next_handshake_i]; | 1027 | const handshake = cleartext[ct_i..next_handshake_i]; |
| 992 | switch (handshake_type) { | 1028 | switch (handshake_type) { |
| 993 | .new_session_ticket => { | 1029 | .new_session_ticket => { |
| | 1030 | std.debug.print("new_session_ticket\n", .{}); |
| 994 | // This client implementation ignores new session tickets. | 1031 | // This client implementation ignores new session tickets. |
| 995 | }, | 1032 | }, |
| 996 | .key_update => { | 1033 | .key_update => { |
| | 1034 | std.debug.print("key_update\n", .{}); |
| 997 | switch (c.application_cipher) { | 1035 | switch (c.application_cipher) { |
| 998 | inline else => |*p| { | 1036 | inline else => |*p| { |
| 999 | const P = @TypeOf(p.*); | 1037 | const P = @TypeOf(p.*); |
| ... | @@ -1042,10 +1080,13 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -1042,10 +1080,13 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 1042 | const dest = c.partially_read_buffer[c.partial_ciphertext_idx..]; | 1080 | const dest = c.partially_read_buffer[c.partial_ciphertext_idx..]; |
| 1043 | mem.copy(u8, dest, msg); | 1081 | mem.copy(u8, dest, msg); |
| 1044 | c.partial_ciphertext_idx = @intCast(@TypeOf(c.partial_ciphertext_idx), c.partial_ciphertext_idx + msg.len); | 1082 | c.partial_ciphertext_idx = @intCast(@TypeOf(c.partial_ciphertext_idx), c.partial_ciphertext_idx + msg.len); |
| | 1083 | std.debug.print("application_data {d} bytes to partial buffer\n", .{msg.len}); |
| 1045 | } else { | 1084 | } else { |
| 1046 | const amt = vp.put(msg); | 1085 | const amt = vp.put(msg); |
| | 1086 | std.debug.print("application_data {d} bytes to read buffer\n", .{msg.len}); |
| 1047 | if (amt < msg.len) { | 1087 | if (amt < msg.len) { |
| 1048 | const rest = msg[amt..]; | 1088 | const rest = msg[amt..]; |
| | 1089 | std.debug.print(" {d} bytes to partial buffer\n", .{rest.len}); |
| 1049 | c.partial_cleartext_idx = 0; | 1090 | c.partial_cleartext_idx = 0; |
| 1050 | c.partial_ciphertext_idx = @intCast(@TypeOf(c.partial_ciphertext_idx), rest.len); | 1091 | c.partial_ciphertext_idx = @intCast(@TypeOf(c.partial_ciphertext_idx), rest.len); |
| 1051 | mem.copy(u8, &c.partially_read_buffer, rest); | 1092 | mem.copy(u8, &c.partially_read_buffer, rest); |
| ... | @@ -1055,6 +1096,7 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove | ... | @@ -1055,6 +1096,7 @@ pub fn readvAdvanced(c: *Client, stream: net.Stream, iovecs: []const std.os.iove |
| 1055 | // Output buffer was used directly which means no | 1096 | // Output buffer was used directly which means no |
| 1056 | // memory copying needs to occur, and we can move | 1097 | // memory copying needs to occur, and we can move |
| 1057 | // on to the next ciphertext record. | 1098 | // on to the next ciphertext record. |
| | 1099 | std.debug.print("application_data {d} bytes directly to read buffer\n", .{cleartext.len - 1}); |
| 1058 | vp.next(cleartext.len - 1); | 1100 | vp.next(cleartext.len - 1); |
| 1059 | } | 1101 | } |
| 1060 | }, | 1102 | }, |
| ... | @@ -1166,10 +1208,6 @@ const VecPut = struct { | ... | @@ -1166,10 +1208,6 @@ const VecPut = struct { |
| 1166 | const src = bytes[bytes_i..][0..@min(dest.len, bytes.len - bytes_i)]; | 1208 | const src = bytes[bytes_i..][0..@min(dest.len, bytes.len - bytes_i)]; |
| 1167 | mem.copy(u8, dest, src); | 1209 | mem.copy(u8, dest, src); |
| 1168 | bytes_i += src.len; | 1210 | bytes_i += src.len; |
| 1169 | if (bytes_i >= bytes.len) { | | |
| 1170 | vp.total += bytes_i; | | |
| 1171 | return bytes_i; | | |
| 1172 | } | | |
| 1173 | vp.off += src.len; | 1211 | vp.off += src.len; |
| 1174 | if (vp.off >= v.iov_len) { | 1212 | if (vp.off >= v.iov_len) { |
| 1175 | vp.off = 0; | 1213 | vp.off = 0; |
| ... | @@ -1179,6 +1217,10 @@ const VecPut = struct { | ... | @@ -1179,6 +1217,10 @@ const VecPut = struct { |
| 1179 | return bytes_i; | 1217 | return bytes_i; |
| 1180 | } | 1218 | } |
| 1181 | } | 1219 | } |
| | 1220 | if (bytes_i >= bytes.len) { |
| | 1221 | vp.total += bytes_i; |
| | 1222 | return bytes_i; |
| | 1223 | } |
| 1182 | } | 1224 | } |
| 1183 | } | 1225 | } |
| 1184 | | 1226 | |
| ... | @@ -1201,17 +1243,11 @@ const VecPut = struct { | ... | @@ -1201,17 +1243,11 @@ const VecPut = struct { |
| 1201 | } | 1243 | } |
| 1202 | | 1244 | |
| 1203 | fn freeSize(vp: VecPut) usize { | 1245 | fn freeSize(vp: VecPut) usize { |
| | 1246 | if (vp.idx >= vp.iovecs.len) return 0; |
| 1204 | var total: usize = 0; | 1247 | var total: usize = 0; |
| 1205 | | | |
| 1206 | total += vp.iovecs[vp.idx].iov_len - vp.off; | 1248 | total += vp.iovecs[vp.idx].iov_len - vp.off; |
| 1207 | | 1249 | if (vp.idx + 1 >= vp.iovecs.len) return total; |
| 1208 | if (vp.idx + 1 >= vp.iovecs.len) | 1250 | for (vp.iovecs[vp.idx + 1 ..]) |v| total += v.iov_len; |
| 1209 | return total; | | |
| 1210 | | | |
| 1211 | for (vp.iovecs[vp.idx + 1 ..]) |v| { | | |
| 1212 | total += v.iov_len; | | |
| 1213 | } | | |
| 1214 | | | |
| 1215 | return total; | 1251 | return total; |
| 1216 | } | 1252 | } |
| 1217 | }; | 1253 | }; |