@@ -38,8 +38,10 @@ mod _ssl {
3838 } ,
3939 socket:: { self , PySocket } ,
4040 vm:: {
41- Py , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
42- builtins:: { PyBaseExceptionRef , PyBytesRef , PyListRef , PyStrRef , PyTypeRef , PyWeak } ,
41+ AsObject , Py , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
42+ builtins:: {
43+ PyBaseExceptionRef , PyBytesRef , PyListRef , PyOSError , PyStrRef , PyTypeRef , PyWeak ,
44+ } ,
4345 class_or_notimplemented,
4446 convert:: { ToPyException , ToPyObject } ,
4547 exceptions,
@@ -198,63 +200,82 @@ mod _ssl {
198200 parse_version_info ( openssl_api_version)
199201 }
200202
203+ // SSL Exception Types
204+
201205 /// An error occurred in the SSL implementation.
202- #[ pyattr( name = "SSLError" , once) ]
203- fn ssl_error ( vm : & VirtualMachine ) -> PyTypeRef {
204- vm. ctx . new_exception_type (
205- "ssl" ,
206- "SSLError" ,
207- Some ( vec ! [ vm. ctx. exceptions. os_error. to_owned( ) ] ) ,
208- )
206+ #[ pyattr]
207+ #[ pyexception( name = "SSLError" , base = "PyOSError" ) ]
208+ #[ derive( Debug ) ]
209+ pub struct PySslError { }
210+
211+ #[ pyexception]
212+ impl PySslError {
213+ // Returns strerror attribute if available, otherwise str(args)
214+ #[ pymethod]
215+ fn __str__ ( exc : PyBaseExceptionRef , vm : & VirtualMachine ) -> PyResult < PyStrRef > {
216+ // Try to get strerror attribute first (OSError compatibility)
217+ if let Ok ( strerror) = exc. as_object ( ) . get_attr ( "strerror" , vm) && !vm. is_none ( & strerror) {
218+ return strerror. str ( vm) ;
219+ }
220+
221+ // Otherwise return str(args)
222+ exc. args ( ) . as_object ( ) . str ( vm)
223+ }
209224 }
210225
211226 /// A certificate could not be verified.
212- #[ pyattr( name = "SSLCertVerificationError" , once) ]
213- fn ssl_cert_verification_error ( vm : & VirtualMachine ) -> PyTypeRef {
214- vm. ctx . new_exception_type (
215- "ssl" ,
216- "SSLCertVerificationError" ,
217- Some ( vec ! [
218- ssl_error( vm) ,
219- vm. ctx. exceptions. value_error. to_owned( ) ,
220- ] ) ,
221- )
222- }
227+ #[ pyattr]
228+ #[ pyexception( name = "SSLCertVerificationError" , base = "PySslError" ) ]
229+ #[ derive( Debug ) ]
230+ pub struct PySslCertVerificationError { }
231+
232+ #[ pyexception]
233+ impl PySslCertVerificationError { }
223234
224235 /// SSL/TLS session closed cleanly.
225- #[ pyattr( name = "SSLZeroReturnError" , once) ]
226- fn ssl_zero_return_error ( vm : & VirtualMachine ) -> PyTypeRef {
227- vm. ctx
228- . new_exception_type ( "ssl" , "SSLZeroReturnError" , Some ( vec ! [ ssl_error( vm) ] ) )
229- }
236+ #[ pyattr]
237+ #[ pyexception( name = "SSLZeroReturnError" , base = "PySslError" ) ]
238+ #[ derive( Debug ) ]
239+ pub struct PySslZeroReturnError { }
230240
231- /// Non-blocking SSL socket needs to read more data before the requested operation can be completed.
232- #[ pyattr( name = "SSLWantReadError" , once) ]
233- fn ssl_want_read_error ( vm : & VirtualMachine ) -> PyTypeRef {
234- vm. ctx
235- . new_exception_type ( "ssl" , "SSLWantReadError" , Some ( vec ! [ ssl_error( vm) ] ) )
236- }
241+ #[ pyexception]
242+ impl PySslZeroReturnError { }
237243
238- /// Non-blocking SSL socket needs to write more data before the requested operation can be completed.
239- #[ pyattr( name = "SSLWantWriteError" , once) ]
240- fn ssl_want_write_error ( vm : & VirtualMachine ) -> PyTypeRef {
241- vm. ctx
242- . new_exception_type ( "ssl" , "SSLWantWriteError" , Some ( vec ! [ ssl_error( vm) ] ) )
243- }
244+ /// Non-blocking SSL socket needs to read more data.
245+ #[ pyattr]
246+ #[ pyexception( name = "SSLWantReadError" , base = "PySslError" ) ]
247+ #[ derive( Debug ) ]
248+ pub struct PySslWantReadError { }
249+
250+ #[ pyexception]
251+ impl PySslWantReadError { }
252+
253+ /// Non-blocking SSL socket needs to write more data.
254+ #[ pyattr]
255+ #[ pyexception( name = "SSLWantWriteError" , base = "PySslError" ) ]
256+ #[ derive( Debug ) ]
257+ pub struct PySslWantWriteError { }
258+
259+ #[ pyexception]
260+ impl PySslWantWriteError { }
244261
245262 /// System error when attempting SSL operation.
246- #[ pyattr( name = "SSLSyscallError" , once) ]
247- fn ssl_syscall_error ( vm : & VirtualMachine ) -> PyTypeRef {
248- vm. ctx
249- . new_exception_type ( "ssl" , "SSLSyscallError" , Some ( vec ! [ ssl_error( vm) ] ) )
250- }
263+ #[ pyattr]
264+ #[ pyexception( name = "SSLSyscallError" , base = "PySslError" ) ]
265+ #[ derive( Debug ) ]
266+ pub struct PySslSyscallError { }
267+
268+ #[ pyexception]
269+ impl PySslSyscallError { }
251270
252271 /// SSL/TLS connection terminated abruptly.
253- #[ pyattr( name = "SSLEOFError" , once) ]
254- fn ssl_eof_error ( vm : & VirtualMachine ) -> PyTypeRef {
255- vm. ctx
256- . new_exception_type ( "ssl" , "SSLEOFError" , Some ( vec ! [ ssl_error( vm) ] ) )
257- }
272+ #[ pyattr]
273+ #[ pyexception( name = "SSLEOFError" , base = "PySslError" ) ]
274+ #[ derive( Debug ) ]
275+ pub struct PySslEOFError { }
276+
277+ #[ pyexception]
278+ impl PySslEOFError { }
258279
259280 type OpensslVersionInfo = ( u8 , u8 , u8 , u8 , u8 ) ;
260281 const fn parse_version_info ( mut n : i64 ) -> OpensslVersionInfo {
@@ -617,7 +638,10 @@ mod _ssl {
617638 return Err ( exceptions:: cstring_error ( vm) ) ;
618639 }
619640 self . builder ( ) . set_cipher_list ( ciphers) . map_err ( |_| {
620- vm. new_exception_msg ( ssl_error ( vm) , "No cipher can be selected." . to_owned ( ) )
641+ vm. new_exception_msg (
642+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
643+ "No cipher can be selected." . to_owned ( ) ,
644+ )
621645 } )
622646 }
623647
@@ -744,13 +768,13 @@ mod _ssl {
744768
745769 if clear != 0 && sys:: X509_VERIFY_PARAM_clear_flags ( param, clear) == 0 {
746770 return Err ( vm. new_exception_msg (
747- ssl_error ( vm ) ,
771+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
748772 "Failed to clear verify flags" . to_owned ( ) ,
749773 ) ) ;
750774 }
751775 if set != 0 && sys:: X509_VERIFY_PARAM_set_flags ( param, set) == 0 {
752776 return Err ( vm. new_exception_msg (
753- ssl_error ( vm ) ,
777+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
754778 "Failed to set verify flags" . to_owned ( ) ,
755779 ) ) ;
756780 }
@@ -934,13 +958,13 @@ mod _ssl {
934958 // validate socket type and context protocol
935959 if !args. server_side && zelf. protocol == SslVersion :: TlsServer {
936960 return Err ( vm. new_exception_msg (
937- ssl_error ( vm ) ,
961+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
938962 "Cannot create a client socket with a PROTOCOL_TLS_SERVER context" . to_owned ( ) ,
939963 ) ) ;
940964 }
941965 if args. server_side && zelf. protocol == SslVersion :: TlsClient {
942966 return Err ( vm. new_exception_msg (
943- ssl_error ( vm ) ,
967+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
944968 "Cannot create a server socket with a PROTOCOL_TLS_CLIENT context" . to_owned ( ) ,
945969 ) ) ;
946970 }
@@ -1124,7 +1148,7 @@ mod _ssl {
11241148
11251149 fn socket_closed_error ( vm : & VirtualMachine ) -> PyBaseExceptionRef {
11261150 vm. new_exception_msg (
1127- ssl_error ( vm ) ,
1151+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
11281152 "Underlying socket has been closed." . to_owned ( ) ,
11291153 )
11301154 }
@@ -1390,7 +1414,7 @@ mod _ssl {
13901414 let result = unsafe { SSL_verify_client_post_handshake ( stream. ssl ( ) . as_ptr ( ) ) } ;
13911415 if result == 0 {
13921416 Err ( vm. new_exception_msg (
1393- ssl_error ( vm ) ,
1417+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
13941418 "Post-handshake authentication failed" . to_owned ( ) ,
13951419 ) )
13961420 } else {
@@ -1422,7 +1446,7 @@ mod _ssl {
14221446 // Return the underlying socket
14231447 } else {
14241448 return Err ( vm. new_exception_msg (
1425- ssl_error ( vm ) ,
1449+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
14261450 format ! ( "SSL shutdown failed: error code {}" , err) ,
14271451 ) ) ;
14281452 }
@@ -1854,7 +1878,7 @@ mod _ssl {
18541878 fn write ( & self , data : ArgBytesLike , vm : & VirtualMachine ) -> PyResult < i32 > {
18551879 if self . eof_written . load ( ) {
18561880 return Err ( vm. new_exception_msg (
1857- ssl_error ( vm ) ,
1881+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
18581882 "cannot write() after write_eof()" . to_owned ( ) ,
18591883 ) ) ;
18601884 }
@@ -1953,7 +1977,7 @@ mod _ssl {
19531977
19541978 #[ track_caller]
19551979 fn convert_openssl_error ( vm : & VirtualMachine , err : ErrorStack ) -> PyBaseExceptionRef {
1956- let cls = ssl_error ( vm ) ;
1980+ let cls = PySslError :: class ( & vm . ctx ) . to_owned ( ) ;
19571981 match err. errors ( ) . last ( ) {
19581982 Some ( e) => {
19591983 let caller = std:: panic:: Location :: caller ( ) ;
@@ -2012,25 +2036,31 @@ mod _ssl {
20122036 let e = e. borrow ( ) ;
20132037 let ( cls, msg) = match e. code ( ) {
20142038 ssl:: ErrorCode :: WANT_READ => (
2015- vm. class ( "_ssl" , "SSLWantReadError" ) ,
2039+ PySslWantReadError :: class ( & vm. ctx ) . to_owned ( ) ,
20162040 "The operation did not complete (read)" ,
20172041 ) ,
20182042 ssl:: ErrorCode :: WANT_WRITE => (
2019- vm. class ( "_ssl" , "SSLWantWriteError" ) ,
2043+ PySslWantWriteError :: class ( & vm. ctx ) . to_owned ( ) ,
20202044 "The operation did not complete (write)" ,
20212045 ) ,
20222046 ssl:: ErrorCode :: SYSCALL => match e. io_error ( ) {
20232047 Some ( io_err) => return io_err. to_pyexception ( vm) ,
20242048 None => (
2025- vm. class ( "_ssl" , "SSLSyscallError" ) ,
2049+ PySslSyscallError :: class ( & vm. ctx ) . to_owned ( ) ,
20262050 "EOF occurred in violation of protocol" ,
20272051 ) ,
20282052 } ,
20292053 ssl:: ErrorCode :: SSL => match e. ssl_error ( ) {
20302054 Some ( e) => return convert_openssl_error ( vm, e. clone ( ) ) ,
2031- None => ( ssl_error ( vm) , "A failure in the SSL library occurred" ) ,
2055+ None => (
2056+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
2057+ "A failure in the SSL library occurred" ,
2058+ ) ,
20322059 } ,
2033- _ => ( ssl_error ( vm) , "A failure in the SSL library occurred" ) ,
2060+ _ => (
2061+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
2062+ "A failure in the SSL library occurred" ,
2063+ ) ,
20342064 } ;
20352065 vm. new_exception_msg ( cls, msg. to_owned ( ) )
20362066 }
0 commit comments