@@ -158,19 +158,35 @@ impl CertPaths {
158
158
}
159
159
160
160
let mut certs = match & self . file {
161
- Some ( cert_file) => load_pem_certs ( cert_file) ?,
161
+ Some ( cert_file) => {
162
+ load_pem_certs ( cert_file) . map_err ( |err| Self :: load_err ( cert_file, err) ) ?
163
+ }
162
164
None => Vec :: new ( ) ,
163
165
} ;
164
166
165
167
if let Some ( cert_dir) = & self . dir {
166
- certs. append ( & mut load_pem_certs_from_dir ( cert_dir) ?) ;
168
+ certs. append (
169
+ & mut load_pem_certs_from_dir ( cert_dir)
170
+ . map_err ( |err| Self :: load_err ( cert_dir, err) ) ?,
171
+ ) ;
167
172
}
168
173
169
174
certs. sort_unstable_by ( |a, b| a. cmp ( b) ) ;
170
175
certs. dedup ( ) ;
171
176
172
177
Ok ( Some ( certs) )
173
178
}
179
+
180
+ fn load_err ( path : & Path , err : Error ) -> Error {
181
+ Error :: new (
182
+ err. kind ( ) ,
183
+ format ! (
184
+ "could not load certs from {} {}: {err}" ,
185
+ if path. is_file( ) { "file" } else { "dir" } ,
186
+ path. display( )
187
+ ) ,
188
+ )
189
+ }
174
190
}
175
191
176
192
/// Load certificate from certificate directory (what OpenSSL calls CAdir)
@@ -211,16 +227,7 @@ fn load_pem_certs_from_dir(dir: &Path) -> Result<Vec<CertificateDer<'static>>, E
211
227
}
212
228
213
229
fn load_pem_certs ( path : & Path ) -> Result < Vec < CertificateDer < ' static > > , Error > {
214
- let mut f = BufReader :: new ( File :: open ( path) ?) ;
215
- rustls_pemfile:: certs ( & mut f)
216
- . map ( |result| match result {
217
- Ok ( der) => Ok ( der) ,
218
- Err ( err) => Err ( Error :: new (
219
- ErrorKind :: InvalidData ,
220
- format ! ( "could not load PEM file {path:?}: {err}" ) ,
221
- ) ) ,
222
- } )
223
- . collect ( )
230
+ rustls_pemfile:: certs ( & mut BufReader :: new ( File :: open ( path) ?) ) . collect ( )
224
231
}
225
232
226
233
/// Check if this is a hash-based file name for a certificate
@@ -259,7 +266,11 @@ const ENV_CERT_DIR: &str = "SSL_CERT_DIR";
259
266
mod tests {
260
267
use super :: * ;
261
268
269
+ #[ cfg( unix) ]
270
+ use std:: fs:: Permissions ;
262
271
use std:: io:: Write ;
272
+ #[ cfg( unix) ]
273
+ use std:: os:: unix:: fs:: PermissionsExt ;
263
274
264
275
#[ test]
265
276
fn valid_hash_file_name ( ) {
@@ -376,4 +387,57 @@ mod tests {
376
387
let certs = load_pem_certs ( Path :: new ( "/dev/null" ) ) . unwrap ( ) ;
377
388
assert_eq ! ( certs. len( ) , 0 ) ;
378
389
}
390
+
391
+ #[ test]
392
+ #[ cfg( unix) ]
393
+ fn from_env_bad_dir_perms ( ) {
394
+ // Create a temp dir that we can't read from.
395
+ let temp_dir = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
396
+ fs:: set_permissions ( temp_dir. path ( ) , Permissions :: from_mode ( 0 ) ) . unwrap ( ) ;
397
+
398
+ test_cert_paths_bad_perms ( CertPaths {
399
+ file : None ,
400
+ dir : Some ( temp_dir. path ( ) . into ( ) ) ,
401
+ } )
402
+ }
403
+
404
+ #[ test]
405
+ #[ cfg( unix) ]
406
+ fn from_env_bad_file_perms ( ) {
407
+ // Create a tmp dir with a file inside that we can't read from.
408
+ let temp_dir = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
409
+ let file_path = temp_dir. path ( ) . join ( "unreadable.pem" ) ;
410
+ let cert_file = File :: create ( & file_path) . unwrap ( ) ;
411
+ cert_file
412
+ . set_permissions ( Permissions :: from_mode ( 0 ) )
413
+ . unwrap ( ) ;
414
+
415
+ test_cert_paths_bad_perms ( CertPaths {
416
+ file : Some ( file_path. clone ( ) ) ,
417
+ dir : None ,
418
+ } ) ;
419
+ }
420
+
421
+ #[ cfg( unix) ]
422
+ fn test_cert_paths_bad_perms ( cert_paths : CertPaths ) {
423
+ let err = cert_paths. load ( ) . unwrap_err ( ) ;
424
+
425
+ let affected_path = match ( cert_paths. file , cert_paths. dir ) {
426
+ ( Some ( file) , None ) => file,
427
+ ( None , Some ( dir) ) => dir,
428
+ _ => panic ! ( "only one of file or dir should be set" ) ,
429
+ } ;
430
+ let r#type = match affected_path. is_file ( ) {
431
+ true => "file" ,
432
+ false => "dir" ,
433
+ } ;
434
+
435
+ assert_eq ! ( err. kind( ) , ErrorKind :: PermissionDenied ) ;
436
+ assert ! ( err
437
+ . to_string( )
438
+ . contains( & format!( "certs from {type}" ) ) ) ;
439
+ assert ! ( err
440
+ . to_string( )
441
+ . contains( & affected_path. display( ) . to_string( ) ) ) ;
442
+ }
379
443
}
0 commit comments