ironrdp_pdu/rdp/server_license/
server_upgrade_license.rs1#[cfg(test)]
2mod tests;
3
4use ironrdp_core::{
5 cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult,
6 ReadCursor, WriteCursor,
7};
8
9use super::{
10 BlobHeader, BlobType, LicenseEncryptionData, LicenseHeader, PreambleType, ServerLicenseError, BLOB_LENGTH_SIZE,
11 BLOB_TYPE_SIZE, MAC_SIZE, UTF16_NULL_TERMINATOR_SIZE, UTF8_NULL_TERMINATOR_SIZE,
12};
13use crate::crypto::rc4::Rc4;
14use crate::utils;
15use crate::utils::CharacterSet;
16
17const LICENSE_INFO_STATIC_FIELDS_SIZE: usize = 20;
18
19#[derive(Debug, PartialEq, Eq)]
23pub struct ServerUpgradeLicense {
24 pub license_header: LicenseHeader,
25 pub encrypted_license_info: Vec<u8>,
26 pub mac_data: Vec<u8>,
27}
28
29impl ServerUpgradeLicense {
30 pub fn verify_server_license(&self, encryption_data: &LicenseEncryptionData) -> Result<(), ServerLicenseError> {
31 let decrypted_license_info = self.decrypted_license_info(encryption_data);
32 let mac_data =
33 super::compute_mac_data(encryption_data.mac_salt_key.as_slice(), decrypted_license_info.as_ref());
34
35 if mac_data != self.mac_data {
36 return Err(ServerLicenseError::InvalidMacData);
37 }
38
39 Ok(())
40 }
41
42 pub fn new_license_info(&self, encryption_data: &LicenseEncryptionData) -> DecodeResult<LicenseInformation> {
43 let data = self.decrypted_license_info(encryption_data);
44 LicenseInformation::decode(&mut ReadCursor::new(&data))
45 }
46
47 fn decrypted_license_info(&self, encryption_data: &LicenseEncryptionData) -> Vec<u8> {
48 let mut rc4 = Rc4::new(encryption_data.license_key.as_slice());
49 rc4.process(self.encrypted_license_info.as_slice())
50 }
51}
52
53impl ServerUpgradeLicense {
54 const NAME: &'static str = "ServerUpgradeLicense";
55}
56
57impl ServerUpgradeLicense {
58 pub fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
59 ensure_size!(in: dst, size: self.size());
60
61 self.license_header.encode(dst)?;
62 BlobHeader::new(BlobType::ENCRYPTED_DATA, self.encrypted_license_info.len()).encode(dst)?;
63 dst.write_slice(&self.encrypted_license_info);
64 dst.write_slice(&self.mac_data);
65
66 Ok(())
67 }
68
69 pub fn name(&self) -> &'static str {
70 Self::NAME
71 }
72
73 pub fn size(&self) -> usize {
74 self.license_header.size() + BLOB_LENGTH_SIZE + BLOB_TYPE_SIZE + self.encrypted_license_info.len() + MAC_SIZE
75 }
76}
77
78impl ServerUpgradeLicense {
79 pub fn decode(license_header: LicenseHeader, src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
80 if license_header.preamble_message_type != PreambleType::UpgradeLicense
81 && license_header.preamble_message_type != PreambleType::NewLicense
82 {
83 return Err(invalid_field_err!(
84 "preambleType",
85 "got unexpected message preamble type"
86 ));
87 }
88
89 let encrypted_license_info_blob = BlobHeader::decode(src)?;
90 if encrypted_license_info_blob.blob_type != BlobType::ENCRYPTED_DATA {
91 return Err(invalid_field_err!("blobType", "unexpected blob type"));
92 }
93
94 ensure_size!(in: src, size: encrypted_license_info_blob.length + MAC_SIZE);
95 let encrypted_license_info = src.read_slice(encrypted_license_info_blob.length).into();
96 let mac_data = src.read_slice(MAC_SIZE).into();
97
98 Ok(Self {
99 license_header,
100 encrypted_license_info,
101 mac_data,
102 })
103 }
104}
105
106#[derive(Debug, PartialEq, Eq, Hash)]
107pub struct LicenseInformation {
108 pub version: u32,
109 pub scope: String,
110 pub company_name: String,
111 pub product_id: String,
112 pub license_info: Vec<u8>,
113}
114
115impl LicenseInformation {
116 const NAME: &'static str = "LicenseInformation";
117
118 const FIXED_PART_SIZE: usize = LICENSE_INFO_STATIC_FIELDS_SIZE;
119}
120
121impl Encode for LicenseInformation {
122 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
123 ensure_size!(in: dst, size: self.size());
124
125 dst.write_u32(self.version);
126
127 dst.write_u32(cast_length!("scopeLen", self.scope.len() + UTF8_NULL_TERMINATOR_SIZE)?);
128 utils::write_string_to_cursor(dst, &self.scope, CharacterSet::Ansi, true)?;
129
130 dst.write_u32(cast_length!(
131 "companyLen",
132 self.company_name.len() * 2 + UTF16_NULL_TERMINATOR_SIZE
133 )?);
134 utils::write_string_to_cursor(dst, &self.company_name, CharacterSet::Unicode, true)?;
135
136 dst.write_u32(cast_length!(
137 "produceIdLen",
138 self.product_id.len() * 2 + UTF16_NULL_TERMINATOR_SIZE
139 )?);
140 utils::write_string_to_cursor(dst, &self.product_id, CharacterSet::Unicode, true)?;
141
142 dst.write_u32(cast_length!("licenseInfoLen", self.license_info.len())?);
143 dst.write_slice(self.license_info.as_slice());
144
145 Ok(())
146 }
147
148 fn name(&self) -> &'static str {
149 Self::NAME
150 }
151
152 fn size(&self) -> usize {
153 Self::FIXED_PART_SIZE
154 + self.scope.len() + UTF8_NULL_TERMINATOR_SIZE
155 + self.company_name.len() * 2 + UTF16_NULL_TERMINATOR_SIZE
157 + self.product_id.len() * 2 + UTF16_NULL_TERMINATOR_SIZE
159 + self.license_info.len()
160 }
161}
162
163impl<'de> Decode<'de> for LicenseInformation {
164 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
165 ensure_fixed_part_size!(in: src);
166
167 let version = src.read_u32();
168
169 let scope_len: usize = cast_length!("scopeLen", src.read_u32())?;
170 ensure_size!(in: src, size: scope_len);
171 let scope = utils::decode_string(src.read_slice(scope_len), CharacterSet::Ansi, true)?;
172
173 let company_name_len: usize = cast_length!("companyLen", src.read_u32())?;
174 ensure_size!(in: src, size: company_name_len);
175 let company_name = utils::decode_string(src.read_slice(company_name_len), CharacterSet::Unicode, true)?;
176
177 let product_id_len: usize = cast_length!("productIdLen", src.read_u32())?;
178 ensure_size!(in: src, size: product_id_len);
179 let product_id = utils::decode_string(src.read_slice(product_id_len), CharacterSet::Unicode, true)?;
180
181 let license_info_len = cast_length!("licenseInfoLen", src.read_u32())?;
182 ensure_size!(in: src, size: license_info_len);
183 let license_info = src.read_slice(license_info_len).into();
184
185 Ok(Self {
186 version,
187 scope,
188 company_name,
189 product_id,
190 license_info,
191 })
192 }
193}