Repository navigation
Fix windows ssl #3210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix windows ssl #3210
Changes from all commits
8223cb3
6d4de56
61c3e9b
f8c45d1
7d47878
7ba2187
dba3249
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,33 +22,50 @@ use openssl::{ | |
| error::ErrorStack, | ||
| nid::Nid, | ||
| ssl::{self, SslContextBuilder, SslOptions, SslVerifyMode}, | ||
| x509::{self, X509Object, X509Ref, X509}, | ||
| x509::{self, X509Ref, X509}, | ||
| }; | ||
| use std::convert::TryFrom; | ||
| use std::ffi::CStr; | ||
| use std::fmt; | ||
| use std::io::{Read, Write}; | ||
| use std::time::Instant; | ||
|
|
||
| mod sys { | ||
| #![allow(non_camel_case_types, unused)] | ||
| use libc::{c_char, c_double, c_int, c_long, c_void}; | ||
| pub use openssl_sys::*; | ||
| extern "C" { | ||
| pub fn OBJ_txt2obj(s: *const c_char, no_name: c_int) -> *mut ASN1_OBJECT; | ||
| pub fn OBJ_nid2obj(n: c_int) -> *mut ASN1_OBJECT; | ||
| pub fn X509_get_default_cert_file_env() -> *const c_char; | ||
| pub fn X509_get_default_cert_file() -> *const c_char; | ||
| pub fn X509_get_default_cert_dir_env() -> *const c_char; | ||
| pub fn X509_get_default_cert_dir() -> *const c_char; | ||
| #[cfg(ossl111)] | ||
| pub fn SSL_CTX_set_post_handshake_auth(ctx: *mut SSL_CTX, val: c_int); | ||
| pub fn RAND_add(buf: *const c_void, num: c_int, randomness: c_double); | ||
| pub fn RAND_pseudo_bytes(buf: *const u8, num: c_int) -> c_int; | ||
| pub fn X509_get_version(x: *const X509) -> c_long; | ||
| pub fn SSLv3_method() -> *const SSL_METHOD; | ||
| pub fn TLSv1_method() -> *const SSL_METHOD; | ||
| pub fn COMP_get_type(meth: *const COMP_METHOD) -> i32; | ||
| use openssl_sys as sys; | ||
|
|
||
| mod bio { | ||
| //! based off rust-openssl's private `bio` module | ||
|
|
||
| use super::*; | ||
|
|
||
| use libc::c_int; | ||
| use std::marker::PhantomData; | ||
|
|
||
| pub struct MemBioSlice<'a>(*mut sys::BIO, PhantomData<&'a [u8]>); | ||
|
|
||
| impl<'a> Drop for MemBioSlice<'a> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| sys::BIO_free_all(self.0); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<'a> MemBioSlice<'a> { | ||
| pub fn new(buf: &'a [u8]) -> Result<MemBioSlice<'a>, ErrorStack> { | ||
| openssl::init(); | ||
|
|
||
| assert!(buf.len() <= c_int::max_value() as usize); | ||
| let bio = unsafe { sys::BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int) }; | ||
| if bio.is_null() { | ||
| return Err(ErrorStack::get()); | ||
| } | ||
|
|
||
| Ok(MemBioSlice(bio, PhantomData)) | ||
| } | ||
|
|
||
| pub fn as_ptr(&self) -> *mut sys::BIO { | ||
| self.0 | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -119,9 +136,17 @@ fn obj2txt(obj: &Asn1ObjectRef, no_name: bool) -> Option<String> { | |
| if buflen == 0 { | ||
| return None; | ||
| } | ||
| let mut buf = vec![0u8; buflen as usize]; | ||
| let ret = sys::OBJ_obj2txt(buf.as_mut_ptr() as *mut libc::c_char, buflen, ptr, no_name); | ||
| let buflen = buflen as usize; | ||
| let mut buf = Vec::<u8>::with_capacity(buflen + 1); | ||
| let ret = sys::OBJ_obj2txt( | ||
| buf.as_mut_ptr() as *mut libc::c_char, | ||
| buf.capacity() as _, | ||
| ptr, | ||
| no_name, | ||
| ); | ||
| assert!(ret >= 0); | ||
| // SAFETY: set_len is safe when capacity is enoguh and all values are already initialized | ||
| buf.set_len(buflen); | ||
| String::from_utf8(buf) | ||
| .unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned()) | ||
| }; | ||
|
|
@@ -243,7 +268,7 @@ fn _ssl_rand_pseudo_bytes(n: i32, vm: &VirtualMachine) -> PyResult<(Vec<u8>, boo | |
| return Err(vm.new_value_error("num must be positive".to_owned())); | ||
| } | ||
| let mut buf = vec![0; n as usize]; | ||
| let ret = unsafe { sys::RAND_pseudo_bytes(buf.as_mut_ptr(), n) }; | ||
| let ret = unsafe { sys::RAND_bytes(buf.as_mut_ptr(), n) }; | ||
| match ret { | ||
| 0 | 1 => Ok((buf, ret == 1)), | ||
| _ => Err(convert_openssl_error(vm, ErrorStack::get())), | ||
|
|
@@ -277,7 +302,6 @@ impl SlotConstructor for PySslContext { | |
| let method = match proto { | ||
| // SslVersion::Ssl3 => unsafe { ssl::SslMethod::from_ptr(sys::SSLv3_method()) }, | ||
| SslVersion::Tls => ssl::SslMethod::tls(), | ||
| SslVersion::Tls1 => unsafe { ssl::SslMethod::from_ptr(sys::TLSv1_method()) }, | ||
| // TODO: Tls1_1, Tls1_2 ? | ||
| SslVersion::TlsClient => ssl::SslMethod::tls_client(), | ||
| SslVersion::TlsServer => ssl::SslMethod::tls_server(), | ||
|
|
@@ -461,22 +485,22 @@ impl PySslContext { | |
| } | ||
|
|
||
| if let Some(cadata) = args.cadata { | ||
| let cert = match cadata { | ||
| let certs = match cadata { | ||
| Either::A(s) => { | ||
| if !s.as_str().is_ascii() { | ||
| if !s.is_ascii() { | ||
| return Err(vm.new_type_error("Must be an ascii string".to_owned())); | ||
| } | ||
| X509::from_pem(s.as_str().as_bytes()) | ||
| X509::stack_from_pem(s.as_str().as_bytes()) | ||
| } | ||
| Either::B(b) => b.with_ref(X509::from_der), | ||
| Either::B(b) => b.with_ref(x509_stack_from_der), | ||
| }; | ||
| let cert = cert.map_err(|e| convert_openssl_error(vm, e))?; | ||
| let ret = self.exec_ctx(|ctx| { | ||
| let store = ctx.cert_store(); | ||
| unsafe { sys::X509_STORE_add_cert(store.as_ptr(), cert.as_ptr()) } | ||
| }); | ||
| if ret <= 0 { | ||
| return Err(convert_openssl_error(vm, ErrorStack::get())); | ||
| let certs = certs.map_err(|e| convert_openssl_error(vm, e))?; | ||
| let mut ctx = self.builder(); | ||
| let store = ctx.cert_store_mut(); | ||
| for cert in certs { | ||
| store | ||
| .add_cert(cert) | ||
| .map_err(|e| convert_openssl_error(vm, e))?; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -511,22 +535,17 @@ impl PySslContext { | |
|
|
||
| #[pymethod] | ||
| fn get_ca_certs(&self, binary_form: OptionalArg<bool>, vm: &VirtualMachine) -> PyResult { | ||
| use openssl::stack::StackRef; | ||
| let binary_form = binary_form.unwrap_or(false); | ||
| let certs = unsafe { | ||
| let stack = | ||
| sys::X509_STORE_get0_objects(self.exec_ctx(|ctx| ctx.cert_store().as_ptr())); | ||
| assert!(!stack.is_null()); | ||
| StackRef::<X509Object>::from_ptr(stack) | ||
| }; | ||
| let certs = certs | ||
| .iter() | ||
| .filter_map(|cert| { | ||
| let cert = cert.x509()?; | ||
| Some(cert_to_py(vm, cert, binary_form)) | ||
| }) | ||
| .collect::<Result<Vec<_>, _>>()?; | ||
| Ok(vm.ctx.new_list(certs)) | ||
| self.exec_ctx(|ctx| { | ||
| let certs = ctx | ||
| .cert_store() | ||
| .objects() | ||
| .iter() | ||
| .filter_map(|obj| obj.x509()) | ||
| .map(|cert| cert_to_py(vm, cert, binary_form)) | ||
| .collect::<Result<Vec<_>, _>>()?; | ||
| Ok(vm.ctx.new_list(certs)) | ||
| }) | ||
| } | ||
|
|
||
| #[pymethod] | ||
|
|
@@ -949,19 +968,30 @@ fn ssl_error(vm: &VirtualMachine) -> PyTypeRef { | |
| vm.class("_ssl", "SSLError") | ||
| } | ||
|
|
||
| #[track_caller] | ||
| fn convert_openssl_error(vm: &VirtualMachine, err: ErrorStack) -> PyBaseExceptionRef { | ||
| let cls = ssl_error(vm); | ||
| match err.errors().last() { | ||
| Some(e) => { | ||
| let caller = std::panic::Location::caller(); | ||
| let (file, line) = (caller.file(), caller.line()); | ||
| let file = file | ||
| .rsplit_once(&['/', '\\'][..]) | ||
| .map_or(file, |(_, basename)| basename); | ||
| // TODO: map the error codes to code names, e.g. "CERTIFICATE_VERIFY_FAILED", just requires a big hashmap/dict | ||
| let errstr = e.reason().unwrap_or("unknown error"); | ||
| let msg = format!("{} (_ssl.c:{})", errstr, e.line()); | ||
| let msg = if let Some(lib) = e.library() { | ||
| format!("[{}] {} ({}:{})", lib, errstr, file, line) | ||
| } else { | ||
| format!("{} ({}:{})", errstr, file, line) | ||
| }; | ||
| let reason = sys::ERR_GET_REASON(e.code()); | ||
| vm.new_exception(cls, vec![vm.ctx.new_int(reason), vm.ctx.new_utf8_str(msg)]) | ||
| } | ||
| None => vm.new_exception_empty(cls), | ||
| } | ||
| } | ||
| #[track_caller] | ||
| fn convert_ssl_error( | ||
| vm: &VirtualMachine, | ||
| e: impl std::borrow::Borrow<ssl::Error>, | ||
|
|
@@ -992,6 +1022,33 @@ fn convert_ssl_error( | |
| vm.new_exception_msg(cls, msg.to_owned()) | ||
| } | ||
|
|
||
| fn x509_stack_from_der(der: &[u8]) -> Result<Vec<X509>, ErrorStack> { | ||
| unsafe { | ||
| openssl::init(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of rust-openssl's functions call |
||
| let bio = bio::MemBioSlice::new(der)?; | ||
|
|
||
| let mut certs = vec![]; | ||
| loop { | ||
| let r = sys::d2i_X509_bio(bio.as_ptr(), std::ptr::null_mut()); | ||
| if r.is_null() { | ||
| let err = sys::ERR_peek_last_error(); | ||
| if sys::ERR_GET_LIB(err) == sys::ERR_LIB_ASN1 | ||
| && sys::ERR_GET_REASON(err) == sys::ASN1_R_HEADER_TOO_LONG | ||
| { | ||
| sys::ERR_clear_error(); | ||
| break; | ||
| } | ||
|
|
||
| return Err(ErrorStack::get()); | ||
| } else { | ||
| certs.push(X509::from_ptr(r)); | ||
| } | ||
| } | ||
|
|
||
| Ok(certs) | ||
| } | ||
| } | ||
|
|
||
| type CipherTuple = (&'static str, &'static str, i32); | ||
|
|
||
| fn cipher_to_tuple(cipher: &ssl::SslCipherRef) -> CipherTuple { | ||
|
|
@@ -1019,9 +1076,7 @@ fn cert_to_py(vm: &VirtualMachine, cert: &X509Ref, binary: bool) -> PyResult { | |
|
|
||
| dict.set_item("subject", name_to_py(cert.subject_name())?, vm)?; | ||
| dict.set_item("issuer", name_to_py(cert.issuer_name())?, vm)?; | ||
|
|
||
| let version = unsafe { sys::X509_get_version(cert.as_ptr()) }; | ||
| dict.set_item("version", vm.ctx.new_int(version), vm)?; | ||
| dict.set_item("version", vm.ctx.new_int(cert.version()), vm)?; | ||
|
|
||
| let serial_num = cert | ||
| .serial_number() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| fn main() { | ||
| if cfg!(windows) { | ||
| if let Ok(real_path) = std::fs::read_to_string("Lib") { | ||
| println!("rustc-env:win_lib_path={:?}", real_path); | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.