| ... | @@ -9,12 +9,14 @@ application_cipher: ApplicationCipher, | ... | @@ -9,12 +9,14 @@ application_cipher: ApplicationCipher, |
| 9 | read_seq: u64, | 9 | read_seq: u64, |
| 10 | write_seq: u64, | 10 | write_seq: u64, |
| 11 | /// The size is enough to contain exactly one TLSCiphertext record. | 11 | /// The size is enough to contain exactly one TLSCiphertext record. |
| 12 | partially_read_buffer: [max_ciphertext_len + ciphertext_record_header_len]u8, | 12 | partially_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`. |
| 14 | partially_read_len: u15, | 14 | partially_read_len: u15, |
| | 15 | eof: bool, |
| 15 | | 16 | |
| 16 | pub const ciphertext_record_header_len = 5; | 17 | pub const ciphertext_record_header_len = 5; |
| 17 | pub const max_ciphertext_len = (1 << 14) + 256; | 18 | pub const max_ciphertext_len = (1 << 14) + 256; |
| | 19 | pub const max_ciphertext_record_len = max_ciphertext_len + ciphertext_record_header_len; |
| 18 | | 20 | |
| 19 | pub const ProtocolVersion = enum(u16) { | 21 | pub 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 { |
| 416 | | 418 | |
| 417 | var cipher_params: CipherParams = undefined; | 419 | var cipher_params: CipherParams = undefined; |
| 418 | | 420 | |
| 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 | }; |
| 638 | | 645 | |
| 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); |
| 690 | | 698 | |
| 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 | } | | |
| 704 | | 703 | |
| 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 | } |
| 754 | | 760 | |
| 755 | pub fn write(tls: *Tls, stream: net.Stream, bytes: []const u8) !usize { | 761 | pub 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; |
| 771 | | 783 | |
| 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]; |
| 774 | | 789 | |
| 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); |
| 791 | | 806 | //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 | }; |
| 811 | | 835 | |
| 812 | // Ideally we would call writev exactly once here, however, we must ensure | 836 | // 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 that | 847 | // Rely on the property that iovecs delineate records, meaning that |
| 823 | // if amt equals zero here, we have fortunately found ourselves | 848 | // 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; |
| 854 | | 884 | |
| 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) catch | 928 | 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 | }; |
| 904 | | 942 | |
| 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 | } |