192f3ab15Sopenharmony_ci//! Errors returned by OpenSSL library.
292f3ab15Sopenharmony_ci//!
392f3ab15Sopenharmony_ci//! OpenSSL errors are stored in an `ErrorStack`.  Most methods in the crate
492f3ab15Sopenharmony_ci//! returns a `Result<T, ErrorStack>` type.
592f3ab15Sopenharmony_ci//!
692f3ab15Sopenharmony_ci//! # Examples
792f3ab15Sopenharmony_ci//!
892f3ab15Sopenharmony_ci//! ```
992f3ab15Sopenharmony_ci//! use openssl::error::ErrorStack;
1092f3ab15Sopenharmony_ci//! use openssl::bn::BigNum;
1192f3ab15Sopenharmony_ci//!
1292f3ab15Sopenharmony_ci//! let an_error = BigNum::from_dec_str("Cannot parse letters");
1392f3ab15Sopenharmony_ci//! match an_error {
1492f3ab15Sopenharmony_ci//!     Ok(_)  => (),
1592f3ab15Sopenharmony_ci//!     Err(e) => println!("Parsing Error: {:?}", e),
1692f3ab15Sopenharmony_ci//! }
1792f3ab15Sopenharmony_ci//! ```
1892f3ab15Sopenharmony_ciuse cfg_if::cfg_if;
1992f3ab15Sopenharmony_ciuse libc::{c_char, c_int};
2092f3ab15Sopenharmony_ciuse std::borrow::Cow;
2192f3ab15Sopenharmony_ci#[cfg(boringssl)]
2292f3ab15Sopenharmony_ciuse std::convert::TryInto;
2392f3ab15Sopenharmony_ciuse std::error;
2492f3ab15Sopenharmony_ciuse std::ffi::CStr;
2592f3ab15Sopenharmony_ciuse std::fmt;
2692f3ab15Sopenharmony_ciuse std::io;
2792f3ab15Sopenharmony_ciuse std::ptr;
2892f3ab15Sopenharmony_ciuse std::str;
2992f3ab15Sopenharmony_ci
3092f3ab15Sopenharmony_ci#[cfg(not(boringssl))]
3192f3ab15Sopenharmony_citype ErrType = libc::c_ulong;
3292f3ab15Sopenharmony_ci#[cfg(boringssl)]
3392f3ab15Sopenharmony_citype ErrType = libc::c_uint;
3492f3ab15Sopenharmony_ci
3592f3ab15Sopenharmony_ci/// Collection of [`Error`]s from OpenSSL.
3692f3ab15Sopenharmony_ci///
3792f3ab15Sopenharmony_ci/// [`Error`]: struct.Error.html
3892f3ab15Sopenharmony_ci#[derive(Debug, Clone)]
3992f3ab15Sopenharmony_cipub struct ErrorStack(Vec<Error>);
4092f3ab15Sopenharmony_ci
4192f3ab15Sopenharmony_ciimpl ErrorStack {
4292f3ab15Sopenharmony_ci    /// Returns the contents of the OpenSSL error stack.
4392f3ab15Sopenharmony_ci    pub fn get() -> ErrorStack {
4492f3ab15Sopenharmony_ci        let mut vec = vec![];
4592f3ab15Sopenharmony_ci        while let Some(err) = Error::get() {
4692f3ab15Sopenharmony_ci            vec.push(err);
4792f3ab15Sopenharmony_ci        }
4892f3ab15Sopenharmony_ci        ErrorStack(vec)
4992f3ab15Sopenharmony_ci    }
5092f3ab15Sopenharmony_ci
5192f3ab15Sopenharmony_ci    /// Pushes the errors back onto the OpenSSL error stack.
5292f3ab15Sopenharmony_ci    pub fn put(&self) {
5392f3ab15Sopenharmony_ci        for error in self.errors() {
5492f3ab15Sopenharmony_ci            error.put();
5592f3ab15Sopenharmony_ci        }
5692f3ab15Sopenharmony_ci    }
5792f3ab15Sopenharmony_ci}
5892f3ab15Sopenharmony_ci
5992f3ab15Sopenharmony_ciimpl ErrorStack {
6092f3ab15Sopenharmony_ci    /// Returns the errors in the stack.
6192f3ab15Sopenharmony_ci    pub fn errors(&self) -> &[Error] {
6292f3ab15Sopenharmony_ci        &self.0
6392f3ab15Sopenharmony_ci    }
6492f3ab15Sopenharmony_ci}
6592f3ab15Sopenharmony_ci
6692f3ab15Sopenharmony_ciimpl fmt::Display for ErrorStack {
6792f3ab15Sopenharmony_ci    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
6892f3ab15Sopenharmony_ci        if self.0.is_empty() {
6992f3ab15Sopenharmony_ci            return fmt.write_str("OpenSSL error");
7092f3ab15Sopenharmony_ci        }
7192f3ab15Sopenharmony_ci
7292f3ab15Sopenharmony_ci        let mut first = true;
7392f3ab15Sopenharmony_ci        for err in &self.0 {
7492f3ab15Sopenharmony_ci            if !first {
7592f3ab15Sopenharmony_ci                fmt.write_str(", ")?;
7692f3ab15Sopenharmony_ci            }
7792f3ab15Sopenharmony_ci            write!(fmt, "{}", err)?;
7892f3ab15Sopenharmony_ci            first = false;
7992f3ab15Sopenharmony_ci        }
8092f3ab15Sopenharmony_ci        Ok(())
8192f3ab15Sopenharmony_ci    }
8292f3ab15Sopenharmony_ci}
8392f3ab15Sopenharmony_ci
8492f3ab15Sopenharmony_ciimpl error::Error for ErrorStack {}
8592f3ab15Sopenharmony_ci
8692f3ab15Sopenharmony_ciimpl From<ErrorStack> for io::Error {
8792f3ab15Sopenharmony_ci    fn from(e: ErrorStack) -> io::Error {
8892f3ab15Sopenharmony_ci        io::Error::new(io::ErrorKind::Other, e)
8992f3ab15Sopenharmony_ci    }
9092f3ab15Sopenharmony_ci}
9192f3ab15Sopenharmony_ci
9292f3ab15Sopenharmony_ciimpl From<ErrorStack> for fmt::Error {
9392f3ab15Sopenharmony_ci    fn from(_: ErrorStack) -> fmt::Error {
9492f3ab15Sopenharmony_ci        fmt::Error
9592f3ab15Sopenharmony_ci    }
9692f3ab15Sopenharmony_ci}
9792f3ab15Sopenharmony_ci
9892f3ab15Sopenharmony_ci/// An error reported from OpenSSL.
9992f3ab15Sopenharmony_ci#[derive(Clone)]
10092f3ab15Sopenharmony_cipub struct Error {
10192f3ab15Sopenharmony_ci    code: ErrType,
10292f3ab15Sopenharmony_ci    file: ShimStr,
10392f3ab15Sopenharmony_ci    line: c_int,
10492f3ab15Sopenharmony_ci    func: Option<ShimStr>,
10592f3ab15Sopenharmony_ci    data: Option<Cow<'static, str>>,
10692f3ab15Sopenharmony_ci}
10792f3ab15Sopenharmony_ci
10892f3ab15Sopenharmony_ciunsafe impl Sync for Error {}
10992f3ab15Sopenharmony_ciunsafe impl Send for Error {}
11092f3ab15Sopenharmony_ci
11192f3ab15Sopenharmony_ciimpl Error {
11292f3ab15Sopenharmony_ci    /// Returns the first error on the OpenSSL error stack.
11392f3ab15Sopenharmony_ci    pub fn get() -> Option<Error> {
11492f3ab15Sopenharmony_ci        unsafe {
11592f3ab15Sopenharmony_ci            ffi::init();
11692f3ab15Sopenharmony_ci
11792f3ab15Sopenharmony_ci            let mut file = ptr::null();
11892f3ab15Sopenharmony_ci            let mut line = 0;
11992f3ab15Sopenharmony_ci            let mut func = ptr::null();
12092f3ab15Sopenharmony_ci            let mut data = ptr::null();
12192f3ab15Sopenharmony_ci            let mut flags = 0;
12292f3ab15Sopenharmony_ci            match ERR_get_error_all(&mut file, &mut line, &mut func, &mut data, &mut flags) {
12392f3ab15Sopenharmony_ci                0 => None,
12492f3ab15Sopenharmony_ci                code => {
12592f3ab15Sopenharmony_ci                    // The memory referenced by data is only valid until that slot is overwritten
12692f3ab15Sopenharmony_ci                    // in the error stack, so we'll need to copy it off if it's dynamic
12792f3ab15Sopenharmony_ci                    let data = if flags & ffi::ERR_TXT_STRING != 0 {
12892f3ab15Sopenharmony_ci                        let bytes = CStr::from_ptr(data as *const _).to_bytes();
12992f3ab15Sopenharmony_ci                        let data = str::from_utf8(bytes).unwrap();
13092f3ab15Sopenharmony_ci                        #[cfg(not(boringssl))]
13192f3ab15Sopenharmony_ci                        let data = if flags & ffi::ERR_TXT_MALLOCED != 0 {
13292f3ab15Sopenharmony_ci                            Cow::Owned(data.to_string())
13392f3ab15Sopenharmony_ci                        } else {
13492f3ab15Sopenharmony_ci                            Cow::Borrowed(data)
13592f3ab15Sopenharmony_ci                        };
13692f3ab15Sopenharmony_ci                        #[cfg(boringssl)]
13792f3ab15Sopenharmony_ci                        let data = Cow::Borrowed(data);
13892f3ab15Sopenharmony_ci                        Some(data)
13992f3ab15Sopenharmony_ci                    } else {
14092f3ab15Sopenharmony_ci                        None
14192f3ab15Sopenharmony_ci                    };
14292f3ab15Sopenharmony_ci
14392f3ab15Sopenharmony_ci                    let file = ShimStr::new(file);
14492f3ab15Sopenharmony_ci
14592f3ab15Sopenharmony_ci                    let func = if func.is_null() {
14692f3ab15Sopenharmony_ci                        None
14792f3ab15Sopenharmony_ci                    } else {
14892f3ab15Sopenharmony_ci                        Some(ShimStr::new(func))
14992f3ab15Sopenharmony_ci                    };
15092f3ab15Sopenharmony_ci
15192f3ab15Sopenharmony_ci                    Some(Error {
15292f3ab15Sopenharmony_ci                        code,
15392f3ab15Sopenharmony_ci                        file,
15492f3ab15Sopenharmony_ci                        line,
15592f3ab15Sopenharmony_ci                        func,
15692f3ab15Sopenharmony_ci                        data,
15792f3ab15Sopenharmony_ci                    })
15892f3ab15Sopenharmony_ci                }
15992f3ab15Sopenharmony_ci            }
16092f3ab15Sopenharmony_ci        }
16192f3ab15Sopenharmony_ci    }
16292f3ab15Sopenharmony_ci
16392f3ab15Sopenharmony_ci    /// Pushes the error back onto the OpenSSL error stack.
16492f3ab15Sopenharmony_ci    pub fn put(&self) {
16592f3ab15Sopenharmony_ci        self.put_error();
16692f3ab15Sopenharmony_ci
16792f3ab15Sopenharmony_ci        unsafe {
16892f3ab15Sopenharmony_ci            let data = match self.data {
16992f3ab15Sopenharmony_ci                Some(Cow::Borrowed(data)) => Some((data.as_ptr() as *mut c_char, 0)),
17092f3ab15Sopenharmony_ci                Some(Cow::Owned(ref data)) => {
17192f3ab15Sopenharmony_ci                    let ptr = ffi::CRYPTO_malloc(
17292f3ab15Sopenharmony_ci                        (data.len() + 1) as _,
17392f3ab15Sopenharmony_ci                        concat!(file!(), "\0").as_ptr() as _,
17492f3ab15Sopenharmony_ci                        line!() as _,
17592f3ab15Sopenharmony_ci                    ) as *mut c_char;
17692f3ab15Sopenharmony_ci                    if ptr.is_null() {
17792f3ab15Sopenharmony_ci                        None
17892f3ab15Sopenharmony_ci                    } else {
17992f3ab15Sopenharmony_ci                        ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());
18092f3ab15Sopenharmony_ci                        *ptr.add(data.len()) = 0;
18192f3ab15Sopenharmony_ci                        Some((ptr, ffi::ERR_TXT_MALLOCED))
18292f3ab15Sopenharmony_ci                    }
18392f3ab15Sopenharmony_ci                }
18492f3ab15Sopenharmony_ci                None => None,
18592f3ab15Sopenharmony_ci            };
18692f3ab15Sopenharmony_ci            if let Some((ptr, flags)) = data {
18792f3ab15Sopenharmony_ci                ffi::ERR_set_error_data(ptr, flags | ffi::ERR_TXT_STRING);
18892f3ab15Sopenharmony_ci            }
18992f3ab15Sopenharmony_ci        }
19092f3ab15Sopenharmony_ci    }
19192f3ab15Sopenharmony_ci
19292f3ab15Sopenharmony_ci    #[cfg(ossl300)]
19392f3ab15Sopenharmony_ci    fn put_error(&self) {
19492f3ab15Sopenharmony_ci        unsafe {
19592f3ab15Sopenharmony_ci            ffi::ERR_new();
19692f3ab15Sopenharmony_ci            ffi::ERR_set_debug(
19792f3ab15Sopenharmony_ci                self.file.as_ptr(),
19892f3ab15Sopenharmony_ci                self.line,
19992f3ab15Sopenharmony_ci                self.func.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
20092f3ab15Sopenharmony_ci            );
20192f3ab15Sopenharmony_ci            ffi::ERR_set_error(self.library_code(), self.reason_code(), ptr::null());
20292f3ab15Sopenharmony_ci        }
20392f3ab15Sopenharmony_ci    }
20492f3ab15Sopenharmony_ci
20592f3ab15Sopenharmony_ci    #[cfg(not(ossl300))]
20692f3ab15Sopenharmony_ci    fn put_error(&self) {
20792f3ab15Sopenharmony_ci        #[cfg(not(boringssl))]
20892f3ab15Sopenharmony_ci        let line = self.line;
20992f3ab15Sopenharmony_ci        #[cfg(boringssl)]
21092f3ab15Sopenharmony_ci        let line = self.line.try_into().unwrap();
21192f3ab15Sopenharmony_ci        unsafe {
21292f3ab15Sopenharmony_ci            ffi::ERR_put_error(
21392f3ab15Sopenharmony_ci                self.library_code(),
21492f3ab15Sopenharmony_ci                ffi::ERR_GET_FUNC(self.code),
21592f3ab15Sopenharmony_ci                self.reason_code(),
21692f3ab15Sopenharmony_ci                self.file.as_ptr(),
21792f3ab15Sopenharmony_ci                line,
21892f3ab15Sopenharmony_ci            );
21992f3ab15Sopenharmony_ci        }
22092f3ab15Sopenharmony_ci    }
22192f3ab15Sopenharmony_ci
22292f3ab15Sopenharmony_ci    /// Returns the raw OpenSSL error code for this error.
22392f3ab15Sopenharmony_ci    pub fn code(&self) -> ErrType {
22492f3ab15Sopenharmony_ci        self.code
22592f3ab15Sopenharmony_ci    }
22692f3ab15Sopenharmony_ci
22792f3ab15Sopenharmony_ci    /// Returns the name of the library reporting the error, if available.
22892f3ab15Sopenharmony_ci    pub fn library(&self) -> Option<&'static str> {
22992f3ab15Sopenharmony_ci        unsafe {
23092f3ab15Sopenharmony_ci            let cstr = ffi::ERR_lib_error_string(self.code);
23192f3ab15Sopenharmony_ci            if cstr.is_null() {
23292f3ab15Sopenharmony_ci                return None;
23392f3ab15Sopenharmony_ci            }
23492f3ab15Sopenharmony_ci            let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
23592f3ab15Sopenharmony_ci            Some(str::from_utf8(bytes).unwrap())
23692f3ab15Sopenharmony_ci        }
23792f3ab15Sopenharmony_ci    }
23892f3ab15Sopenharmony_ci
23992f3ab15Sopenharmony_ci    /// Returns the raw OpenSSL error constant for the library reporting the
24092f3ab15Sopenharmony_ci    /// error.
24192f3ab15Sopenharmony_ci    // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on
24292f3ab15Sopenharmony_ci    // OpenSSL/LibreSSL they're safe.
24392f3ab15Sopenharmony_ci    #[allow(unused_unsafe)]
24492f3ab15Sopenharmony_ci    pub fn library_code(&self) -> libc::c_int {
24592f3ab15Sopenharmony_ci        unsafe { ffi::ERR_GET_LIB(self.code) }
24692f3ab15Sopenharmony_ci    }
24792f3ab15Sopenharmony_ci
24892f3ab15Sopenharmony_ci    /// Returns the name of the function reporting the error.
24992f3ab15Sopenharmony_ci    pub fn function(&self) -> Option<RetStr<'_>> {
25092f3ab15Sopenharmony_ci        self.func.as_ref().map(|s| s.as_str())
25192f3ab15Sopenharmony_ci    }
25292f3ab15Sopenharmony_ci
25392f3ab15Sopenharmony_ci    /// Returns the reason for the error.
25492f3ab15Sopenharmony_ci    pub fn reason(&self) -> Option<&'static str> {
25592f3ab15Sopenharmony_ci        unsafe {
25692f3ab15Sopenharmony_ci            let cstr = ffi::ERR_reason_error_string(self.code);
25792f3ab15Sopenharmony_ci            if cstr.is_null() {
25892f3ab15Sopenharmony_ci                return None;
25992f3ab15Sopenharmony_ci            }
26092f3ab15Sopenharmony_ci            let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
26192f3ab15Sopenharmony_ci            Some(str::from_utf8(bytes).unwrap())
26292f3ab15Sopenharmony_ci        }
26392f3ab15Sopenharmony_ci    }
26492f3ab15Sopenharmony_ci
26592f3ab15Sopenharmony_ci    /// Returns the raw OpenSSL error constant for the reason for the error.
26692f3ab15Sopenharmony_ci    // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on
26792f3ab15Sopenharmony_ci    // OpenSSL/LibreSSL they're safe.
26892f3ab15Sopenharmony_ci    #[allow(unused_unsafe)]
26992f3ab15Sopenharmony_ci    pub fn reason_code(&self) -> libc::c_int {
27092f3ab15Sopenharmony_ci        unsafe { ffi::ERR_GET_REASON(self.code) }
27192f3ab15Sopenharmony_ci    }
27292f3ab15Sopenharmony_ci
27392f3ab15Sopenharmony_ci    /// Returns the name of the source file which encountered the error.
27492f3ab15Sopenharmony_ci    pub fn file(&self) -> RetStr<'_> {
27592f3ab15Sopenharmony_ci        self.file.as_str()
27692f3ab15Sopenharmony_ci    }
27792f3ab15Sopenharmony_ci
27892f3ab15Sopenharmony_ci    /// Returns the line in the source file which encountered the error.
27992f3ab15Sopenharmony_ci    pub fn line(&self) -> u32 {
28092f3ab15Sopenharmony_ci        self.line as u32
28192f3ab15Sopenharmony_ci    }
28292f3ab15Sopenharmony_ci
28392f3ab15Sopenharmony_ci    /// Returns additional data describing the error.
28492f3ab15Sopenharmony_ci    #[allow(clippy::option_as_ref_deref)]
28592f3ab15Sopenharmony_ci    pub fn data(&self) -> Option<&str> {
28692f3ab15Sopenharmony_ci        self.data.as_ref().map(|s| &**s)
28792f3ab15Sopenharmony_ci    }
28892f3ab15Sopenharmony_ci}
28992f3ab15Sopenharmony_ci
29092f3ab15Sopenharmony_ciimpl fmt::Debug for Error {
29192f3ab15Sopenharmony_ci    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
29292f3ab15Sopenharmony_ci        let mut builder = fmt.debug_struct("Error");
29392f3ab15Sopenharmony_ci        builder.field("code", &self.code());
29492f3ab15Sopenharmony_ci        if let Some(library) = self.library() {
29592f3ab15Sopenharmony_ci            builder.field("library", &library);
29692f3ab15Sopenharmony_ci        }
29792f3ab15Sopenharmony_ci        if let Some(function) = self.function() {
29892f3ab15Sopenharmony_ci            builder.field("function", &function);
29992f3ab15Sopenharmony_ci        }
30092f3ab15Sopenharmony_ci        if let Some(reason) = self.reason() {
30192f3ab15Sopenharmony_ci            builder.field("reason", &reason);
30292f3ab15Sopenharmony_ci        }
30392f3ab15Sopenharmony_ci        builder.field("file", &self.file());
30492f3ab15Sopenharmony_ci        builder.field("line", &self.line());
30592f3ab15Sopenharmony_ci        if let Some(data) = self.data() {
30692f3ab15Sopenharmony_ci            builder.field("data", &data);
30792f3ab15Sopenharmony_ci        }
30892f3ab15Sopenharmony_ci        builder.finish()
30992f3ab15Sopenharmony_ci    }
31092f3ab15Sopenharmony_ci}
31192f3ab15Sopenharmony_ci
31292f3ab15Sopenharmony_ciimpl fmt::Display for Error {
31392f3ab15Sopenharmony_ci    // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on
31492f3ab15Sopenharmony_ci    // OpenSSL/LibreSSL they're safe.
31592f3ab15Sopenharmony_ci    #[allow(unused_unsafe)]
31692f3ab15Sopenharmony_ci    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
31792f3ab15Sopenharmony_ci        write!(fmt, "error:{:08X}", self.code())?;
31892f3ab15Sopenharmony_ci        match self.library() {
31992f3ab15Sopenharmony_ci            Some(l) => write!(fmt, ":{}", l)?,
32092f3ab15Sopenharmony_ci            None => write!(fmt, ":lib({})", self.library_code())?,
32192f3ab15Sopenharmony_ci        }
32292f3ab15Sopenharmony_ci        match self.function() {
32392f3ab15Sopenharmony_ci            Some(f) => write!(fmt, ":{}", f)?,
32492f3ab15Sopenharmony_ci            None => write!(fmt, ":func({})", unsafe { ffi::ERR_GET_FUNC(self.code()) })?,
32592f3ab15Sopenharmony_ci        }
32692f3ab15Sopenharmony_ci        match self.reason() {
32792f3ab15Sopenharmony_ci            Some(r) => write!(fmt, ":{}", r)?,
32892f3ab15Sopenharmony_ci            None => write!(fmt, ":reason({})", self.reason_code())?,
32992f3ab15Sopenharmony_ci        }
33092f3ab15Sopenharmony_ci        write!(
33192f3ab15Sopenharmony_ci            fmt,
33292f3ab15Sopenharmony_ci            ":{}:{}:{}",
33392f3ab15Sopenharmony_ci            self.file(),
33492f3ab15Sopenharmony_ci            self.line(),
33592f3ab15Sopenharmony_ci            self.data().unwrap_or("")
33692f3ab15Sopenharmony_ci        )
33792f3ab15Sopenharmony_ci    }
33892f3ab15Sopenharmony_ci}
33992f3ab15Sopenharmony_ci
34092f3ab15Sopenharmony_ciimpl error::Error for Error {}
34192f3ab15Sopenharmony_ci
34292f3ab15Sopenharmony_cicfg_if! {
34392f3ab15Sopenharmony_ci    if #[cfg(ossl300)] {
34492f3ab15Sopenharmony_ci        use std::ffi::{CString};
34592f3ab15Sopenharmony_ci        use ffi::ERR_get_error_all;
34692f3ab15Sopenharmony_ci
34792f3ab15Sopenharmony_ci        type RetStr<'a> = &'a str;
34892f3ab15Sopenharmony_ci
34992f3ab15Sopenharmony_ci        #[derive(Clone)]
35092f3ab15Sopenharmony_ci        struct ShimStr(CString);
35192f3ab15Sopenharmony_ci
35292f3ab15Sopenharmony_ci        impl ShimStr {
35392f3ab15Sopenharmony_ci            unsafe fn new(s: *const c_char) -> Self {
35492f3ab15Sopenharmony_ci                ShimStr(CStr::from_ptr(s).to_owned())
35592f3ab15Sopenharmony_ci            }
35692f3ab15Sopenharmony_ci
35792f3ab15Sopenharmony_ci            fn as_ptr(&self) -> *const c_char {
35892f3ab15Sopenharmony_ci                self.0.as_ptr()
35992f3ab15Sopenharmony_ci            }
36092f3ab15Sopenharmony_ci
36192f3ab15Sopenharmony_ci            fn as_str(&self) -> &str {
36292f3ab15Sopenharmony_ci                self.0.to_str().unwrap()
36392f3ab15Sopenharmony_ci            }
36492f3ab15Sopenharmony_ci        }
36592f3ab15Sopenharmony_ci    } else {
36692f3ab15Sopenharmony_ci        #[allow(bad_style)]
36792f3ab15Sopenharmony_ci        unsafe extern "C" fn ERR_get_error_all(
36892f3ab15Sopenharmony_ci            file: *mut *const c_char,
36992f3ab15Sopenharmony_ci            line: *mut c_int,
37092f3ab15Sopenharmony_ci            func: *mut *const c_char,
37192f3ab15Sopenharmony_ci            data: *mut *const c_char,
37292f3ab15Sopenharmony_ci            flags: *mut c_int,
37392f3ab15Sopenharmony_ci        ) -> ErrType {
37492f3ab15Sopenharmony_ci            let code = ffi::ERR_get_error_line_data(file, line, data, flags);
37592f3ab15Sopenharmony_ci            *func = ffi::ERR_func_error_string(code);
37692f3ab15Sopenharmony_ci            code
37792f3ab15Sopenharmony_ci        }
37892f3ab15Sopenharmony_ci
37992f3ab15Sopenharmony_ci        type RetStr<'a> = &'static str;
38092f3ab15Sopenharmony_ci
38192f3ab15Sopenharmony_ci        #[derive(Clone)]
38292f3ab15Sopenharmony_ci        struct ShimStr(*const c_char);
38392f3ab15Sopenharmony_ci
38492f3ab15Sopenharmony_ci        impl ShimStr {
38592f3ab15Sopenharmony_ci            unsafe fn new(s: *const c_char) -> Self {
38692f3ab15Sopenharmony_ci                ShimStr(s)
38792f3ab15Sopenharmony_ci            }
38892f3ab15Sopenharmony_ci
38992f3ab15Sopenharmony_ci            fn as_ptr(&self) -> *const c_char {
39092f3ab15Sopenharmony_ci                self.0
39192f3ab15Sopenharmony_ci            }
39292f3ab15Sopenharmony_ci
39392f3ab15Sopenharmony_ci            fn as_str(&self) -> &'static str {
39492f3ab15Sopenharmony_ci                unsafe {
39592f3ab15Sopenharmony_ci                    CStr::from_ptr(self.0).to_str().unwrap()
39692f3ab15Sopenharmony_ci                }
39792f3ab15Sopenharmony_ci            }
39892f3ab15Sopenharmony_ci        }
39992f3ab15Sopenharmony_ci    }
40092f3ab15Sopenharmony_ci}
40192f3ab15Sopenharmony_ci
40292f3ab15Sopenharmony_ci#[cfg(test)]
40392f3ab15Sopenharmony_cimod tests {
40492f3ab15Sopenharmony_ci    #[cfg(not(ossl310))]
40592f3ab15Sopenharmony_ci    use crate::nid::Nid;
40692f3ab15Sopenharmony_ci
40792f3ab15Sopenharmony_ci    #[test]
40892f3ab15Sopenharmony_ci    // Due to a bug in OpenSSL 3.1.0, this test can hang there. Skip for now.
40992f3ab15Sopenharmony_ci    #[cfg(not(ossl310))]
41092f3ab15Sopenharmony_ci    fn test_error_library_code() {
41192f3ab15Sopenharmony_ci        let stack = Nid::create("not-an-oid", "invalid", "invalid").unwrap_err();
41292f3ab15Sopenharmony_ci        let errors = stack.errors();
41392f3ab15Sopenharmony_ci        #[cfg(not(boringssl))]
41492f3ab15Sopenharmony_ci        assert_eq!(errors[0].library_code(), ffi::ERR_LIB_ASN1);
41592f3ab15Sopenharmony_ci        #[cfg(boringssl)]
41692f3ab15Sopenharmony_ci        assert_eq!(errors[0].library_code(), ffi::ERR_LIB_OBJ as libc::c_int);
41792f3ab15Sopenharmony_ci    }
41892f3ab15Sopenharmony_ci}
419