ironrdp_pdu/rdp/server_license/
server_upgrade_license.rs

1#[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/// [2.2.2.6] Server Upgrade License (SERVER_UPGRADE_LICENSE)
20///
21/// [2.2.2.6]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpele/e8339fbd-1fe3-42c2-a599-27c04407166d
22#[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
156            + UTF16_NULL_TERMINATOR_SIZE
157            + self.product_id.len() * 2 // utf16
158            + 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}