use super::PathOrBlob;
use crate::{
blob::Blob,
config::setopt::{EasyHandle, SetOpt, SetOptError, SetOptProxy},
handler::BlobOptions,
};
use curl_sys::{
CURLOPT_PROXY_SSLCERT_BLOB, CURLOPT_PROXY_SSLKEY_BLOB, CURLOPT_SSLCERT_BLOB,
CURLOPT_SSLKEY_BLOB,
};
use std::path::PathBuf;
#[derive(Clone, Debug)]
pub struct Identity {
format: CertFormat,
data: PathOrBlob,
private_key: Option<PrivateKey>,
password: Option<String>,
}
impl Identity {
pub fn from_pem<B>(bytes: B, private_key: Option<PrivateKey>) -> Self
where
B: AsRef<[u8]> + Send + Sync + 'static,
{
Self {
format: CertFormat::Pem,
data: PathOrBlob::Blob(Blob::new(bytes)),
private_key,
password: None,
}
}
pub fn from_der<B>(bytes: B, private_key: Option<PrivateKey>) -> Self
where
B: AsRef<[u8]> + Send + Sync + 'static,
{
Self {
format: CertFormat::Der,
data: PathOrBlob::Blob(Blob::new(bytes)),
private_key,
password: None,
}
}
pub fn from_pkcs12<B>(bytes: B, password: Option<String>) -> Self
where
B: AsRef<[u8]> + Send + Sync + 'static,
{
Self {
format: CertFormat::Pkcs12,
data: PathOrBlob::Blob(Blob::new(bytes)),
private_key: None,
password,
}
}
pub fn from_pem_file<P>(path: P, private_key: Option<PrivateKey>) -> Self
where
P: Into<PathBuf>,
{
Self {
format: CertFormat::Pem,
data: PathOrBlob::Path(path.into()),
private_key,
password: None,
}
}
pub fn from_der_file<P>(path: P, private_key: Option<PrivateKey>) -> Self
where
P: Into<PathBuf>,
{
Self {
format: CertFormat::Der,
data: PathOrBlob::Path(path.into()),
private_key,
password: None,
}
}
pub fn from_pkcs12_file<P>(path: P, password: Option<String>) -> Self
where
P: Into<PathBuf>,
{
Self {
format: CertFormat::Pkcs12,
data: PathOrBlob::Path(path.into()),
private_key: None,
password,
}
}
}
impl SetOpt for Identity {
fn set_opt(&self, easy: &mut EasyHandle) -> Result<(), SetOptError> {
easy.ssl_cert_type(self.format.as_str())?;
match &self.data {
PathOrBlob::Path(path) => easy.ssl_cert(path.as_path()),
PathOrBlob::Blob(bytes) => unsafe {
easy.setopt_blob_nocopy(CURLOPT_SSLCERT_BLOB, bytes)
},
}?;
if let Some(key) = self.private_key.as_ref() {
key.set_opt(easy)?;
}
if let Some(password) = self.password.as_ref() {
easy.key_password(password)?;
}
Ok(())
}
}
impl SetOptProxy for Identity {
fn set_opt_proxy(&self, easy: &mut EasyHandle) -> Result<(), SetOptError> {
easy.proxy_sslcert_type(self.format.as_str())?;
match &self.data {
PathOrBlob::Path(path) => easy.proxy_sslcert(path.to_str().unwrap()),
PathOrBlob::Blob(bytes) => unsafe {
easy.setopt_blob_nocopy(CURLOPT_PROXY_SSLCERT_BLOB, bytes)
},
}?;
if let Some(key) = self.private_key.as_ref() {
key.set_opt_proxy(easy)?;
}
if let Some(password) = self.password.as_ref() {
easy.proxy_key_password(password)?;
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct PrivateKey {
format: CertFormat,
data: PathOrBlob,
password: Option<String>,
}
impl PrivateKey {
pub fn from_pem<B, P>(bytes: B, password: P) -> Self
where
B: AsRef<[u8]> + Send + Sync + 'static,
P: Into<Option<String>>,
{
Self {
format: CertFormat::Pem,
data: PathOrBlob::Blob(Blob::new(bytes)),
password: password.into(),
}
}
pub fn from_der<B, P>(bytes: B, password: P) -> Self
where
B: AsRef<[u8]> + Send + Sync + 'static,
P: Into<Option<String>>,
{
Self {
format: CertFormat::Der,
data: PathOrBlob::Blob(Blob::new(bytes)),
password: password.into(),
}
}
pub fn from_pem_file(path: impl Into<PathBuf>, password: impl Into<Option<String>>) -> Self {
Self {
format: CertFormat::Pem,
data: PathOrBlob::Path(path.into()),
password: password.into(),
}
}
pub fn from_der_file(path: impl Into<PathBuf>, password: impl Into<Option<String>>) -> Self {
Self {
format: CertFormat::Der,
data: PathOrBlob::Path(path.into()),
password: password.into(),
}
}
}
impl SetOpt for PrivateKey {
fn set_opt(&self, easy: &mut EasyHandle) -> Result<(), SetOptError> {
easy.ssl_key_type(self.format.as_str())?;
match &self.data {
PathOrBlob::Path(path) => easy.ssl_key(path.as_path()),
PathOrBlob::Blob(blob) => unsafe { easy.setopt_blob_nocopy(CURLOPT_SSLKEY_BLOB, blob) },
}?;
if let Some(password) = self.password.as_ref() {
easy.key_password(password)?;
}
Ok(())
}
}
impl SetOptProxy for PrivateKey {
fn set_opt_proxy(&self, easy: &mut EasyHandle) -> Result<(), SetOptError> {
easy.proxy_sslkey_type(self.format.as_str())?;
match &self.data {
PathOrBlob::Path(path) => easy.proxy_sslkey(path.to_str().unwrap()),
PathOrBlob::Blob(blob) => unsafe {
easy.setopt_blob_nocopy(CURLOPT_PROXY_SSLKEY_BLOB, blob)
},
}?;
if let Some(password) = self.password.as_ref() {
easy.proxy_key_password(password)?;
}
Ok(())
}
}
#[derive(Clone, Copy, Debug)]
enum CertFormat {
Pem,
Der,
Pkcs12,
}
impl CertFormat {
fn as_str(&self) -> &'static str {
match self {
CertFormat::Pem => "PEM",
CertFormat::Der => "DER",
CertFormat::Pkcs12 => "P12",
}
}
}