| 1227 | |
| 1228 | #[pymethod] |
| 1229 | fn load_verify_locations( |
| 1230 | &self, |
| 1231 | args: LoadVerifyLocationsArgs, |
| 1232 | vm: &VirtualMachine, |
| 1233 | ) -> PyResult<()> { |
| 1234 | // Check that at least one argument is provided |
| 1235 | let has_cafile = matches!(&args.cafile, OptionalArg::Present(Some(_))); |
| 1236 | let has_capath = matches!(&args.capath, OptionalArg::Present(Some(_))); |
| 1237 | let has_cadata = matches!(&args.cadata, OptionalArg::Present(Some(_))); |
| 1238 | |
| 1239 | if !has_cafile && !has_capath && !has_cadata { |
| 1240 | return Err(vm.new_type_error("cafile, capath and cadata cannot be all omitted")); |
| 1241 | } |
| 1242 | |
| 1243 | // Parse arguments BEFORE acquiring locks to reduce lock scope |
| 1244 | let cafile_path = if let OptionalArg::Present(Some(ref cafile_obj)) = args.cafile { |
| 1245 | Some(Self::parse_path_arg(cafile_obj, vm)?) |
| 1246 | } else { |
| 1247 | None |
| 1248 | }; |
| 1249 | |
| 1250 | let capath_dir = if let OptionalArg::Present(Some(ref capath_obj)) = args.capath { |
| 1251 | Some(Self::parse_path_arg(capath_obj, vm)?) |
| 1252 | } else { |
| 1253 | None |
| 1254 | }; |
| 1255 | |
| 1256 | let cadata_parsed = if let OptionalArg::Present(Some(ref cadata_obj)) = args.cadata { |
| 1257 | let is_string = matches!(cadata_obj, Either::A(_)); |
| 1258 | let data_vec = self.parse_cadata_arg(cadata_obj, vm)?; |
| 1259 | Some((data_vec, is_string)) |
| 1260 | } else { |
| 1261 | None |
| 1262 | }; |
| 1263 | |
| 1264 | // Check for CRL before acquiring main locks |
| 1265 | let (crl_opt, cafile_is_crl) = if let Some(ref path) = cafile_path { |
| 1266 | let crl = self.load_crl_from_file(path, vm)?; |
| 1267 | let is_crl = crl.is_some(); |
| 1268 | (crl, is_crl) |
| 1269 | } else { |
| 1270 | (None, false) |
| 1271 | }; |
| 1272 | |
| 1273 | // If it's a CRL, just add it (separate lock, no conflict with root_store) |
| 1274 | if let Some(crl) = crl_opt { |
| 1275 | self.crls.write().push(crl); |
| 1276 | } |
| 1277 | |
| 1278 | // Now acquire write locks for certificate loading |
| 1279 | let mut root_store = self.root_certs.write(); |
| 1280 | let mut ca_certs_der = self.ca_certs_der.write(); |
| 1281 | |
| 1282 | // Load from file (if not CRL) |
| 1283 | if let Some(ref path) = cafile_path |
| 1284 | && !cafile_is_crl |
| 1285 | { |
| 1286 | // Not a CRL, load as certificate |