ai-remote 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/{src/index.ts → dist/index.d.ts} +0 -1
  2. package/dist/index.js +0 -1
  3. package/dist/protocols/index.d.ts +31 -0
  4. package/dist/protocols/index.js +0 -1
  5. package/dist/protocols/rdp/buffer.d.ts +38 -0
  6. package/dist/protocols/rdp/buffer.js +0 -1
  7. package/dist/protocols/rdp/caps.d.ts +49 -0
  8. package/dist/protocols/rdp/caps.js +0 -1
  9. package/dist/protocols/rdp/cert.d.ts +18 -0
  10. package/dist/protocols/rdp/cert.js +0 -1
  11. package/dist/protocols/rdp/client.d.ts +56 -0
  12. package/dist/protocols/rdp/client.js +0 -1
  13. package/dist/protocols/rdp/cliprdr.d.ts +27 -0
  14. package/dist/protocols/rdp/cliprdr.js +0 -1
  15. package/dist/protocols/rdp/credssp.d.ts +34 -0
  16. package/dist/protocols/rdp/credssp.js +0 -1
  17. package/dist/protocols/rdp/crypto.d.ts +63 -0
  18. package/dist/protocols/rdp/crypto.js +0 -1
  19. package/dist/protocols/rdp/display.d.ts +38 -0
  20. package/dist/protocols/rdp/display.js +0 -1
  21. package/dist/protocols/rdp/gcc.d.ts +23 -0
  22. package/dist/protocols/rdp/gcc.js +0 -1
  23. package/dist/protocols/rdp/keymap.d.ts +9 -0
  24. package/dist/protocols/rdp/keymap.js +0 -1
  25. package/dist/protocols/rdp/mcs.d.ts +40 -0
  26. package/dist/protocols/rdp/mcs.js +0 -1
  27. package/dist/protocols/rdp/ntlm.d.ts +61 -0
  28. package/dist/protocols/rdp/ntlm.js +0 -1
  29. package/dist/protocols/rdp/pdu.d.ts +155 -0
  30. package/dist/protocols/rdp/pdu.js +0 -1
  31. package/dist/protocols/rdp/rail.d.ts +119 -0
  32. package/dist/protocols/rdp/rail.js +0 -1
  33. package/dist/protocols/rdp/rle.d.ts +13 -0
  34. package/dist/protocols/rdp/rle.js +0 -1
  35. package/dist/protocols/rdp/sec.d.ts +59 -0
  36. package/dist/protocols/rdp/sec.js +0 -1
  37. package/dist/protocols/rdp/session.d.ts +62 -0
  38. package/dist/protocols/rdp/session.js +0 -1
  39. package/dist/protocols/rdp/tls.d.ts +18 -0
  40. package/dist/protocols/rdp/tls.js +0 -1
  41. package/dist/protocols/rdp/vchannel.d.ts +28 -0
  42. package/dist/protocols/rdp/vchannel.js +0 -1
  43. package/dist/protocols/rdp/x224.d.ts +40 -0
  44. package/dist/protocols/rdp/x224.js +0 -1
  45. package/dist/protocols/ssh/kex.d.ts +97 -0
  46. package/dist/protocols/ssh/kex.js +0 -1
  47. package/dist/protocols/ssh/messages.d.ts +50 -0
  48. package/dist/protocols/ssh/messages.js +0 -1
  49. package/dist/protocols/ssh/session.d.ts +66 -0
  50. package/dist/protocols/ssh/session.js +0 -1
  51. package/dist/protocols/ssh/terminal.d.ts +46 -0
  52. package/dist/protocols/ssh/terminal.js +0 -1
  53. package/dist/protocols/ssh/transport.d.ts +62 -0
  54. package/dist/protocols/ssh/transport.js +0 -1
  55. package/dist/protocols/ssh/wire.d.ts +52 -0
  56. package/dist/protocols/ssh/wire.js +0 -1
  57. package/dist/protocols/types.d.ts +127 -0
  58. package/dist/protocols/types.js +0 -1
  59. package/dist/protocols/vnc/input.d.ts +5 -0
  60. package/dist/protocols/vnc/input.js +0 -1
  61. package/dist/protocols/vnc/session.d.ts +12 -0
  62. package/dist/protocols/vnc/session.js +0 -1
  63. package/dist/shared/connection.d.ts +81 -0
  64. package/dist/shared/connection.js +0 -1
  65. package/dist/shared/device.d.ts +26 -0
  66. package/dist/shared/device.js +0 -1
  67. package/dist/shared/hosts.d.ts +63 -0
  68. package/dist/shared/hosts.js +0 -1
  69. package/dist/shared/icons.d.ts +46 -0
  70. package/dist/shared/icons.js +0 -1
  71. package/dist/shared/protocol.d.ts +28 -0
  72. package/dist/shared/protocol.js +0 -1
  73. package/dist/shared/signals.d.ts +37 -0
  74. package/dist/shared/signals.js +0 -1
  75. package/package.json +10 -11
  76. package/dist/index.js.map +0 -7
  77. package/dist/protocols/index.js.map +0 -7
  78. package/dist/protocols/rdp/buffer.js.map +0 -7
  79. package/dist/protocols/rdp/caps.js.map +0 -7
  80. package/dist/protocols/rdp/cert.js.map +0 -7
  81. package/dist/protocols/rdp/client.js.map +0 -7
  82. package/dist/protocols/rdp/cliprdr.js.map +0 -7
  83. package/dist/protocols/rdp/credssp.js.map +0 -7
  84. package/dist/protocols/rdp/crypto.js.map +0 -7
  85. package/dist/protocols/rdp/display.js.map +0 -7
  86. package/dist/protocols/rdp/gcc.js.map +0 -7
  87. package/dist/protocols/rdp/keymap.js.map +0 -7
  88. package/dist/protocols/rdp/mcs.js.map +0 -7
  89. package/dist/protocols/rdp/ntlm.js.map +0 -7
  90. package/dist/protocols/rdp/pdu.js.map +0 -7
  91. package/dist/protocols/rdp/rail.js.map +0 -7
  92. package/dist/protocols/rdp/rle.js.map +0 -7
  93. package/dist/protocols/rdp/sec.js.map +0 -7
  94. package/dist/protocols/rdp/session.js.map +0 -7
  95. package/dist/protocols/rdp/tls.js.map +0 -7
  96. package/dist/protocols/rdp/vchannel.js.map +0 -7
  97. package/dist/protocols/rdp/x224.js.map +0 -7
  98. package/dist/protocols/ssh/kex.js.map +0 -7
  99. package/dist/protocols/ssh/messages.js.map +0 -7
  100. package/dist/protocols/ssh/session.js.map +0 -7
  101. package/dist/protocols/ssh/terminal.js.map +0 -7
  102. package/dist/protocols/ssh/transport.js.map +0 -7
  103. package/dist/protocols/ssh/wire.js.map +0 -7
  104. package/dist/protocols/types.js.map +0 -7
  105. package/dist/protocols/vnc/input.js.map +0 -7
  106. package/dist/protocols/vnc/session.js.map +0 -7
  107. package/dist/shared/connection.js.map +0 -7
  108. package/dist/shared/device.js.map +0 -7
  109. package/dist/shared/hosts.js.map +0 -7
  110. package/dist/shared/icons.js.map +0 -7
  111. package/dist/shared/protocol.js.map +0 -7
  112. package/dist/shared/signals.js.map +0 -7
  113. package/src/cli/cli.ts +0 -462
  114. package/src/cli/daemon.ts +0 -306
  115. package/src/cli/framebuffer.ts +0 -115
  116. package/src/cli/generated/viewer-bundle.ts +0 -5
  117. package/src/cli/ipc.ts +0 -78
  118. package/src/cli/native/window.swift +0 -151
  119. package/src/cli/paths.ts +0 -28
  120. package/src/cli/png.ts +0 -106
  121. package/src/cli/session.ts +0 -263
  122. package/src/cli/shell.ts +0 -184
  123. package/src/cli/transport.ts +0 -86
  124. package/src/cli/viewer-client/assets.d.ts +0 -4
  125. package/src/cli/viewer-client/main.ts +0 -323
  126. package/src/cli/viewer-page.ts +0 -138
  127. package/src/cli/viewer.ts +0 -296
  128. package/src/cli/window.ts +0 -140
  129. package/src/cli/wsserver.ts +0 -144
  130. package/src/protocols/index.ts +0 -72
  131. package/src/protocols/rdp/buffer.ts +0 -204
  132. package/src/protocols/rdp/caps.ts +0 -304
  133. package/src/protocols/rdp/cert.ts +0 -190
  134. package/src/protocols/rdp/client.ts +0 -1371
  135. package/src/protocols/rdp/cliprdr.ts +0 -344
  136. package/src/protocols/rdp/credssp.ts +0 -319
  137. package/src/protocols/rdp/crypto.ts +0 -416
  138. package/src/protocols/rdp/display.ts +0 -750
  139. package/src/protocols/rdp/gcc.ts +0 -162
  140. package/src/protocols/rdp/keymap.ts +0 -68
  141. package/src/protocols/rdp/mcs.ts +0 -283
  142. package/src/protocols/rdp/ntlm.ts +0 -380
  143. package/src/protocols/rdp/pdu.ts +0 -497
  144. package/src/protocols/rdp/rail.ts +0 -480
  145. package/src/protocols/rdp/rle.ts +0 -343
  146. package/src/protocols/rdp/sec.ts +0 -184
  147. package/src/protocols/rdp/session.ts +0 -393
  148. package/src/protocols/rdp/tls.ts +0 -452
  149. package/src/protocols/rdp/vchannel.ts +0 -89
  150. package/src/protocols/rdp/x224.ts +0 -139
  151. package/src/protocols/ssh/kex.ts +0 -227
  152. package/src/protocols/ssh/messages.ts +0 -54
  153. package/src/protocols/ssh/session.ts +0 -879
  154. package/src/protocols/ssh/terminal.ts +0 -242
  155. package/src/protocols/ssh/transport.ts +0 -745
  156. package/src/protocols/ssh/wire.ts +0 -220
  157. package/src/protocols/types.ts +0 -146
  158. package/src/protocols/vnc/input.ts +0 -13
  159. package/src/protocols/vnc/novnc.d.ts +0 -75
  160. package/src/protocols/vnc/session.ts +0 -367
  161. package/src/shared/connection.ts +0 -206
  162. package/src/shared/device.ts +0 -28
  163. package/src/shared/hosts.ts +0 -240
  164. package/src/shared/icons.ts +0 -49
  165. package/src/shared/protocol.ts +0 -55
  166. package/src/shared/signals.ts +0 -67
@@ -1,304 +0,0 @@
1
- // Capability exchange (MS-RDPBCGR 2.2.7).
2
- //
3
- // This client deliberately advertises no drawing-order support and no bitmap
4
- // cache, which makes the host fall back to plain bitmap updates for the whole
5
- // screen. That is the one output path a from-scratch client can implement
6
- // correctly, and it is what keeps the rest of this module small.
7
-
8
- import { Reader, Writer, concatBytes } from './buffer';
9
-
10
- export const CAPSET = {
11
- GENERAL: 1,
12
- BITMAP: 2,
13
- ORDER: 3,
14
- BITMAPCACHE: 4,
15
- CONTROL: 5,
16
- ACTIVATION: 7,
17
- POINTER: 8,
18
- SHARE: 9,
19
- COLORCACHE: 10,
20
- SOUND: 12,
21
- INPUT: 13,
22
- FONT: 14,
23
- BRUSH: 15,
24
- GLYPHCACHE: 16,
25
- OFFSCREENCACHE: 17,
26
- VIRTUALCHANNEL: 20,
27
- RAIL: 23,
28
- WINDOW: 24,
29
- MULTIFRAGMENTUPDATE: 26,
30
- LARGE_POINTER: 27,
31
- SURFACE_COMMANDS: 28,
32
- BITMAP_CODECS: 29,
33
- };
34
-
35
- const INPUT_FLAG_SCANCODES = 0x0001;
36
- const INPUT_FLAG_MOUSEX = 0x0004;
37
- const INPUT_FLAG_UNICODE = 0x0010;
38
-
39
- const FASTPATH_OUTPUT_SUPPORTED = 0x0001;
40
- const LONG_CREDENTIALS_SUPPORTED = 0x0004;
41
- const NEGOTIATE_ORDER_SUPPORT = 0x0002;
42
- const ZERO_BOUNDS_DELTA_SUPPORT = 0x0008;
43
-
44
- function capabilitySet(type: number, body: Uint8Array) {
45
- const writer = new Writer(body.length + 4);
46
- writer.u16le(type).u16le(body.length + 4).raw(body);
47
- return writer.take();
48
- }
49
-
50
- function generalCapability() {
51
- const writer = new Writer(24);
52
- writer.u16le(1); // osMajorType: Windows
53
- writer.u16le(3); // osMinorType: Windows NT
54
- writer.u16le(0x0200); // protocolVersion
55
- writer.u16le(0); // pad
56
- writer.u16le(0); // generalCompressionTypes
57
- // Fast-path output has to be advertised. Windows 8 and later send graphics
58
- // only on the fast path, so a client that asks for the slow path alone gets a
59
- // clean session that never paints anything.
60
- writer.u16le(FASTPATH_OUTPUT_SUPPORTED | LONG_CREDENTIALS_SUPPORTED); // extraFlags
61
- writer.u16le(0); // updateCapabilityFlag
62
- writer.u16le(0); // remoteUnshareFlag
63
- writer.u16le(0); // generalCompressionLevel
64
- // Both are declarations that the client may SEND these PDUs. The initial
65
- // full-screen paint depends on it: a host that thinks the client cannot ask
66
- // for a refresh has no reason to honour the request.
67
- writer.u8(1); // refreshRectSupport
68
- writer.u8(1); // suppressOutputSupport
69
- return capabilitySet(CAPSET.GENERAL, writer.take());
70
- }
71
-
72
- function bitmapCapability(width: number, height: number) {
73
- const writer = new Writer(28);
74
- writer.u16le(16); // preferredBitsPerPixel
75
- writer.u16le(1); // receive1BitPerPixel
76
- writer.u16le(1); // receive4BitsPerPixel
77
- writer.u16le(1); // receive8BitsPerPixel
78
- writer.u16le(width);
79
- writer.u16le(height);
80
- writer.u16le(0); // pad
81
- writer.u16le(1); // desktopResizeFlag
82
- writer.u16le(1); // bitmapCompressionFlag
83
- writer.u8(0); // highColorFlags
84
- writer.u8(0); // drawingFlags
85
- writer.u16le(1); // multipleRectangleSupport
86
- writer.u16le(0); // pad
87
- return capabilitySet(CAPSET.BITMAP, writer.take());
88
- }
89
-
90
- function orderCapability() {
91
- const writer = new Writer(88);
92
- writer.zeros(16); // terminalDescriptor
93
- writer.u32le(0); // pad
94
- writer.u16le(1); // desktopSaveXGranularity
95
- writer.u16le(20); // desktopSaveYGranularity
96
- writer.u16le(0); // pad
97
- writer.u16le(1); // maximumOrderLevel
98
- writer.u16le(0); // numberFonts
99
- writer.u16le(NEGOTIATE_ORDER_SUPPORT | ZERO_BOUNDS_DELTA_SUPPORT);
100
- writer.zeros(32); // orderSupport: none
101
- writer.u16le(0); // textFlags
102
- writer.u16le(0); // orderSupportExFlags
103
- writer.u32le(0); // pad
104
- writer.u32le(230400); // desktopSaveSize
105
- writer.u16le(0); // pad
106
- writer.u16le(0); // pad
107
- writer.u16le(0); // textANSICodePage
108
- writer.u16le(0); // pad
109
- return capabilitySet(CAPSET.ORDER, writer.take());
110
- }
111
-
112
- /** Zero entries in every cache: the host must send bitmaps, never cache hits. */
113
- function bitmapCacheCapability() {
114
- const writer = new Writer(40);
115
- writer.zeros(24); // pad1..pad6
116
- writer.u16le(0).u16le(0);
117
- writer.u16le(0).u16le(0);
118
- writer.u16le(0).u16le(0);
119
- return capabilitySet(CAPSET.BITMAPCACHE, writer.take());
120
- }
121
-
122
- function controlCapability() {
123
- const writer = new Writer(12);
124
- writer.u16le(0); // controlFlags
125
- writer.u16le(0); // remoteDetachFlag
126
- writer.u16le(2); // controlInterest: never
127
- writer.u16le(2); // detachInterest: never
128
- return capabilitySet(CAPSET.CONTROL, writer.take());
129
- }
130
-
131
- function activationCapability() {
132
- const writer = new Writer(12);
133
- writer.u16le(0).u16le(0).u16le(0).u16le(0);
134
- return capabilitySet(CAPSET.ACTIVATION, writer.take());
135
- }
136
-
137
- function pointerCapability() {
138
- const writer = new Writer(10);
139
- writer.u16le(1); // colorPointerFlag
140
- writer.u16le(20); // colorPointerCacheSize
141
- writer.u16le(20); // pointerCacheSize
142
- return capabilitySet(CAPSET.POINTER, writer.take());
143
- }
144
-
145
- function shareCapability() {
146
- const writer = new Writer(8);
147
- writer.u16le(0).u16le(0);
148
- return capabilitySet(CAPSET.SHARE, writer.take());
149
- }
150
-
151
- function colorCacheCapability() {
152
- const writer = new Writer(8);
153
- writer.u16le(6).u16le(0);
154
- return capabilitySet(CAPSET.COLORCACHE, writer.take());
155
- }
156
-
157
- function soundCapability() {
158
- const writer = new Writer(8);
159
- writer.u16le(0).u16le(0);
160
- return capabilitySet(CAPSET.SOUND, writer.take());
161
- }
162
-
163
- function inputCapability(keyboardLayout: number) {
164
- const writer = new Writer(88);
165
- writer.u16le(INPUT_FLAG_SCANCODES | INPUT_FLAG_MOUSEX | INPUT_FLAG_UNICODE);
166
- writer.u16le(0); // pad
167
- writer.u32le(keyboardLayout);
168
- writer.u32le(4); // keyboardType: IBM enhanced
169
- writer.u32le(0); // keyboardSubType
170
- writer.u32le(12); // keyboardFunctionKey
171
- writer.zeros(64); // imeFileName
172
- return capabilitySet(CAPSET.INPUT, writer.take());
173
- }
174
-
175
- function fontCapability() {
176
- const writer = new Writer(8);
177
- writer.u16le(1).u16le(0);
178
- return capabilitySet(CAPSET.FONT, writer.take());
179
- }
180
-
181
- function brushCapability() {
182
- const writer = new Writer(8);
183
- writer.u32le(0); // BRUSH_DEFAULT
184
- return capabilitySet(CAPSET.BRUSH, writer.take());
185
- }
186
-
187
- function glyphCacheCapability() {
188
- const writer = new Writer(52);
189
- for (let i = 0; i < 10; i++) writer.u16le(0).u16le(0); // GlyphCache entries
190
- writer.u32le(0); // FragCache
191
- writer.u16le(0); // GLYPH_SUPPORT_NONE
192
- writer.u16le(0); // pad
193
- return capabilitySet(CAPSET.GLYPHCACHE, writer.take());
194
- }
195
-
196
- function offscreenCacheCapability() {
197
- const writer = new Writer(12);
198
- writer.u32le(0); // offscreenSupportLevel: none
199
- writer.u16le(0); // offscreenCacheSize
200
- writer.u16le(0); // offscreenCacheEntries
201
- return capabilitySet(CAPSET.OFFSCREENCACHE, writer.take());
202
- }
203
-
204
- function remoteProgramsCapability() {
205
- const writer = new Writer(4);
206
- writer.u32le(0x00000001); // TS_RAIL_LEVEL_SUPPORTED
207
- return capabilitySet(CAPSET.RAIL, writer.take());
208
- }
209
-
210
- function windowListCapability(iconCaches = 0, iconCacheEntries = 0) {
211
- const writer = new Writer(7);
212
- writer.u32le(0x00000001); // TS_WINDOW_LEVEL_SUPPORTED
213
- writer.u8(iconCaches);
214
- writer.u16le(iconCacheEntries);
215
- return capabilitySet(CAPSET.WINDOW, writer.take());
216
- }
217
-
218
- export function buildClientCapabilities({ width, height, keyboardLayout, remoteApp = false, remoteAppCaps = null }) {
219
- const sets = [
220
- generalCapability(),
221
- bitmapCapability(width, height),
222
- orderCapability(),
223
- bitmapCacheCapability(),
224
- colorCacheCapability(),
225
- activationCapability(),
226
- controlCapability(),
227
- pointerCapability(),
228
- shareCapability(),
229
- inputCapability(keyboardLayout),
230
- brushCapability(),
231
- glyphCacheCapability(),
232
- soundCapability(),
233
- fontCapability(),
234
- offscreenCacheCapability(),
235
- ];
236
-
237
- if (remoteApp) {
238
- sets.push(remoteProgramsCapability());
239
- sets.push(windowListCapability(
240
- remoteAppCaps?.numIconCaches || 0,
241
- remoteAppCaps?.numIconCacheEntries || 0
242
- ));
243
- }
244
-
245
- return { bytes: concatBytes(...sets), count: sets.length };
246
- }
247
-
248
- /**
249
- * Read the host's Demand Active capabilities. The desktop size it reports wins
250
- * over anything the client asked for.
251
- */
252
- export function parseServerCapabilities(bytes: Uint8Array) {
253
- const reader = new Reader(bytes);
254
- const numberCapabilities = reader.u16le();
255
- reader.u16le(); // pad
256
-
257
- const result = {
258
- desktopWidth: 0,
259
- desktopHeight: 0,
260
- preferredBitsPerPixel: 16,
261
- refreshRectSupport: false,
262
- railSupportLevel: 0,
263
- windowSupportLevel: 0,
264
- numIconCaches: 0,
265
- numIconCacheEntries: 0,
266
- types: [],
267
- };
268
-
269
- for (let i = 0; i < numberCapabilities && reader.remaining >= 4; i++) {
270
- const type = reader.u16le();
271
- const length = reader.u16le();
272
- if (length < 4 || length - 4 > reader.remaining) break;
273
- const body = new Reader(reader.raw(length - 4));
274
- result.types.push(type);
275
-
276
- if (type === CAPSET.BITMAP && body.remaining >= 20) {
277
- result.preferredBitsPerPixel = body.u16le();
278
- body.skip(6); // receive1/4/8BitsPerPixel
279
- result.desktopWidth = body.u16le();
280
- result.desktopHeight = body.u16le();
281
- continue;
282
- }
283
-
284
- if (type === CAPSET.GENERAL && body.remaining >= 20) {
285
- body.skip(18);
286
- result.refreshRectSupport = body.u8() !== 0;
287
- continue;
288
- }
289
-
290
- if (type === CAPSET.RAIL && body.remaining >= 4) {
291
- result.railSupportLevel = body.u32le();
292
- continue;
293
- }
294
-
295
- if (type === CAPSET.WINDOW && body.remaining >= 7) {
296
- result.windowSupportLevel = body.u32le();
297
- result.numIconCaches = body.u8();
298
- result.numIconCacheEntries = body.u16le();
299
- continue;
300
- }
301
- }
302
-
303
- return result;
304
- }
@@ -1,190 +0,0 @@
1
- // Server public key extraction for the RDP Standard Security layer.
2
- //
3
- // A host either hands out a "proprietary" certificate -- little more than a
4
- // wrapper around an RSA public key -- or an X.509 chain whose leaf holds the
5
- // key (MS-RDPBCGR 2.2.1.4.3.1). Either way the client random is encrypted with
6
- // that key, so all we need out of it is a modulus and an exponent.
7
- //
8
- // Note the proprietary certificate is signed with a private key Microsoft
9
- // published, so it authenticates nothing: RDP Standard Security gives
10
- // confidentiality on the wire, not proof of the host's identity.
11
-
12
- import { Reader } from './buffer';
13
-
14
- const CERT_PROPRIETARY = 1;
15
- const CERT_X509 = 2;
16
- const RSA1_MAGIC = 0x31415352;
17
- const BB_RSA_KEY_BLOB = 0x0006;
18
-
19
- const OID_RSA_ENCRYPTION = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
20
-
21
- // --- DER --------------------------------------------------------------------
22
-
23
- function derRead(bytes: Uint8Array, offset: number) {
24
- let cursor = offset;
25
- const tag = bytes[cursor++];
26
-
27
- let length = bytes[cursor++];
28
- if (length & 0x80) {
29
- const byteCount = length & 0x7f;
30
- length = 0;
31
- for (let i = 0; i < byteCount; i++) length = (length << 8) | bytes[cursor++];
32
- }
33
-
34
- return {
35
- tag,
36
- contentStart: cursor,
37
- contentEnd: cursor + length,
38
- next: cursor + length,
39
- content: bytes.subarray(cursor, cursor + length),
40
- };
41
- }
42
-
43
- function derChildren(bytes: Uint8Array) {
44
- const children = [];
45
- let offset = 0;
46
- while (offset < bytes.length) {
47
- const node = derRead(bytes, offset);
48
- children.push(node);
49
- if (node.next <= offset) break;
50
- offset = node.next;
51
- }
52
- return children;
53
- }
54
-
55
- function containsOid(bytes: Uint8Array, oid: string) {
56
- outer: for (let i = 0; i + oid.length <= bytes.length; i++) {
57
- for (let j = 0; j < oid.length; j++) {
58
- if (bytes[i + j] !== oid[j]) continue outer;
59
- }
60
- return true;
61
- }
62
- return false;
63
- }
64
-
65
- /** Big-endian DER integer -> little-endian bytes with the sign byte removed. */
66
- function derIntegerToLe(content: Uint8Array) {
67
- let start = 0;
68
- while (start < content.length - 1 && content[start] === 0x00) start++;
69
- return content.subarray(start).slice().reverse();
70
- }
71
-
72
- /**
73
- * Find SubjectPublicKeyInfo in an X.509 certificate and return the RSA key.
74
- * The structure is walked rather than indexed by position: optional fields in
75
- * TBSCertificate make fixed offsets wrong for many real certificates.
76
- */
77
- function rsaKeyFromX509(der: Uint8Array) {
78
- const certificate = derRead(der, 0);
79
- const tbsCertificate = derRead(der, certificate.contentStart);
80
-
81
- for (const child of derChildren(tbsCertificate.content)) {
82
- if (child.tag !== 0x30) continue;
83
-
84
- const parts = derChildren(child.content);
85
- if (parts.length < 2) continue;
86
- if (parts[0].tag !== 0x30 || !containsOid(parts[0].content, OID_RSA_ENCRYPTION)) continue;
87
- if (parts[1].tag !== 0x03) continue;
88
-
89
- // BIT STRING content starts with an "unused bits" count.
90
- const publicKey = derRead(parts[1].content.subarray(1), 0);
91
- const [modulus, exponent] = derChildren(publicKey.content);
92
- if (!modulus || !exponent) break;
93
-
94
- return {
95
- modulus: derIntegerToLe(modulus.content),
96
- exponent: derIntegerToLe(exponent.content),
97
- source: 'x509',
98
- };
99
- }
100
-
101
- throw new Error('RDP: no RSA public key found in the host X.509 certificate');
102
- }
103
-
104
- function rsaKeyFromProprietary(reader: Reader) {
105
- reader.u32le(); // dwSigAlgId
106
- reader.u32le(); // dwKeyAlgId
107
-
108
- const publicKeyBlobType = reader.u16le();
109
- const publicKeyBlobLength = reader.u16le();
110
- if (publicKeyBlobType !== BB_RSA_KEY_BLOB) {
111
- throw new Error(`RDP: unsupported public key blob type 0x${publicKeyBlobType.toString(16)}`);
112
- }
113
-
114
- const blob = new Reader(reader.raw(publicKeyBlobLength));
115
- if (blob.u32le() !== RSA1_MAGIC) {
116
- throw new Error('RDP: the host RSA public key blob is not in RSA1 format');
117
- }
118
-
119
- const keyLength = blob.u32le();
120
- blob.u32le(); // bitlen
121
- blob.u32le(); // datalen
122
- const exponent = blob.raw(4).slice();
123
-
124
- // The blob reserves 8 trailing bytes of padding after the modulus.
125
- if (keyLength < 9) throw new Error('RDP: the host RSA modulus is too short');
126
- const modulus = blob.raw(keyLength - 8).slice();
127
-
128
- return { modulus, exponent, source: 'proprietary' };
129
- }
130
-
131
- /**
132
- * Pull the RSA public key out of a DER X.509 certificate, for the TLS layer.
133
- *
134
- * CredSSP needs the exact bytes of the certificate's subjectPublicKey BIT
135
- * STRING contents -- the DER RSAPublicKey -- because that is what both ends
136
- * hash to bind the authentication to this TLS channel (MS-CSSP 3.1.5).
137
- */
138
- export function parseX509PublicKey(der: Uint8Array) {
139
- const certificate = derRead(der, 0);
140
- const tbsCertificate = derRead(der, certificate.contentStart);
141
-
142
- for (const child of derChildren(tbsCertificate.content)) {
143
- if (child.tag !== 0x30) continue;
144
-
145
- const parts = derChildren(child.content);
146
- if (parts.length < 2) continue;
147
- if (parts[0].tag !== 0x30 || !containsOid(parts[0].content, OID_RSA_ENCRYPTION)) continue;
148
- if (parts[1].tag !== 0x03) continue;
149
-
150
- const subjectPublicKey = parts[1].content.subarray(1); // drop the unused-bit count
151
- const publicKey = derRead(subjectPublicKey, 0);
152
- const [modulus, exponent] = derChildren(publicKey.content);
153
- if (!modulus || !exponent) break;
154
-
155
- const stripLeadingZero = (bytes: Uint8Array) => {
156
- let start = 0;
157
- while (start < bytes.length - 1 && bytes[start] === 0x00) start++;
158
- return bytes.subarray(start);
159
- };
160
-
161
- return {
162
- modulus: stripLeadingZero(modulus.content),
163
- exponent: stripLeadingZero(exponent.content),
164
- subjectPublicKey,
165
- };
166
- }
167
-
168
- throw new Error('TLS: no RSA public key found in the host certificate');
169
- }
170
-
171
- /** Parse a server certificate blob into an RSA public key. */
172
- export function parseServerCertificate(certificateBytes: Uint8Array) {
173
- const reader = new Reader(certificateBytes);
174
- const version = reader.u32le() & 0x7fffffff;
175
-
176
- if (version === CERT_PROPRIETARY) return rsaKeyFromProprietary(reader);
177
-
178
- if (version === CERT_X509) {
179
- const certificateCount = reader.u32le();
180
- let leaf = null;
181
- for (let i = 0; i < certificateCount; i++) {
182
- const length = reader.u32le();
183
- leaf = reader.raw(length);
184
- }
185
- if (!leaf) throw new Error('RDP: the host sent an empty X.509 certificate chain');
186
- return rsaKeyFromX509(leaf);
187
- }
188
-
189
- throw new Error(`RDP: unsupported server certificate version ${version}`);
190
- }