@@ -2,7 +2,9 @@ use bytes::buf::Chain;
22use bytes:: Bytes ;
33use digest:: { Digest , OutputSizeUser } ;
44use generic_array:: GenericArray ;
5+ #[ cfg( feature = "rsa" ) ]
56use rand:: thread_rng;
7+ #[ cfg( feature = "rsa" ) ]
68use rsa:: { pkcs8:: DecodePublicKey , Oaep , RsaPublicKey } ;
79use sha1:: Sha1 ;
810use sha2:: Sha256 ;
@@ -131,9 +133,9 @@ fn scramble_sha256(
131133
132134async fn encrypt_rsa < ' s > (
133135 stream : & ' s mut MySqlStream ,
134- public_key_request_id : u8 ,
136+ _public_key_request_id : u8 ,
135137 password : & ' s str ,
136- nonce : & ' s Chain < Bytes , Bytes > ,
138+ _nonce : & ' s Chain < Bytes , Bytes > ,
137139) -> Result < Vec < u8 > , Error > {
138140 // https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/
139141
@@ -142,29 +144,41 @@ async fn encrypt_rsa<'s>(
142144 return Ok ( to_asciz ( password) ) ;
143145 }
144146
145- // client sends a public key request
146- stream. write_packet ( & [ public_key_request_id] [ ..] ) ?;
147- stream. flush ( ) . await ?;
148-
149- // server sends a public key response
150- let packet = stream. recv_packet ( ) . await ?;
151- let rsa_pub_key = & packet[ 1 ..] ;
152-
153- // xor the password with the given nonce
154- let mut pass = to_asciz ( password) ;
155-
156- let ( a, b) = ( nonce. first_ref ( ) , nonce. last_ref ( ) ) ;
157- let mut nonce = Vec :: with_capacity ( a. len ( ) + b. len ( ) ) ;
158- nonce. extend_from_slice ( a) ;
159- nonce. extend_from_slice ( b) ;
160-
161- xor_eq ( & mut pass, & nonce) ;
162-
163- // client sends an RSA encrypted password
164- let pkey = parse_rsa_pub_key ( rsa_pub_key) ?;
165- let padding = Oaep :: new :: < sha1:: Sha1 > ( ) ;
166- pkey. encrypt ( & mut thread_rng ( ) , padding, & pass[ ..] )
167- . map_err ( Error :: protocol)
147+ // Non-TLS RSA password encryption requires the `rsa` feature.
148+ // It is opt-in because RUSTSEC-2023-0071 (Marvin Attack timing side-channel)
149+ // has no patched release; disable it when all connections use TLS.
150+ #[ cfg( not( feature = "rsa" ) ) ]
151+ return Err ( err_protocol ! (
152+ "sha256_password / caching_sha2_password over non-TLS requires the `rsa` feature \
153+ (disabled by default due to RUSTSEC-2023-0071)"
154+ ) ) ;
155+
156+ #[ cfg( feature = "rsa" ) ]
157+ {
158+ // client sends a public key request
159+ stream. write_packet ( & [ _public_key_request_id] [ ..] ) ?;
160+ stream. flush ( ) . await ?;
161+
162+ // server sends a public key response
163+ let packet = stream. recv_packet ( ) . await ?;
164+ let rsa_pub_key = & packet[ 1 ..] ;
165+
166+ // xor the password with the given nonce
167+ let mut pass = to_asciz ( password) ;
168+
169+ let ( a, b) = ( _nonce. first_ref ( ) , _nonce. last_ref ( ) ) ;
170+ let mut nonce = Vec :: with_capacity ( a. len ( ) + b. len ( ) ) ;
171+ nonce. extend_from_slice ( a) ;
172+ nonce. extend_from_slice ( b) ;
173+
174+ xor_eq ( & mut pass, & nonce) ;
175+
176+ // client sends an RSA encrypted password
177+ let pkey = parse_rsa_pub_key ( rsa_pub_key) ?;
178+ let padding = Oaep :: new :: < sha1:: Sha1 > ( ) ;
179+ pkey. encrypt ( & mut thread_rng ( ) , padding, & pass[ ..] )
180+ . map_err ( Error :: protocol)
181+ }
168182}
169183
170184// XOR(x, y)
@@ -186,6 +200,7 @@ fn to_asciz(s: &str) -> Vec<u8> {
186200}
187201
188202// https://docs.rs/rsa/0.3.0/rsa/struct.RSAPublicKey.html?search=#example-1
203+ #[ cfg( feature = "rsa" ) ]
189204fn parse_rsa_pub_key ( key : & [ u8 ] ) -> Result < RsaPublicKey , Error > {
190205 let pem = std:: str:: from_utf8 ( key) . map_err ( Error :: protocol) ?;
191206
0 commit comments