Diffstat (limited to 'noncore/net/opierdesktop/licence.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/net/opierdesktop/licence.cpp | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/noncore/net/opierdesktop/licence.cpp b/noncore/net/opierdesktop/licence.cpp new file mode 100644 index 0000000..4e5bc38 --- a/dev/null +++ b/noncore/net/opierdesktop/licence.cpp | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | rdesktop: A Remote Desktop Protocol client. | ||
3 | RDP licensing negotiation | ||
4 | Copyright (C) Matthew Chapman 1999-2002 | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "rdesktop.h" | ||
22 | |||
23 | #ifdef WITH_OPENSSL | ||
24 | #include <openssl/rc4.h> | ||
25 | #else | ||
26 | #include "crypto/rc4.h" | ||
27 | #endif | ||
28 | |||
29 | extern char username[16]; | ||
30 | extern char hostname[16]; | ||
31 | |||
32 | static uint8 licence_key[16]; | ||
33 | static uint8 licence_sign_key[16]; | ||
34 | |||
35 | BOOL licence_issued = False; | ||
36 | |||
37 | /* Generate a session key and RC4 keys, given client and server randoms */ | ||
38 | static void | ||
39 | licence_generate_keys(uint8 * client_key, uint8 * server_key, uint8 * client_rsa) | ||
40 | { | ||
41 | uint8 session_key[48]; | ||
42 | uint8 temp_hash[48]; | ||
43 | |||
44 | /* Generate session key - two rounds of sec_hash_48 */ | ||
45 | sec_hash_48(temp_hash, client_rsa, client_key, server_key, 65); | ||
46 | sec_hash_48(session_key, temp_hash, server_key, client_key, 65); | ||
47 | |||
48 | /* Store first 16 bytes of session key, for generating signatures */ | ||
49 | memcpy(licence_sign_key, session_key, 16); | ||
50 | |||
51 | /* Generate RC4 key */ | ||
52 | sec_hash_16(licence_key, &session_key[16], client_key, server_key); | ||
53 | } | ||
54 | |||
55 | static void | ||
56 | licence_generate_hwid(uint8 * hwid) | ||
57 | { | ||
58 | buf_out_uint32(hwid, 2); | ||
59 | strncpy((char *) (hwid + 4), hostname, LICENCE_HWID_SIZE - 4); | ||
60 | } | ||
61 | |||
62 | /* Present an existing licence to the server */ | ||
63 | static void | ||
64 | licence_present(uint8 * client_random, uint8 * rsa_data, | ||
65 | uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) | ||
66 | { | ||
67 | uint32 sec_flags = SEC_LICENCE_NEG; | ||
68 | uint16 length = | ||
69 | 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + | ||
70 | licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; | ||
71 | STREAM s; | ||
72 | |||
73 | s = sec_init(sec_flags, length + 4); | ||
74 | |||
75 | out_uint16_le(s, LICENCE_TAG_PRESENT); | ||
76 | out_uint16_le(s, length); | ||
77 | |||
78 | out_uint32_le(s, 1); | ||
79 | out_uint16(s, 0); | ||
80 | out_uint16_le(s, 0x0201); | ||
81 | |||
82 | out_uint8p(s, client_random, SEC_RANDOM_SIZE); | ||
83 | out_uint16(s, 0); | ||
84 | out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); | ||
85 | out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); | ||
86 | out_uint8s(s, SEC_PADDING_SIZE); | ||
87 | |||
88 | out_uint16_le(s, 1); | ||
89 | out_uint16_le(s, licence_size); | ||
90 | out_uint8p(s, licence_data, licence_size); | ||
91 | |||
92 | out_uint16_le(s, 1); | ||
93 | out_uint16_le(s, LICENCE_HWID_SIZE); | ||
94 | out_uint8p(s, hwid, LICENCE_HWID_SIZE); | ||
95 | |||
96 | out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); | ||
97 | |||
98 | s_mark_end(s); | ||
99 | sec_send(s, sec_flags); | ||
100 | } | ||
101 | |||
102 | /* Send a licence request packet */ | ||
103 | static void | ||
104 | licence_send_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) | ||
105 | { | ||
106 | uint32 sec_flags = SEC_LICENCE_NEG; | ||
107 | uint16 userlen = strlen(user) + 1; | ||
108 | uint16 hostlen = strlen(host) + 1; | ||
109 | uint16 length = 128 + userlen + hostlen; | ||
110 | STREAM s; | ||
111 | |||
112 | s = sec_init(sec_flags, length + 2); | ||
113 | |||
114 | out_uint16_le(s, LICENCE_TAG_REQUEST); | ||
115 | out_uint16_le(s, length); | ||
116 | |||
117 | out_uint32_le(s, 1); | ||
118 | out_uint16(s, 0); | ||
119 | out_uint16_le(s, 0xff01); | ||
120 | |||
121 | out_uint8p(s, client_random, SEC_RANDOM_SIZE); | ||
122 | out_uint16(s, 0); | ||
123 | out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); | ||
124 | out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); | ||
125 | out_uint8s(s, SEC_PADDING_SIZE); | ||
126 | |||
127 | out_uint16(s, LICENCE_TAG_USER); | ||
128 | out_uint16(s, userlen); | ||
129 | out_uint8p(s, user, userlen); | ||
130 | |||
131 | out_uint16(s, LICENCE_TAG_HOST); | ||
132 | out_uint16(s, hostlen); | ||
133 | out_uint8p(s, host, hostlen); | ||
134 | |||
135 | s_mark_end(s); | ||
136 | sec_send(s, sec_flags); | ||
137 | } | ||
138 | |||
139 | /* Process a licence demand packet */ | ||
140 | static void | ||
141 | licence_process_demand(STREAM s) | ||
142 | { | ||
143 | uint8 null_data[SEC_MODULUS_SIZE]; | ||
144 | uint8 *server_random; | ||
145 | uint8 signature[LICENCE_SIGNATURE_SIZE]; | ||
146 | uint8 hwid[LICENCE_HWID_SIZE]; | ||
147 | uint8 *licence_data; | ||
148 | int licence_size; | ||
149 | RC4_KEY crypt_key; | ||
150 | |||
151 | /* Retrieve the server random from the incoming packet */ | ||
152 | in_uint8p(s, server_random, SEC_RANDOM_SIZE); | ||
153 | |||
154 | /* We currently use null client keys. This is a bit naughty but, hey, | ||
155 | the security of licence negotiation isn't exactly paramount. */ | ||
156 | memset(null_data, 0, sizeof(null_data)); | ||
157 | licence_generate_keys(null_data, server_random, null_data); | ||
158 | |||
159 | licence_size = load_licence(&licence_data); | ||
160 | if (licence_size != -1) | ||
161 | { | ||
162 | /* Generate a signature for the HWID buffer */ | ||
163 | licence_generate_hwid(hwid); | ||
164 | sec_sign(signature, 16, licence_sign_key, 16, hwid, sizeof(hwid)); | ||
165 | |||
166 | /* Now encrypt the HWID */ | ||
167 | RC4_set_key(&crypt_key, 16, licence_key); | ||
168 | RC4(&crypt_key, sizeof(hwid), hwid, hwid); | ||
169 | |||
170 | licence_present(null_data, null_data, licence_data, licence_size, hwid, signature); | ||
171 | xfree(licence_data); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | licence_send_request(null_data, null_data, username, hostname); | ||
176 | } | ||
177 | |||
178 | /* Send an authentication response packet */ | ||
179 | static void | ||
180 | licence_send_authresp(uint8 * token, uint8 * crypt_hwid, uint8 * signature) | ||
181 | { | ||
182 | uint32 sec_flags = SEC_LICENCE_NEG; | ||
183 | uint16 length = 58; | ||
184 | STREAM s; | ||
185 | |||
186 | s = sec_init(sec_flags, length + 2); | ||
187 | |||
188 | out_uint16_le(s, LICENCE_TAG_AUTHRESP); | ||
189 | out_uint16_le(s, length); | ||
190 | |||
191 | out_uint16_le(s, 1); | ||
192 | out_uint16_le(s, LICENCE_TOKEN_SIZE); | ||
193 | out_uint8p(s, token, LICENCE_TOKEN_SIZE); | ||
194 | |||
195 | out_uint16_le(s, 1); | ||
196 | out_uint16_le(s, LICENCE_HWID_SIZE); | ||
197 | out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE); | ||
198 | |||
199 | out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); | ||
200 | |||
201 | s_mark_end(s); | ||
202 | sec_send(s, sec_flags); | ||
203 | } | ||
204 | |||
205 | /* Parse an authentication request packet */ | ||
206 | static BOOL | ||
207 | licence_parse_authreq(STREAM s, uint8 ** token, uint8 ** signature) | ||
208 | { | ||
209 | uint16 tokenlen; | ||
210 | |||
211 | in_uint8s(s, 6);/* unknown: f8 3d 15 00 04 f6 */ | ||
212 | |||
213 | in_uint16_le(s, tokenlen); | ||
214 | if (tokenlen != LICENCE_TOKEN_SIZE) | ||
215 | { | ||
216 | error("token len %d\n", tokenlen); | ||
217 | return False; | ||
218 | } | ||
219 | |||
220 | in_uint8p(s, *token, tokenlen); | ||
221 | in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); | ||
222 | |||
223 | return s_check_end(s); | ||
224 | } | ||
225 | |||
226 | /* Process an authentication request packet */ | ||
227 | static void | ||
228 | licence_process_authreq(STREAM s) | ||
229 | { | ||
230 | uint8 *in_token, *in_sig; | ||
231 | uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE]; | ||
232 | uint8 hwid[LICENCE_HWID_SIZE], crypt_hwid[LICENCE_HWID_SIZE]; | ||
233 | uint8 sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; | ||
234 | uint8 out_sig[LICENCE_SIGNATURE_SIZE]; | ||
235 | RC4_KEY crypt_key; | ||
236 | |||
237 | /* Parse incoming packet and save the encrypted token */ | ||
238 | licence_parse_authreq(s, &in_token, &in_sig); | ||
239 | memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); | ||
240 | |||
241 | /* Decrypt the token. It should read TEST in Unicode. */ | ||
242 | RC4_set_key(&crypt_key, 16, licence_key); | ||
243 | RC4(&crypt_key, LICENCE_TOKEN_SIZE, in_token, decrypt_token); | ||
244 | |||
245 | /* Generate a signature for a buffer of token and HWID */ | ||
246 | licence_generate_hwid(hwid); | ||
247 | memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); | ||
248 | memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); | ||
249 | sec_sign(out_sig, 16, licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer)); | ||
250 | |||
251 | /* Now encrypt the HWID */ | ||
252 | RC4_set_key(&crypt_key, 16, licence_key); | ||
253 | RC4(&crypt_key, LICENCE_HWID_SIZE, hwid, crypt_hwid); | ||
254 | |||
255 | licence_send_authresp(out_token, crypt_hwid, out_sig); | ||
256 | } | ||
257 | |||
258 | /* Process an licence issue packet */ | ||
259 | static void | ||
260 | licence_process_issue(STREAM s) | ||
261 | { | ||
262 | RC4_KEY crypt_key; | ||
263 | uint32 length; | ||
264 | uint16 check; | ||
265 | |||
266 | in_uint8s(s, 2);/* 3d 45 - unknown */ | ||
267 | in_uint16_le(s, length); | ||
268 | if (!s_check_rem(s, length)) | ||
269 | return; | ||
270 | |||
271 | RC4_set_key(&crypt_key, 16, licence_key); | ||
272 | RC4(&crypt_key, length, s->p, s->p); | ||
273 | |||
274 | in_uint16(s, check); | ||
275 | if (check != 0) | ||
276 | return; | ||
277 | |||
278 | licence_issued = True; | ||
279 | save_licence(s->p, length - 2); | ||
280 | } | ||
281 | |||
282 | /* Process a licence packet */ | ||
283 | void | ||
284 | licence_process(STREAM s) | ||
285 | { | ||
286 | uint16 tag; | ||
287 | |||
288 | in_uint16_le(s, tag); | ||
289 | in_uint8s(s, 2);/* length */ | ||
290 | |||
291 | switch (tag) | ||
292 | { | ||
293 | case LICENCE_TAG_DEMAND: | ||
294 | licence_process_demand(s); | ||
295 | break; | ||
296 | |||
297 | case LICENCE_TAG_AUTHREQ: | ||
298 | licence_process_authreq(s); | ||
299 | break; | ||
300 | |||
301 | case LICENCE_TAG_ISSUE: | ||
302 | licence_process_issue(s); | ||
303 | break; | ||
304 | |||
305 | case LICENCE_TAG_REISSUE: | ||
306 | break; | ||
307 | |||
308 | case LICENCE_TAG_RESULT: | ||
309 | break; | ||
310 | |||
311 | default: | ||
312 | unimpl("licence tag 0x%x\n", tag); | ||
313 | } | ||
314 | } | ||