1use std::fmt;
10
11use crate::types::{service_types::SignatureData, status_code::StatusCode, ByteString, UAString};
12pub use {
13 aeskey::*, certificate_store::*, hash::*, pkey::*, security_policy::*, thumbprint::*,
14 user_identity::*, x509::*,
15};
16
17#[cfg(test)]
18mod tests;
19
20pub mod aeskey;
21pub mod certificate_store;
22pub mod hash;
23pub mod pkey;
24pub mod random;
25pub mod security_policy;
26pub mod thumbprint;
27pub mod user_identity;
28pub mod x509;
29
30pub const SHA1_SIZE: usize = 20;
32pub const SHA256_SIZE: usize = 32;
34
35pub(crate) mod algorithms {
37 pub const ENC_RSA_15: &str = "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
45
46 pub const ENC_RSA_OAEP: &str = "http://www.w3.org/2001/04/xmlenc#rsa-oaep";
48
49 pub const ENC_RSA_OAEP_SHA256: &str = "http://opcfoundation.org/UA/security/rsa-oaep-sha2-256";
51
52 pub const DSIG_HMAC_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#hmac-sha1";
57
58 pub const DSIG_HMAC_SHA256: &str = "http://www.w3.org/2000/09/xmldsig#hmac-sha256";
60
61 pub const DSIG_RSA_SHA1: &str = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
63
64 pub const DSIG_RSA_SHA256: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
66
67 pub const DSIG_RSA_PSS_SHA2_256: &str = "http://opcfoundation.org/UA/security/rsa-pss-sha2-256";
69
70 }
76
77fn concat_data_and_nonce(data: &[u8], nonce: &[u8]) -> Vec<u8> {
78 let mut buffer: Vec<u8> = Vec::with_capacity(data.len() + nonce.len());
79 buffer.extend_from_slice(data);
80 buffer.extend_from_slice(nonce);
81 buffer
82}
83
84pub fn create_signature_data(
86 signing_key: &PrivateKey,
87 security_policy: SecurityPolicy,
88 contained_cert: &ByteString,
89 nonce: &ByteString,
90) -> Result<SignatureData, StatusCode> {
91 let (algorithm, signature) = if contained_cert.is_null() || nonce.is_null() {
96 (UAString::null(), ByteString::null())
97 } else {
98 let data = concat_data_and_nonce(contained_cert.as_ref(), nonce.as_ref());
99 match security_policy {
101 SecurityPolicy::None => (UAString::null(), ByteString::null()),
102 SecurityPolicy::Unknown => {
103 error!(
104 "An unknown security policy was passed to create_signature_data and rejected"
105 );
106 (UAString::null(), ByteString::null())
107 }
108 security_policy => {
109 let signing_key_size = signing_key.size();
110 let mut signature = vec![0u8; signing_key_size];
111 let _ = security_policy.asymmetric_sign(signing_key, &data, &mut signature)?;
112 (
113 UAString::from(security_policy.asymmetric_signature_algorithm()),
114 ByteString::from(&signature),
115 )
116 }
117 }
118 };
119 let signature_data = SignatureData {
120 algorithm,
121 signature,
122 };
123 trace!("Creating signature contained_cert = {:?}", signature_data);
124 Ok(signature_data)
125}
126
127pub fn verify_signature_data(
130 signature: &SignatureData,
131 security_policy: SecurityPolicy,
132 signing_cert: &X509,
133 contained_cert: &X509,
134 contained_nonce: &[u8],
135) -> StatusCode {
136 if let Ok(verification_key) = signing_cert.public_key() {
137 let contained_cert = contained_cert.as_byte_string();
139 let data = concat_data_and_nonce(contained_cert.as_ref(), contained_nonce);
140
141 let result = security_policy.asymmetric_verify_signature(
143 &verification_key,
144 &data,
145 signature.signature.as_ref(),
146 None,
147 );
148 match result {
149 Ok(_) => StatusCode::Good,
150 Err(result) => {
151 error!(
152 "Client signature verification failed, status code = {}",
153 result
154 );
155 result
156 }
157 }
158 } else {
159 error!(
160 "Signature verification failed, signing certificate has no public key to verify with"
161 );
162 StatusCode::BadUnexpectedError
163 }
164}
165
166#[derive(Debug)]
167pub struct HostnameError;
168
169impl fmt::Display for HostnameError {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(f, "HostnameError")
172 }
173}
174
175impl std::error::Error for HostnameError {}
176
177pub fn hostname() -> Result<String, HostnameError> {
179 use gethostname::gethostname;
180 gethostname().into_string().map_err(|_| HostnameError {})
181}