1use std::{sync::Arc, time::Duration};
2
3use opcua_core::{
4 comms::url::hostname_from_url, sync::RwLock, trace_read_lock, trace_write_lock, ResponseMessage,
5};
6use opcua_crypto::{
7 self, legacy_encrypt_secret, random, CertificateStore, PKey, SecurityPolicy, X509,
8};
9use opcua_types::{
10 ActivateSessionRequest, ActivateSessionResponse, AnonymousIdentityToken,
11 ApplicationDescription, ByteString, CancelRequest, CancelResponse, CloseSessionRequest,
12 CloseSessionResponse, CreateSessionRequest, CreateSessionResponse, EndpointDescription, Error,
13 ExtensionObject, IntegerId, IssuedIdentityToken, MessageSecurityMode, NodeId, SignatureData,
14 SignedSoftwareCertificate, StatusCode, UAString, UserNameIdentityToken, UserTokenType,
15 X509IdentityToken,
16};
17use rsa::RsaPrivateKey;
18use tracing::{debug_span, error, info_span, Instrument};
19
20use crate::{
21 session::{
22 process_service_result, process_unexpected_response,
23 request_builder::{builder_base, builder_debug, builder_error, RequestHeaderBuilder},
24 },
25 AsyncSecureChannel, IdentityToken, Session, UARequest,
26};
27
28#[derive(Clone)]
29pub struct CreateSession<'a> {
41 client_description: ApplicationDescription,
42 server_uri: UAString,
43 endpoint_url: UAString,
44 session_name: UAString,
45 client_certificate: Option<X509>,
46 session_timeout: f64,
47 max_response_message_size: u32,
48 certificate_store: &'a RwLock<CertificateStore>,
49 endpoint: &'a EndpointDescription,
50 nonce_length: usize,
51
52 header: RequestHeaderBuilder,
53}
54
55builder_base!(CreateSession<'a>);
56
57impl<'a> CreateSession<'a> {
58 pub(crate) fn new(session: &'a Session) -> Self {
62 Self {
63 endpoint_url: session.endpoint_info().endpoint.endpoint_url.clone(),
64 server_uri: UAString::null(),
65 client_description: session.application_description.clone(),
66 session_name: session.session_name.clone(),
67 client_certificate: session.channel.read_own_certificate(),
68 endpoint: &session.endpoint_info().endpoint,
69 certificate_store: session.channel.certificate_store(),
70 session_timeout: session.session_timeout,
71 max_response_message_size: 0,
72 nonce_length: session.session_nonce_length,
73 header: RequestHeaderBuilder::new_from_session(session),
74 }
75 }
76
77 pub fn new_manual(
79 certificate_store: &'a RwLock<CertificateStore>,
80 endpoint: &'a EndpointDescription,
81 session_id: u32,
82 timeout: Duration,
83 auth_token: NodeId,
84 request_handle: IntegerId,
85 ) -> Self {
86 Self {
87 endpoint_url: UAString::null(),
88 server_uri: UAString::null(),
89 client_description: ApplicationDescription::default(),
90 session_name: UAString::null(),
91 client_certificate: None,
92 session_timeout: 0.0,
93 max_response_message_size: 0,
94 certificate_store,
95 endpoint,
96 nonce_length: 32,
97 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
98 }
99 }
100
101 pub fn client_description(mut self, desc: impl Into<ApplicationDescription>) -> Self {
103 self.client_description = desc.into();
104 self
105 }
106
107 pub fn server_uri(mut self, server_uri: impl Into<UAString>) -> Self {
109 self.server_uri = server_uri.into();
110 self
111 }
112
113 pub fn endpoint_url(mut self, endpoint_url: impl Into<UAString>) -> Self {
115 self.endpoint_url = endpoint_url.into();
116 self
117 }
118
119 pub fn session_name(mut self, session_name: impl Into<UAString>) -> Self {
121 self.session_name = session_name.into();
122 self
123 }
124
125 pub fn client_certificate(mut self, client_certificate: X509) -> Self {
127 self.client_certificate = Some(client_certificate);
128 self
129 }
130
131 pub fn client_cert_from_store(mut self, certificate_store: &RwLock<CertificateStore>) -> Self {
133 let cert_store = trace_read_lock!(certificate_store);
134 self.client_certificate = cert_store.read_own_cert().ok();
135 self
136 }
137
138 pub fn session_timeout(mut self, session_timeout: f64) -> Self {
140 self.session_timeout = session_timeout;
141 self
142 }
143
144 pub fn max_response_message_size(mut self, max_response_message_size: u32) -> Self {
146 self.max_response_message_size = max_response_message_size;
147 self
148 }
149
150 pub fn nonce_length(mut self, nonce_length: usize) -> Self {
152 self.nonce_length = nonce_length;
153 self
154 }
155}
156
157impl UARequest for CreateSession<'_> {
158 type Out = CreateSessionResponse;
159
160 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
161 where
162 Self: 'a,
163 {
164 let security_policy = channel.security_policy();
165
166 let span = info_span!(
167 "Sending CreateSession request",
168 endpoint = %self.endpoint_url,
169 server_uri = %self.server_uri,
170 requested_session_timeout = self.session_timeout,
171 max_response_message_size = self.max_response_message_size,
172 session_name = %self.session_name
173 );
174 let client_nonce = random::byte_string(self.nonce_length);
175
176 let request = {
177 let _h = span.enter();
178
179 CreateSessionRequest {
180 request_header: self.header.header,
181 client_description: self.client_description,
182 server_uri: self.server_uri,
183 endpoint_url: self.endpoint_url,
184 session_name: self.session_name,
185 client_nonce: client_nonce.clone(),
186 client_certificate: self
187 .client_certificate
188 .as_ref()
189 .map(|v| v.as_byte_string())
190 .unwrap_or_default(),
191 requested_session_timeout: self.session_timeout,
192 max_response_message_size: self.max_response_message_size,
193 }
194 };
195
196 let response = channel
197 .send(request, self.header.timeout)
198 .instrument(span.clone())
199 .await?;
200
201 let _h = span.enter();
202
203 if let ResponseMessage::CreateSession(response) = response {
204 builder_debug!(self, "create_session, success");
205 process_service_result(&response.response_header)?;
206
207 if security_policy != SecurityPolicy::None {
208 if self.endpoint.server_certificate != response.server_certificate {
209 error!("Server certificate in CreateSession response does not match channel certificate");
210 return Err(Error::new(StatusCode::BadCertificateInvalid, "Server certificate in CreateSession response does not match channel certificate"));
211 }
212 let server_certificate =
213 opcua_crypto::X509::from_byte_string(&response.server_certificate)
214 .inspect_err(|e| error!("Failed to parse server certificate: {e}"))?;
215 let hostname =
217 hostname_from_url(self.endpoint.endpoint_url.as_ref()).map_err(|e| {
218 Error::new(
219 StatusCode::BadUnexpectedError,
220 format!(
221 "Failed to extract hostname from endpoint URL ({}): {e}",
222 self.endpoint.endpoint_url
223 ),
224 )
225 })?;
226 let application_uri = self.endpoint.server.application_uri.as_ref();
227
228 let certificate_store = trace_write_lock!(self.certificate_store);
229 certificate_store
230 .validate_or_reject_application_instance_cert(
231 &server_certificate,
232 security_policy,
233 Some(&hostname),
234 Some(application_uri),
235 )
236 .inspect_err(|e| {
237 error!("Rejected server certificate in create session response: {e}");
238 })?;
239
240 opcua_crypto::verify_signature_data(
241 &response.server_signature,
242 security_policy,
243 &server_certificate,
244 self.client_certificate.as_ref().ok_or_else(|| {
245 Error::new(
246 StatusCode::BadCertificateInvalid,
247 "Missing client certificate in request",
248 )
249 })?,
250 client_nonce.as_ref(),
251 )
252 .inspect_err(|e| {
253 error!("Failed to verify server signature in create session response: {e}");
254 })?;
255 }
256
257 tracing::debug!(
258 "Successfully created session, session_id = {}, max_request_message_size = {}, revised_session_timeout = {}",
259 response.session_id,
260 response.max_request_message_size,
261 response.revised_session_timeout
262 );
263
264 channel
265 .update_from_created_session(
266 &response.server_nonce,
267 &response.server_certificate,
268 &response.authentication_token,
269 )
270 .inspect_err(|e| {
271 error!("Failed to update channel from created session: {e}");
272 })?;
273
274 Ok(*response)
275 } else {
276 tracing::error!("create_session failed");
277 Err(process_unexpected_response(response))
278 }
279 }
280}
281
282#[derive(Debug, Clone)]
283pub struct ActivateSession {
291 identity_token: IdentityToken,
292 private_key: Option<PKey<RsaPrivateKey>>,
293 locale_ids: Vec<UAString>,
294 client_software_certificates: Vec<SignedSoftwareCertificate>,
295 endpoint: EndpointDescription,
296
297 header: RequestHeaderBuilder,
298}
299
300builder_base!(ActivateSession);
301
302impl ActivateSession {
303 pub(crate) fn new(session: &Session) -> Self {
307 Self {
308 identity_token: session.endpoint_info().user_identity_token.clone(),
309 private_key: session.channel.read_own_private_key(),
310 locale_ids: session
311 .endpoint_info()
312 .preferred_locales
313 .iter()
314 .map(UAString::from)
315 .collect(),
316 client_software_certificates: Vec::new(),
317 endpoint: session.endpoint_info().endpoint.clone(),
318 header: RequestHeaderBuilder::new_from_session(session),
319 }
320 }
321
322 pub fn new_manual(
324 endpoint: EndpointDescription,
325 session_id: u32,
326 timeout: Duration,
327 auth_token: NodeId,
328 request_handle: IntegerId,
329 ) -> Self {
330 Self {
331 identity_token: IdentityToken::Anonymous,
332 private_key: None,
333 locale_ids: Vec::new(),
334 client_software_certificates: Vec::new(),
335 endpoint,
336 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
337 }
338 }
339
340 pub fn identity_token(mut self, identity_token: IdentityToken) -> Self {
342 self.identity_token = identity_token;
343 self
344 }
345
346 pub fn private_key(mut self, private_key: PKey<RsaPrivateKey>) -> Self {
348 self.private_key = Some(private_key);
349 self
350 }
351
352 pub fn locale_ids(mut self, locale_ids: Vec<UAString>) -> Self {
354 self.locale_ids = locale_ids;
355 self
356 }
357
358 pub fn locale_id(mut self, locale_id: impl Into<UAString>) -> Self {
360 self.locale_ids.push(locale_id.into());
361 self
362 }
363
364 pub fn client_software_certificates(
366 mut self,
367 certificates: Vec<SignedSoftwareCertificate>,
368 ) -> Self {
369 self.client_software_certificates = certificates;
370 self
371 }
372
373 pub fn client_software_certificate(mut self, certificate: SignedSoftwareCertificate) -> Self {
375 self.client_software_certificates.push(certificate);
376 self
377 }
378
379 async fn user_identity_token(
380 &self,
381 remote_nonce: &ByteString,
382 remote_cert: &Option<X509>,
383 security_mode: MessageSecurityMode,
384 channel_security_policy: SecurityPolicy,
385 ) -> Result<(ExtensionObject, SignatureData), Error> {
386 let user_token_type = match &self.identity_token {
387 IdentityToken::Anonymous => UserTokenType::Anonymous,
388 IdentityToken::UserName(_, _) => UserTokenType::UserName,
389 IdentityToken::X509(_, _) => UserTokenType::Certificate,
390 IdentityToken::IssuedToken(_) => UserTokenType::IssuedToken,
391 };
392 let Some(policy) = self.endpoint.find_policy(user_token_type) else {
393 builder_error!(
394 self,
395 "Cannot find user token type {:?} for this endpoint, cannot connect",
396 user_token_type
397 );
398 return Err(Error::new(
399 StatusCode::BadSecurityPolicyRejected,
400 format!(
401 "Cannot find user token type {user_token_type:?} for this endpoint, cannot connect"
402 ),
403 ));
404 };
405 let security_policy = if policy.security_policy_uri.is_empty() {
406 SecurityPolicy::None
408 } else {
409 SecurityPolicy::from_uri(policy.security_policy_uri.as_ref())
410 };
411
412 if security_policy == SecurityPolicy::Unknown {
413 error!("Unknown security policy {}", policy.security_policy_uri);
414 return Err(Error::new(
415 StatusCode::BadSecurityPolicyRejected,
416 format!("Unknown security policy {}", policy.security_policy_uri),
417 ));
418 }
419
420 match &self.identity_token {
421 IdentityToken::Anonymous => {
422 let identity_token = AnonymousIdentityToken {
423 policy_id: policy.policy_id.clone(),
424 };
425 let identity_token = ExtensionObject::from_message(identity_token);
426 Ok((identity_token, SignatureData::null()))
427 }
428 IdentityToken::UserName(user, pass) => {
429 let nonce = remote_nonce.as_ref();
430 let cert = remote_cert;
431 let secret = legacy_encrypt_secret(
432 channel_security_policy,
433 security_mode,
434 policy,
435 nonce,
436 cert,
437 pass.0.as_bytes(),
438 )?;
439 let identity_token = UserNameIdentityToken {
440 policy_id: secret.policy,
441 user_name: UAString::from(user.as_str()),
442 password: secret.secret,
443 encryption_algorithm: secret.encryption_algorithm,
444 };
445 Ok((
446 ExtensionObject::from_message(identity_token),
447 SignatureData::null(),
448 ))
449 }
450 IdentityToken::X509(cert, private_key) => {
451 let nonce = remote_nonce.as_ref();
452 let server_cert = remote_cert;
453 let Some(server_cert) = &server_cert else {
454 error!("Cannot create an X509IdentityToken because the remote server has no cert with which to create a signature");
455 return Err(Error::new(StatusCode::BadCertificateInvalid, "Cannot create an X509IdentityToken because the remote server has no cert with which to create a signature"));
456 };
457
458 let user_token_signature = opcua_crypto::create_signature_data(
459 private_key,
460 security_policy,
461 &server_cert.as_byte_string(),
462 &ByteString::from(&nonce),
463 )?;
464
465 let identity_token = X509IdentityToken {
467 policy_id: policy.policy_id.clone(),
468 certificate_data: cert.as_byte_string(),
469 };
470
471 Ok((
472 ExtensionObject::from_message(identity_token),
473 user_token_signature,
474 ))
475 }
476 IdentityToken::IssuedToken(source) => {
477 let token = source.0.get_issued_token().await?;
478 let nonce = remote_nonce.as_ref();
479 let cert = remote_cert;
480 let secret = legacy_encrypt_secret(
481 channel_security_policy,
482 security_mode,
483 policy,
484 nonce,
485 cert,
486 token.as_ref(),
487 )?;
488 let identity_token = IssuedIdentityToken {
489 policy_id: secret.policy,
490 encryption_algorithm: secret.encryption_algorithm,
491 token_data: secret.secret,
492 };
493 Ok((
494 ExtensionObject::from_message(identity_token),
495 SignatureData::null(),
496 ))
497 }
498 }
499 }
500
501 async fn build_request(
502 self,
503 channel: &AsyncSecureChannel,
504 ) -> Result<ActivateSessionRequest, Error> {
505 let (remote_cert, remote_nonce, security_policy, message_security_mode) = {
506 let secure_channel = trace_read_lock!(channel.secure_channel);
507 (
508 secure_channel.remote_cert(),
509 secure_channel.remote_nonce_as_byte_string(),
510 secure_channel.security_policy(),
511 secure_channel.security_mode(),
512 )
513 };
514 let (user_identity_token, user_token_signature) = self
515 .user_identity_token(
516 &remote_nonce,
517 &remote_cert,
518 message_security_mode,
519 security_policy,
520 )
521 .in_current_span()
522 .await?;
523 let client_signature = match security_policy {
524 SecurityPolicy::None => SignatureData::null(),
525 _ => {
526 let Some(client_pkey) = self.private_key else {
527 error!("Cannot create client signature - no pkey!");
528 return Err(Error::new(
529 StatusCode::BadUnexpectedError,
530 "Cannot sign request, no private key provided",
531 ));
532 };
533
534 let Some(server_cert) = remote_cert else {
535 error!("Cannot sign server certificate because server cert is null");
536 return Err(Error::new(
537 StatusCode::BadUnexpectedError,
538 "Cannot sign request, missing server certificate",
539 ));
540 };
541
542 let server_nonce = remote_nonce;
543 if server_nonce.is_null_or_empty() {
544 error!("Cannot sign server certificate because server nonce is empty");
545 return Err(Error::new(
546 StatusCode::BadUnexpectedError,
547 "Cannot sign request, empty remote nonce",
548 ));
549 }
550
551 let server_cert = server_cert.as_byte_string();
552 opcua_crypto::create_signature_data(
553 &client_pkey,
554 security_policy,
555 &server_cert,
556 &server_nonce,
557 )?
558 }
559 };
560
561 Ok(ActivateSessionRequest {
562 request_header: self.header.header,
563 client_signature,
564 client_software_certificates: if self.client_software_certificates.is_empty() {
565 None
566 } else {
567 Some(self.client_software_certificates)
568 },
569 locale_ids: if self.locale_ids.is_empty() {
570 None
571 } else {
572 Some(self.locale_ids)
573 },
574 user_identity_token,
575 user_token_signature,
576 })
577 }
578}
579
580impl UARequest for ActivateSession {
581 type Out = ActivateSessionResponse;
582
583 async fn send<'a>(self, channel: &'a crate::AsyncSecureChannel) -> Result<Self::Out, Error>
584 where
585 Self: 'a,
586 {
587 let timeout = self.header.timeout;
588 let span = info_span!("Sending ActivateSession request",
589 endpoint = %self.endpoint.endpoint_url,
590 session_id = self.header.session_id,
591 );
592 let request = self.build_request(channel).instrument(span.clone()).await?;
593
594 let response = channel
595 .send(request, timeout)
596 .instrument(span.clone())
597 .await?;
598
599 let _h = span.enter();
600 if let ResponseMessage::ActivateSession(response) = response {
601 tracing::debug!("activate_session success");
602 process_service_result(&response.response_header)?;
604 channel.update_from_activated_session(&response.server_nonce)?;
605 Ok(*response)
606 } else {
607 tracing::error!("activate_session failed");
608 Err(process_unexpected_response(response))
609 }
610 }
611}
612
613#[derive(Debug, Clone)]
614pub struct CloseSession {
619 delete_subscriptions: bool,
620 header: RequestHeaderBuilder,
621}
622
623builder_base!(CloseSession);
624
625impl CloseSession {
626 pub(crate) fn new(session: &Session) -> Self {
630 Self {
631 delete_subscriptions: true,
632 header: RequestHeaderBuilder::new_from_session(session),
633 }
634 }
635
636 pub fn new_manual(
638 session_id: u32,
639 timeout: Duration,
640 auth_token: NodeId,
641 request_handle: IntegerId,
642 ) -> Self {
643 Self {
644 delete_subscriptions: true,
645 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
646 }
647 }
648
649 pub fn delete_subscriptions(mut self, delete_subscriptions: bool) -> Self {
652 self.delete_subscriptions = delete_subscriptions;
653 self
654 }
655}
656
657impl UARequest for CloseSession {
658 type Out = CloseSessionResponse;
659
660 async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
661 where
662 Self: 'a,
663 {
664 let request = CloseSessionRequest {
665 delete_subscriptions: self.delete_subscriptions,
666 request_header: self.header.header,
667 };
668 let span = debug_span!(
669 "Sending CloseSession request",
670 session_id = self.header.session_id,
671 );
672 let response = channel
673 .send(request, self.header.timeout)
674 .instrument(span.clone())
675 .await?;
676 let _h = span.enter();
677 if let ResponseMessage::CloseSession(response) = response {
678 builder_debug!(self, "close_session success");
679 process_service_result(&response.response_header)?;
680 Ok(*response)
681 } else {
682 builder_error!(self, "close_session failed {:?}", response);
683 Err(process_unexpected_response(response))
684 }
685 }
686}
687
688#[derive(Debug, Clone)]
689pub struct Cancel {
693 request_handle: IntegerId,
694 header: RequestHeaderBuilder,
695}
696
697builder_base!(Cancel);
698
699impl Cancel {
700 pub fn new(request_to_cancel: IntegerId, session: &Session) -> Self {
702 Self {
703 request_handle: request_to_cancel,
704 header: RequestHeaderBuilder::new_from_session(session),
705 }
706 }
707
708 pub fn new_manual(
710 request_to_cancel: IntegerId,
711 session_id: u32,
712 timeout: Duration,
713 auth_token: NodeId,
714 request_handle: IntegerId,
715 ) -> Self {
716 Self {
717 request_handle: request_to_cancel,
718 header: RequestHeaderBuilder::new(session_id, timeout, auth_token, request_handle),
719 }
720 }
721}
722
723impl UARequest for Cancel {
724 type Out = CancelResponse;
725
726 async fn send<'a>(self, channel: &'a AsyncSecureChannel) -> Result<Self::Out, Error>
727 where
728 Self: 'a,
729 {
730 let request = CancelRequest {
731 request_header: self.header.header,
732 request_handle: self.request_handle,
733 };
734 let span = debug_span!(
735 "Sending Cancel request",
736 request_handle = self.request_handle,
737 session_id = self.header.session_id,
738 );
739
740 let response = channel
741 .send(request, self.header.timeout)
742 .instrument(span.clone())
743 .await?;
744 let _h = span.enter();
745 if let ResponseMessage::Cancel(response) = response {
746 process_service_result(&response.response_header)?;
747 Ok(*response)
748 } else {
749 Err(process_unexpected_response(response))
750 }
751 }
752}
753
754impl Session {
755 pub(crate) async fn create_session(&self) -> Result<NodeId, Error> {
767 let response = CreateSession::new(self).send(&self.channel).await?;
768
769 let session_id = {
770 self.session_id.store(Arc::new(response.session_id.clone()));
771 response.session_id.clone()
772 };
773
774 Ok(session_id)
775 }
776
777 pub(crate) async fn activate_session(&self) -> Result<(), Error> {
787 ActivateSession::new(self).send(&self.channel).await?;
788 Ok(())
789 }
790
791 pub(crate) async fn close_session(&self, delete_subscriptions: bool) -> Result<(), Error> {
795 CloseSession::new(self)
796 .delete_subscriptions(delete_subscriptions)
797 .send(&self.channel)
798 .await?;
799 Ok(())
800 }
801
802 pub async fn cancel(&self, request_handle: IntegerId) -> Result<u32, Error> {
816 Ok(Cancel::new(request_handle, self)
817 .send(&self.channel)
818 .await?
819 .cancel_count)
820 }
821}