ice-rs 0.3.0

ZeroC Ice for Rust
Documentation
use std::io::prelude::*;
use openssl::ssl::SslVersion;
use openssl::x509::*;
use openssl::pkcs12::*;
use openssl::pkey::*;
use std::fs::File;
use std::path::Path;

use crate::errors::*;

pub (crate) fn read_pem(pem_file: &str, dir: &Path) ->Result<(Option<X509>, Option<PKey<Private>>), Box<dyn std::error::Error + Sync + Send>> {
    let mut buffer = vec![];
    let mut file = File::open(&dir.join(pem_file))?;
    file.read_to_end(&mut buffer)?;

    match (X509::from_pem(&buffer), PKey::private_key_from_pem(&buffer)) {
        (Ok(cert), Ok(pkey)) => {
            Ok((Some(cert), Some(pkey)))
        }
        (Ok(cert), _) => {
            Ok((Some(cert), None))
        }
        (_, Ok(pkey)) => {
            Ok((None, Some(pkey)))
        }
        _ => Err(Box::new(ProtocolError::new(&format!("SSL: Error reading PEM file: {}", pem_file))))
    }
}

pub (crate) fn read_pkcs12(pkcs12_path: &Path, password: &str, dir: &Path) -> Result<ParsedPkcs12, Box<dyn std::error::Error + Sync + Send>> {
    let mut buffer = vec![];
    let mut file = File::open(&dir.join(pkcs12_path))?;
    file.read_to_end(&mut buffer)?;

    match Pkcs12::from_der(&buffer) {
        Ok(pkcs12) => {
            match pkcs12.parse(password) {
                Ok(parsed) => Ok(parsed),
                _ => Err(Box::new(ProtocolError::new("SSL: Could not parse pkcs12")))
            }
        },
        _ => Err(Box::new(ProtocolError::new("SSL: Could not read pkcs12")))
    }
}

pub (crate) fn parse_protocol(protocol: &str) -> Option<SslVersion> {
    match protocol.to_lowercase().as_ref() {
        "ssl3" | "sslv3" => {
            Some(SslVersion::SSL3)
        },
        "tls1_3" | "tlsv1_3" => {
            Some(SslVersion::TLS1_3)
        }
        "tls1_2" | "tlsv1_2" => {
            Some(SslVersion::TLS1_2)
        }
        "tls1_1" | "tlsv1_1" => {
            Some(SslVersion::TLS1_1)
        }
        "tls1" | "tlsv1" | "tls1_0" | "tlsv1_0" => {
            Some(SslVersion::TLS1)
        }
        _ => {
            None
        }
    }
}

fn protocol_to_num(version: SslVersion) -> i32 {
    match version {
        SslVersion::TLS1 => 1,
        SslVersion::TLS1_1 => 2,
        SslVersion::TLS1_2 => 3,
        SslVersion::TLS1_3 => 4,
        _ => 0
    }
}

fn num_to_protocol(num: i32) -> SslVersion {
    match num {
        4 => SslVersion::TLS1_3,
        3 => SslVersion::TLS1_2,
        2 => SslVersion::TLS1_1,
        1 => SslVersion::TLS1,
        _ => SslVersion::SSL3,
    }
}

pub (crate) fn max_protocol(new_value: SslVersion, current_max: Option<SslVersion>) -> SslVersion {
    let new_numeric = protocol_to_num(new_value);
    if let Some(current_max) = current_max {
        num_to_protocol(std::cmp::max(new_numeric, protocol_to_num(current_max)))
    } else {
        new_value
    }
}

pub (crate) fn min_protocol(new_value: SslVersion, current_min: Option<SslVersion>) -> SslVersion {
    let new_numeric = protocol_to_num(new_value);
    if let Some(current_min) = current_min {
        num_to_protocol(std::cmp::min(new_numeric, protocol_to_num(current_min)))
    } else {
        new_value
    }
}