@@ -106,6 +106,46 @@ fn obj2py(obj: &Asn1ObjectRef) -> PyNid {
106
106
)
107
107
}
108
108
109
+ #[ cfg( windows) ]
110
+ fn ssl_enum_certificates ( store_name : PyStringRef , vm : & VirtualMachine ) -> PyResult < PyObjectRef > {
111
+ use crate :: obj:: objset:: PyFrozenSet ;
112
+ use schannel:: { cert_context:: ValidUses , cert_store:: CertStore , RawPointer } ;
113
+ use winapi:: um:: wincrypt;
114
+ // TODO: check every store for it, not just 2 of them:
115
+ // https://github.com/python/cpython/blob/3.8/Modules/_ssl.c#L5603-L5610
116
+ let open_fns = [ CertStore :: open_current_user, CertStore :: open_local_machine] ;
117
+ let stores = open_fns
118
+ . iter ( )
119
+ . filter_map ( |open| open ( store_name. as_str ( ) ) . ok ( ) )
120
+ . collect :: < Vec < _ > > ( ) ;
121
+ let certs = stores. iter ( ) . map ( |s| s. certs ( ) ) . flatten ( ) . map ( |c| {
122
+ let cert = vm. ctx . new_bytes ( c. to_der ( ) . to_owned ( ) ) ;
123
+ let enc_type = unsafe {
124
+ let ptr = c. as_ptr ( ) as wincrypt:: PCCERT_CONTEXT ;
125
+ ( * ptr) . dwCertEncodingType
126
+ } ;
127
+ let enc_type = match enc_type {
128
+ wincrypt:: X509_ASN_ENCODING => vm. new_str ( "x509_asn" . to_owned ( ) ) ,
129
+ wincrypt:: PKCS_7_ASN_ENCODING => vm. new_str ( "pkcs_7_asn" . to_owned ( ) ) ,
130
+ other => vm. new_int ( other) ,
131
+ } ;
132
+ let usage = match c. valid_uses ( ) ? {
133
+ ValidUses :: All => vm. new_bool ( true ) ,
134
+ ValidUses :: Oids ( oids) => {
135
+ PyFrozenSet :: from_iter ( vm, oids. into_iter ( ) . map ( |oid| vm. new_str ( oid) ) )
136
+ . unwrap ( )
137
+ . into_ref ( vm)
138
+ . into_object ( )
139
+ }
140
+ } ;
141
+ Ok ( vm. ctx . new_tuple ( vec ! [ cert, enc_type, usage] ) )
142
+ } ) ;
143
+ let certs = certs
144
+ . collect :: < Result < Vec < _ > , _ > > ( )
145
+ . map_err ( |e| super :: os:: convert_io_error ( vm, e) ) ?;
146
+ Ok ( vm. ctx . new_list ( certs) )
147
+ }
148
+
109
149
#[ derive( FromArgs ) ]
110
150
struct Txt2ObjArgs {
111
151
#[ pyarg( positional_or_keyword) ]
@@ -518,7 +558,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
518
558
& vm. ctx . types . type_type ,
519
559
& vm. ctx . exceptions . os_error ,
520
560
) ;
521
- py_module ! ( vm, "_ssl" , {
561
+ let module = py_module ! ( vm, "_ssl" , {
522
562
"_SSLContext" => PySslContext :: make_class( ctx) ,
523
563
"_SSLSocket" => PySslSocket :: make_class( ctx) ,
524
564
"SSLError" => ssl_error,
@@ -570,5 +610,20 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
570
610
"ALERT_DESCRIPTION_DECODE_ERROR" => ctx. new_int( sys:: SSL_AD_DECODE_ERROR ) ,
571
611
"ALERT_DESCRIPTION_ILLEGAL_PARAMETER" => ctx. new_int( sys:: SSL_AD_ILLEGAL_PARAMETER ) ,
572
612
"ALERT_DESCRIPTION_UNRECOGNIZED_NAME" => ctx. new_int( sys:: SSL_AD_UNRECOGNIZED_NAME ) ,
613
+ } ) ;
614
+
615
+ extend_module_platform_specific ( & module, vm) ;
616
+
617
+ module
618
+ }
619
+
620
+ #[ cfg( windows) ]
621
+ fn extend_module_platform_specific ( module : & PyObjectRef , vm : & VirtualMachine ) {
622
+ let ctx = & vm. ctx ;
623
+ extend_module ! ( vm, module, {
624
+ "enum_certificates" => ctx. new_function( ssl_enum_certificates) ,
573
625
} )
574
626
}
627
+
628
+ #[ cfg( not( windows) ) ]
629
+ fn extend_module_platform_specific ( _module : & PyObjectRef , _vm : & VirtualMachine ) { }
0 commit comments