Convert DER-encoded certificate to Python dict (for get_ca_certs) Similar to cert_to_dict but includes additional fields like crlDistributionPoints and uses CPython's specific ordering: issuer, notAfter, notBefore, serialNumber, subject, version
(vm: &VirtualMachine, cert_der: &[u8])
| 368 | /// Similar to cert_to_dict but includes additional fields like crlDistributionPoints |
| 369 | /// and uses CPython's specific ordering: issuer, notAfter, notBefore, serialNumber, subject, version |
| 370 | pub fn cert_der_to_dict_helper(vm: &VirtualMachine, cert_der: &[u8]) -> PyResult<PyObjectRef> { |
| 371 | // Parse the certificate using x509-parser |
| 372 | let (_, cert) = x509_parser::parse_x509_certificate(cert_der) |
| 373 | .map_err(|e| vm.new_value_error(format!("Failed to parse certificate: {e}")))?; |
| 374 | |
| 375 | // Helper to convert X509Name to nested tuple format |
| 376 | let name_to_tuple = |name: &x509_parser::x509::X509Name<'_>| -> PyResult { |
| 377 | let mut entries = Vec::new(); |
| 378 | for rdn in name.iter() { |
| 379 | for attr in rdn.iter() { |
| 380 | let oid_str = attr.attr_type().to_id_string(); |
| 381 | |
| 382 | // Get value as bytes and convert to string |
| 383 | let value_str = if let Ok(s) = attr.attr_value().as_str() { |
| 384 | s.to_string() |
| 385 | } else { |
| 386 | let value_bytes = attr.attr_value().data; |
| 387 | match core::str::from_utf8(value_bytes) { |
| 388 | Ok(s) => s.to_string(), |
| 389 | Err(_) => String::from_utf8_lossy(value_bytes).into_owned(), |
| 390 | } |
| 391 | }; |
| 392 | |
| 393 | let key = oid_to_attribute_name(&oid_str); |
| 394 | |
| 395 | let entry = |
| 396 | vm.new_tuple((vm.ctx.new_str(key.to_string()), vm.ctx.new_str(value_str))); |
| 397 | entries.push(vm.new_tuple((entry,)).into()); |
| 398 | } |
| 399 | } |
| 400 | Ok(vm.ctx.new_tuple(entries).into()) |
| 401 | }; |
| 402 | |
| 403 | let dict = vm.ctx.new_dict(); |
| 404 | |
| 405 | // CPython ordering: issuer, notAfter, notBefore, serialNumber, subject, version |
| 406 | dict.set_item("issuer", name_to_tuple(cert.issuer())?, vm)?; |
| 407 | |
| 408 | // Validity - format with GMT using chrono |
| 409 | dict.set_item( |
| 410 | "notAfter", |
| 411 | vm.ctx |
| 412 | .new_str(format_asn1_time(&cert.validity().not_after)) |
| 413 | .into(), |
| 414 | vm, |
| 415 | )?; |
| 416 | dict.set_item( |
| 417 | "notBefore", |
| 418 | vm.ctx |
| 419 | .new_str(format_asn1_time(&cert.validity().not_before)) |
| 420 | .into(), |
| 421 | vm, |
| 422 | )?; |
| 423 | |
| 424 | // Serial number - hex format with even length |
| 425 | let serial = format_serial_number(&cert.serial); |
| 426 | dict.set_item("serialNumber", vm.ctx.new_str(serial).into(), vm)?; |
| 427 |
no test coverage detected