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