Skip to main content

instro_opcua/
lib.rs

1pub mod browse;
2pub mod client;
3pub(crate) mod metrics;
4pub mod types;
5
6use anyhow::Context as _;
7use anyhow::Result;
8use open62541::Certificate;
9use open62541::PrivateKey;
10use open62541::create_certificate;
11use open62541::ua;
12
13/// Generates a self-signed X.509 certificate/key pair suitable for OPC-UA client authentication.
14///
15/// Returns a tuple containing the certificate and private key or an error if the certificate generation fails.
16pub fn generate_self_signed_cert() -> Result<(Certificate, PrivateKey)> {
17    let subject = ua::Array::from_slice(&[
18        ua::String::new("C=US").context("building client cert subject")?,
19        ua::String::new("O=Nominal").context("building client cert subject")?,
20        ua::String::new("CN=Nominal@localhost").context("building client cert subject")?,
21    ]);
22
23    let subject_alt_name = ua::Array::from_slice(&[
24        ua::String::new("DNS:localhost").context("building client cert SAN")?,
25        ua::String::new("URI:urn:nominal:connect-opc-ua-client")
26            .context("building client cert SAN")?,
27    ]);
28
29    create_certificate(
30        &subject,
31        &subject_alt_name,
32        &ua::CertificateFormat::PEM,
33        None,
34    )
35    .context("generating client certificate")
36}
37
38#[cfg(test)]
39mod tests {
40    use super::generate_self_signed_cert;
41
42    #[test]
43    fn generate_cert_produces_nonempty_keypair() {
44        let (certificate, private_key) =
45            generate_self_signed_cert().expect("failed to generate self-signed certificate");
46
47        assert!(!certificate.as_bytes().is_empty(), "certificate is empty");
48        assert!(!private_key.as_bytes().is_empty(), "private key is empty");
49    }
50}