use std::fmt;
use crate::types::{service_types::SignatureData, status_code::StatusCode, ByteString, UAString};
pub use {
aeskey::*, certificate_store::*, hash::*, pkey::*, security_policy::*, thumbprint::*,
user_identity::*, x509::*,
};
#[cfg(test)]
mod tests;
pub mod aeskey;
pub mod certificate_store;
pub mod hash;
pub mod pkey;
pub mod random;
pub mod security_policy;
pub mod thumbprint;
pub mod user_identity;
pub mod x509;
pub const SHA1_SIZE: usize = 20;
pub const SHA256_SIZE: usize = 32;
pub(crate) mod algorithms {
pub const ENC_RSA_15: &str = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
pub const ENC_RSA_OAEP: &str = "http://www.w3.org/2001/04/xmlenc#rsa-oaep";
pub const ENC_RSA_OAEP_SHA256: &str = "http://opcfoundation.org/UA/security/rsa-oaep-sha2-256";
pub const DSIG_HMAC_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#hmac-sha1";
pub const DSIG_HMAC_SHA256: &str = "http://www.w3.org/2000/09/xmldsig#hmac-sha256";
pub const DSIG_RSA_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
pub const DSIG_RSA_SHA256: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
pub const DSIG_RSA_PSS_SHA2_256: &str = "http://opcfoundation.org/UA/security/rsa-pss-sha2-256";
}
fn concat_data_and_nonce(data: &[u8], nonce: &[u8]) -> Vec<u8> {
let mut buffer: Vec<u8> = Vec::with_capacity(data.len() + nonce.len());
buffer.extend_from_slice(data);
buffer.extend_from_slice(nonce);
buffer
}
pub fn create_signature_data(
signing_key: &PrivateKey,
security_policy: SecurityPolicy,
contained_cert: &ByteString,
nonce: &ByteString,
) -> Result<SignatureData, StatusCode> {
let (algorithm, signature) = if contained_cert.is_null() || nonce.is_null() {
(UAString::null(), ByteString::null())
} else {
let data = concat_data_and_nonce(contained_cert.as_ref(), nonce.as_ref());
match security_policy {
SecurityPolicy::None => (UAString::null(), ByteString::null()),
SecurityPolicy::Unknown => {
error!(
"An unknown security policy was passed to create_signature_data and rejected"
);
(UAString::null(), ByteString::null())
}
security_policy => {
let signing_key_size = signing_key.size();
let mut signature = vec![0u8; signing_key_size];
let _ = security_policy.asymmetric_sign(signing_key, &data, &mut signature)?;
(
UAString::from(security_policy.asymmetric_signature_algorithm()),
ByteString::from(&signature),
)
}
}
};
let signature_data = SignatureData {
algorithm,
signature,
};
trace!("Creating signature contained_cert = {:?}", signature_data);
Ok(signature_data)
}
pub fn verify_signature_data(
signature: &SignatureData,
security_policy: SecurityPolicy,
signing_cert: &X509,
contained_cert: &X509,
contained_nonce: &[u8],
) -> StatusCode {
if let Ok(verification_key) = signing_cert.public_key() {
let contained_cert = contained_cert.as_byte_string();
let data = concat_data_and_nonce(contained_cert.as_ref(), contained_nonce);
let result = security_policy.asymmetric_verify_signature(
&verification_key,
&data,
signature.signature.as_ref(),
None,
);
match result {
Ok(_) => StatusCode::Good,
Err(result) => {
error!(
"Client signature verification failed, status code = {}",
result
);
result
}
}
} else {
error!(
"Signature verification failed, signing certificate has no public key to verify with"
);
StatusCode::BadUnexpectedError
}
}
#[derive(Debug)]
pub struct HostnameError;
impl fmt::Display for HostnameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HostnameError")
}
}
impl std::error::Error for HostnameError {}
pub fn hostname() -> Result<String, HostnameError> {
use gethostname::gethostname;
gethostname().into_string().map_err(|_| HostnameError {})
}