MCPcopy Index your code
hub / github.com/RustPython/RustPython / cert_to_dict

Function cert_to_dict

crates/stdlib/src/openssl/cert.rs:188–342  ·  view source on GitHub ↗

Helper to convert X509 to dict (for getpeercert with binary=False)

(vm: &VirtualMachine, cert: &X509Ref)

Source from the content-addressed store, hash-verified

186
187 // Helper to convert X509 to dict (for getpeercert with binary=False)
188 fn cert_to_dict(vm: &VirtualMachine, cert: &X509Ref) -> PyResult {
189 let dict = vm.ctx.new_dict();
190
191 dict.set_item("subject", name_to_py(vm, cert.subject_name())?, vm)?;
192 dict.set_item("issuer", name_to_py(vm, cert.issuer_name())?, vm)?;
193 // X.509 version: OpenSSL uses 0-based (0=v1, 1=v2, 2=v3) but Python uses 1-based (1=v1, 2=v2, 3=v3)
194 dict.set_item("version", vm.new_pyobj(cert.version() + 1), vm)?;
195
196 let serial_num = cert
197 .serial_number()
198 .to_bn()
199 .and_then(|bn| bn.to_hex_str())
200 .map_err(|e| convert_openssl_error(vm, e))?;
201 // Serial number must have even length (each byte = 2 hex chars)
202 // BigNum::to_hex_str() strips leading zeros, so we need to pad
203 let serial_str = serial_num.to_string();
204 let serial_str = if serial_str.len() % 2 == 1 {
205 format!("0{}", serial_str)
206 } else {
207 serial_str
208 };
209 dict.set_item("serialNumber", vm.ctx.new_str(serial_str).into(), vm)?;
210
211 dict.set_item(
212 "notBefore",
213 vm.ctx.new_str(cert.not_before().to_string()).into(),
214 vm,
215 )?;
216 dict.set_item(
217 "notAfter",
218 vm.ctx.new_str(cert.not_after().to_string()).into(),
219 vm,
220 )?;
221
222 if let Some(names) = cert.subject_alt_names() {
223 let san: Vec<PyObjectRef> = names
224 .iter()
225 .map(|gen_name| {
226 if let Some(email) = gen_name.email() {
227 vm.new_tuple((ascii!("email"), email)).into()
228 } else if let Some(dnsname) = gen_name.dnsname() {
229 vm.new_tuple((ascii!("DNS"), dnsname)).into()
230 } else if let Some(ip) = gen_name.ipaddress() {
231 // Parse IP address properly (IPv4 or IPv6)
232 let ip_str = if ip.len() == 4 {
233 // IPv4
234 format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
235 } else if ip.len() == 16 {
236 // IPv6 - format with all zeros visible (not compressed)
237 let ip_addr =
238 std::net::Ipv6Addr::from(<[u8; 16]>::try_from(&ip[0..16]).unwrap());
239 let s = ip_addr.segments();
240 format!(
241 "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
242 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]
243 )
244 } else {
245 // Fallback for unexpected length

Callers 2

get_infoMethod · 0.70
cert_to_pyFunction · 0.70

Calls 15

convert_openssl_errorFunction · 0.85
obj2txtFunction · 0.85
newFunction · 0.85
new_dictMethod · 0.80
new_pyobjMethod · 0.80
to_stringMethod · 0.80
collectMethod · 0.80
into_ownedMethod · 0.80
name_to_pyFunction · 0.70
set_itemMethod · 0.45
versionMethod · 0.45
lenMethod · 0.45

Tested by

no test coverage detected