@@ -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,84 @@ 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)
218+ && !vm. is_none ( & strerror)
219+ {
220+ return strerror. str ( vm) ;
221+ }
222+
223+ // Otherwise return str(args)
224+ exc. args ( ) . as_object ( ) . str ( vm)
225+ }
209226 }
210227
211228 /// 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- }
229+ #[ pyattr]
230+ #[ pyexception( name = "SSLCertVerificationError" , base = "PySslError" ) ]
231+ #[ derive( Debug ) ]
232+ pub struct PySslCertVerificationError { }
233+
234+ #[ pyexception]
235+ impl PySslCertVerificationError { }
223236
224237 /// 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- }
238+ #[ pyattr]
239+ #[ pyexception( name = "SSLZeroReturnError" , base = "PySslError" ) ]
240+ #[ derive( Debug ) ]
241+ pub struct PySslZeroReturnError { }
230242
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- }
243+ #[ pyexception]
244+ impl PySslZeroReturnError { }
237245
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- }
246+ /// Non-blocking SSL socket needs to read more data.
247+ #[ pyattr]
248+ #[ pyexception( name = "SSLWantReadError" , base = "PySslError" ) ]
249+ #[ derive( Debug ) ]
250+ pub struct PySslWantReadError { }
251+
252+ #[ pyexception]
253+ impl PySslWantReadError { }
254+
255+ /// Non-blocking SSL socket needs to write more data.
256+ #[ pyattr]
257+ #[ pyexception( name = "SSLWantWriteError" , base = "PySslError" ) ]
258+ #[ derive( Debug ) ]
259+ pub struct PySslWantWriteError { }
260+
261+ #[ pyexception]
262+ impl PySslWantWriteError { }
244263
245264 /// 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- }
265+ #[ pyattr]
266+ #[ pyexception( name = "SSLSyscallError" , base = "PySslError" ) ]
267+ #[ derive( Debug ) ]
268+ pub struct PySslSyscallError { }
269+
270+ #[ pyexception]
271+ impl PySslSyscallError { }
251272
252273 /// 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- }
274+ #[ pyattr]
275+ #[ pyexception( name = "SSLEOFError" , base = "PySslError" ) ]
276+ #[ derive( Debug ) ]
277+ pub struct PySslEOFError { }
278+
279+ #[ pyexception]
280+ impl PySslEOFError { }
258281
259282 type OpensslVersionInfo = ( u8 , u8 , u8 , u8 , u8 ) ;
260283 const fn parse_version_info ( mut n : i64 ) -> OpensslVersionInfo {
@@ -617,7 +640,10 @@ mod _ssl {
617640 return Err ( exceptions:: cstring_error ( vm) ) ;
618641 }
619642 self . builder ( ) . set_cipher_list ( ciphers) . map_err ( |_| {
620- vm. new_exception_msg ( ssl_error ( vm) , "No cipher can be selected." . to_owned ( ) )
643+ vm. new_exception_msg (
644+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
645+ "No cipher can be selected." . to_owned ( ) ,
646+ )
621647 } )
622648 }
623649
@@ -744,13 +770,13 @@ mod _ssl {
744770
745771 if clear != 0 && sys:: X509_VERIFY_PARAM_clear_flags ( param, clear) == 0 {
746772 return Err ( vm. new_exception_msg (
747- ssl_error ( vm ) ,
773+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
748774 "Failed to clear verify flags" . to_owned ( ) ,
749775 ) ) ;
750776 }
751777 if set != 0 && sys:: X509_VERIFY_PARAM_set_flags ( param, set) == 0 {
752778 return Err ( vm. new_exception_msg (
753- ssl_error ( vm ) ,
779+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
754780 "Failed to set verify flags" . to_owned ( ) ,
755781 ) ) ;
756782 }
@@ -934,13 +960,13 @@ mod _ssl {
934960 // validate socket type and context protocol
935961 if !args. server_side && zelf. protocol == SslVersion :: TlsServer {
936962 return Err ( vm. new_exception_msg (
937- ssl_error ( vm ) ,
963+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
938964 "Cannot create a client socket with a PROTOCOL_TLS_SERVER context" . to_owned ( ) ,
939965 ) ) ;
940966 }
941967 if args. server_side && zelf. protocol == SslVersion :: TlsClient {
942968 return Err ( vm. new_exception_msg (
943- ssl_error ( vm ) ,
969+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
944970 "Cannot create a server socket with a PROTOCOL_TLS_CLIENT context" . to_owned ( ) ,
945971 ) ) ;
946972 }
@@ -1124,7 +1150,7 @@ mod _ssl {
11241150
11251151 fn socket_closed_error ( vm : & VirtualMachine ) -> PyBaseExceptionRef {
11261152 vm. new_exception_msg (
1127- ssl_error ( vm ) ,
1153+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
11281154 "Underlying socket has been closed." . to_owned ( ) ,
11291155 )
11301156 }
@@ -1390,7 +1416,7 @@ mod _ssl {
13901416 let result = unsafe { SSL_verify_client_post_handshake ( stream. ssl ( ) . as_ptr ( ) ) } ;
13911417 if result == 0 {
13921418 Err ( vm. new_exception_msg (
1393- ssl_error ( vm ) ,
1419+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
13941420 "Post-handshake authentication failed" . to_owned ( ) ,
13951421 ) )
13961422 } else {
@@ -1422,7 +1448,7 @@ mod _ssl {
14221448 // Return the underlying socket
14231449 } else {
14241450 return Err ( vm. new_exception_msg (
1425- ssl_error ( vm ) ,
1451+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
14261452 format ! ( "SSL shutdown failed: error code {}" , err) ,
14271453 ) ) ;
14281454 }
@@ -1854,7 +1880,7 @@ mod _ssl {
18541880 fn write ( & self , data : ArgBytesLike , vm : & VirtualMachine ) -> PyResult < i32 > {
18551881 if self . eof_written . load ( ) {
18561882 return Err ( vm. new_exception_msg (
1857- ssl_error ( vm ) ,
1883+ PySslError :: class ( & vm . ctx ) . to_owned ( ) ,
18581884 "cannot write() after write_eof()" . to_owned ( ) ,
18591885 ) ) ;
18601886 }
@@ -1953,7 +1979,7 @@ mod _ssl {
19531979
19541980 #[ track_caller]
19551981 fn convert_openssl_error ( vm : & VirtualMachine , err : ErrorStack ) -> PyBaseExceptionRef {
1956- let cls = ssl_error ( vm ) ;
1982+ let cls = PySslError :: class ( & vm . ctx ) . to_owned ( ) ;
19571983 match err. errors ( ) . last ( ) {
19581984 Some ( e) => {
19591985 let caller = std:: panic:: Location :: caller ( ) ;
@@ -2012,25 +2038,31 @@ mod _ssl {
20122038 let e = e. borrow ( ) ;
20132039 let ( cls, msg) = match e. code ( ) {
20142040 ssl:: ErrorCode :: WANT_READ => (
2015- vm. class ( "_ssl" , "SSLWantReadError" ) ,
2041+ PySslWantReadError :: class ( & vm. ctx ) . to_owned ( ) ,
20162042 "The operation did not complete (read)" ,
20172043 ) ,
20182044 ssl:: ErrorCode :: WANT_WRITE => (
2019- vm. class ( "_ssl" , "SSLWantWriteError" ) ,
2045+ PySslWantWriteError :: class ( & vm. ctx ) . to_owned ( ) ,
20202046 "The operation did not complete (write)" ,
20212047 ) ,
20222048 ssl:: ErrorCode :: SYSCALL => match e. io_error ( ) {
20232049 Some ( io_err) => return io_err. to_pyexception ( vm) ,
20242050 None => (
2025- vm. class ( "_ssl" , "SSLSyscallError" ) ,
2051+ PySslSyscallError :: class ( & vm. ctx ) . to_owned ( ) ,
20262052 "EOF occurred in violation of protocol" ,
20272053 ) ,
20282054 } ,
20292055 ssl:: ErrorCode :: SSL => match e. ssl_error ( ) {
20302056 Some ( e) => return convert_openssl_error ( vm, e. clone ( ) ) ,
2031- None => ( ssl_error ( vm) , "A failure in the SSL library occurred" ) ,
2057+ None => (
2058+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
2059+ "A failure in the SSL library occurred" ,
2060+ ) ,
20322061 } ,
2033- _ => ( ssl_error ( vm) , "A failure in the SSL library occurred" ) ,
2062+ _ => (
2063+ PySslError :: class ( & vm. ctx ) . to_owned ( ) ,
2064+ "A failure in the SSL library occurred" ,
2065+ ) ,
20342066 } ;
20352067 vm. new_exception_msg ( cls, msg. to_owned ( ) )
20362068 }
0 commit comments