@@ -1232,8 +1232,8 @@ pub mod stream {
12321232 pending_len : usize ,
12331233 output : OutputQueue < 1024 > ,
12341234 finished : bool ,
1235- finalized : bool ,
12361235 failed : bool ,
1236+ finalized : bool ,
12371237 }
12381238
12391239 impl < W , A , const PAD : bool > Decoder < W , A , PAD >
@@ -1693,6 +1693,13 @@ pub mod stream {
16931693 )
16941694 }
16951695
1696+ fn stream_encoder_failed_error ( ) -> io:: Error {
1697+ io:: Error :: new (
1698+ io:: ErrorKind :: InvalidInput ,
1699+ "base64 stream encoder is failed after internal error" ,
1700+ )
1701+ }
1702+
16961703 /// A streaming Base64 decoder for `std::io::Read`.
16971704 ///
16981705 /// For padded engines, this reader stops at the terminal padded Base64
@@ -2067,6 +2074,7 @@ pub mod stream {
20672074 pending_len : usize ,
20682075 output : OutputQueue < 1024 > ,
20692076 finished : bool ,
2077+ failed : bool ,
20702078 }
20712079
20722080 impl < R , A , const PAD : bool > EncoderReader < R , A , PAD >
@@ -2083,6 +2091,7 @@ pub mod stream {
20832091 pending_len : 0 ,
20842092 output : OutputQueue :: new ( ) ,
20852093 finished : false ,
2094+ failed : false ,
20862095 }
20872096 }
20882097
@@ -2181,11 +2190,18 @@ pub mod stream {
21812190 self . finished && self . output . is_empty ( )
21822191 }
21832192
2193+ /// Returns whether this adapter has failed closed after an internal
2194+ /// stream error.
2195+ #[ must_use]
2196+ pub const fn is_failed ( & self ) -> bool {
2197+ self . failed
2198+ }
2199+
21842200 /// Returns whether [`Self::try_into_inner`] can recover the wrapped
21852201 /// reader without discarding pending input or buffered encoded output.
21862202 #[ must_use]
21872203 pub const fn can_into_inner ( & self ) -> bool {
2188- self . is_finished ( )
2204+ self . is_finished ( ) && ! self . failed
21892205 }
21902206
21912207 /// Consumes the encoder reader and returns the wrapped reader.
@@ -2265,6 +2281,7 @@ pub mod stream {
22652281 )
22662282 . field ( "can_into_inner" , & self . can_into_inner ( ) )
22672283 . field ( "finished" , & self . finished )
2284+ . field ( "failed" , & self . failed )
22682285 . finish ( )
22692286 }
22702287 }
@@ -2275,6 +2292,10 @@ pub mod stream {
22752292 A : Alphabet ,
22762293 {
22772294 fn read ( & mut self , output : & mut [ u8 ] ) -> io:: Result < usize > {
2295+ if self . failed {
2296+ return Err ( stream_encoder_failed_error ( ) ) ;
2297+ }
2298+
22782299 if output. is_empty ( ) {
22792300 return Ok ( 0 ) ;
22802301 }
@@ -2304,7 +2325,10 @@ pub mod stream {
23042325 if read == 0 {
23052326 crate :: wipe_bytes ( & mut input) ;
23062327 self . finished = true ;
2307- self . push_final_pending ( ) ?;
2328+ if let Err ( err) = self . push_final_pending ( ) {
2329+ self . failed = true ;
2330+ return Err ( err) ;
2331+ }
23082332 return Ok ( ( ) ) ;
23092333 }
23102334
@@ -2326,6 +2350,7 @@ pub mod stream {
23262350 crate :: wipe_bytes ( & mut chunk) ;
23272351 if let Err ( err) = result {
23282352 crate :: wipe_bytes ( & mut input) ;
2353+ self . failed = true ;
23292354 return Err ( err) ;
23302355 }
23312356 self . clear_pending ( ) ;
@@ -2345,6 +2370,7 @@ pub mod stream {
23452370 crate :: wipe_bytes ( & mut input) ;
23462371 if let Err ( err) = result {
23472372 crate :: wipe_bytes ( & mut tail) ;
2373+ self . failed = true ;
23482374 return Err ( err) ;
23492375 }
23502376 self . pending [ ..tail_len] . copy_from_slice ( & tail[ ..tail_len] ) ;
@@ -7720,7 +7746,8 @@ fn ct_validate_padded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77207746 let mut read = 0 ;
77217747
77227748 while read + 4 < input. len ( ) {
7723- let [ b0, b1, b2, b3] = read_quad ( input, read) ?;
7749+ let [ b0, b1, b2, b3] =
7750+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
77247751 let ( _, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
77257752 let ( _, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
77267753 let ( _, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -7735,7 +7762,8 @@ fn ct_validate_padded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77357762 read += 4 ;
77367763 }
77377764
7738- let final_chunk = read_quad ( input, read) ?;
7765+ let final_chunk =
7766+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
77397767 let ( _, final_invalid_byte, final_invalid_padding, _) =
77407768 ct_padded_final_quantum :: < A > ( final_chunk, padding) ;
77417769 invalid_byte |= final_invalid_byte;
@@ -7754,7 +7782,8 @@ fn ct_validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77547782 let mut read = 0 ;
77557783
77567784 while read + 4 <= input. len ( ) {
7757- let [ b0, b1, b2, b3] = read_quad ( input, read) ?;
7785+ let [ b0, b1, b2, b3] =
7786+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
77587787 let ( _, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
77597788 let ( _, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
77607789 let ( _, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -7772,9 +7801,9 @@ fn ct_validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77727801 read += 4 ;
77737802 }
77747803
7775- match input . get ( read.. ) {
7776- Some ( [ ] ) => { }
7777- Some ( [ b0, b1] ) => {
7804+ match read_tail_or_mark_invalid ( input , read, & mut invalid_byte , & mut invalid_padding ) {
7805+ [ ] => { }
7806+ [ b0, b1] => {
77787807 let ( _, valid0) = ct_decode_alphabet_byte :: < A > ( * b0) ;
77797808 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( * b1) ;
77807809 invalid_byte |= !valid0;
@@ -7783,7 +7812,7 @@ fn ct_validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77837812 invalid_padding |= ct_mask_eq_u8 ( * b1, b'=' ) ;
77847813 invalid_padding |= ct_mask_nonzero_u8 ( v1 & 0b0000_1111 ) ;
77857814 }
7786- Some ( [ b0, b1, b2] ) => {
7815+ [ b0, b1, b2] => {
77877816 let ( _, valid0) = ct_decode_alphabet_byte :: < A > ( * b0) ;
77887817 let ( _, valid1) = ct_decode_alphabet_byte :: < A > ( * b1) ;
77897818 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( * b2) ;
@@ -7795,7 +7824,10 @@ fn ct_validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
77957824 invalid_padding |= ct_mask_eq_u8 ( * b2, b'=' ) ;
77967825 invalid_padding |= ct_mask_nonzero_u8 ( v2 & 0b0000_0011 ) ;
77977826 }
7798- _ => return Err ( DecodeError :: InvalidLength ) ,
7827+ _ => {
7828+ invalid_byte = 0xff ;
7829+ invalid_padding = 0xff ;
7830+ }
77997831 }
78007832
78017833 report_ct_error ( invalid_byte, invalid_padding)
@@ -7815,7 +7847,7 @@ fn ct_padded_final_quantum<A: Alphabet>(
78157847 0 => 0 ,
78167848 1 => 1 ,
78177849 2 => 2 ,
7818- _ => 3 ,
7850+ _ => return ( [ 0 ; 3 ] , 0xff , 0xff , 0 ) ,
78197851 } ;
78207852 let no_padding = ct_mask_eq_u8 ( padding_byte, 0 ) ;
78217853 let one_padding = ct_mask_eq_u8 ( padding_byte, 1 ) ;
@@ -7856,7 +7888,8 @@ fn ct_decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usiz
78567888 let mut read = 0 ;
78577889
78587890 while read + 4 < input. len ( ) {
7859- let [ b0, b1, b2, b3] = read_quad ( input, read) ?;
7891+ let [ b0, b1, b2, b3] =
7892+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
78607893 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
78617894 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
78627895 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -7875,7 +7908,8 @@ fn ct_decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usiz
78757908 read += 4 ;
78767909 }
78777910
7878- let final_chunk = read_quad ( input, read) ?;
7911+ let final_chunk =
7912+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
78797913 let ( final_bytes, final_invalid_byte, final_invalid_padding, final_written) =
78807914 ct_padded_final_quantum :: < A > ( final_chunk, padding) ;
78817915 invalid_byte |= final_invalid_byte;
@@ -7905,13 +7939,8 @@ fn ct_decode_padded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize, De
79057939 let mut read = 0 ;
79067940
79077941 while read + 4 < buffer. len ( ) {
7908- let [ b0, b1, b2, b3] = match read_quad ( buffer, read) {
7909- Ok ( quad) => quad,
7910- Err ( err) => {
7911- wipe_bytes ( buffer) ;
7912- return Err ( err) ;
7913- }
7914- } ;
7942+ let [ b0, b1, b2, b3] =
7943+ read_quad_or_mark_invalid ( buffer, read, & mut invalid_byte, & mut invalid_padding) ;
79157944 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
79167945 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
79177946 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -7930,13 +7959,8 @@ fn ct_decode_padded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize, De
79307959 read += 4 ;
79317960 }
79327961
7933- let final_chunk = match read_quad ( buffer, read) {
7934- Ok ( quad) => quad,
7935- Err ( err) => {
7936- wipe_bytes ( buffer) ;
7937- return Err ( err) ;
7938- }
7939- } ;
7962+ let final_chunk =
7963+ read_quad_or_mark_invalid ( buffer, read, & mut invalid_byte, & mut invalid_padding) ;
79407964 let ( final_bytes, final_invalid_byte, final_invalid_padding, final_written) =
79417965 ct_padded_final_quantum :: < A > ( final_chunk, padding) ;
79427966 invalid_byte |= final_invalid_byte;
@@ -7972,7 +7996,8 @@ fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<us
79727996 let mut read = 0 ;
79737997
79747998 while read + 4 <= input. len ( ) {
7975- let [ b0, b1, b2, b3] = read_quad ( input, read) ?;
7999+ let [ b0, b1, b2, b3] =
8000+ read_quad_or_mark_invalid ( input, read, & mut invalid_byte, & mut invalid_padding) ;
79768001 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
79778002 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
79788003 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -7994,9 +8019,9 @@ fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<us
79948019 write += 3 ;
79958020 }
79968021
7997- match input . get ( read.. ) {
7998- Some ( [ ] ) => { }
7999- Some ( [ b0, b1] ) => {
8022+ match read_tail_or_mark_invalid ( input , read, & mut invalid_byte , & mut invalid_padding ) {
8023+ [ ] => { }
8024+ [ b0, b1] => {
80008025 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( * b0) ;
80018026 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( * b1) ;
80028027 invalid_byte |= !valid0;
@@ -8007,7 +8032,7 @@ fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<us
80078032 output[ write] = ( v0 << 2 ) | ( v1 >> 4 ) ;
80088033 write += 1 ;
80098034 }
8010- Some ( [ b0, b1, b2] ) => {
8035+ [ b0, b1, b2] => {
80118036 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( * b0) ;
80128037 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( * b1) ;
80138038 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( * b2) ;
@@ -8022,7 +8047,10 @@ fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<us
80228047 output[ write + 1 ] = ( v1 << 4 ) | ( v2 >> 2 ) ;
80238048 write += 2 ;
80248049 }
8025- _ => return Err ( DecodeError :: InvalidLength ) ,
8050+ _ => {
8051+ invalid_byte = 0xff ;
8052+ invalid_padding = 0xff ;
8053+ }
80268054 }
80278055
80288056 report_ct_error ( invalid_byte, invalid_padding) ?;
@@ -8046,13 +8074,8 @@ fn ct_decode_unpadded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize,
80468074 let mut read = 0 ;
80478075
80488076 while read + 4 <= buffer. len ( ) {
8049- let [ b0, b1, b2, b3] = match read_quad ( buffer, read) {
8050- Ok ( quad) => quad,
8051- Err ( err) => {
8052- wipe_bytes ( buffer) ;
8053- return Err ( err) ;
8054- }
8055- } ;
8077+ let [ b0, b1, b2, b3] =
8078+ read_quad_or_mark_invalid ( buffer, read, & mut invalid_byte, & mut invalid_padding) ;
80568079 let ( v0, valid0) = ct_decode_alphabet_byte :: < A > ( b0) ;
80578080 let ( v1, valid1) = ct_decode_alphabet_byte :: < A > ( b1) ;
80588081 let ( v2, valid2) = ct_decode_alphabet_byte :: < A > ( b2) ;
@@ -8074,13 +8097,7 @@ fn ct_decode_unpadded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize,
80748097 write += 3 ;
80758098 }
80768099
8077- let tail = match read_tail ( buffer, read) {
8078- Ok ( tail) => tail,
8079- Err ( err) => {
8080- wipe_bytes ( buffer) ;
8081- return Err ( err) ;
8082- }
8083- } ;
8100+ let tail = read_tail_or_mark_invalid ( buffer, read, & mut invalid_byte, & mut invalid_padding) ;
80848101 match tail {
80858102 [ ] => { }
80868103 [ b0, b1] => {
@@ -8109,7 +8126,10 @@ fn ct_decode_unpadded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize,
81098126 buffer[ write + 1 ] = ( v1 << 4 ) | ( v2 >> 2 ) ;
81108127 write += 2 ;
81118128 }
8112- _ => return Err ( DecodeError :: InvalidLength ) ,
8129+ _ => {
8130+ invalid_byte = 0xff ;
8131+ invalid_padding = 0xff ;
8132+ }
81138133 }
81148134
81158135 if write != required {
@@ -8125,6 +8145,44 @@ fn read_tail(input: &[u8], offset: usize) -> Result<&[u8], DecodeError> {
81258145 input. get ( offset..) . ok_or ( DecodeError :: InvalidLength )
81268146}
81278147
8148+ fn read_quad_or_mark_invalid (
8149+ input : & [ u8 ] ,
8150+ offset : usize ,
8151+ invalid_byte : & mut u8 ,
8152+ invalid_padding : & mut u8 ,
8153+ ) -> [ u8 ; 4 ] {
8154+ if let Ok ( quad) = read_quad ( input, offset) {
8155+ quad
8156+ } else {
8157+ debug_assert ! (
8158+ false ,
8159+ "read_quad failed inside length-validated constant-time decode loop"
8160+ ) ;
8161+ * invalid_byte = 0xff ;
8162+ * invalid_padding = 0xff ;
8163+ [ 0 ; 4 ]
8164+ }
8165+ }
8166+
8167+ fn read_tail_or_mark_invalid < ' a > (
8168+ input : & ' a [ u8 ] ,
8169+ offset : usize ,
8170+ invalid_byte : & mut u8 ,
8171+ invalid_padding : & mut u8 ,
8172+ ) -> & ' a [ u8 ] {
8173+ if let Ok ( tail) = read_tail ( input, offset) {
8174+ tail
8175+ } else {
8176+ debug_assert ! (
8177+ false ,
8178+ "read_tail failed inside length-validated constant-time decode loop"
8179+ ) ;
8180+ * invalid_byte = 0xff ;
8181+ * invalid_padding = 0xff ;
8182+ & [ ]
8183+ }
8184+ }
8185+
81288186#[ inline( never) ]
81298187fn ct_decode_alphabet_byte < A : Alphabet > ( byte : u8 ) -> ( u8 , u8 ) {
81308188 let mut decoded = 0u8 ;
@@ -8549,6 +8607,20 @@ mod tests {
85498607 }
85508608 }
85518609
8610+ #[ test]
8611+ fn ct_padded_final_quantum_fails_closed_for_invalid_padding_count ( ) {
8612+ let ( _, invalid_byte, invalid_padding, written) =
8613+ ct_padded_final_quantum :: < Standard > ( * b"ABCD" , 3 ) ;
8614+
8615+ assert_ne ! ( invalid_byte, 0 ) ;
8616+ assert_ne ! ( invalid_padding, 0 ) ;
8617+ assert_eq ! ( written, 0 ) ;
8618+ assert_eq ! (
8619+ report_ct_error( invalid_byte, invalid_padding) ,
8620+ Err ( DecodeError :: InvalidInput )
8621+ ) ;
8622+ }
8623+
85528624 #[ cfg( feature = "simd" ) ]
85538625 #[ test]
85548626 fn simd_dispatch_scaffold_keeps_scalar_active ( ) {
0 commit comments