@@ -61,9 +61,6 @@ pub const ReadError = error{
61
61
TlsUnexpectedMessage ,
62
62
TlsIllegalParameter ,
63
63
TlsSequenceOverflow ,
64
- /// The buffer provided to the read function was not at least
65
- /// `min_buffer_len`.
66
- OutputBufferUndersize ,
67
64
};
68
65
69
66
pub const SslKeyLog = struct {
@@ -372,7 +369,8 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
372
369
};
373
370
P .AEAD .decrypt (cleartext , ciphertext , auth_tag , record_header , nonce , pv .server_handshake_key ) catch
374
371
return error .TlsBadRecordMac ;
375
- cleartext_fragment_end += std .mem .trimEnd (u8 , cleartext , "\x00 " ).len ;
372
+ // TODO use scalar, non-slice version
373
+ cleartext_fragment_end += mem .trimEnd (u8 , cleartext , "\x00 " ).len ;
376
374
},
377
375
}
378
376
read_seq += 1 ;
@@ -395,9 +393,9 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
395
393
const cleartext_fragment_buf = cleartext_buf [cleartext_fragment_end .. ];
396
394
if (message_len > cleartext_fragment_buf .len ) return error .TlsRecordOverflow ;
397
395
const cleartext = cleartext_fragment_buf [0.. message_len ];
398
- const ad = std . mem .toBytes (big (read_seq )) ++
396
+ const ad = mem .toBytes (big (read_seq )) ++
399
397
record_header [0 .. 1 + 2 ] ++
400
- std . mem .toBytes (big (message_len ));
398
+ mem .toBytes (big (message_len ));
401
399
const record_iv = record_decoder .array (P .record_iv_length ).* ;
402
400
const masked_read_seq = read_seq &
403
401
comptime std .math .shl (u64 , std .math .maxInt (u64 ), 8 * P .record_iv_length );
@@ -738,7 +736,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
738
736
&.{ "server finished" , & p .transcript_hash .finalResult () },
739
737
P .verify_data_length ,
740
738
),
741
- .app_cipher = std . mem .bytesToValue (P .Tls_1_2 , & key_block ),
739
+ .app_cipher = mem .bytesToValue (P .Tls_1_2 , & key_block ),
742
740
} };
743
741
const pv = & p .version .tls_1_2 ;
744
742
const nonce : [P .AEAD .nonce_length ]u8 = nonce : {
@@ -756,7 +754,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
756
754
client_verify_cleartext .len .. ][0.. client_verify_cleartext .len ],
757
755
client_verify_msg [client_verify_msg .len - P .mac_length .. ][0.. P .mac_length ],
758
756
& client_verify_cleartext ,
759
- std . mem .toBytes (big (write_seq )) ++ client_verify_msg [0 .. 1 + 2 ] ++ int (u16 , client_verify_cleartext .len ),
757
+ mem .toBytes (big (write_seq )) ++ client_verify_msg [0 .. 1 + 2 ] ++ int (u16 , client_verify_cleartext .len ),
760
758
nonce ,
761
759
pv .app_cipher .client_write_key ,
762
760
);
@@ -873,7 +871,10 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
873
871
.input = input ,
874
872
.reader = .{
875
873
.buffer = options .read_buffer ,
876
- .vtable = &.{ .stream = stream },
874
+ .vtable = &.{
875
+ .stream = stream ,
876
+ .readVec = readVec ,
877
+ },
877
878
.seek = 0 ,
878
879
.end = 0 ,
879
880
},
@@ -1017,7 +1018,7 @@ fn prepareCiphertextRecord(
1017
1018
const nonce = nonce : {
1018
1019
const V = @Vector (P .AEAD .nonce_length , u8 );
1019
1020
const pad = [1 ]u8 {0 } ** (P .AEAD .nonce_length - 8 );
1020
- const operand : V = pad ++ std . mem .toBytes (big (c .write_seq ));
1021
+ const operand : V = pad ++ mem .toBytes (big (c .write_seq ));
1021
1022
break :nonce @as (V , pv .client_iv ) ^ operand ;
1022
1023
};
1023
1024
P .AEAD .encrypt (ciphertext , auth_tag , cleartext , ad , nonce , pv .client_key );
@@ -1048,7 +1049,7 @@ fn prepareCiphertextRecord(
1048
1049
record_header .* = .{@intFromEnum (inner_content_type )} ++
1049
1050
int (u16 , @intFromEnum (tls .ProtocolVersion .tls_1_2 )) ++
1050
1051
int (u16 , P .record_iv_length + message_len + P .mac_length );
1051
- const ad = std . mem .toBytes (big (c .write_seq )) ++ record_header [0 .. 1 + 2 ] ++ int (u16 , message_len );
1052
+ const ad = mem .toBytes (big (c .write_seq )) ++ record_header [0 .. 1 + 2 ] ++ int (u16 , message_len );
1052
1053
const record_iv = ciphertext_buf [ciphertext_end .. ][0.. P .record_iv_length ];
1053
1054
ciphertext_end += P .record_iv_length ;
1054
1055
const nonce : [P .AEAD .nonce_length ]u8 = nonce : {
@@ -1076,7 +1077,22 @@ pub fn eof(c: Client) bool {
1076
1077
}
1077
1078
1078
1079
fn stream (r : * Reader , w : * Writer , limit : std.Io.Limit ) Reader.StreamError ! usize {
1080
+ // This function writes exclusively to the buffer.
1081
+ _ = w ;
1082
+ _ = limit ;
1083
+ const c : * Client = @alignCast (@fieldParentPtr ("reader" , r ));
1084
+ return readIndirect (c );
1085
+ }
1086
+
1087
+ fn readVec (r : * Reader , data : [][]u8 ) Reader.Error ! usize {
1088
+ // This function writes exclusively to the buffer.
1089
+ _ = data ;
1079
1090
const c : * Client = @alignCast (@fieldParentPtr ("reader" , r ));
1091
+ return readIndirect (c );
1092
+ }
1093
+
1094
+ fn readIndirect (c : * Client ) Reader.Error ! usize {
1095
+ const r = & c .reader ;
1080
1096
if (c .eof ()) return error .EndOfStream ;
1081
1097
const input = c .input ;
1082
1098
// If at least one full encrypted record is not buffered, read once.
@@ -1108,8 +1124,13 @@ fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize
1108
1124
if (record_end > input .buffered ().len ) return 0 ;
1109
1125
}
1110
1126
1111
- var cleartext_stack_buffer : [max_ciphertext_len ]u8 = undefined ;
1112
- const cleartext , const inner_ct : tls.ContentType = cleartext : switch (c .application_cipher ) {
1127
+ if (r .seek == r .end ) {
1128
+ r .seek = 0 ;
1129
+ r .end = 0 ;
1130
+ }
1131
+ const cleartext_buffer = r .buffer [r .end .. ];
1132
+
1133
+ const cleartext_len , const inner_ct : tls.ContentType = cleartext : switch (c .application_cipher ) {
1113
1134
inline else = > | * p | switch (c .tls_version ) {
1114
1135
.tls_1_3 = > {
1115
1136
const pv = & p .tls_1_3 ;
@@ -1121,23 +1142,24 @@ fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize
1121
1142
const nonce = nonce : {
1122
1143
const V = @Vector (P .AEAD .nonce_length , u8 );
1123
1144
const pad = [1 ]u8 {0 } ** (P .AEAD .nonce_length - 8 );
1124
- const operand : V = pad ++ std . mem .toBytes (big (c .read_seq ));
1145
+ const operand : V = pad ++ mem .toBytes (big (c .read_seq ));
1125
1146
break :nonce @as (V , pv .server_iv ) ^ operand ;
1126
1147
};
1127
- const cleartext = cleartext_stack_buffer [0.. ciphertext .len ];
1148
+ const cleartext = cleartext_buffer [0.. ciphertext .len ];
1128
1149
P .AEAD .decrypt (cleartext , ciphertext , auth_tag , ad , nonce , pv .server_key ) catch
1129
1150
return failRead (c , error .TlsBadRecordMac );
1151
+ // TODO use scalar, non-slice version
1130
1152
const msg = mem .trimRight (u8 , cleartext , "\x00 " );
1131
- break :cleartext .{ msg [ 0 .. msg . len - 1 ] , @enumFromInt (msg [msg .len - 1 ]) };
1153
+ break :cleartext .{ msg . len - 1 , @enumFromInt (msg [msg .len - 1 ]) };
1132
1154
},
1133
1155
.tls_1_2 = > {
1134
1156
const pv = & p .tls_1_2 ;
1135
1157
const P = @TypeOf (p .* );
1136
1158
const message_len : u16 = record_len - P .record_iv_length - P .mac_length ;
1137
1159
const ad_header = input .take (tls .record_header_len ) catch unreachable ; // already peeked
1138
- const ad = std . mem .toBytes (big (c .read_seq )) ++
1160
+ const ad = mem .toBytes (big (c .read_seq )) ++
1139
1161
ad_header [0 .. 1 + 2 ] ++
1140
- std . mem .toBytes (big (message_len ));
1162
+ mem .toBytes (big (message_len ));
1141
1163
const record_iv = (input .takeArray (P .record_iv_length ) catch unreachable ).* ; // already peeked
1142
1164
const masked_read_seq = c .read_seq &
1143
1165
comptime std .math .shl (u64 , std .math .maxInt (u64 ), 8 * P .record_iv_length );
@@ -1149,14 +1171,15 @@ fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize
1149
1171
};
1150
1172
const ciphertext = input .take (message_len ) catch unreachable ; // already peeked
1151
1173
const auth_tag = (input .takeArray (P .mac_length ) catch unreachable ).* ; // already peeked
1152
- const cleartext = cleartext_stack_buffer [0.. ciphertext .len ];
1174
+ const cleartext = cleartext_buffer [0.. ciphertext .len ];
1153
1175
P .AEAD .decrypt (cleartext , ciphertext , auth_tag , ad , nonce , pv .server_write_key ) catch
1154
1176
return failRead (c , error .TlsBadRecordMac );
1155
- break :cleartext .{ cleartext , ct };
1177
+ break :cleartext .{ cleartext . len , ct };
1156
1178
},
1157
1179
else = > unreachable ,
1158
1180
},
1159
1181
};
1182
+ const cleartext = cleartext_buffer [0.. cleartext_len ];
1160
1183
c .read_seq = std .math .add (u64 , c .read_seq , 1 ) catch return failRead (c , error .TlsSequenceOverflow );
1161
1184
switch (inner_ct ) {
1162
1185
.alert = > {
@@ -1245,9 +1268,8 @@ fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize
1245
1268
return 0 ;
1246
1269
},
1247
1270
.application_data = > {
1248
- if (@intFromEnum (limit ) < cleartext .len ) return failRead (c , error .OutputBufferUndersize );
1249
- try w .writeAll (cleartext );
1250
- return cleartext .len ;
1271
+ r .end += cleartext .len ;
1272
+ return 0 ;
1251
1273
},
1252
1274
else = > return failRead (c , error .TlsUnexpectedMessage ),
1253
1275
}
0 commit comments