Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  err.rs   Sprache: unbekannt

 
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]
#![allow(clippy::upper_case_acronyms)]

use std::os::raw::c_char;
use std::str::Utf8Error;

use crate::nss_prelude::*;
use crate::prtypes::*;

include!(concat!(env!("OUT_DIR"), "/nspr_error.rs"));
mod codes {
    #![allow(non_snake_case)]
    include!(concat!(env!("OUT_DIR"), "/nss_secerr.rs"));
    include!(concat!(env!("OUT_DIR"), "/nss_sslerr.rs"));
    include!(concat!(env!("OUT_DIR"), "/mozpkix.rs"));
}
pub use codes::mozilla_pkix_ErrorCode as mozpkix;
pub use codes::SECErrorCodes as sec;
pub use codes::SSLErrorCodes as ssl;
pub mod nspr {
    include!(concat!(env!("OUT_DIR"), "/nspr_err.rs"));
}

pub type Res<T> = Result<T, Error>;

#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub enum Error {
    AeadError,
    AeadTruncated,
    CertificateLoading,
    CipherInitFailure,
    CreateSslSocket,
    EchRetry(Vec<u8>),
    HkdfError,
    InternalError,
    IntegerOverflow,
    InvalidEpoch,
    InvalidInput,
    MixedHandshakeMethod,
    NoDataAvailable,
    NssError {
        name: String,
        code: PRErrorCode,
        desc: String,
    },
    OverrunError,
    SelfEncryptFailure,
    StringError,
    TimeTravelError,
    UnsupportedCipher,
    UnsupportedCurve,
    UnsupportedHash,
    UnsupportedVersion,
}

impl Error {
    pub(crate) fn last_nss_error() -> Self {
        Self::from(unsafe { PR_GetError() })
    }
}

impl std::error::Error for Error {
    #[must_use]
    fn cause(&self) -> Option<&dyn std::error::Error> {
        None
    }
    #[must_use]
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Error: {:?}", self)
    }
}

impl From<std::num::TryFromIntError> for Error {
    #[must_use]
    fn from(_: std::num::TryFromIntError) -> Self {
        Self::IntegerOverflow
    }
}
impl From<std::ffi::NulError> for Error {
    #[must_use]
    fn from(_: std::ffi::NulError) -> Self {
        Self::InternalError
    }
}
impl From<Utf8Error> for Error {
    fn from(_: Utf8Error) -> Self {
        Self::StringError
    }
}
impl From<PRErrorCode> for Error {
    fn from(code: PRErrorCode) -> Self {
        let name = wrap_str_fn(|| unsafe { PR_ErrorToName(code) }, "UNKNOWN_ERROR");
        let desc = wrap_str_fn(
            || unsafe { PR_ErrorToString(code, PR_LANGUAGE_I_DEFAULT) },
            "...",
        );
        Self::NssError { name, code, desc }
    }
}

use std::ffi::CStr;

fn wrap_str_fn<F>(f: F, dflt: &str) -> String
where
    F: FnOnce() -> *const c_char,
{
    unsafe {
        let p = f();
        if p.is_null() {
            return dflt.to_string();
        }
        CStr::from_ptr(p).to_string_lossy().into_owned()
    }
}

pub fn is_blocked(result: &Res<()>) -> bool {
    match result {
        Err(Error::NssError { code, .. }) => *code == nspr::PR_WOULD_BLOCK_ERROR,
        _ => false,
    }
}

pub trait IntoResult {
    /// The `Ok` type for the result.
    type Ok;

    /// Unsafe in our implementors because they take a pointer and have no way
    /// to ensure that the pointer is valid. An invalid pointer could cause UB
    /// in `impl Drop for Scoped`.
    unsafe fn into_result(self) -> Result<Self::Ok, Error>;
}

pub unsafe fn into_result<P>(ptr: *mut P) -> Result<*mut P, Error> {
    if ptr.is_null() {
        Err(Error::last_nss_error())
    } else {
        Ok(ptr)
    }
}

// This can be used to implement `IntoResult` for pointer types that do not make
// sense as smart pointers. For smart pointers use `scoped_ptr!`.
macro_rules! impl_into_result {
    ($pointer:ty) => {
        impl $crate::err::IntoResult for *mut $pointer {
            type Ok = *mut $pointer;

            unsafe fn into_result(self) -> Result<Self::Ok, $crate::err::Error> {
                $crate::err::into_result(self)
            }
        }
    };
}

impl IntoResult for SECStatus {
    type Ok = ();

    unsafe fn into_result(self) -> Result<(), Error> {
        if self == SECSuccess {
            Ok(())
        } else {
            Err(Error::last_nss_error())
        }
    }
}

pub fn secstatus_to_res(code: SECStatus) -> Res<()> {
    // Unsafe in the trait, but this impl should be safe.
    unsafe { SECStatus::into_result(code) }
}

#[cfg(test)]
mod tests {
    use crate::err::{self, is_blocked, secstatus_to_res, Error, PRErrorCode, PR_SetError};
    use crate::ssl::{SECFailure, SECSuccess};
    use test_fixture::fixture_init;

    fn set_error_code(code: PRErrorCode) {
        // This code doesn't work without initializing NSS first.
        fixture_init();
        unsafe {
            PR_SetError(code, 0);
        }
    }

    #[test]
    fn error_code() {
        fixture_init();
        assert_eq!(15 - 0x3000, err::ssl::SSL_ERROR_BAD_MAC_READ);
        assert_eq!(166 - 0x2000, err::sec::SEC_ERROR_LIBPKIX_INTERNAL);
        assert_eq!(-5998, err::nspr::PR_WOULD_BLOCK_ERROR);
    }

    #[test]
    fn is_ok() {
        assert!(secstatus_to_res(SECSuccess).is_ok());
    }

    #[test]
    fn is_err() {
        set_error_code(err::ssl::SSL_ERROR_BAD_MAC_READ);
        let r = secstatus_to_res(SECFailure);
        assert!(r.is_err());
        match r.unwrap_err() {
            Error::NssError { name, code, desc } => {
                assert_eq!(name, "SSL_ERROR_BAD_MAC_READ");
                assert_eq!(code, -12273);
                assert_eq!(
                    desc,
                    "SSL received a record with an incorrect Message Authentication Code."
                );
            }
            _ => unreachable!(),
        }
    }

    #[test]
    fn is_err_zero_code() {
        set_error_code(0);
        let r = secstatus_to_res(SECFailure);
        assert!(r.is_err());
        match r.unwrap_err() {
            Error::NssError { name, code, .. } => {
                assert_eq!(name, "UNKNOWN_ERROR");
                assert_eq!(code, 0);
                // Note that we don't test |desc| here because that comes from
                // strerror(0), which is platform-dependent.
            }
            _ => unreachable!(),
        }
    }

    #[test]
    fn blocked() {
        set_error_code(err::nspr::PR_WOULD_BLOCK_ERROR);
        let r = secstatus_to_res(SECFailure);
        assert!(r.is_err());
        assert!(is_blocked(&r));
        match r.unwrap_err() {
            Error::NssError { name, code, desc } => {
                assert_eq!(name, "PR_WOULD_BLOCK_ERROR");
                assert_eq!(code, -5998);
                assert_eq!(desc, "The operation would have blocked");
            }
            _ => panic!("bad error type"),
        }
    }
}

[ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge