22
33mod cert;
44
5+ // Conditional compilation for OpenSSL version-specific error codes
6+ cfg_if:: cfg_if! {
7+ if #[ cfg( ossl310) ] {
8+ // OpenSSL 3.1.0+
9+ #[ path = "ssl/ssl_data_31.rs" ]
10+ mod ssl_data;
11+ } else if #[ cfg( ossl300) ] {
12+ // OpenSSL 3.0.0+
13+ #[ path = "ssl/ssl_data_300.rs" ]
14+ mod ssl_data;
15+ } else {
16+ // OpenSSL 1.1.1+ (fallback)
17+ #[ path = "ssl/ssl_data_111.rs" ]
18+ mod ssl_data;
19+ }
20+ }
21+
522use crate :: vm:: { PyRef , VirtualMachine , builtins:: PyModule } ;
623use openssl_probe:: ProbeResult ;
724
@@ -48,7 +65,7 @@ mod _ssl {
4865 ArgBytesLike , ArgCallable , ArgMemoryBuffer , ArgStrOrBytesLike , Either , FsPath ,
4966 OptionalArg , PyComparisonValue ,
5067 } ,
51- types:: { Comparable , Constructor , PyComparisonOp , PyTypeFlags } ,
68+ types:: { Comparable , Constructor , PyComparisonOp } ,
5269 utils:: ToCString ,
5370 } ,
5471 } ;
@@ -726,16 +743,16 @@ mod _ssl {
726743 let ctx_ptr = builder. as_ptr ( ) ;
727744 match proto {
728745 SslVersion :: Tls1 => {
729- sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_VERSION as i32 ) ;
730- sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_VERSION as i32 ) ;
746+ sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_VERSION ) ;
747+ sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_VERSION ) ;
731748 }
732749 SslVersion :: Tls1_1 => {
733- sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_1_VERSION as i32 ) ;
734- sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_1_VERSION as i32 ) ;
750+ sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_1_VERSION ) ;
751+ sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_1_VERSION ) ;
735752 }
736753 SslVersion :: Tls1_2 => {
737- sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_2_VERSION as i32 ) ;
738- sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_2_VERSION as i32 ) ;
754+ sys:: SSL_CTX_set_min_proto_version ( ctx_ptr, sys:: TLS1_2_VERSION ) ;
755+ sys:: SSL_CTX_set_max_proto_version ( ctx_ptr, sys:: TLS1_2_VERSION ) ;
739756 }
740757 _ => {
741758 // For Tls, TlsClient, TlsServer, use default (no restrictions)
@@ -987,12 +1004,12 @@ mod _ssl {
9871004 let proto_version = match value {
9881005 -2 => {
9891006 // PY_PROTO_MINIMUM_SUPPORTED -> use minimum available (TLS 1.2)
990- sys:: TLS1_2_VERSION as i32
1007+ sys:: TLS1_2_VERSION
9911008 }
9921009 -1 => {
9931010 // PY_PROTO_MAXIMUM_SUPPORTED -> use maximum available
9941011 // For max on min_proto_version, we use the newest available
995- sys:: TLS1_3_VERSION as i32
1012+ sys:: TLS1_3_VERSION
9961013 }
9971014 _ => value,
9981015 } ;
@@ -1025,7 +1042,7 @@ mod _ssl {
10251042 }
10261043 -2 => {
10271044 // PY_PROTO_MINIMUM_SUPPORTED -> use minimum available (TLS 1.2)
1028- sys:: TLS1_2_VERSION as i32
1045+ sys:: TLS1_2_VERSION
10291046 }
10301047 _ => value,
10311048 } ;
@@ -3033,21 +3050,33 @@ mod _ssl {
30333050 let file = file
30343051 . rsplit_once ( & [ '/' , '\\' ] [ ..] )
30353052 . map_or ( file, |( _, basename) | basename) ;
3036- // TODO: finish map
3037- let default_errstr = e. reason ( ) . unwrap_or ( "unknown error" ) ;
3038- let ( errstr, is_cert_verify_error) = match default_errstr {
3039- "certificate verify failed" => ( "CERTIFICATE_VERIFY_FAILED" , true ) ,
3040- "no shared cipher" => ( "NO_SHARED_CIPHER" , false ) ,
3041- "sslv3 alert handshake failure" => ( "SSLV3_ALERT_HANDSHAKE_FAILURE" , false ) ,
3042- "tlsv1 alert internal error" => ( "TLSV1_ALERT_INTERNAL_ERROR" , false ) ,
3043- "tlsv1 alert access denied" => ( "TLSV1_ALERT_ACCESS_DENIED" , false ) ,
3044- "tlsv1 alert unknown ca" => ( "TLSV1_ALERT_UNKNOWN_CA" , false ) ,
3045- "sslv3 alert certificate revoked" => ( "SSLV3_ALERT_CERTIFICATE_REVOKED" , false ) ,
3046- "sslv3 alert certificate expired" => ( "SSLV3_ALERT_CERTIFICATE_EXPIRED" , false ) ,
3047- "wrong version number" => ( "WRONG_VERSION_NUMBER" , false ) ,
3048- "wrong ssl version" => ( "WRONG_SSL_VERSION" , false ) ,
3049- _ => ( default_errstr, false ) ,
3050- } ;
3053+
3054+ // Get error codes - same approach as CPython
3055+ // CPython: Modules/_ssl.c:474-496
3056+ let lib = sys:: ERR_GET_LIB ( e. code ( ) ) ;
3057+ let reason = sys:: ERR_GET_REASON ( e. code ( ) ) ;
3058+
3059+ // Look up error mnemonic from our static tables
3060+ // CPython uses dict lookup: err_codes_to_names[(lib, reason)]
3061+ let key = super :: ssl_data:: encode_error_key ( lib, reason) ;
3062+ let errstr = super :: ssl_data:: ERROR_CODES
3063+ . get ( & key)
3064+ . copied ( )
3065+ . or_else ( || {
3066+ // Fallback: use OpenSSL's error string
3067+ e. reason ( )
3068+ } )
3069+ . unwrap_or ( "unknown error" ) ;
3070+
3071+ // Check if this is a certificate verification error
3072+ // CPython: Modules/_ssl.c:663-666, 683-686
3073+ // ERR_LIB_SSL = 20 (from _ssl_data_300.h)
3074+ // SSL_R_CERTIFICATE_VERIFY_FAILED = 134 (from _ssl_data_300.h)
3075+ let is_cert_verify_error = lib == 20 && reason == 134 ;
3076+
3077+ // Look up library name from our static table
3078+ // CPython uses: lib_codes_to_names[lib]
3079+ let lib_name = super :: ssl_data:: LIBRARY_CODES . get ( & ( lib as u32 ) ) . copied ( ) ;
30513080
30523081 // Use SSLCertVerificationError for certificate verification failures
30533082 let cls = if is_cert_verify_error {
@@ -3057,9 +3086,9 @@ mod _ssl {
30573086 } ;
30583087
30593088 // Build message
3060- let lib_obj = e . library ( ) ;
3061- let msg = if let Some ( lib ) = lib_obj {
3062- format ! ( "[{lib }] {errstr} ({file}:{line})" )
3089+ // CPython: Modules/_ssl.c:539-549
3090+ let msg = if let Some ( lib_str ) = lib_name {
3091+ format ! ( "[{lib_str }] {errstr} ({file}:{line})" )
30633092 } else {
30643093 format ! ( "{errstr} ({file}:{line})" )
30653094 } ;
@@ -3079,8 +3108,8 @@ mod _ssl {
30793108 let _ = exc_obj. set_attr ( "reason" , reason_value, vm) ;
30803109
30813110 // Set library attribute (None if not available)
3082- let library_value: PyObjectRef = if let Some ( lib ) = lib_obj {
3083- vm. ctx . new_str ( lib ) . into ( )
3111+ let library_value: PyObjectRef = if let Some ( lib_str ) = lib_name {
3112+ vm. ctx . new_str ( lib_str ) . into ( )
30843113 } else {
30853114 vm. ctx . none ( )
30863115 } ;
0 commit comments