@@ -1189,6 +1189,69 @@ mod _ssl {
11891189 . map ( cipher_to_tuple)
11901190 }
11911191
1192+ #[ pymethod]
1193+ fn shared_ciphers ( & self , vm : & VirtualMachine ) -> Option < PyObjectRef > {
1194+ #[ cfg( ossl110) ]
1195+ {
1196+ let stream = self . stream . read ( ) ;
1197+ unsafe {
1198+ let server_ciphers = SSL_get_ciphers ( stream. ssl ( ) . as_ptr ( ) ) ;
1199+ if server_ciphers. is_null ( ) {
1200+ return None ;
1201+ }
1202+
1203+ let client_ciphers = SSL_get_client_ciphers ( stream. ssl ( ) . as_ptr ( ) ) ;
1204+ if client_ciphers. is_null ( ) {
1205+ return None ;
1206+ }
1207+
1208+ let mut result = Vec :: new ( ) ;
1209+ let num_server = sys:: OPENSSL_sk_num ( server_ciphers as * const _ ) ;
1210+ let num_client = sys:: OPENSSL_sk_num ( client_ciphers as * const _ ) ;
1211+
1212+ for i in 0 ..num_server {
1213+ let server_cipher_ptr = sys:: OPENSSL_sk_value ( server_ciphers as * const _ , i)
1214+ as * const sys:: SSL_CIPHER ;
1215+
1216+ // Check if client supports this cipher by comparing pointers
1217+ let mut found = false ;
1218+ for j in 0 ..num_client {
1219+ let client_cipher_ptr =
1220+ sys:: OPENSSL_sk_value ( client_ciphers as * const _ , j)
1221+ as * const sys:: SSL_CIPHER ;
1222+
1223+ if server_cipher_ptr == client_cipher_ptr {
1224+ found = true ;
1225+ break ;
1226+ }
1227+ }
1228+
1229+ if found {
1230+ let cipher = ssl:: SslCipherRef :: from_ptr ( server_cipher_ptr as * mut _ ) ;
1231+ let ( name, version, bits) = cipher_to_tuple ( cipher) ;
1232+ let tuple = vm. new_tuple ( (
1233+ vm. ctx . new_str ( name) ,
1234+ vm. ctx . new_str ( version) ,
1235+ vm. ctx . new_int ( bits) ,
1236+ ) ) ;
1237+ result. push ( tuple. into ( ) ) ;
1238+ }
1239+ }
1240+
1241+ if result. is_empty ( ) {
1242+ None
1243+ } else {
1244+ Some ( vm. ctx . new_list ( result) . into ( ) )
1245+ }
1246+ }
1247+ }
1248+ #[ cfg( not( ossl110) ) ]
1249+ {
1250+ let _ = vm;
1251+ None
1252+ }
1253+ }
1254+
11921255 #[ pymethod]
11931256 fn selected_alpn_protocol ( & self ) -> Option < String > {
11941257 #[ cfg( ossl102) ]
@@ -1564,6 +1627,16 @@ mod _ssl {
15641627 unsafe impl Send for PySslMemoryBio { }
15651628 unsafe impl Sync for PySslMemoryBio { }
15661629
1630+ // OpenSSL functions not in openssl-sys
1631+ unsafe extern "C" {
1632+ fn SSL_get_ciphers ( ssl : * const sys:: SSL ) -> * const sys:: stack_st_SSL_CIPHER ;
1633+ }
1634+
1635+ #[ cfg( ossl110) ]
1636+ unsafe extern "C" {
1637+ fn SSL_get_client_ciphers ( ssl : * const sys:: SSL ) -> * const sys:: stack_st_SSL_CIPHER ;
1638+ }
1639+
15671640 // OpenSSL BIO helper functions
15681641 // These are typically macros in OpenSSL, implemented via BIO_ctrl
15691642 const BIO_CTRL_PENDING : libc:: c_int = 10 ;
0 commit comments