|
| 1 | +use super::{legacy, ConnectorError, ConnectorErrorExt}; |
| 2 | +use crate::{encode_send_data_request, ConnectorResult, ConnectorResultExt as _, Sequence, State, Written}; |
| 3 | +use core::fmt::Debug; |
1 | 4 | use core::{fmt, mem};
|
2 |
| - |
3 | 5 | use ironrdp_core::WriteBuf;
|
4 |
| -use ironrdp_pdu::rdp::server_license::{self, LicensePdu, ServerLicenseError}; |
| 6 | +use ironrdp_pdu::rdp::server_license::{self, LicenseInformation, LicensePdu, ServerLicenseError}; |
5 | 7 | use ironrdp_pdu::PduHint;
|
6 | 8 | use rand_core::{OsRng, RngCore as _};
|
7 |
| - |
8 |
| -use super::legacy; |
9 |
| -use crate::{encode_send_data_request, ConnectorResult, ConnectorResultExt as _, Sequence, State, Written}; |
| 9 | +use std::str; |
| 10 | +use std::sync::Arc; |
10 | 11 |
|
11 | 12 | #[derive(Default, Debug)]
|
12 | 13 | #[non_exhaustive]
|
@@ -57,15 +58,43 @@ pub struct LicenseExchangeSequence {
|
57 | 58 | pub io_channel_id: u16,
|
58 | 59 | pub username: String,
|
59 | 60 | pub domain: Option<String>,
|
| 61 | + pub hardware_id: [u32; 4], |
| 62 | + pub license_cache: Arc<dyn LicenseCache>, |
| 63 | +} |
| 64 | + |
| 65 | +pub trait LicenseCache: Sync + Send + Debug { |
| 66 | + fn get_license(&self, license_info: LicenseInformation) -> ConnectorResult<Option<Vec<u8>>>; |
| 67 | + fn store_license(&self, license_info: LicenseInformation) -> ConnectorResult<()>; |
| 68 | +} |
| 69 | + |
| 70 | +#[derive(Debug)] |
| 71 | +pub(crate) struct NoopLicenseCache; |
| 72 | + |
| 73 | +impl LicenseCache for NoopLicenseCache { |
| 74 | + fn get_license(&self, _license_info: LicenseInformation) -> ConnectorResult<Option<Vec<u8>>> { |
| 75 | + Ok(None) |
| 76 | + } |
| 77 | + |
| 78 | + fn store_license(&self, _license_info: LicenseInformation) -> ConnectorResult<()> { |
| 79 | + Ok(()) |
| 80 | + } |
60 | 81 | }
|
61 | 82 |
|
62 | 83 | impl LicenseExchangeSequence {
|
63 |
| - pub fn new(io_channel_id: u16, username: String, domain: Option<String>) -> Self { |
| 84 | + pub fn new( |
| 85 | + io_channel_id: u16, |
| 86 | + username: String, |
| 87 | + domain: Option<String>, |
| 88 | + hardware_id: [u32; 4], |
| 89 | + license_cache: Arc<dyn LicenseCache>, |
| 90 | + ) -> Self { |
64 | 91 | Self {
|
65 | 92 | state: LicenseExchangeState::NewLicenseRequest,
|
66 | 93 | io_channel_id,
|
67 | 94 | username,
|
68 | 95 | domain,
|
| 96 | + hardware_id, |
| 97 | + license_cache, |
69 | 98 | }
|
70 | 99 | }
|
71 | 100 | }
|
@@ -107,52 +136,102 @@ impl Sequence for LicenseExchangeSequence {
|
107 | 136 | let mut premaster_secret = [0u8; server_license::PREMASTER_SECRET_SIZE];
|
108 | 137 | OsRng.fill_bytes(&mut premaster_secret);
|
109 | 138 |
|
110 |
| - match server_license::ClientNewLicenseRequest::from_server_license_request( |
111 |
| - &license_request, |
112 |
| - &client_random, |
113 |
| - &premaster_secret, |
114 |
| - &self.username, |
115 |
| - self.domain.as_deref().unwrap_or(""), |
116 |
| - ) { |
117 |
| - Ok((new_license_request, encryption_data)) => { |
118 |
| - trace!(?encryption_data, "Successfully generated Client New License Request"); |
119 |
| - info!(message = ?new_license_request, "Send"); |
120 |
| - |
121 |
| - let written = encode_send_data_request::<LicensePdu>( |
122 |
| - send_data_indication_ctx.initiator_id, |
123 |
| - send_data_indication_ctx.channel_id, |
124 |
| - &new_license_request.into(), |
125 |
| - output, |
126 |
| - )?; |
127 |
| - |
128 |
| - ( |
129 |
| - Written::from_size(written)?, |
130 |
| - LicenseExchangeState::PlatformChallenge { encryption_data }, |
131 |
| - ) |
| 139 | + let license_info = license_request |
| 140 | + .scope_list |
| 141 | + .iter() |
| 142 | + .filter_map(|scope| { |
| 143 | + self.license_cache |
| 144 | + .get_license(LicenseInformation { |
| 145 | + version: license_request.product_info.version, |
| 146 | + scope: scope.0.clone(), |
| 147 | + company_name: license_request.product_info.company_name.clone(), |
| 148 | + product_id: license_request.product_info.product_id.clone(), |
| 149 | + license_info: vec![], |
| 150 | + }) |
| 151 | + .transpose() |
| 152 | + }) |
| 153 | + .next() |
| 154 | + .transpose()?; |
| 155 | + |
| 156 | + if let Some(info) = license_info { |
| 157 | + match server_license::ClientLicenseInfo::from_server_license_request( |
| 158 | + &license_request, |
| 159 | + &client_random, |
| 160 | + &premaster_secret, |
| 161 | + self.hardware_id, |
| 162 | + info, |
| 163 | + ) { |
| 164 | + Ok((client_license_info, encryption_data)) => { |
| 165 | + trace!(?encryption_data, "Successfully generated Client License Info"); |
| 166 | + info!(message = ?client_license_info, "Send"); |
| 167 | + |
| 168 | + let written = encode_send_data_request::<LicensePdu>( |
| 169 | + send_data_indication_ctx.initiator_id, |
| 170 | + send_data_indication_ctx.channel_id, |
| 171 | + &client_license_info.into(), |
| 172 | + output, |
| 173 | + )?; |
| 174 | + |
| 175 | + trace!(?written, "Written ClientLicenseInfo"); |
| 176 | + |
| 177 | + ( |
| 178 | + Written::from_size(written)?, |
| 179 | + LicenseExchangeState::PlatformChallenge { encryption_data }, |
| 180 | + ) |
| 181 | + } |
| 182 | + Err(err) => { |
| 183 | + return Err(custom_err!("ClientNewLicenseRequest", err)); |
| 184 | + } |
132 | 185 | }
|
133 |
| - Err(error) => { |
134 |
| - if let ServerLicenseError::InvalidX509Certificate { |
135 |
| - source: error, |
136 |
| - cert_der, |
137 |
| - } = &error |
138 |
| - { |
139 |
| - struct BytesHexFormatter<'a>(&'a [u8]); |
140 |
| - |
141 |
| - impl fmt::Display for BytesHexFormatter<'_> { |
142 |
| - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
143 |
| - write!(f, "0x")?; |
144 |
| - self.0.iter().try_for_each(|byte| write!(f, "{byte:02X}")) |
| 186 | + } else { |
| 187 | + let hwid = self.hardware_id; |
| 188 | + match server_license::ClientNewLicenseRequest::from_server_license_request( |
| 189 | + &license_request, |
| 190 | + &client_random, |
| 191 | + &premaster_secret, |
| 192 | + &self.username, |
| 193 | + &format!("{:X}-{:X}-{:X}-{:X}", hwid[0], hwid[1], hwid[2], hwid[3]), |
| 194 | + ) { |
| 195 | + Ok((new_license_request, encryption_data)) => { |
| 196 | + trace!(?encryption_data, "Successfully generated Client New License Request"); |
| 197 | + info!(message = ?new_license_request, "Send"); |
| 198 | + |
| 199 | + let written = encode_send_data_request::<LicensePdu>( |
| 200 | + send_data_indication_ctx.initiator_id, |
| 201 | + send_data_indication_ctx.channel_id, |
| 202 | + &new_license_request.into(), |
| 203 | + output, |
| 204 | + )?; |
| 205 | + |
| 206 | + ( |
| 207 | + Written::from_size(written)?, |
| 208 | + LicenseExchangeState::PlatformChallenge { encryption_data }, |
| 209 | + ) |
| 210 | + } |
| 211 | + Err(error) => { |
| 212 | + if let ServerLicenseError::InvalidX509Certificate { |
| 213 | + source: error, |
| 214 | + cert_der, |
| 215 | + } = &error |
| 216 | + { |
| 217 | + struct BytesHexFormatter<'a>(&'a [u8]); |
| 218 | + |
| 219 | + impl fmt::Display for BytesHexFormatter<'_> { |
| 220 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 221 | + write!(f, "0x")?; |
| 222 | + self.0.iter().try_for_each(|byte| write!(f, "{byte:02X}")) |
| 223 | + } |
145 | 224 | }
|
| 225 | + |
| 226 | + error!( |
| 227 | + %error, |
| 228 | + cert_der = %BytesHexFormatter(cert_der), |
| 229 | + "Unsupported or invalid X509 certificate received during license exchange step" |
| 230 | + ); |
146 | 231 | }
|
147 | 232 |
|
148 |
| - error!( |
149 |
| - %error, |
150 |
| - cert_der = %BytesHexFormatter(cert_der), |
151 |
| - "Unsupported or invalid X509 certificate received during license exchange step" |
152 |
| - ); |
| 233 | + return Err(custom_err!("ClientNewLicenseRequest", error)); |
153 | 234 | }
|
154 |
| - |
155 |
| - return Err(custom_err!("ClientNewLicenseRequest", error)); |
156 | 235 | }
|
157 | 236 | }
|
158 | 237 | }
|
@@ -188,7 +267,7 @@ impl Sequence for LicenseExchangeSequence {
|
188 | 267 | let challenge_response =
|
189 | 268 | server_license::ClientPlatformChallengeResponse::from_server_platform_challenge(
|
190 | 269 | &challenge,
|
191 |
| - self.domain.as_deref().unwrap_or(""), |
| 270 | + self.hardware_id, |
192 | 271 | &encryption_data,
|
193 | 272 | )
|
194 | 273 | .map_err(|e| custom_err!("ClientPlatformChallengeResponse", e))?;
|
@@ -242,6 +321,12 @@ impl Sequence for LicenseExchangeSequence {
|
242 | 321 | .map_err(|e| custom_err!("license verification", e))?;
|
243 | 322 |
|
244 | 323 | debug!("License verified with success");
|
| 324 | + |
| 325 | + let license_info = upgrade_license |
| 326 | + .new_license_info(&encryption_data) |
| 327 | + .map_err(ConnectorError::decode)?; |
| 328 | + |
| 329 | + self.license_cache.store_license(license_info)? |
245 | 330 | }
|
246 | 331 | LicensePdu::LicensingErrorMessage(error_message) => {
|
247 | 332 | if error_message.error_code != server_license::LicenseErrorCode::StatusValidClient {
|
|
0 commit comments