GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — More openssl impl by youknowone · Pull Request #6464 · RustPython/RustPython Conversation
|
|
Caution Review failedThe pull request is closed. WalkthroughAdds OpenSSL-specific CI build step and extensive OpenSSL/ssl changes: PSK client/server callback storage and APIs, callable password support for certificate loading, stricter DER/PEM handling, certificate trait/visibility updates, ALPN and select/handshake refinements, and related ex_data lifecycle logic. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
crates/stdlib/src/openssl/cert.rs (1)
108-134: Equality comparison logic uses unusual pattern.The comparison at line 133 uses
eq.cmp(&true)which is an unusual way to express boolean equality. While it works, it's less readable than a direct approach.🔎 Suggested simplification
- let eq = self_der == other_der; - Ok(op.eval_ord(eq.cmp(&true)).into()) + let result = self_der == other_der; + Ok(PyComparisonValue::Implemented(op.eval_eq(result)))Alternatively, if
eval_eqis not available, consider:- Ok(op.eval_ord(eq.cmp(&true)).into()) + let matches = match op { + PyComparisonOp::Eq => result, + PyComparisonOp::Ne => !result, + _ => unreachable!(), + }; + Ok(PyComparisonValue::Implemented(matches))
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
.github/workflows/ci.yaml (1 hunks)crates/stdlib/src/openssl.rs (24 hunks)crates/stdlib/src/openssl/cert.rs (8 hunks)📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style by runningcargo fmtto format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
crates/stdlib/src/openssl/cert.rscrates/stdlib/src/openssl.rsLearnt from: CR
Repo: RustPython/RustPython PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-29T12:17:28.606Z
Learning: Run `cargo test --workspace --exclude rustpython_wasm` to execute Rust unit tests
Applied to files:
.github/workflows/ci.yamlcrates/stdlib/src/openssl.rs (4)
convert_openssl_error(3664-3767)new(537-541)new(4093-4103)value(3025-3026)
.github/workflows/ci.yaml (1)
150-154: LGTM - OpenSSL build verification step.This CI step ensures the
ssl-opensslfeature compiles correctly on Linux. The restriction to Linux is appropriate given cross-platform OpenSSL complexities.crates/stdlib/src/openssl/cert.rs (6)
137-143: LGTM - Hashable implementation.Using
X509_subject_name_hashis a reasonable approach for certificate hashing, consistent with how OpenSSL identifies certificates.
145-166: LGTM - Representable implementation.The representation logic correctly handles edge cases like missing short names and non-UTF8 data, providing a readable certificate description.
88-97: LGTM - PEM encoding returns string.Returning PEM as a string aligns with CPython's
sslmodule behavior where PEM-encoded certificates are text.
201-209: LGTM - Serial number even-length padding.Ensuring the serial number hex string has even length (byte-aligned) matches CPython's certificate representation.
287-339: LGTM - Certificate extension fields.The additions for OCSP responders, CA Issuers, and CRL distribution points correctly populate the certificate dictionary, matching CPython's
sslmodule output.
260-276: Union field access for GEN_RID is implemented correctly.The code properly accesses the GENERAL_NAME union field
dfor GEN_RID type. After verifying the type with(*ptr).type_ == sys::GEN_RID, it correctly casts(*ptr).dto*const sys::ASN1_OBJECT. The implementation includes proper null checking and uses the standard OpenSSLobj2txt()conversion function. The union access pattern is safe and follows C FFI conventions for discriminated union handling.crates/stdlib/src/openssl.rs (11)
605-636: LGTM - Message callback ex_data management.The dedicated ex_data index for msg_callback and the free function properly manage the Python object reference lifecycle, preventing memory leaks and use-after-free issues.
1126-1146: LGTM - Options update with clear/set delta.The logic correctly computes which options to clear and set, ensuring the final options match the requested value rather than just ORing new options.
1367-1373: LGTM - ALPN protocol slice bounds fix.Using
pos..pos + proto.len()correctly returns only the selected protocol bytes, preventing potential buffer overread.
1485-1500: LGTM - Empty cadata error handling.The differentiated error messages for PEM vs DER format help users understand why their certificate data wasn't loaded.
1960-1977: LGTM - Password bytes extraction helper.The helper correctly handles all expected password types (str, bytes, bytearray) with clear error messaging.
2117-2134: LGTM - ex_data setup with proper reference counting.The pattern of cloning, calling
into_raw(), and relying onmsg_callback_data_freeto decrement the refcount correctly manages the Python object lifecycle.
2555-2578: LGTM - Server-side peer cert chain fix.Correctly handles the OpenSSL behavior where
SSL_get_peer_cert_chainexcludes the peer certificate for server-side sockets, matching CPython's behavior.
2844-2880: LGTM - DER certificate loading with improved EOF detection.The enhanced logic correctly distinguishes between:
- Clean EOF (all data consumed as valid certificates)
- Parse error (garbage data after valid certificates)
- Empty/invalid data
This matches CPython's certificate loading behavior.
1599-1601: LGTM - X509_check_ca return value fix.
X509_check_careturns non-zero for any CA certificate type (not just 1), so the!= 0check is correct.
886-889: LGTM - PSK callback field additions.The new fields for PSK callbacks and identity hint are properly initialized with
PyMutex<Option<_>>for thread-safe optional storage.
1872-1921: Password callback implementation is safe.The callback closure captures
vmandpw_objby reference within a synchronous operation. OpenSSL's PEM_read_bio_PrivateKey invokes the callback immediately during the read operation to request the password, and the closure is not stored for later use. The references remain valid throughout the function's execution, and error propagation viaRefCellis correctly implemented.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| #[pymethod] | ||
| fn set_psk_client_callback( | ||
| &self, | ||
| callback: PyObjectRef, | ||
| vm: &VirtualMachine, | ||
| ) -> PyResult<()> { | ||
| // Cannot add PSK client callback to a server context | ||
| if self.protocol == SslVersion::TlsServer { | ||
| return Err(vm | ||
| .new_os_subtype_error( | ||
| PySSLError::class(&vm.ctx).to_owned(), | ||
| None, | ||
| "Cannot add PSK client callback to a PROTOCOL_TLS_SERVER context" | ||
| .to_owned(), | ||
| ) | ||
| .upcast()); | ||
| } | ||
|
|
||
| if vm.is_none(&callback) { | ||
| *self.psk_client_callback.lock() = None; | ||
| unsafe { | ||
| sys::SSL_CTX_set_psk_client_callback(self.builder().as_ptr(), None); | ||
| } | ||
| } else { | ||
| if !callback.is_callable() { | ||
| return Err(vm.new_type_error("callback must be callable".to_owned())); | ||
| } | ||
| *self.psk_client_callback.lock() = Some(callback); | ||
| // Note: The actual callback will be invoked via SSL app_data mechanism | ||
| // when do_handshake is called | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[pymethod] | ||
| fn set_psk_server_callback( | ||
| &self, | ||
| callback: PyObjectRef, | ||
| identity_hint: OptionalArg<PyStrRef>, | ||
| vm: &VirtualMachine, | ||
| ) -> PyResult<()> { | ||
| // Cannot add PSK server callback to a client context | ||
| if self.protocol == SslVersion::TlsClient { | ||
| return Err(vm | ||
| .new_os_subtype_error( | ||
| PySSLError::class(&vm.ctx).to_owned(), | ||
| None, | ||
| "Cannot add PSK server callback to a PROTOCOL_TLS_CLIENT context" | ||
| .to_owned(), | ||
| ) | ||
| .upcast()); | ||
| } | ||
|
|
||
| if vm.is_none(&callback) { | ||
| *self.psk_server_callback.lock() = None; | ||
| *self.psk_identity_hint.lock() = None; | ||
| unsafe { | ||
| sys::SSL_CTX_set_psk_server_callback(self.builder().as_ptr(), None); | ||
| } | ||
| } else { | ||
| if !callback.is_callable() { | ||
| return Err(vm.new_type_error("callback must be callable".to_owned())); | ||
| } | ||
| *self.psk_server_callback.lock() = Some(callback); | ||
| if let OptionalArg::Present(hint) = identity_hint { | ||
| *self.psk_identity_hint.lock() = Some(hint.as_str().to_owned()); | ||
| } | ||
| // Note: The actual callback will be invoked via SSL app_data mechanism | ||
| } | ||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
🏁 Script executed:
#!/bin/bash # Search for where psk_client_callback and psk_server_callback are actually used rg -n "psk_client_callback|psk_server_callback" --type rust -B 3 -A 3 crates/stdlib/src/openssl.rs
Repository: RustPython/RustPython
Length of output: 2720
🏁 Script executed:
#!/bin/bash # Search for do_handshake implementation and any usage of stored callbacks rg -n "do_handshake|psk_client_callback\|psk_server_callback" --type rust crates/stdlib/src/openssl.rs | head -50
Repository: RustPython/RustPython
Length of output: 820
🏁 Script executed:
#!/bin/bash # Get the do_handshake implementation around line 2866 sed -n '2860,2920p' crates/stdlib/src/openssl.rs
Repository: RustPython/RustPython
Length of output: 2828
🏁 Script executed:
#!/bin/bash # Search for where psk_client_callback and psk_server_callback are USED (not just stored) # Look for any invocations or retrievals of these stored callbacks rg -n "psk_client_callback\|psk_server_callback" --type rust crates/stdlib/src/openssl.rs | grep -v "fn set_psk" | grep -v "\.lock()"
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
#!/bin/bash # Search more broadly for callback usage and wrapper functions rg -n "psk_client_callback|psk_server_callback|raw_client_psk|raw_server_psk" --type rust crates/stdlib/src/openssl.rs
Repository: RustPython/RustPython
Length of output: 852
🏁 Script executed:
#!/bin/bash # Check if there are any wrapper functions defined for PSK callbacks rg -n "extern.*psk|fn.*psk.*callback|unsafe.*psk" --type rust crates/stdlib/src/openssl.rs | head -20
Repository: RustPython/RustPython
Length of output: 146
🏁 Script executed:
#!/bin/bash # Final check: see if callbacks are ever retrieved from the lock anywhere rg -n "\.psk_client_callback\|\.psk_server_callback" --type rust crates/stdlib/src/openssl.rs
Repository: RustPython/RustPython
Length of output: 47
🏁 Script executed:
#!/bin/bash # Confirm: search for any actual invocation/retrieval of these callbacks rg -n "lock()" crates/stdlib/src/openssl.rs | grep -i psk
Repository: RustPython/RustPython
Length of output: 482
PSK callbacks stored but not registered with OpenSSL—no callback wrapper function is invoked.
The methods store Python callbacks in psk_client_callback/psk_server_callback, but fail to register C-compatible wrapper functions with OpenSSL. When a non-None callback is set, the code should call sys::SSL_CTX_set_psk_client_callback(self.builder().as_ptr(), Some(wrapper_fn)) to register an actual C callback. Currently this only happens when clearing (setting to None). The stored callbacks are never retrieved or invoked—they're unreachable from both OpenSSL and the handshake code. Either implement the wrapper function and OpenSSL registration, or clarify if this is an intentional partial implementation pending follow-up work.
In crates/stdlib/src/openssl.rs around lines 1384-1454, the PSK client/server
setters store Python callbacks but do not register C-compatible wrapper
functions with OpenSSL, so OpenSSL cannot call into the stored Python callbacks;
fix by implementing extern "C" wrapper functions for client and server PSK
callbacks that retrieve the Rust context (via SSL_CTX app_data or ex_data),
acquire the GIL, call the stored PyObject callback and translate return values
into the OpenSSL-required types (handle errors by returning appropriate failure
codes), and when setting a non-None callback call
sys::SSL_CTX_set_psk_client_callback(self.builder().as_ptr(),
Some(psk_client_wrapper)) or sys::SSL_CTX_set_psk_server_callback(...,
Some(psk_server_wrapper)); also ensure you set the context pointer in OpenSSL
(app_data/ex_data) so the wrapper can find self, and when clearing (None)
unregister the callback by passing None and clear the stored app_data/ex_data;
include proper locking, lifetime and error handling around the Python call.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.