├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── lib
├── asn1
│ ├── ber.js
│ ├── index.js
│ ├── spec.js
│ └── univ.js
├── core
│ ├── error.js
│ ├── index.js
│ ├── layer.js
│ ├── log.js
│ ├── rle.js
│ └── type.js
├── index.js
├── protocol
│ ├── cert.js
│ ├── index.js
│ ├── pdu
│ │ ├── caps.js
│ │ ├── data.js
│ │ ├── global.js
│ │ ├── index.js
│ │ ├── lic.js
│ │ └── sec.js
│ ├── rdp.js
│ ├── t125
│ │ ├── gcc.js
│ │ ├── index.js
│ │ ├── mcs.js
│ │ └── per.js
│ ├── tpkt.js
│ └── x224.js
└── security
│ ├── index.js
│ ├── jsbn.js
│ ├── rsa.js
│ └── x509.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | README.md~
3 | npm_modules/*
4 | .settings/*
5 | node_modules/*
6 | *.log
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.2.1 - 20150708
2 | * Minor bug fix
3 |
4 | ## 0.2.0 - 20150707
5 | * Add this changelog
6 | * Configure keyboard layout for client side of protocol
7 | * Handle TLS error
8 | * Add log level
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | node-rdpjs
2 | ========
3 |
4 | Remote Desktop Protocol for Node.js
5 |
6 | node-rdpjs is a pure implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (client and server side). node-rdpjs support only SSL security layer.
7 |
8 | ## Install
9 |
10 | You can install last release node-rdpjs through npm :
11 |
12 | ```
13 | npm install node-rdpjs
14 | ```
15 |
16 | Or work with dev branch :
17 |
18 | ```
19 | git clone https://github.com/citronneur/node-rdpjs.git
20 | cd node-rdpjs
21 | npm install
22 | ```
23 |
24 | ## RDP Client
25 |
26 | To create a simple rdp client :
27 |
28 | ```javascript
29 | var rdp = require('node-rdpjs');
30 |
31 | var client = rdp.createClient({
32 | domain : 'my_domain',
33 | userName : 'my_username',
34 | password : 'my_password',
35 | enablePerf : true,
36 | autoLogin : true,
37 | decompress : false,
38 | screen : { width : 800, height : 600 },
39 | locale : 'en',
40 | logLevel : 'INFO'
41 | }).on('connect', function () {
42 | }).on('close', function() {
43 | }).on('bitmap', function(bitmap) {
44 | }).on('error', function(err) {
45 | }).connect('XXX.XXX.XXX.XXX', 3389);
46 | ```
47 |
48 | Client parameters :
49 |
50 | * domain {string} Microsoft domain
51 | * userName {string} Username
52 | * password {string} password
53 | * enablePerf {boolean} Active some performance features (disable wallpaper)
54 | * autoLogin {boolean} start session if login informations are good
55 | * decompress {boolean} use RLE algorrithm for decompress bitmap
56 | * screen {object} screen size
57 | - width {integer} width of screen
58 | - height {integer} height of screen
59 | * locale {string} keyboard layout
60 | - en qwerty layout
61 | - fr azerty layout
62 | * logLevel {string} console log level of library
63 | - DEBUG
64 | - INFO
65 | - WARN
66 | - ERROR
67 |
68 | Use of decompress parameter impact performance.
69 |
70 | ### Client Events
71 |
72 | List of all available events from server
73 |
74 | #### connect
75 |
76 | Connect event is received when rdp stack is connected
77 |
78 | #### close
79 |
80 | Close event is received when rdp stack is close cleanly
81 |
82 | #### error
83 |
84 | Error event is received when a protocol error happened
85 |
86 | #### bitmap
87 |
88 | Bitmap event is received for a bitmap refresh order :
89 |
90 | * destTop {integer} y min position
91 | * destLeft {integer} x min position
92 | * destBottom {integer} y max position
93 | * destRight {integer} x max position
94 | * width {integer} width of bitmap data
95 | * height {integer} height of bitmap data
96 | * bitsPerPixel {integer} [15|16|24|32] bits per pixel
97 | * isCompress {boolean} true if bitmap is compressed with RLE algorithm
98 | * data : {Buffer} bitmap data
99 |
100 | ### Client Inputs
101 |
102 | Client inputs are mainly user inputs (mouse and keyboard).
103 |
104 | #### Mouse
105 |
106 | ```javascript
107 | client.sendPointerEvent(x, y, button, isPressed);
108 | ```
109 |
110 | * x {integer} mouse x position in pixel
111 | * y {integer} mouse y position in pixel
112 | * button {integer} [ 1 (left) | 2 (right) | 3 (middle) ]
113 | * isPressed {boolean} true for a pressed button event
114 |
115 | #### Keyboard
116 |
117 | ```javascript
118 | client.sendKeyEventScancode(code, isPressed);
119 | ```
120 |
121 | * code {integer} scancode of key
122 | * isPressed {boolean} true for a key pressed event
123 |
124 | ```javascript
125 | client.sendKeyEventUnicode(code, isPressed);
126 | ```
127 |
128 | * code {integer} unicode char of key
129 | * isPressed {boolean} true for a key pressed event
130 |
131 | ## Project
132 |
133 | Please see [**mstsc.js**](https://github.com/citronneur/mstsc.js) project page to watch an example of node-rdpjs.
134 |
135 | ## Roadmap
136 |
137 | * Protocol server side
138 | * NLA Authentication security layer
139 | * RDP security layer for windows xp compatibility
140 | * Win32 orders
141 | * RemoteFX (H.264) codec
142 |
--------------------------------------------------------------------------------
/lib/asn1/ber.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../core').type;
21 | var log = require('../core').log;
22 | var error = require('../core').error;
23 |
24 | /**
25 | * Parse tag(T) field of BER TLV
26 | * And check with expected tag
27 | * @param s {type.Stream}
28 | * @param tag {spec.tag}
29 | * @returns {Boolean} True for valid tag matching
30 | */
31 | function decodeTag(s, tag) {
32 | var nextTag = new type.UInt8().read(s).value;
33 | if (tag.tagNumber > 30) {
34 | nextTagNumber = new type.UInt8().read(s).value;
35 | }
36 | else {
37 | nextTagNumber = nextTag & 0x1F;
38 | }
39 |
40 | return ((nextTag & 0xE0) === (tag.tagClass | tag.tagFormat)) && (nextTagNumber === tag.tagNumber);
41 | };
42 |
43 | /**
44 | * Parse length(L) field of BER TLV
45 | * @param s {type.Stream}
46 | * @returns {integer}
47 | */
48 | function decodeLength(s) {
49 | var size = new type.UInt8().read(s).value;
50 | if(size & 0x80) {
51 | size &= ~0x80;
52 | if(size === 1) {
53 | size = new type.UInt8().read(s).value;
54 | }
55 | else if(size === 2) {
56 | size = new type.UInt16Be().read(s).value;
57 | }
58 | else{
59 | throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_LENGTH');
60 | }
61 | }
62 | return size;
63 | };
64 |
65 | /**
66 | * Decode tuple TLV (Tag Length Value) of BER
67 | * @param s {type.Stream}
68 | * @param tag {spec.Asn1Tag} expected tag
69 | * @returns {type.BinaryString} Value of tuple
70 | */
71 | function decode(s, tag) {
72 | if (!decodeTag(s, tag)) {
73 | throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_TAG');
74 | }
75 | var length = decodeLength(s);
76 |
77 | if (length === 0) {
78 | return new type.Stream(0);
79 | }
80 | return new type.BinaryString(null,{ readLength : new type.CallableValue(length) }).read(s);
81 | };
82 |
83 | function encodeTag(tag) {
84 | if(tag.tagNumber > 30) {
85 | return new type.Component([new type.UInt8(tag.tagClass | tag.tagFormat | 0x1F), new type.UInt8(tag.tagNumber)]);
86 | }
87 | else {
88 | return new type.UInt8((tag.tagClass | tag.tagFormat) | (tag.tagNumber & 0x1F));
89 | }
90 | }
91 |
92 | function encodeLength(length) {
93 | if(length > 0x7f) {
94 | return new type.Component([new type.UInt8(0x82), new type.UInt16Be(length)]);
95 | }
96 | else {
97 | return new type.UInt8(length);
98 | }
99 | }
100 |
101 | function encode(tag, buffer) {
102 | return new type.Component([encodeTag(tag), encodeLength(buffer.size()), buffer]);
103 | }
104 |
105 | /**
106 | * Module Export
107 | */
108 | module.exports = {
109 | decode : decode,
110 | encode : encode
111 | };
112 |
--------------------------------------------------------------------------------
/lib/asn1/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var ber = require('./ber');
21 | var univ = require('./univ');
22 | var spec = require('./spec');
23 |
24 | module.exports = {
25 | ber : ber,
26 | univ : univ,
27 | spec : spec
28 | };
29 |
--------------------------------------------------------------------------------
/lib/asn1/spec.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var type = require('../core').type;
22 | var error = require('../core').error;
23 |
24 | /**
25 | * Tag Class
26 | */
27 | var TagClass = {
28 | Universal : 0x00,
29 | Application : 0x40,
30 | Context : 0x80,
31 | Private : 0xC0
32 | };
33 |
34 | /**
35 | * Tag Format
36 | */
37 | var TagFormat = {
38 | Primitive : 0x00,
39 | Constructed : 0x20
40 | };
41 |
42 | /**
43 | * ASN.1 tag
44 | * @param tagClass {TagClass}
45 | * @param tagFormat {TagFormat}
46 | * @param tagNumber {integer}
47 | */
48 | function Asn1Tag(tagClass, tagFormat, tagNumber) {
49 | this.tagClass = tagClass;
50 | this.tagFormat = tagFormat;
51 | this.tagNumber = tagNumber;
52 | }
53 |
54 | /**
55 | * ASN.1 Specification
56 | * @param tag {Asn1Tag}
57 | */
58 | function Asn1Spec(tag) {
59 | this.tag = tag;
60 | this.opt = false;
61 | }
62 |
63 | /**
64 | * Add an implicit tag
65 | * override tag
66 | * @param tag {Asn1Tag}
67 | * @returns {Asn1Spec}
68 | */
69 | Asn1Spec.prototype.implicitTag = function(tag) {
70 | this.tag = tag;
71 | return this;
72 | };
73 |
74 | /**
75 | * Set optional to true
76 | * @returns {Asn1Spec}
77 | */
78 | Asn1Spec.prototype.optional = function() {
79 | this.opt = true;
80 | return this;
81 | };
82 |
83 | /**
84 | * Add explicit tag
85 | * Append new tag header to existing tag
86 | * @param tag {Asn1Tag}
87 | * @returns {Asn1SpecExplicitTag}
88 | */
89 | Asn1Spec.prototype.explicitTag = function(tag) {
90 | return new Asn1SpecExplicitTag(tag, this);
91 | };
92 |
93 | /**
94 | * Decode must be implemented by all sub type
95 | * @param s {type.Stream}
96 | * @param decoder
97 | */
98 | Asn1Spec.prototype.decode = function(s, decoder) {
99 | throw new error.FatalError('NODE_RDP_AS1_SPEC_DECODE_NOT_IMPLEMENTED');
100 | };
101 |
102 | /**
103 | * Encode must be implemented by all sub type
104 | * @param decoder
105 | */
106 | Asn1Spec.prototype.encode = function(encoder) {
107 | throw new error.FatalError('NODE_RDP_AS1_SPEC_ENCODE_NOT_IMPLEMENTED');
108 | };
109 |
110 | /**
111 | * Component Asn1Spec object
112 | */
113 | function Asn1SpecExplicitTag(tag, spec) {
114 | Asn1Spec.call(this, tag);
115 | this.spec = spec;
116 | }
117 |
118 | inherits(Asn1SpecExplicitTag, Asn1Spec);
119 |
120 | /**
121 | * Decode first header
122 | * @param s {type.Stream}
123 | * @param decoder
124 | */
125 | Asn1Spec.prototype.decode = function(s, decoder) {
126 | var specStream = new type.Stream(decoder.decode(s, this.tag).value);
127 | this.spec.decode(specStream, decoder);
128 | };
129 |
130 | /**
131 | * Module exports
132 | */
133 | module.exports = {
134 | TagClass : TagClass,
135 | TagFormat : TagFormat,
136 | Asn1Tag : Asn1Tag,
137 | Asn1Spec : Asn1Spec,
138 | Asn1SpecExplicitTag : Asn1SpecExplicitTag
139 | };
140 |
--------------------------------------------------------------------------------
/lib/asn1/univ.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var spec = require('./spec');
21 | var type = require('../core').type;
22 | var error = require('../core').error;
23 | var inherits = require('util').inherits;
24 |
25 | /**
26 | * ASN.1 Universal tags
27 | * @see http://www.obj-sys.com/asn1tutorial/node124.html
28 | */
29 | var UniversalTag = {
30 | Boolean : 1,
31 | Integer : 2,
32 | BitString : 3,
33 | OctetString : 4,
34 | Null : 5,
35 | ObjectIdentifier : 6,
36 | ObjectDescriptor : 7,
37 | Enumerate : 10,
38 | UTF8String : 12,
39 | Sequence : 16,
40 | Set : 17,
41 | PrintableString : 19,
42 | T61String : 20,
43 | IA5String : 22,
44 | UTCTime : 23,
45 | GeneralizedTime : 24,
46 | UniversalString : 28,
47 | BMPString : 30
48 | };
49 |
50 | /**
51 | * Boolean type
52 | * @param value {boolean} inner value
53 | */
54 | function Boolean(value) {
55 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Boolean));
56 | this.value = value || false;
57 | }
58 |
59 | inherits(Boolean, spec.Asn1Spec);
60 |
61 | /**
62 | * @param s {type.Stream}
63 | * @param decoder {ber.decoder}
64 | * @returns {Boolean}
65 | */
66 | Boolean.prototype.decode = function(s, decoder) {
67 | this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value !== 0;
68 | return this;
69 | };
70 |
71 | /**
72 | * @param decoder {ber.decoder}
73 | * @returns {type.*}
74 | */
75 | Boolean.prototype.encode = function(encoder) {
76 | if(this.value) {
77 | return encoder.encode(this.tag, new type.UInt8(0xff));
78 | }
79 | else {
80 | return encoder.encode(this.tag, new type.UInt8(0));
81 | }
82 | };
83 |
84 | /**
85 | * Integer type
86 | * @param value {integer | Buffer}
87 | */
88 | function Integer(value) {
89 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Integer));
90 | this.value = value || 0;
91 | }
92 |
93 | inherits(Integer, spec.Asn1Spec);
94 |
95 | /**
96 | * @param s {type.Stream}
97 | * @param decoder {ber.decoder}
98 | * @returns {Integer}
99 | */
100 | Integer.prototype.decode = function(s, decoder) {
101 | var integerBuffer = decoder.decode(s, this.tag).value;
102 | if(integerBuffer.length < 5) {
103 | var integerStream = new type.Stream(integerBuffer);
104 | while (integerStream.availableLength() > 0) {
105 | this.value = this.value << 8;
106 | this.value |= new type.UInt8().read(integerStream).value;
107 | }
108 | }
109 | // bignum case
110 | else {
111 | this.value = integerBuffer;
112 | }
113 | return this;
114 | };
115 |
116 | /**
117 | * @param encoder {ber.decoder}
118 | * @returns {type.*}
119 | */
120 | Integer.prototype.encode = function(encoder) {
121 | if(this.value <= 0xff) {
122 | return encoder.encode(this.tag, new type.UInt8(this.value));
123 | }
124 | else if(this.value <= 0xffff) {
125 | return encoder.encode(this.tag, new type.UInt16Be(this.value));
126 | }
127 | else {
128 | return encoder.encode(this.tag, new type.UInt32Be(this.value));
129 | }
130 | };
131 |
132 | /**
133 | * Sequence type
134 | * @param value {object}
135 | */
136 | function Sequence(value) {
137 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence));
138 | this.value = value || [];
139 | }
140 |
141 | inherits(Sequence, spec.Asn1Spec);
142 |
143 | /**
144 | * @param s {type.Stream}
145 | * @param decoder {ber.decoder}
146 | * @returns {Sequence}
147 | */
148 | Sequence.prototype.decode = function(s, decoder) {
149 | var sequenceStream = new type.Stream(decoder.decode(s, this.tag).value);
150 | for (var i in this.value) {
151 | var rec = sequenceStream.offset;
152 | try {
153 | this.value[i].decode(sequenceStream, decoder);
154 | } catch(e) {
155 | if ((e.message === 'NODE_RDP_ASN1_BER_INVALID_TAG') && !this.value[i].opt) {
156 | throw new error.ProtocolError('NODE_RDP_ASN1_UNIV_SEQUENCE_FIELD_NOT_PRESENT');
157 | }
158 | sequenceStream.offset = rec;
159 | }
160 | }
161 | return this;
162 | };
163 |
164 | /**
165 | * Encode sequence
166 | * @param encoder
167 | * @returns {type.Component}
168 | */
169 | Sequence.prototype.encode = function(encoder) {
170 | var sequence = new type.Component([]);
171 | for (var i in this.value) {
172 | sequence.obj.push(this.value[i].encode(encoder))
173 | }
174 | return encoder.encode(this.tag, sequence);
175 | };
176 |
177 |
178 | /**
179 | * Enumerate type
180 | * @param value {integer}
181 | */
182 | function Enumerate(value) {
183 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Enumerate));
184 | this.value = value || 0;
185 | }
186 |
187 | inherits(Enumerate, spec.Asn1Spec);
188 |
189 | /**
190 | * @param s {type.Stream}
191 | * @param decoder {ber.decoder}
192 | * @returns {Enumerate}
193 | */
194 | Enumerate.prototype.decode = function(s, decoder) {
195 | this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value;
196 | return this;
197 | };
198 |
199 | /**
200 | * Encode enumerate type
201 | * @param encoder
202 | * @returns {type.Component}
203 | */
204 | Enumerate.prototype.encode = function(encoder) {
205 | return encoder.encode(this.tag, new type.UInt8(this.value));
206 | };
207 |
208 | /**
209 | * OctetString type
210 | * @param value {Buffer}
211 | */
212 | function OctetString(value) {
213 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.OctetString));
214 | this.value = value || new Buffer(0);
215 | }
216 |
217 | inherits(OctetString, spec.Asn1Spec);
218 |
219 | /**
220 | * @param s {type.Stream}
221 | * @param decoder {ber.decoder}
222 | * @returns {OctetString}
223 | */
224 | OctetString.prototype.decode = function(s, decoder) {
225 | this.value = decoder.decode(s, this.tag).value;
226 | return this;
227 | };
228 |
229 | /**
230 | * Encode Octet String
231 | * @param encoder
232 | * @returns {type.Component}
233 | */
234 | OctetString.prototype.encode = function(encoder) {
235 | return encoder.encode(this.tag, new type.BinaryString(this.value));
236 | };
237 |
238 | /**
239 | * ObjectIdentifier type
240 | * @param value {Buffer}
241 | */
242 | function ObjectIdentifier(value) {
243 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.ObjectIdentifier));
244 | this.value = value || new Buffer(5);
245 | }
246 |
247 | inherits(ObjectIdentifier, spec.Asn1Spec);
248 |
249 | /**
250 | * @param s {type.Stream}
251 | * @param decoder {ber.decoder}
252 | * @returns {ObjectIdentifier}
253 | */
254 | ObjectIdentifier.prototype.decode = function(s, decoder) {
255 | this.value = decoder.decode(s, this.tag).value;
256 | return this;
257 | };
258 |
259 | /**
260 | * Null type
261 | */
262 | function Null() {
263 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Null));
264 | }
265 |
266 | inherits(Null, spec.Asn1Spec);
267 |
268 | /**
269 | * @param s {type.Stream}
270 | * @param decoder {ber.decoder}
271 | * @returns {Null}
272 | */
273 | Null.prototype.decode = function(s, decoder) {
274 | decoder.decode(s, this.tag);
275 | return this;
276 | };
277 |
278 | /**
279 | * Choice type
280 | * @param value {object} list of available type
281 | */
282 | function Choice(value) {
283 | // not tagged type
284 | spec.Asn1Spec.call(this, new spec.Asn1Tag());
285 | this.value = value;
286 | }
287 |
288 | inherits(Choice, spec.Asn1Spec);
289 |
290 | /**
291 | * @param s {type.Stream}
292 | * @param decoder {ber.decoder}
293 | * @returns {Choice}
294 | */
295 | Choice.prototype.decode = function(s, decoder) {
296 | for (var i in this.value) {
297 | var rec = s.offset;
298 | try {
299 | this.value[i].decode(s, decoder);
300 | break;
301 | }
302 | catch(e) {
303 | s.offset = rec;
304 | }
305 | }
306 | return this;
307 | };
308 |
309 | /**
310 | * SetOf type
311 | * @param factory {function} type builder
312 | * @param value {object} list of available type
313 | */
314 | function SetOf(factory, value) {
315 | // not tagged type
316 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Set));
317 | this.factory = factory;
318 | this.value = value || [];
319 | }
320 |
321 | inherits(SetOf, spec.Asn1Spec);
322 |
323 | /**
324 | * @param s {type.Stream}
325 | * @param decoder {ber.decoder}
326 | * @returns {SetOf}
327 | */
328 | SetOf.prototype.decode = function(s, decoder) {
329 | var setOfStream = new type.Stream(decoder.decode(s, this.tag).value);
330 | while (setOfStream.availableLength() > 0) {
331 | this.value.push(this.factory().decode(setOfStream, decoder));
332 | }
333 | return this;
334 | };
335 |
336 | /**
337 | * SequenceOf type
338 | * @param factory {function} type builder
339 | * @param value {object} list of available type
340 | */
341 | function SequenceOf(factory, value) {
342 | // not tagged type
343 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence));
344 | this.factory = factory;
345 | this.value = value || [];
346 | }
347 |
348 | inherits(SequenceOf, spec.Asn1Spec);
349 |
350 | /**
351 | * @param s {type.Stream}
352 | * @param decoder {ber.decoder}
353 | * @returns {SequenceOf}
354 | */
355 | SequenceOf.prototype.decode = function(s, decoder) {
356 | var sequenceOfStream = new type.Stream(decoder.decode(s, this.tag).value);
357 | while (sequenceOfStream.availableLength() > 0) {
358 | this.value.push(this.factory().decode(sequenceOfStream, decoder));
359 | }
360 | return this;
361 | };
362 |
363 | /**
364 | * BitString type
365 | * @param value {Buffer}
366 | */
367 | function BitString(value) {
368 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BitString));
369 | this.value = [];
370 | }
371 |
372 | inherits(BitString, spec.Asn1Spec);
373 |
374 | /**
375 | * @param s {type.Stream}
376 | * @param decoder {ber.decoder}
377 | * @returns {BitString}
378 | */
379 | BitString.prototype.decode = function(s, decoder) {
380 | var bitStream = new type.Stream(decoder.decode(s, this.tag).value);
381 | var padding = new type.UInt8().read(bitStream).value;
382 | var value = [];
383 | for(var i = 0; i < padding; i++) {
384 | value.push(0);
385 | }
386 |
387 | while(bitStream.availableLength() > 0) {
388 | var octet = new type.UInt8().read(bitStream).value;
389 | var currentPadding = 0;
390 | if(bitStream.availableLength() === 0) {
391 | currentPadding = padding;
392 | }
393 | for(var i = 7; i >= currentPadding; i--) {
394 | value.push(((octet >> i) & 1)?1:0);
395 | }
396 | }
397 | this.value = value;
398 | return this;
399 | };
400 |
401 | /**
402 | * Convert bit string to buffer object
403 | * @returns {Buffer}
404 | */
405 | BitString.prototype.toBuffer = function () {
406 | var length = this.value.length / 8;
407 | var resultStream = new type.Stream(length);
408 | for (var i = 0; i < length; i ++) {
409 | var currentOctet = 0;
410 | for (var j = 0; j < 8; j++) {
411 | currentOctet = currentOctet | (this.value[i * 8 + j] << (7 - j));
412 | }
413 | new type.UInt8(currentOctet).write(resultStream);
414 | }
415 | return resultStream.buffer;
416 | }
417 |
418 | /**
419 | * T61String type
420 | * @param value {Buffer}
421 | */
422 | function T61String(value) {
423 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.T61String));
424 | this.value = value;
425 | }
426 |
427 | inherits(T61String, spec.Asn1Spec);
428 |
429 | /**
430 | * @param s {type.Stream}
431 | * @param decoder {ber.decoder}
432 | * @returns {T61String}
433 | */
434 | T61String.prototype.decode = function(s, decoder) {
435 | this.value = decoder.decode(s, this.tag).value;
436 | return this;
437 | };
438 |
439 | /**
440 | * PrintableString type
441 | * @param value {Buffer}
442 | */
443 | function PrintableString(value) {
444 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.PrintableString));
445 | this.value = value;
446 | }
447 |
448 | inherits(PrintableString, spec.Asn1Spec);
449 |
450 | /**
451 | * @param s {type.Stream}
452 | * @param decoder {ber.decoder}
453 | * @returns {PrintableString}
454 | */
455 | PrintableString.prototype.decode = function(s, decoder) {
456 | this.value = decoder.decode(s, this.tag).value;
457 | return this;
458 | };
459 |
460 | /**
461 | * UniversalString type
462 | * @param value {Buffer}
463 | */
464 | function UniversalString(value) {
465 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UniversalString));
466 | this.value = value;
467 | }
468 |
469 | inherits(UniversalString, spec.Asn1Spec);
470 |
471 | /**
472 | * @param s {type.Stream}
473 | * @param decoder {ber.decoder}
474 | * @returns {UniversalString}
475 | */
476 | UniversalString.prototype.decode = function(s, decoder) {
477 | this.value = decoder.decode(s, this.tag).value;
478 | return this;
479 | };
480 |
481 | /**
482 | * UTF8String type
483 | * @param value {Buffer}
484 | */
485 | function UTF8String(value) {
486 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTF8String));
487 | this.value = value;
488 | }
489 |
490 | inherits(UTF8String, spec.Asn1Spec);
491 |
492 | /**
493 | * @param s {type.Stream}
494 | * @param decoder {ber.decoder}
495 | * @returns {UTF8String}
496 | */
497 | UTF8String.prototype.decode = function(s, decoder) {
498 | this.value = decoder.decode(s, this.tag).value;
499 | return this;
500 | };
501 |
502 | /**
503 | * BMPString type
504 | * @param value {Buffer}
505 | */
506 | function BMPString(value) {
507 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BMPString));
508 | this.value = value;
509 | }
510 |
511 | inherits(BMPString, spec.Asn1Spec);
512 |
513 | /**
514 | * @param s {type.Stream}
515 | * @param decoder {ber.decoder}
516 | * @returns {BMPString}
517 | */
518 | BMPString.prototype.decode = function(s, decoder) {
519 | this.value = decoder.decode(s, this.tag).value;
520 | return this;
521 | };
522 |
523 | /**
524 | * IA5String type
525 | * @param value {Buffer}
526 | */
527 | function IA5String(value) {
528 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.IA5String));
529 | this.value = value;
530 | }
531 |
532 | inherits(IA5String, spec.Asn1Spec);
533 |
534 | /**
535 | * @param s {type.Stream}
536 | * @param decoder {ber.decoder}
537 | * @returns {IA5String}
538 | */
539 | IA5String.prototype.decode = function(s, decoder) {
540 | this.value = decoder.decode(s, this.tag).value;
541 | return this;
542 | };
543 |
544 | /**
545 | * UTCTime type
546 | * @param value {Buffer}
547 | */
548 | function UTCTime(value) {
549 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTCTime));
550 | this.value = value;
551 | }
552 |
553 | inherits(UTCTime, spec.Asn1Spec);
554 |
555 | /**
556 | * @param s {type.Stream}
557 | * @param decoder {ber.decoder}
558 | * @returns {UTCTime}
559 | */
560 | UTCTime.prototype.decode = function(s, decoder) {
561 | this.value = decoder.decode(s, this.tag).value;
562 | return this;
563 | };
564 |
565 | /**
566 | * GeneralizedTime type
567 | * @param value {Buffer}
568 | */
569 | function GeneralizedTime(value) {
570 | spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.GeneralizedTime));
571 | this.value = value;
572 | }
573 |
574 | inherits(GeneralizedTime, spec.Asn1Spec);
575 |
576 | /**
577 | * @param s {type.Stream}
578 | * @param decoder {ber.decoder}
579 | * @returns {GeneralizedTime}
580 | */
581 | GeneralizedTime.prototype.decode = function(s, decoder) {
582 | this.value = decoder.decode(s, this.tag).value;
583 | return this;
584 | };
585 |
586 | module.exports = {
587 | Boolean : Boolean,
588 | Integer : Integer,
589 | Sequence : Sequence,
590 | Enumerate : Enumerate,
591 | OctetString : OctetString,
592 | ObjectIdentifier : ObjectIdentifier,
593 | Null : Null,
594 | Choice : Choice,
595 | SequenceOf : SequenceOf,
596 | SetOf : SetOf,
597 | BitString : BitString,
598 | T61String : T61String,
599 | PrintableString : PrintableString,
600 | UniversalString : UniversalString,
601 | UTF8String : UTF8String,
602 | BMPString : BMPString,
603 | IA5String : IA5String,
604 | UTCTime : UTCTime,
605 | GeneralizedTime : GeneralizedTime
606 | };
607 |
--------------------------------------------------------------------------------
/lib/core/error.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 |
22 | /**
23 | * Fatal error stop program
24 | */
25 | function FatalError(message, code) {
26 | Error.captureStackTrace(this);
27 | this.message = message || "";
28 | this.code = code || 'NODE_RDP_CORE_ERROR_NO_ERROR_CODE';
29 | }
30 |
31 | /**
32 | * inherit from error
33 | */
34 | inherits(FatalError, Error);
35 |
36 | /**
37 | * Protocol error (non fatal);
38 | */
39 | function ProtocolError(code, message) {
40 | Error.captureStackTrace(this);
41 | this.code = code;
42 | this.message = message || "";
43 | }
44 |
45 | /**
46 | * inherit from error
47 | */
48 | inherits(ProtocolError, Error);
49 |
50 | /**
51 | * ImplementationError error (non fatal);
52 | */
53 | function ImplementationError(code, message) {
54 | Error.captureStackTrace(this);
55 | this.code = code;
56 | this.message = message || "";
57 | }
58 |
59 | /**
60 | * inherit from error
61 | */
62 | inherits(ImplementationError, Error);
63 |
64 | /**
65 | * Module exports
66 | */
67 | module.exports = {
68 | FatalError : FatalError,
69 | ProtocolError : ProtocolError,
70 | ImplementationError : ImplementationError
71 | };
--------------------------------------------------------------------------------
/lib/core/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var layer = require('./layer');
21 | var type = require('./type');
22 | var log = require('./log');
23 | var error = require('./error');
24 | var rle = require('./rle');
25 |
26 | module.exports = {
27 | layer : layer,
28 | type : type,
29 | log : log,
30 | error : error,
31 | rle : rle
32 | };
33 |
--------------------------------------------------------------------------------
/lib/core/layer.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var fs = require('fs');
22 | var type = require('./type');
23 | var log = require('./log');
24 | var tls = require('tls');
25 | var crypto = require('crypto');
26 | var events = require('events');
27 |
28 | /**
29 | * Buffer data from socket to present
30 | * well formed packets
31 | */
32 | function BufferLayer(socket) {
33 | //for ssl connection
34 | this.secureSocket = null;
35 | this.socket = socket;
36 |
37 | var self = this;
38 | // bind event
39 | this.socket.on('data', function(data) {
40 | try {
41 | self.recv(data);
42 | }
43 | catch(e) {
44 | self.socket.destroy();
45 | self.emit('error', e);
46 | }
47 | }).on('close', function() {
48 | self.emit('close');
49 | }).on('error', function (err) {
50 | self.emit('error', err);
51 | });
52 |
53 | //buffer data
54 | this.buffers = [];
55 | this.bufferLength = 0;
56 | //expected size
57 | this.expectedSize = 0;
58 | }
59 |
60 | inherits(BufferLayer, events.EventEmitter);
61 |
62 | /**
63 | * Call from tcp layer
64 | * @param data tcp stream
65 | */
66 | BufferLayer.prototype.recv = function(data) {
67 | this.buffers[this.buffers.length] = data;
68 | this.bufferLength += data.length;
69 |
70 | while(this.bufferLength >= this.expectedSize) {
71 | //linear buffer
72 | var expectedData = new type.Stream(this.expectedSize);
73 |
74 | //create expected data
75 | while(expectedData.availableLength() > 0) {
76 |
77 | var rest = expectedData.availableLength();
78 | var buffer = this.buffers.shift();
79 |
80 | if(buffer.length > expectedData.availableLength()) {
81 | this.buffers.unshift(buffer.slice(rest));
82 | new type.BinaryString(buffer, { readLength : new type.CallableValue(expectedData.availableLength()) }).write(expectedData);
83 | }
84 | else {
85 | new type.BinaryString(buffer).write(expectedData);
86 | }
87 | }
88 |
89 | this.bufferLength -= this.expectedSize;
90 | expectedData.offset = 0;
91 | this.emit('data', expectedData);
92 | }
93 | };
94 |
95 | /**
96 | * Call tcp socket to write stream
97 | * @param {type.Type} packet
98 | */
99 | BufferLayer.prototype.send = function(data) {
100 | var s = new type.Stream(data.size());
101 | data.write(s);
102 | if(this.secureSocket) {
103 | this.secureSocket.write(s.buffer);
104 | }
105 | else {
106 | this.socket.write(s.buffer);
107 | }
108 | };
109 |
110 | /**
111 | * Wait expected size data before call callback function
112 | * @param {number} expectSize size expected
113 | */
114 | BufferLayer.prototype.expect = function(expectedSize) {
115 | this.expectedSize = expectedSize;
116 | };
117 |
118 | /**
119 | * Convert connection to TLS connection
120 | * @param callback {func} when connection is done
121 | */
122 | BufferLayer.prototype.startTLS = function(callback) {
123 | var self = this;
124 |
125 | this.secureSocket = tls.connect({
126 | socket: this.socket,
127 | secureContext: tls.createSecureContext(),
128 | isServer: false,
129 | requestCert: false,
130 | rejectUnauthorized: false
131 | }, (err) => {
132 | log.warn(err);
133 | callback(err);
134 | });
135 |
136 | this.secureSocket.on('data', function(data) {
137 | try {
138 | self.recv(data);
139 | }
140 | catch(e) {
141 | self.socket.destroy();
142 | self.emit('error', e);
143 | }
144 | }).on('error', function (err) {
145 | self.emit('error', err);
146 | });
147 | };
148 |
149 | /**
150 | * Convert connection to TLS server
151 | * @param keyFilePath {string} key file path
152 | * @param crtFilePath {string} certificat file path
153 | * @param callback {function}
154 | */
155 | BufferLayer.prototype.listenTLS = function(keyFilePath, crtFilePath, callback) {
156 | var self = this;
157 |
158 | this.secureSocket = tls.connect({
159 | socket: this.socket,
160 | secureContext: tls.createSecureContext({
161 | key: fs.readFileSync(keyFilePath),
162 | cert: fs.readFileSync(crtFilePath),
163 | }),
164 | isServer: true,
165 | requestCert: false,
166 | rejectUnauthorized: false
167 | }, (err) => {
168 | log.warn(err);
169 | callback(err);
170 | });
171 |
172 | this.secureSocket.on('data', function(data) {
173 | try {
174 | self.recv(data);
175 | }
176 | catch(e) {
177 | self.socket.destroy();
178 | self.emit('error', e);
179 | }
180 | }).on('error', function (err) {
181 | self.emit('error', err);
182 | });
183 | };
184 |
185 | /**
186 | * close stack
187 | */
188 | BufferLayer.prototype.close = function() {
189 | this.socket.end();
190 | };
191 |
192 | /**
193 | * Module exports
194 | */
195 | module.exports = {
196 | BufferLayer : BufferLayer
197 | };
198 |
--------------------------------------------------------------------------------
/lib/core/log.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var Logger = require('bunyan');
21 |
22 | var Levels = {
23 | 'DEBUG': 1,
24 | 'INFO': 2,
25 | 'WARN': 3,
26 | 'ERROR': 4
27 | }
28 |
29 | let logStreams = [];
30 |
31 | if (process.env.enable_log_file === 'true') {
32 | logStreams.push(
33 | {
34 | type: 'rotating-file',
35 | period: '1d',
36 | count: 2,
37 | path: `node-rdpjs${process.pid}.log`,
38 | level: process.env.log_level
39 | }
40 | );
41 | }
42 |
43 | logStreams.push(
44 | {
45 | stream: process.stderr,
46 | level: process.env.log_level
47 | }
48 | );
49 |
50 | var logger = Logger.createLogger({
51 | name: 'node-rdpjs',
52 | streams: logStreams
53 | });
54 |
55 |
56 | function log(level, message) {
57 | if (Levels[level] < module.exports.level) return;
58 | console.log("[node-rdpjs] " + level + ":\t" + message);
59 | }
60 |
61 | /**
62 | * Module exports
63 | */
64 | module.exports = {
65 | level: Levels.INFO,
66 | Levels: Levels,
67 | debug: function (message) { logger.debug(message); },
68 | info: function (message) { logger.info(message); },
69 | warn: function (message) { logger.warn(message); },
70 | error: function (message) { logger.error(message); }
71 | };
72 |
--------------------------------------------------------------------------------
/lib/core/type.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var log = require('./log');
22 | var error = require('./error');
23 |
24 | /**
25 | * Stream wrapper around buffer type
26 | * @param i {Buffer | integer} size of init buffer
27 | * @returns
28 | */
29 | function Stream(i) {
30 | this.offset = 0;
31 | if (i instanceof Buffer) {
32 | this.buffer = i;
33 | }
34 | else {
35 | this.buffer = new Buffer(i || 8192);
36 | }
37 | }
38 |
39 | /**
40 | * Return length of available data in stream
41 | * @returns {Number} length of available data in stream
42 | */
43 | Stream.prototype.availableLength = function() {
44 | return this.buffer.length - this.offset;
45 | };
46 |
47 | /**
48 | * increment offset
49 | * @param length {integer} length of padding
50 | */
51 | Stream.prototype.readPadding = function(length) {
52 | this.offset += length;
53 | };
54 |
55 | /**
56 | * Format string buffer
57 | * @returns {string} buffer stringified
58 | */
59 | Stream.prototype.getValue = function() {
60 | return this.buffer;
61 | };
62 |
63 | /**
64 | * @param value {object | function} inner value
65 | * @returns
66 | */
67 | function CallableValue(value) {
68 | if(value) {
69 | this.value = value;
70 | }
71 | }
72 |
73 | /**
74 | * For syntaxic purpose
75 | */
76 | Object.defineProperty(CallableValue.prototype, "value", {
77 | get: function() { return this._value(); },
78 | set: function(e) {
79 | if(typeof e !== 'function') {
80 | this._value = function () { return e; };
81 | }
82 | else {
83 | this._value = e;
84 | }
85 | }
86 | });
87 |
88 | /**
89 | * Type readable or writable by binary stream
90 | * @param {object} opt
91 | * .conditional {boolean} read or write type depend on conditional call
92 | * @returns
93 | */
94 | function Type(opt) {
95 | CallableValue.call(this);
96 | this.opt = opt || {};
97 | this.isReaded = false;
98 | this.isWritten = false;
99 | }
100 |
101 | inherits(Type, CallableValue);
102 |
103 | /**
104 | * Write type into binary stream s
105 | * @param {type.Stream} s binary stream
106 | */
107 | Type.prototype.write = function(s) {
108 | //do not write false conditional type
109 | if(this.opt.conditional && !this.opt.conditional())
110 | return this;
111 |
112 | this.isWritten = true;
113 |
114 | this.writeValue(s);
115 | return this;
116 | };
117 |
118 | /**
119 | * Read type from binary stream
120 | * @param {type.Stream} s binary stream
121 | * @returns this to chain call
122 | */
123 | Type.prototype.read = function(s) {
124 | //do not read false conditional type
125 | if(this.opt.conditional && !this.opt.conditional())
126 | return this;
127 |
128 | if(this.opt.optional && s.availableLength() < this.size())
129 | return this;
130 |
131 | this.isReaded = true;
132 |
133 | //constant case
134 | if(this.opt.constant) {
135 | var oldValue = this.value;
136 | try {
137 | this.readValue(s);
138 | }
139 | catch(e) {
140 | if (e instanceof RangeError) {
141 | throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL");
142 | }
143 | throw e;
144 | }
145 |
146 | if(oldValue !== this.value) {
147 | log.error('constant value mismatch ' + oldValue + ' != ' + this.value);
148 | throw new error.ProtocolError("NODE_RDP_CORE_TYPE_CONSTANT_VALUE_MISMATCH");
149 | }
150 | }
151 | else {
152 | try {
153 | this.readValue(s);
154 | }
155 | catch(e) {
156 | if (e instanceof RangeError) {
157 | throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL");
158 | }
159 | throw e;
160 | }
161 | }
162 |
163 | return this;
164 | };
165 |
166 | /**
167 | * Size of type
168 | * @returns {int} Size of type
169 | */
170 | Type.prototype.size = function() {
171 | if(this.opt.conditional && !this.opt.conditional())
172 | return 0;
173 | return this._size_();
174 | };
175 |
176 | /**
177 | * Convert type to stream
178 | * Usefull when you want to buffer
179 | * @returns {Stream}
180 | */
181 | Type.prototype.toStream = function() {
182 | var result = new Stream(this.size());
183 | this.write(result);
184 | return result;
185 | };
186 |
187 | /**
188 | * Node of Raw types
189 | * @param {object} obj composite object
190 | * @param {object} opt Type parameters
191 | */
192 | function Component(obj, opt) {
193 | Type.call(this, opt);
194 | this.obj = obj;
195 | }
196 |
197 | //inherit from type
198 | inherits(Component, Type);
199 |
200 | /**
201 | * ignore criterion
202 | * @param i {string} index name in obj
203 | * @returns {Boolean} true if can be ignore
204 | */
205 | Component.prototype.ignore = function(i) {
206 | // ignore meta information
207 | if(i.lastIndexOf("__", 0) === 0) {
208 | return true;
209 | }
210 | // ignore function
211 | if(typeof(this.obj[i]) === 'function') {
212 | return true;
213 | }
214 | return false;
215 | };
216 |
217 | /**
218 | * Write each sub type into stream
219 | * @param {Stream} s
220 | */
221 | Component.prototype.writeValue = function(s) {
222 | for(var i in this.obj) {
223 | if(this.ignore(i)) {
224 | continue;
225 | }
226 | try {
227 | this.obj[i].write(s);
228 | }
229 | catch(e) {
230 | log.info('during write of field ' + i);
231 | throw e;
232 | }
233 | }
234 | };
235 |
236 | /**
237 | * Read each sub type into stream
238 | * @param {Stream} s from read stream
239 | */
240 | Component.prototype.readValue = function(s) {
241 | var readStream = s;
242 | if(this.opt.readLength) {
243 | readStream = new Stream(s.buffer.slice(s.offset, s.offset + this.opt.readLength.value));
244 | }
245 |
246 | for(var i in this.obj) {
247 | // ignore meta information
248 | if(this.ignore(i)) {
249 | continue;
250 | }
251 | try {
252 | this.obj[i].read(readStream);
253 | }
254 | catch(e) {
255 | log.info('during read of field ' + i);
256 | throw e;
257 | }
258 | }
259 |
260 | // padding
261 | if (this.opt.readLength) {
262 | s.offset += this.opt.readLength.value;
263 | if (readStream.offset < this.opt.readLength.value) {
264 | log.debug('still have available data : read it as padding');
265 | }
266 | }
267 | };
268 |
269 | /**
270 | * Sum size of sub types
271 | */
272 | Component.prototype._size_ = function() {
273 | var size = 0;
274 | for(var i in this.obj) {
275 | if(this.ignore(i)) {
276 | continue;
277 | }
278 | size += this.obj[i].size();
279 | }
280 | return size;
281 | };
282 |
283 | /**
284 | * Leaf of tree type
285 | * @param {number} value of type
286 | * @param {function} readBufferCallback Buffer prototype read function
287 | * @param {function} writeBufferCallback Buffer prototype write function
288 | * @param {object} opt Type parameter
289 | */
290 | function SingleType(value, nbBytes, readBufferCallback, writeBufferCallback, opt){
291 | Type.call(this, opt);
292 | this.value = value || 0;
293 | this.nbBytes = nbBytes;
294 | this.readBufferCallback = readBufferCallback;
295 | this.writeBufferCallback = writeBufferCallback;
296 | }
297 |
298 | //inherit from type
299 | inherits(SingleType, Type);
300 |
301 | /**
302 | * Write SingleType value into stream
303 | * @param s
304 | */
305 | SingleType.prototype.writeValue = function(s) {
306 | this.writeBufferCallback.call(s.buffer, this.value, s.offset);
307 | s.offset += this._size_();
308 | };
309 |
310 | /**
311 | * Read SingleType value into stream
312 | * @param {Stream} s from read stream
313 | */
314 | SingleType.prototype.readValue = function(s) {
315 | this.value = this.readBufferCallback.call(s.buffer, s.offset);
316 | s.offset += this._size_();
317 | };
318 |
319 | /**
320 | * Size of single type
321 | * @returns Size of single type
322 | */
323 | SingleType.prototype._size_ = function() {
324 | return this.nbBytes;
325 | };
326 |
327 | /**
328 | * Integer on 1 byte
329 | * @param {number | function} value of type
330 | * @param {object} opt Type parameter
331 | * @returns
332 | */
333 | function UInt8(value, opt) {
334 | SingleType.call(this, value, 1, Buffer.prototype.readUInt8, Buffer.prototype.writeUInt8, opt);
335 | }
336 |
337 | //inherit from type
338 | inherits(UInt8, SingleType);
339 |
340 | /**
341 | * Integer on 2 bytes in Little Endian
342 | * @param {number | function} value to write or compare if constant
343 | * @param {object} opt Type parameter
344 | * @returns
345 | */
346 | function UInt16Le(value, opt) {
347 | SingleType.call(this, value, 2, Buffer.prototype.readUInt16LE, Buffer.prototype.writeUInt16LE, opt);
348 | }
349 |
350 | //inherit from type
351 | inherits(UInt16Le, SingleType);
352 |
353 | /**
354 | * Integer on 2 bytes in Big Endian
355 | * @param {number | function} value to write or compare if constant
356 | * @param {object} opt Type parameter
357 | * @returns
358 | */
359 | function UInt16Be(value, opt) {
360 | SingleType.call(this, value, 2, Buffer.prototype.readUInt16BE, Buffer.prototype.writeUInt16BE, opt);
361 | }
362 |
363 | //inherit from type
364 | inherits(UInt16Be, SingleType);
365 |
366 | /**
367 | * Integer on 4 bytes in Little Endian
368 | * @param {number | function} value to write or compare if constant
369 | * @param {object} opt Type parameter
370 | * @returns
371 | */
372 | function UInt32Le(value, opt) {
373 | SingleType.call(this, value, 4, Buffer.prototype.readUInt32LE, Buffer.prototype.writeUInt32LE, opt);
374 | }
375 |
376 | //inherit from type
377 | inherits(UInt32Le, SingleType);
378 |
379 | /**
380 | * Integer on 4 bytes in Big Endian
381 | * @param {number | function} value to write or compare if constant
382 | * @param {object} opt Type parameter
383 | * @returns
384 | */
385 | function UInt32Be(value, opt) {
386 | SingleType.call(this, value, 4, Buffer.prototype.readUInt32BE, Buffer.prototype.writeUInt32BE, opt);
387 | }
388 |
389 | //inherit from type
390 | inherits(UInt32Be, SingleType);
391 |
392 | /**
393 | * @param value {Buffer} javascript source string
394 | * @param opt {object} type options
395 | * .readLength {type} length for reading operation
396 | * @returns {type.BinaryString}
397 | */
398 | function BinaryString(value, opt) {
399 | Type.call(this, opt);
400 | this.value = value || new Buffer("");
401 | }
402 |
403 | //inherit from type
404 | inherits(BinaryString, Type);
405 |
406 | /**
407 | * Write value into string
408 | * @param s {type.Stream}
409 | */
410 | BinaryString.prototype.writeValue = function(s) {
411 | this.value.copy(s.buffer, s.offset);
412 | s.offset += this._size_();
413 | };
414 |
415 | /**
416 | * Read string from offset to read length if specified or end of stream
417 | * @param s {type.Stream}
418 | */
419 | BinaryString.prototype.readValue = function(s) {
420 | if(this.opt.readLength) {
421 | this.value = s.buffer.slice(s.offset, s.offset + this.opt.readLength.value);
422 | }
423 | else {
424 | this.value = s.buffer.slice(s.offset);
425 | }
426 | s.offset += this._size_();
427 | };
428 |
429 | /**
430 | * @returns {integer} length of string
431 | */
432 | BinaryString.prototype._size_ = function() {
433 | return this.value.length;
434 | };
435 |
436 | /**
437 | * Dynamic built type depend on factory function
438 | * @param message {object} parent object
439 | * @param field {string} name of object field
440 | * @param factory {function} factory use to built new type
441 | * @param opt {object} type options
442 | */
443 | function Factory(factory, opt) {
444 | Type.call(this, opt);
445 | this.factory = factory;
446 | }
447 |
448 | //inherit from type
449 | inherits(Factory, Type);
450 |
451 | /**
452 | * build type and write into stream
453 | * @param s {Stream} input stream
454 | */
455 | Factory.prototype.writeValue = function(s) {
456 | this.factory(s);
457 | };
458 |
459 | /**
460 | * build type and read from stream
461 | * @param s {Stream} input stream
462 | */
463 | Factory.prototype.readValue = function(s) {
464 | this.factory(s);
465 | };
466 |
467 | /**
468 | * must be never called
469 | */
470 | Factory.prototype._size_ = function() {
471 | throw new error.FatalError('NODE_RDP_CORE_TYPE_FACTORY_TYPE_HAVE_NO_SIZE');
472 | };
473 |
474 | /**
475 | * Module exports
476 | */
477 | module.exports = {
478 | Stream : Stream,
479 | Component : Component,
480 | UInt8 : UInt8,
481 | UInt16Le : UInt16Le,
482 | UInt16Be : UInt16Be,
483 | UInt32Le : UInt32Le,
484 | UInt32Be : UInt32Be,
485 | BinaryString : BinaryString,
486 | CallableValue : CallableValue,
487 | Factory : Factory
488 | };
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var protocol = require('./protocol');
21 | module.exports = {
22 | createClient : protocol.rdp.createClient,
23 | createServer : protocol.rdp.createServer
24 | };
25 |
--------------------------------------------------------------------------------
/lib/protocol/cert.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../core').type;
21 | var log = require('../core').log;
22 | var x509 = require('../security').x509;
23 | var rsa = require('../security').rsa;
24 | var asn1 = require('../asn1');
25 |
26 | /**
27 | * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
28 | */
29 | var CertificateType = {
30 | CERT_CHAIN_VERSION_1 : 0x00000001,
31 | CERT_CHAIN_VERSION_2 : 0x00000002
32 | };
33 |
34 | /**
35 | * @see http://msdn.microsoft.com/en-us/library/cc240520.aspx
36 | * @returns
37 | */
38 | function rsaPublicKey(opt) {
39 | var self = {
40 | magic : new type.UInt32Le(0x31415352, { constant : true }),
41 | keylen : new type.UInt32Le(function() {
42 | return self.modulus.size() + self.paddinf.size();
43 | }),
44 | bitlen : new type.UInt32Le(function() {
45 | return (self.keylen.value - 8) * 8;
46 | }),
47 | datalen : new type.UInt32Le(function() {
48 | return (self.bitlen.value / 8) - 1;
49 | }),
50 | pubExp : new type.UInt32Le(),
51 | modulus : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
52 | return self.keylen.value - 8;
53 | }) }),
54 | padding : new type.BinaryString(new Buffer(Array(8 + 1).join('\x00')), { readLength : new type.CallableValue(8) })
55 | };
56 |
57 | return new type.Component(self, opt);
58 | }
59 |
60 | /**
61 | * http://msdn.microsoft.com/en-us/library/cc240519.aspx
62 | * @returns {type.Component}
63 | */
64 | function proprietaryCertificate() {
65 | var self = {
66 | __TYPE__ : CertificateType.CERT_CHAIN_VERSION_1,
67 | dwSigAlgId : new type.UInt32Le(0x00000001, { constant : true }),
68 | dwKeyAlgId : new type.UInt32Le(0x00000001, { constant : true }),
69 | wPublicKeyBlobType : new type.UInt16Le(0x0006, { constant : true }),
70 | wPublicKeyBlobLen : new type.UInt16Le(function() {
71 | return self.PublicKeyBlob.size();
72 | }),
73 | PublicKeyBlob : rsaPublicKey({ readLength : new type.CallableValue(function() {
74 | return self.wPublicKeyBlobLen.value;
75 | }) }),
76 | wSignatureBlobType : new type.UInt16Le(0x0008, { constant : true }),
77 | wSignatureBlobLen : new type.UInt16Le(function() {
78 | return self.SignatureBlob.size() + self.padding.size();
79 | }),
80 | SignatureBlob : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
81 | return self.wSignatureBlobLen.value - self.padding.size;
82 | }) }),
83 | padding : new type.BinaryString(Array(8 + 1).join('\x00'), { readLength : new type.CallableValue(8) }),
84 | /**
85 | * @return {object} rsa.publicKey
86 | */
87 | getPublicKey : function() {
88 | return rsa.publicKey(self.PublicKeyBlob.obj.modulus.value, self.PublicKeyBlob.obj.pubExp.value);
89 | }
90 | };
91 |
92 | return new type.Component(self);
93 | }
94 |
95 | /**
96 | * For x509 certificate
97 | * @see http://msdn.microsoft.com/en-us/library/cc241911.aspx
98 | * @returns {type.Component}
99 | */
100 | function certBlob() {
101 | var self = {
102 | cbCert : new type.UInt32Le(function() {
103 | return self.abCert.size();
104 | }),
105 | abCert : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
106 | return self.cbCert.value;
107 | }) })
108 | };
109 |
110 | return new type.Component(self);
111 | }
112 |
113 | /**
114 | * x509 certificate chain
115 | * @see http://msdn.microsoft.com/en-us/library/cc241910.aspx
116 | * @returns {type.Component}
117 | */
118 | function x509CertificateChain() {
119 | var self = {
120 | __TYPE__ : CertificateType.CERT_CHAIN_VERSION_2,
121 | NumCertBlobs : new type.UInt32Le(),
122 | CertBlobArray : new type.Factory(function(s) {
123 | self.CertBlobArray = new type.Component([]);
124 | for(var i = 0; i < self.NumCertBlobs.value; i++) {
125 | self.CertBlobArray.obj.push(certBlob().read(s));
126 | }
127 | }),
128 | padding : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
129 | return 8 + 4 * self.NumCertBlobs.value;
130 | }) }),
131 | /**
132 | * @return {object} {n : modulus{bignum}, e : publicexponent{integer}
133 | */
134 | getPublicKey : function(){
135 | var cert = x509.X509Certificate().decode(new type.Stream(self.CertBlobArray.obj[self.CertBlobArray.obj.length - 1].obj.abCert.value), asn1.ber);
136 | var publikeyStream = new type.Stream(cert.value.tbsCertificate.value.subjectPublicKeyInfo.value.subjectPublicKey.toBuffer());
137 | var asn1PublicKey = x509.RSAPublicKey().decode(publikeyStream, asn1.ber);
138 | return rsa.publicKey(asn1PublicKey.value.modulus.value, asn1PublicKey.value.publicExponent.value);
139 | }
140 | };
141 |
142 | return new type.Component(self);
143 | }
144 |
145 | function certificate() {
146 | var self = {
147 | dwVersion : new type.UInt32Le(function() {
148 | return self.certData.__TYPE__;
149 | }),
150 | certData : new type.Factory(function(s) {
151 | switch(self.dwVersion.value & 0x7fffffff) {
152 | case CertificateType.CERT_CHAIN_VERSION_1:
153 | log.debug('read proprietary certificate');
154 | self.certData = proprietaryCertificate().read(s);
155 | break;
156 | case CertificateType.CERT_CHAIN_VERSION_2:
157 | log.debug('read x.509 certificate chain');
158 | self.certData = x509CertificateChain().read(s);
159 | break;
160 | default:
161 | log.error('unknown cert type ' + self.dwVersion.value & 0x7fffffff);
162 | }
163 | })
164 | };
165 |
166 | return new type.Component(self);
167 | }
168 |
169 | /**
170 | * Module exports
171 | */
172 | module.exports = {
173 | CertificateType : CertificateType,
174 | certificate : certificate
175 | };
--------------------------------------------------------------------------------
/lib/protocol/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var TPKT = require('./tpkt');
21 | var x224 = require('./x224');
22 | var t125 = require('./t125');
23 | var rdp = require('./rdp');
24 |
25 | module.exports = {
26 | TPKT : TPKT,
27 | x224 : x224,
28 | t125 : t125,
29 | rdp : rdp
30 | };
31 |
--------------------------------------------------------------------------------
/lib/protocol/pdu/caps.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../../core').type;
21 | var log = require('../../core').log;
22 | var error = require('../../core').error;
23 |
24 | /**
25 | * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
26 | */
27 | var CapsType = {
28 | CAPSTYPE_GENERAL : 0x0001,
29 | CAPSTYPE_BITMAP : 0x0002,
30 | CAPSTYPE_ORDER : 0x0003,
31 | CAPSTYPE_BITMAPCACHE : 0x0004,
32 | CAPSTYPE_CONTROL : 0x0005,
33 | CAPSTYPE_ACTIVATION : 0x0007,
34 | CAPSTYPE_POINTER : 0x0008,
35 | CAPSTYPE_SHARE : 0x0009,
36 | CAPSTYPE_COLORCACHE : 0x000A,
37 | CAPSTYPE_SOUND : 0x000C,
38 | CAPSTYPE_INPUT : 0x000D,
39 | CAPSTYPE_FONT : 0x000E,
40 | CAPSTYPE_BRUSH : 0x000F,
41 | CAPSTYPE_GLYPHCACHE : 0x0010,
42 | CAPSTYPE_OFFSCREENCACHE : 0x0011,
43 | CAPSTYPE_BITMAPCACHE_HOSTSUPPORT : 0x0012,
44 | CAPSTYPE_BITMAPCACHE_REV2 : 0x0013,
45 | CAPSTYPE_VIRTUALCHANNEL : 0x0014,
46 | CAPSTYPE_DRAWNINEGRIDCACHE : 0x0015,
47 | CAPSTYPE_DRAWGDIPLUS : 0x0016,
48 | CAPSTYPE_RAIL : 0x0017,
49 | CAPSTYPE_WINDOW : 0x0018,
50 | CAPSETTYPE_COMPDESK : 0x0019,
51 | CAPSETTYPE_MULTIFRAGMENTUPDATE : 0x001A,
52 | CAPSETTYPE_LARGE_POINTER : 0x001B,
53 | CAPSETTYPE_SURFACE_COMMANDS : 0x001C,
54 | CAPSETTYPE_BITMAP_CODECS : 0x001D,
55 | CAPSSETTYPE_FRAME_ACKNOWLEDGE : 0x001E
56 | };
57 |
58 | /**
59 | * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
60 | */
61 | var MajorType = {
62 | OSMAJORTYPE_UNSPECIFIED : 0x0000,
63 | OSMAJORTYPE_WINDOWS : 0x0001,
64 | OSMAJORTYPE_OS2 : 0x0002,
65 | OSMAJORTYPE_MACINTOSH : 0x0003,
66 | OSMAJORTYPE_UNIX : 0x0004,
67 | OSMAJORTYPE_IOS : 0x0005,
68 | OSMAJORTYPE_OSX : 0x0006,
69 | OSMAJORTYPE_ANDROID : 0x0007
70 | };
71 |
72 | /**
73 | * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
74 | */
75 | var MinorType = {
76 | OSMINORTYPE_UNSPECIFIED : 0x0000,
77 | OSMINORTYPE_WINDOWS_31X : 0x0001,
78 | OSMINORTYPE_WINDOWS_95 : 0x0002,
79 | OSMINORTYPE_WINDOWS_NT : 0x0003,
80 | OSMINORTYPE_OS2_V21 : 0x0004,
81 | OSMINORTYPE_POWER_PC : 0x0005,
82 | OSMINORTYPE_MACINTOSH : 0x0006,
83 | OSMINORTYPE_NATIVE_XSERVER : 0x0007,
84 | OSMINORTYPE_PSEUDO_XSERVER : 0x0008,
85 | OSMINORTYPE_WINDOWS_RT : 0x0009
86 | };
87 |
88 | /**
89 | * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
90 | */
91 | var GeneralExtraFlag = {
92 | FASTPATH_OUTPUT_SUPPORTED : 0x0001,
93 | NO_BITMAP_COMPRESSION_HDR : 0x0400,
94 | LONG_CREDENTIALS_SUPPORTED : 0x0004,
95 | AUTORECONNECT_SUPPORTED : 0x0008,
96 | ENC_SALTED_CHECKSUM : 0x0010
97 | };
98 |
99 | var Boolean = {
100 | FALSE : 0x00,
101 | TRUE : 0x01
102 | };
103 |
104 | /**
105 | * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
106 | */
107 | var OrderFlag = {
108 | NEGOTIATEORDERSUPPORT : 0x0002,
109 | ZEROBOUNDSDELTASSUPPORT : 0x0008,
110 | COLORINDEXSUPPORT : 0x0020,
111 | SOLIDPATTERNBRUSHONLY : 0x0040,
112 | ORDERFLAGS_EXTRA_FLAGS : 0x0080
113 | };
114 |
115 | /**
116 | * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
117 | */
118 | var Order = {
119 | TS_NEG_DSTBLT_INDEX : 0x00,
120 | TS_NEG_PATBLT_INDEX : 0x01,
121 | TS_NEG_SCRBLT_INDEX : 0x02,
122 | TS_NEG_MEMBLT_INDEX : 0x03,
123 | TS_NEG_MEM3BLT_INDEX : 0x04,
124 | TS_NEG_DRAWNINEGRID_INDEX : 0x07,
125 | TS_NEG_LINETO_INDEX : 0x08,
126 | TS_NEG_MULTI_DRAWNINEGRID_INDEX : 0x09,
127 | TS_NEG_SAVEBITMAP_INDEX : 0x0B,
128 | TS_NEG_MULTIDSTBLT_INDEX : 0x0F,
129 | TS_NEG_MULTIPATBLT_INDEX : 0x10,
130 | TS_NEG_MULTISCRBLT_INDEX : 0x11,
131 | TS_NEG_MULTIOPAQUERECT_INDEX : 0x12,
132 | TS_NEG_FAST_INDEX_INDEX : 0x13,
133 | TS_NEG_POLYGON_SC_INDEX : 0x14,
134 | TS_NEG_POLYGON_CB_INDEX : 0x15,
135 | TS_NEG_POLYLINE_INDEX : 0x16,
136 | TS_NEG_FAST_GLYPH_INDEX : 0x18,
137 | TS_NEG_ELLIPSE_SC_INDEX : 0x19,
138 | TS_NEG_ELLIPSE_CB_INDEX : 0x1A,
139 | TS_NEG_INDEX_INDEX : 0x1B
140 | };
141 |
142 | var OrderEx = {
143 | ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT : 0x0002,
144 | ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT : 0x0004
145 | };
146 |
147 | /**
148 | * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
149 | */
150 | var InputFlags = {
151 | INPUT_FLAG_SCANCODES : 0x0001,
152 | INPUT_FLAG_MOUSEX : 0x0004,
153 | INPUT_FLAG_FASTPATH_INPUT : 0x0008,
154 | INPUT_FLAG_UNICODE : 0x0010,
155 | INPUT_FLAG_FASTPATH_INPUT2 : 0x0020,
156 | INPUT_FLAG_UNUSED1 : 0x0040,
157 | INPUT_FLAG_UNUSED2 : 0x0080,
158 | TS_INPUT_FLAG_MOUSE_HWHEEL : 0x0100
159 | };
160 |
161 | /**
162 | * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
163 | */
164 | var BrushSupport = {
165 | BRUSH_DEFAULT : 0x00000000,
166 | BRUSH_COLOR_8x8 : 0x00000001,
167 | BRUSH_COLOR_FULL : 0x00000002
168 | };
169 |
170 | /**
171 | * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
172 | */
173 | var GlyphSupport = {
174 | GLYPH_SUPPORT_NONE : 0x0000,
175 | GLYPH_SUPPORT_PARTIAL : 0x0001,
176 | GLYPH_SUPPORT_FULL : 0x0002,
177 | GLYPH_SUPPORT_ENCODE : 0x0003
178 | };
179 |
180 | /**
181 | * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
182 | */
183 | var OffscreenSupportLevel = {
184 | FALSE : 0x00000000,
185 | TRUE : 0x00000001
186 | };
187 |
188 | /**
189 | * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
190 | */
191 | var VirtualChannelCompressionFlag = {
192 | VCCAPS_NO_COMPR : 0x00000000,
193 | VCCAPS_COMPR_SC : 0x00000001,
194 | VCCAPS_COMPR_CS_8K : 0x00000002
195 | };
196 |
197 | /**
198 | * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
199 | */
200 | var SoundFlag = {
201 | NONE : 0x0000,
202 | SOUND_BEEPS_FLAG : 0x0001
203 | };
204 |
205 | /**
206 | * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
207 | * @param opt {object} type options
208 | * @returns {type.Component}
209 | */
210 | function generalCapability(opt) {
211 | var self = {
212 | __TYPE__ : CapsType.CAPSTYPE_GENERAL,
213 | osMajorType : new type.UInt16Le(),
214 | osMinorType : new type.UInt16Le(),
215 | protocolVersion : new type.UInt16Le(0x0200, {constant : true}),
216 | pad2octetsA : new type.UInt16Le(),
217 | generalCompressionTypes : new type.UInt16Le(0, {constant : true}),
218 | extraFlags : new type.UInt16Le(),
219 | updateCapabilityFlag : new type.UInt16Le(0, {constant : true}),
220 | remoteUnshareFlag : new type.UInt16Le(0, {constant : true}),
221 | generalCompressionLevel : new type.UInt16Le(0, {constant : true}),
222 | refreshRectSupport : new type.UInt8(),
223 | suppressOutputSupport : new type.UInt8()
224 | };
225 |
226 | return new type.Component(self, opt);
227 | }
228 |
229 | /**
230 | * @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
231 | * @param opt {object} type options
232 | * @returns {type.Component}
233 | */
234 | function bitmapCapability(opt) {
235 | var self = {
236 | __TYPE__ : CapsType.CAPSTYPE_BITMAP,
237 | preferredBitsPerPixel : new type.UInt16Le(),
238 | receive1BitPerPixel : new type.UInt16Le(0x0001),
239 | receive4BitsPerPixel : new type.UInt16Le(0x0001),
240 | receive8BitsPerPixel : new type.UInt16Le(0x0001),
241 | desktopWidth : new type.UInt16Le(),
242 | desktopHeight : new type.UInt16Le(),
243 | pad2octets : new type.UInt16Le(),
244 | desktopResizeFlag : new type.UInt16Le(),
245 | bitmapCompressionFlag : new type.UInt16Le(0x0001, {constant : true}),
246 | highColorFlags : new type.UInt8(0),
247 | drawingFlags : new type.UInt8(),
248 | multipleRectangleSupport : new type.UInt16Le(0x0001, {constant : true}),
249 | pad2octetsB : new type.UInt16Le()
250 | };
251 |
252 | return new type.Component(self, opt);
253 | }
254 |
255 | /**
256 | * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
257 | * @param orders {type.BinaryString|null} list of available orders
258 | * @param opt {object} type options
259 | * @returns {type.Component}
260 | */
261 | function orderCapability(orders, opt) {
262 | if(orders && orders.size() !== 32) {
263 | throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_CAPS_BAD_ORDERS_SIZE');
264 | }
265 |
266 | var self = {
267 | __TYPE__ : CapsType.CAPSTYPE_ORDER,
268 | terminalDescriptor : new type.BinaryString(new Buffer(Array(16 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(16)}),
269 | pad4octetsA : new type.UInt32Le(0),
270 | desktopSaveXGranularity : new type.UInt16Le(1),
271 | desktopSaveYGranularity : new type.UInt16Le(20),
272 | pad2octetsA : new type.UInt16Le(0),
273 | maximumOrderLevel : new type.UInt16Le(1),
274 | numberFonts : new type.UInt16Le(),
275 | orderFlags : new type.UInt16Le(OrderFlag.NEGOTIATEORDERSUPPORT),
276 | orderSupport : orders || new type.Factory(function(s) {
277 | self.orderSupport = new type.BinaryString(null, {readLength : new type.CallableValue(32)}).read(s);
278 | }),
279 | textFlags : new type.UInt16Le(),
280 | orderSupportExFlags : new type.UInt16Le(),
281 | pad4octetsB : new type.UInt32Le(),
282 | desktopSaveSize : new type.UInt32Le(480 * 480),
283 | pad2octetsC : new type.UInt16Le(),
284 | pad2octetsD : new type.UInt16Le(),
285 | textANSICodePage : new type.UInt16Le(0),
286 | pad2octetsE : new type.UInt16Le()
287 | };
288 |
289 | return new type.Component(self, opt);
290 | }
291 |
292 | /**
293 | * @see http://msdn.microsoft.com/en-us/library/cc240559.aspx
294 | * @param opt type options
295 | * @returns {type.Component}
296 | */
297 | function bitmapCacheCapability(opt) {
298 | var self = {
299 | __TYPE__ : CapsType.CAPSTYPE_BITMAPCACHE,
300 | pad1 : new type.UInt32Le(),
301 | pad2 : new type.UInt32Le(),
302 | pad3 : new type.UInt32Le(),
303 | pad4 : new type.UInt32Le(),
304 | pad5 : new type.UInt32Le(),
305 | pad6 : new type.UInt32Le(),
306 | cache0Entries : new type.UInt16Le(),
307 | cache0MaximumCellSize : new type.UInt16Le(),
308 | cache1Entries : new type.UInt16Le(),
309 | cache1MaximumCellSize : new type.UInt16Le(),
310 | cache2Entries : new type.UInt16Le(),
311 | cache2MaximumCellSize : new type.UInt16Le()
312 | };
313 |
314 | return new type.Component(self, opt);
315 | }
316 |
317 | /**
318 | *
319 | * @param isServer {boolean} true if in server mode
320 | * @param opt {object} type options
321 | * @returns {type.Component}
322 | */
323 | function pointerCapability(isServer, opt) {
324 | var self = {
325 | __TYPE__ : CapsType.CAPSTYPE_POINTER,
326 | colorPointerFlag : new type.UInt16Le(),
327 | colorPointerCacheSize : new type.UInt16Le(20),
328 | //old version of rdp doesn't support ...
329 | pointerCacheSize : new type.UInt16Le(null, {conditional : function() {
330 | return isServer || false;
331 | }})
332 | };
333 |
334 | return new type.Component(self, opt);
335 | }
336 |
337 | /**
338 | * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
339 | * @param opt {object} type options
340 | * @returns {type.Component}
341 | */
342 | function inputCapability(opt) {
343 | var self = {
344 | __TYPE__ : CapsType.CAPSTYPE_INPUT,
345 | inputFlags : new type.UInt16Le(),
346 | pad2octetsA : new type.UInt16Le(),
347 | // same value as gcc.ClientCoreSettings.kbdLayout
348 | keyboardLayout : new type.UInt32Le(),
349 | // same value as gcc.ClientCoreSettings.keyboardType
350 | keyboardType : new type.UInt32Le(),
351 | // same value as gcc.ClientCoreSettings.keyboardSubType
352 | keyboardSubType : new type.UInt32Le(),
353 | // same value as gcc.ClientCoreSettings.keyboardFnKeys
354 | keyboardFunctionKey : new type.UInt32Le(),
355 | // same value as gcc.ClientCoreSettingrrs.imeFileName
356 | imeFileName : new type.BinaryString(new Buffer(Array(64 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(64)})
357 | };
358 |
359 | return new type.Component(self, opt);
360 | }
361 |
362 | /**
363 | * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
364 | * @param opt {object} type options
365 | * @returns {type.Component}
366 | */
367 | function brushCapability(opt) {
368 | var self = {
369 | __TYPE__ : CapsType.CAPSTYPE_BRUSH,
370 | brushSupportLevel : new type.UInt32Le(BrushSupport.BRUSH_DEFAULT)
371 | };
372 |
373 | return new type.Component(self, opt);
374 | }
375 |
376 | /**
377 | * @see http://msdn.microsoft.com/en-us/library/cc240566.aspx
378 | * @param opt {object} type options
379 | * @returns {type.Component}
380 | */
381 | function cacheEntry(opt) {
382 | var self = {
383 | cacheEntries : new type.UInt16Le(),
384 | cacheMaximumCellSize : new type.UInt16Le()
385 | };
386 |
387 | return new type.Component(self, opt);
388 | }
389 |
390 | /**
391 | * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
392 | * @param entries {type.Component} cache entries
393 | * @param opt {object} type options
394 | * @returns {type.Component}
395 | */
396 | function glyphCapability(entries, opt) {
397 | var self = {
398 | __TYPE__ : CapsType.CAPSTYPE_GLYPHCACHE,
399 | glyphCache : entries || new type.Factory(function(s) {
400 | self.glyphCache = new type.Component([]);
401 | for(var i = 0; i < 10; i++) {
402 | self.glyphCache.obj.push(cacheEntry().read(s));
403 | }
404 | }),
405 | fragCache : new type.UInt32Le(),
406 | // all fonts are sent with bitmap format (very expensive)
407 | glyphSupportLevel : new type.UInt16Le(GlyphSupport.GLYPH_SUPPORT_NONE),
408 | pad2octets : new type.UInt16Le()
409 | };
410 |
411 | return new type.Component(self, opt);
412 | }
413 |
414 | /**
415 | * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
416 | * @param opt {object} type options
417 | * @returns {type.Component}
418 | */
419 | function offscreenBitmapCacheCapability(opt) {
420 | var self = {
421 | __TYPE__ : CapsType.CAPSTYPE_OFFSCREENCACHE,
422 | offscreenSupportLevel : new type.UInt32Le(OffscreenSupportLevel.FALSE),
423 | offscreenCacheSize : new type.UInt16Le(),
424 | offscreenCacheEntries : new type.UInt16Le()
425 | };
426 |
427 | return new type.Component(self, opt);
428 | }
429 |
430 | /**
431 | * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
432 | * @param opt {object} type options
433 | * @returns {type.Component}
434 | */
435 | function virtualChannelCapability(opt) {
436 | var self = {
437 | __TYPE__ : CapsType.CAPSTYPE_VIRTUALCHANNEL,
438 | flags : new type.UInt32Le(VirtualChannelCompressionFlag.VCCAPS_NO_COMPR),
439 | VCChunkSize : new type.UInt32Le(null, {optional : true})
440 | };
441 |
442 | return new type.Component(self, opt);
443 | }
444 |
445 | /**
446 | * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
447 | * @param opt {object} type options
448 | * @returns {type.Component}
449 | */
450 | function soundCapability(opt) {
451 | var self = {
452 | __TYPE__ : CapsType.CAPSTYPE_SOUND,
453 | soundFlags : new type.UInt16Le(SoundFlag.NONE),
454 | pad2octetsA : new type.UInt16Le()
455 | };
456 |
457 | return new type.Component(self, opt);
458 | }
459 |
460 | /**
461 | * @see http://msdn.microsoft.com/en-us/library/cc240568.aspx
462 | * @param opt {object} type options
463 | * @returns {type.Component}
464 | */
465 | function controlCapability(opt) {
466 | var self = {
467 | __TYPE__ : CapsType.CAPSTYPE_CONTROL,
468 | controlFlags : new type.UInt16Le(),
469 | remoteDetachFlag : new type.UInt16Le(),
470 | controlInterest : new type.UInt16Le(0x0002),
471 | detachInterest : new type.UInt16Le(0x0002)
472 | };
473 |
474 | return new type.Component(self, opt);
475 | }
476 |
477 | /**
478 | * @see http://msdn.microsoft.com/en-us/library/cc240569.aspx
479 | * @param opt {object} type options
480 | * @returns {type.Component}
481 | */
482 | function windowActivationCapability(opt) {
483 | var self = {
484 | __TYPE__ : CapsType.CAPSTYPE_ACTIVATION,
485 | helpKeyFlag : new type.UInt16Le(),
486 | helpKeyIndexFlag : new type.UInt16Le(),
487 | helpExtendedKeyFlag : new type.UInt16Le(),
488 | windowManagerKeyFlag : new type.UInt16Le()
489 | };
490 |
491 | return new type.Component(self, opt);
492 | }
493 |
494 | /**
495 | * @see http://msdn.microsoft.com/en-us/library/cc240571.aspx
496 | * @param opt {object} type options
497 | * @returns {type.Component}
498 | */
499 | function fontCapability(opt) {
500 | var self = {
501 | __TYPE__ : CapsType.CAPSTYPE_FONT,
502 | fontSupportFlags : new type.UInt16Le(0x0001),
503 | pad2octets : new type.UInt16Le()
504 | };
505 |
506 | return new type.Component(self, opt);
507 | }
508 |
509 | /**
510 | * @see http://msdn.microsoft.com/en-us/library/cc241564.aspx
511 | * @param opt {object} type options
512 | * @returns {type.Component}
513 | */
514 | function colorCacheCapability(opt) {
515 | var self = {
516 | __TYPE__ : CapsType.CAPSTYPE_COLORCACHE,
517 | colorTableCacheSize : new type.UInt16Le(0x0006),
518 | pad2octets : new type.UInt16Le()
519 | };
520 |
521 | return new type.Component(self, opt);
522 | }
523 |
524 | /**
525 | * @see http://msdn.microsoft.com/en-us/library/cc240570.aspx
526 | * @param opt {object} type options
527 | * @returns {type.Component}
528 | */
529 | function shareCapability(opt) {
530 | var self = {
531 | __TYPE__ : CapsType.CAPSTYPE_SHARE,
532 | nodeId : new type.UInt16Le(),
533 | pad2octets : new type.UInt16Le()
534 | };
535 |
536 | return new type.Component(self, opt);
537 | }
538 |
539 | /**
540 | * @see http://msdn.microsoft.com/en-us/library/cc240649.aspx
541 | * @param opt {object} type options
542 | * @returns {type.Component}
543 | */
544 | function multiFragmentUpdate(opt) {
545 | var self = {
546 | __TYPE__ : CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE,
547 | MaxRequestSize : new type.UInt32Le(0)
548 | };
549 |
550 | return new type.Component(self, opt);
551 | }
552 |
553 | /**
554 | * Capability wrapper packet
555 | * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
556 | * @param cap {type.Component}
557 | * @param opt {object} type options
558 | * @returns {type.Component}
559 | */
560 | function capability(cap, opt) {
561 | var self = {
562 | capabilitySetType : new type.UInt16Le(function() {
563 | return self.capability.obj.__TYPE__;
564 | }),
565 | lengthCapability : new type.UInt16Le(function() {
566 | return new type.Component(self).size();
567 | }),
568 | capability : cap || new type.Factory(function(s) {
569 | switch(self.capabilitySetType.value) {
570 | case CapsType.CAPSTYPE_GENERAL:
571 | self.capability = generalCapability({readLength : new type.CallableValue(function() {
572 | return self.lengthCapability.value - 4;
573 | })}).read(s);
574 | break;
575 | case CapsType.CAPSTYPE_BITMAP:
576 | self.capability = bitmapCapability({readLength : new type.CallableValue(function() {
577 | return self.lengthCapability.value - 4;
578 | })}).read(s);
579 | break;
580 | case CapsType.CAPSTYPE_ORDER:
581 | self.capability = orderCapability(null, {readLength : new type.CallableValue(function() {
582 | return self.lengthCapability.value - 4;
583 | })}).read(s);
584 | break;
585 | case CapsType.CAPSTYPE_BITMAPCACHE:
586 | self.capability = bitmapCacheCapability({readLength : new type.CallableValue(function() {
587 | return self.lengthCapability.value - 4;
588 | })}).read(s);
589 | break;
590 | case CapsType.CAPSTYPE_POINTER:
591 | self.capability = pointerCapability(false, {readLength : new type.CallableValue(function() {
592 | return self.lengthCapability.value - 4;
593 | })}).read(s);
594 | break;
595 | case CapsType.CAPSTYPE_INPUT:
596 | self.capability = inputCapability({readLength : new type.CallableValue(function() {
597 | return self.lengthCapability.value - 4;
598 | })}).read(s);
599 | break;
600 | case CapsType.CAPSTYPE_BRUSH:
601 | self.capability = brushCapability({readLength : new type.CallableValue(function() {
602 | return self.lengthCapability.value - 4;
603 | })}).read(s);
604 | break;
605 | case CapsType.CAPSTYPE_GLYPHCACHE:
606 | self.capability = glyphCapability(null, {readLength : new type.CallableValue(function() {
607 | return self.lengthCapability.value - 4;
608 | })}).read(s);
609 | break;
610 | case CapsType.CAPSTYPE_OFFSCREENCACHE:
611 | self.capability = offscreenBitmapCacheCapability({readLength : new type.CallableValue(function() {
612 | return self.lengthCapability.value - 4;
613 | })}).read(s);
614 | break;
615 | case CapsType.CAPSTYPE_VIRTUALCHANNEL:
616 | self.capability = virtualChannelCapability({readLength : new type.CallableValue(function() {
617 | return self.lengthCapability.value - 4;
618 | })}).read(s);
619 | break;
620 | case CapsType.CAPSTYPE_SOUND:
621 | self.capability = soundCapability({readLength : new type.CallableValue(function() {
622 | return self.lengthCapability.value - 4;
623 | })}).read(s);
624 | break;
625 | case CapsType.CAPSTYPE_CONTROL:
626 | self.capability = controlCapability({readLength : new type.CallableValue(function() {
627 | return self.lengthCapability.value - 4;
628 | })}).read(s);
629 | break;
630 | case CapsType.CAPSTYPE_ACTIVATION:
631 | self.capability = windowActivationCapability({readLength : new type.CallableValue(function() {
632 | return self.lengthCapability.value - 4;
633 | })}).read(s);
634 | break;
635 | case CapsType.CAPSTYPE_FONT:
636 | self.capability = fontCapability({readLength : new type.CallableValue(function() {
637 | return self.lengthCapability.value - 4;
638 | })}).read(s);
639 | break;
640 | case CapsType.CAPSTYPE_COLORCACHE:
641 | self.capability = colorCacheCapability({readLength : new type.CallableValue(function() {
642 | return self.lengthCapability.value - 4;
643 | })}).read(s);
644 | break;
645 | case CapsType.CAPSTYPE_SHARE:
646 | self.capability = shareCapability({readLength : new type.CallableValue(function() {
647 | return self.lengthCapability.value - 4;
648 | })}).read(s);
649 | break;
650 | case CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE:
651 | self.capability = multiFragmentUpdate({readLength : new type.CallableValue(function() {
652 | return self.lengthCapability.value - 4;
653 | })}).read(s);
654 | break;
655 | default:
656 | log.debug('unknown capability ' + self.capabilitySetType.value);
657 | self.capability = new type.BinaryString(null, {readLength : new type.CallableValue(function() {
658 | return self.lengthCapability.value - 4;
659 | })}).read(s);
660 | }
661 | })
662 | };
663 |
664 | return new type.Component(self, opt);
665 | }
666 |
667 | /**
668 | * Module exports
669 | */
670 | module.exports = {
671 | CapsType : CapsType,
672 | MajorType : MajorType,
673 | MinorType : MinorType,
674 | GeneralExtraFlag : GeneralExtraFlag,
675 | Boolean : Boolean,
676 | OrderFlag : OrderFlag,
677 | Order : Order,
678 | OrderEx : OrderEx,
679 | InputFlags : InputFlags,
680 | BrushSupport : BrushSupport,
681 | GlyphSupport : GlyphSupport,
682 | OffscreenSupportLevel : OffscreenSupportLevel,
683 | VirtualChannelCompressionFlag : VirtualChannelCompressionFlag,
684 | SoundFlag : SoundFlag,
685 | generalCapability : generalCapability,
686 | bitmapCapability : bitmapCapability,
687 | orderCapability : orderCapability,
688 | bitmapCacheCapability : bitmapCacheCapability,
689 | pointerCapability : pointerCapability,
690 | inputCapability : inputCapability,
691 | brushCapability : brushCapability,
692 | cacheEntry : cacheEntry,
693 | glyphCapability : glyphCapability,
694 | offscreenBitmapCacheCapability : offscreenBitmapCacheCapability,
695 | virtualChannelCapability : virtualChannelCapability,
696 | soundCapability : soundCapability,
697 | controlCapability : controlCapability,
698 | windowActivationCapability : windowActivationCapability,
699 | fontCapability : fontCapability,
700 | colorCacheCapability : colorCacheCapability,
701 | shareCapability : shareCapability,
702 | multiFragmentUpdate : multiFragmentUpdate,
703 | capability : capability
704 | };
--------------------------------------------------------------------------------
/lib/protocol/pdu/global.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var events = require('events');
22 | var caps = require('./caps');
23 | var data = require('./data');
24 | var type = require('../../core').type;
25 | var log = require('../../core').log;
26 |
27 | /**
28 | * Global channel for all graphic updates
29 | * capabilities exchange and input handles
30 | */
31 | function Global(transport, fastPathTransport) {
32 | this.transport = transport;
33 | this.fastPathTransport = fastPathTransport;
34 | // must be init via connect event
35 | this.userId = 0;
36 | this.serverCapabilities = [];
37 | this.clientCapabilities = [];
38 | }
39 |
40 | //inherit from Layer
41 | inherits(Global, events.EventEmitter);
42 |
43 | /**
44 | * Send formated PDU message
45 | * @param message {type.Component} PDU message
46 | */
47 | Global.prototype.sendPDU = function(message) {
48 | this.transport.send(data.pdu(this.userId, message));
49 | };
50 |
51 | /**
52 | * Send formated Data PDU message
53 | * @param message {type.Component} PDU message
54 | */
55 | Global.prototype.sendDataPDU = function(message) {
56 | this.sendPDU(data.dataPDU(message, this.shareId));
57 | };
58 |
59 | /**
60 | * Client side of Global channel automata
61 | * @param transport
62 | */
63 | function Client(transport, fastPathTransport) {
64 | Global.call(this, transport, fastPathTransport);
65 | var self = this;
66 | this.transport.once('connect', function(core, userId, channelId) {
67 | self.connect(core, userId, channelId);
68 | }).on('close', function() {
69 | self.emit('close');
70 | }).on('error', function (err) {
71 | self.emit('error', err);
72 | });
73 |
74 | if (this.fastPathTransport) {
75 | this.fastPathTransport.on('fastPathData', function (secFlag, s) {
76 | self.recvFastPath(secFlag, s);
77 | });
78 | }
79 |
80 | // init client capabilities
81 | this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL] = caps.generalCapability();
82 | this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP] = caps.bitmapCapability();
83 | this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER] = caps.orderCapability(
84 | new type.Component([
85 | new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
86 | new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
87 | new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
88 | new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0)
89 | ]));
90 | this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAPCACHE] = caps.bitmapCacheCapability();
91 | this.clientCapabilities[caps.CapsType.CAPSTYPE_POINTER] = caps.pointerCapability();
92 | this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT] = caps.inputCapability();
93 | this.clientCapabilities[caps.CapsType.CAPSTYPE_BRUSH] = caps.brushCapability();
94 | this.clientCapabilities[caps.CapsType.CAPSTYPE_GLYPHCACHE] = caps.glyphCapability(
95 | new type.Component([
96 | caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(),
97 | caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry()
98 | ]));
99 | this.clientCapabilities[caps.CapsType.CAPSTYPE_OFFSCREENCACHE] = caps.offscreenBitmapCacheCapability();
100 | this.clientCapabilities[caps.CapsType.CAPSTYPE_VIRTUALCHANNEL] = caps.virtualChannelCapability();
101 | this.clientCapabilities[caps.CapsType.CAPSTYPE_SOUND] = caps.soundCapability();
102 | this.clientCapabilities[caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate();
103 | }
104 |
105 | // inherit from Layer
106 | inherits(Client, Global);
107 |
108 | /**
109 | * connect function
110 | * @param gccCore {type.Component(clientCoreData)}
111 | */
112 | Client.prototype.connect = function(gccCore, userId, channelId) {
113 | this.gccCore = gccCore;
114 | this.userId = userId;
115 | this.channelId = channelId;
116 | var self = this;
117 | this.transport.once('data', function(s) {
118 | self.recvDemandActivePDU(s);
119 | });
120 | };
121 |
122 | /**
123 | * close stack
124 | */
125 | Client.prototype.close = function() {
126 | this.transport.close();
127 | };
128 |
129 | /**
130 | * Receive capabilities from server
131 | * @param s {type.Stream}
132 | */
133 | Client.prototype.recvDemandActivePDU = function(s) {
134 | var pdu = data.pdu().read(s);
135 | if (pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DEMANDACTIVEPDU) {
136 | log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
137 |
138 | // loop on state
139 | var self = this;
140 | this.transport.once('data', function(s) {
141 | self.recvDemandActivePDU(s);
142 | });
143 | return;
144 | }
145 |
146 | // store share id
147 | this.shareId = pdu.obj.pduMessage.obj.shareId.value;
148 |
149 | // store server capabilities
150 | for(var i in pdu.obj.pduMessage.obj.capabilitySets.obj) {
151 | var cap = pdu.obj.pduMessage.obj.capabilitySets.obj[i].obj.capability;
152 | if(!cap.obj) {
153 | continue;
154 | }
155 | this.serverCapabilities[cap.obj.__TYPE__] = cap;
156 | }
157 |
158 | this.transport.enableSecureCheckSum = !!(this.serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj.extraFlags.value & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM);
159 |
160 | this.sendConfirmActivePDU();
161 | this.sendClientFinalizeSynchronizePDU();
162 |
163 | var self = this;
164 | this.transport.once('data', function(s) {
165 | self.recvServerSynchronizePDU(s);
166 | });
167 | };
168 |
169 | /**
170 | * global channel automata state
171 | * @param s {type.Stream}
172 | */
173 | Client.prototype.recvServerSynchronizePDU = function(s) {
174 | var pdu = data.pdu().read(s);
175 | if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
176 | || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_SYNCHRONIZE) {
177 | log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
178 | // loop on state
179 | var self = this;
180 | this.transport.once('data', function(s) {
181 | self.recvServerSynchronizePDU(s);
182 | });
183 | return;
184 | }
185 |
186 | var self = this;
187 | this.transport.once('data', function(s) {
188 | self.recvServerControlCooperatePDU(s);
189 | });
190 | };
191 |
192 | /**
193 | * global channel automata state
194 | * @param s {type.Stream}
195 | */
196 | Client.prototype.recvServerControlCooperatePDU = function(s) {
197 | var pdu = data.pdu().read(s);
198 | if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
199 | || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
200 | || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_COOPERATE) {
201 | log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
202 |
203 | // loop on state
204 | var self = this;
205 | this.transport.once('data', function(s) {
206 | self.recvServerControlCooperatePDU(s);
207 | });
208 | }
209 |
210 | var self = this;
211 | this.transport.once('data', function(s) {
212 | self.recvServerControlGrantedPDU(s);
213 | });
214 | };
215 |
216 | /**
217 | * global channel automata state
218 | * @param s {type.Stream}
219 | */
220 | Client.prototype.recvServerControlGrantedPDU = function(s) {
221 | var pdu = data.pdu().read(s);
222 | if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
223 | || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
224 | || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_GRANTED_CONTROL) {
225 | log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
226 |
227 | // loop on state
228 | var self = this;
229 | this.transport.once('data', function(s) {
230 | self.recvServerControlGrantedPDU(s);
231 | });
232 | }
233 |
234 | var self = this;
235 | this.transport.once('data', function(s) {
236 | self.recvServerFontMapPDU(s);
237 | });
238 | };
239 |
240 | /**
241 | * global channel automata state
242 | * @param s {type.Stream}
243 | */
244 | Client.prototype.recvServerFontMapPDU = function(s) {
245 | var pdu = data.pdu().read(s);
246 | if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
247 | || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_FONTMAP) {
248 | log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
249 |
250 | // loop on state
251 | var self = this;
252 | this.transport.once('data', function(s) {
253 | self.recvServerFontMapPDU(s);
254 | });
255 | }
256 |
257 | this.emit('connect');
258 | var self = this;
259 | this.transport.on('data', function(s) {
260 | self.recvPDU(s);
261 | });
262 | };
263 |
264 | /**
265 | * Main reveive fast path
266 | * @param secFlag {integer}
267 | * @param s {type.Stream}
268 | */
269 | Client.prototype.recvFastPath = function (secFlag, s) {
270 | while (s.availableLength() > 0) {
271 | var pdu = data.fastPathUpdatePDU().read(s);
272 | switch (pdu.obj.updateHeader.value & 0xf) {
273 | case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
274 | this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
275 | break;
276 | default:
277 | }
278 | }
279 | };
280 |
281 | /**
282 | * global channel automata state
283 | * @param s {type.Stream}
284 | */
285 | Client.prototype.recvPDU = function(s) {
286 | while (s.availableLength() > 0) {
287 | var pdu = data.pdu().read(s);
288 | switch(pdu.obj.shareControlHeader.obj.pduType.value) {
289 | case data.PDUType.PDUTYPE_DEACTIVATEALLPDU:
290 | var self = this;
291 | this.transport.removeAllListeners('data');
292 | this.transport.once('data', function(s) {
293 | self.recvDemandActivePDU(s);
294 | });
295 | break;
296 | case data.PDUType.PDUTYPE_DATAPDU:
297 | this.readDataPDU(pdu.obj.pduMessage)
298 | break;
299 | default:
300 | log.debug('ignore pdu type ' + pdu.obj.shareControlHeader.obj.pduType.value);
301 | }
302 | }
303 | };
304 |
305 | /**
306 | * main receive for data PDU packet
307 | * @param dataPDU {data.dataPDU}
308 | */
309 | Client.prototype.readDataPDU = function (dataPDU) {
310 | switch(dataPDU.obj.shareDataHeader.obj.pduType2.value) {
311 | case data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
312 | break;
313 | case data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
314 | this.transport.close();
315 | break;
316 | case data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO:
317 | this.emit('session');
318 | break;
319 | case data.PDUType2.PDUTYPE2_UPDATE:
320 | this.readUpdateDataPDU(dataPDU.obj.pduData)
321 | break;
322 | }
323 | };
324 |
325 | /**
326 | * Main upadate pdu receive function
327 | * @param updateDataPDU
328 | */
329 | Client.prototype.readUpdateDataPDU = function (updateDataPDU) {
330 | switch(updateDataPDU.obj.updateType.value) {
331 | case data.UpdateType.UPDATETYPE_BITMAP:
332 | this.emit('bitmap', updateDataPDU.obj.updateData.obj.rectangles.obj)
333 | break;
334 | }
335 | };
336 |
337 | /**
338 | * send all client capabilities
339 | */
340 | Client.prototype.sendConfirmActivePDU = function () {
341 | var generalCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj;
342 | generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS;
343 | generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT;
344 | generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED
345 | | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
346 | | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM
347 | | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED;
348 |
349 | var bitmapCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].obj;
350 | bitmapCapability.preferredBitsPerPixel.value = this.gccCore.highColorDepth.value;
351 | bitmapCapability.desktopWidth.value = this.gccCore.desktopWidth.value;
352 | bitmapCapability.desktopHeight.value = this.gccCore.desktopHeight.value;
353 |
354 | var orderCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].obj;
355 | orderCapability.orderFlags.value |= caps.OrderFlag.ZEROBOUNDSDELTASSUPPORT;
356 |
357 | var inputCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].obj;
358 | inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE;
359 | inputCapability.keyboardLayout = this.gccCore.kbdLayout;
360 | inputCapability.keyboardType = this.gccCore.keyboardType;
361 | inputCapability.keyboardSubType = this.gccCore.keyboardSubType;
362 | inputCapability.keyboardrFunctionKey = this.gccCore.keyboardFnKeys;
363 | inputCapability.imeFileName = this.gccCore.imeFileName;
364 |
365 | var capabilities = new type.Component([]);
366 | for(var i in this.clientCapabilities) {
367 | capabilities.obj.push(caps.capability(this.clientCapabilities[i]));
368 | }
369 |
370 | var confirmActivePDU = data.confirmActivePDU(capabilities, this.shareId);
371 |
372 | this.sendPDU(confirmActivePDU);
373 | };
374 |
375 | /**
376 | * send synchronize PDU
377 | */
378 | Client.prototype.sendClientFinalizeSynchronizePDU = function() {
379 | this.sendDataPDU(data.synchronizeDataPDU(this.channelId));
380 | this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_COOPERATE));
381 | this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_REQUEST_CONTROL));
382 | this.sendDataPDU(data.fontListDataPDU());
383 | };
384 |
385 | /**
386 | * Send input event as slow path input
387 | * @param inputEvents {array}
388 | */
389 | Client.prototype.sendInputEvents = function (inputEvents) {
390 | var pdu = data.clientInputEventPDU(new type.Component(inputEvents.map(function (e) {
391 | return data.slowPathInputEvent(e);
392 | })));
393 |
394 | this.sendDataPDU(pdu);
395 | };
396 |
397 | /**
398 | * Module exports
399 | */
400 | module.exports = {
401 | Client : Client
402 | };
--------------------------------------------------------------------------------
/lib/protocol/pdu/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var lic = require('./lic');
21 | var sec = require('./sec');
22 | var global = require('./global');
23 | var data = require('./data');
24 |
25 | module.exports = {
26 | lic : lic,
27 | sec : sec,
28 | global : global,
29 | data : data
30 | };
31 |
--------------------------------------------------------------------------------
/lib/protocol/pdu/lic.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../../core').type;
21 |
22 | var MessageType = {
23 | LICENSE_REQUEST : 0x01,
24 | PLATFORM_CHALLENGE : 0x02,
25 | NEW_LICENSE : 0x03,
26 | UPGRADE_LICENSE : 0x04,
27 | LICENSE_INFO : 0x12,
28 | NEW_LICENSE_REQUEST : 0x13,
29 | PLATFORM_CHALLENGE_RESPONSE : 0x15,
30 | ERROR_ALERT : 0xFF
31 | };
32 |
33 | /**
34 | * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
35 | */
36 | var ErrorCode = {
37 | ERR_INVALID_SERVER_CERTIFICATE : 0x00000001,
38 | ERR_NO_LICENSE : 0x00000002,
39 | ERR_INVALID_SCOPE : 0x00000004,
40 | ERR_NO_LICENSE_SERVER : 0x00000006,
41 | STATUS_VALID_CLIENT : 0x00000007,
42 | ERR_INVALID_CLIENT : 0x00000008,
43 | ERR_INVALID_PRODUCTID : 0x0000000B,
44 | ERR_INVALID_MESSAGE_LEN : 0x0000000C,
45 | ERR_INVALID_MAC : 0x00000003
46 | };
47 |
48 | /**
49 | * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
50 | */
51 | var StateTransition = {
52 | ST_TOTAL_ABORT : 0x00000001,
53 | ST_NO_TRANSITION : 0x00000002,
54 | ST_RESET_PHASE_TO_START : 0x00000003,
55 | ST_RESEND_LAST_MESSAGE : 0x00000004
56 | };
57 |
58 | /**
59 | * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
60 | */
61 | var BinaryBlobType = {
62 | BB_ANY_BLOB : 0x0000,
63 | BB_DATA_BLOB : 0x0001,
64 | BB_RANDOM_BLOB : 0x0002,
65 | BB_CERTIFICATE_BLOB : 0x0003,
66 | BB_ERROR_BLOB : 0x0004,
67 | BB_ENCRYPTED_DATA_BLOB : 0x0009,
68 | BB_KEY_EXCHG_ALG_BLOB : 0x000D,
69 | BB_SCOPE_BLOB : 0x000E,
70 | BB_CLIENT_USER_NAME_BLOB : 0x000F,
71 | BB_CLIENT_MACHINE_NAME_BLOB : 0x0010
72 | };
73 |
74 | var Preambule = {
75 | PREAMBLE_VERSION_2_0 : 0x2,
76 | PREAMBLE_VERSION_3_0 : 0x3,
77 | EXTENDED_ERROR_MSG_SUPPORTED : 0x80
78 | };
79 |
80 | /**
81 | * Binary blob to emcompass license information
82 | * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
83 | * @param blobType {BinaryBlobType.*}
84 | * @returns {type.Component}
85 | */
86 | function licenseBinaryBlob(blobType) {
87 | blobType = blobType || BinaryBlobType.BB_ANY_BLOB;
88 | var self = {
89 | wBlobType : new type.UInt16Le(blobType, { constant : (blobType === BinaryBlobType.BB_ANY_BLOB)?false:true }),
90 | wBlobLen : new type.UInt16Le(function() {
91 | return self.blobData.size();
92 | }),
93 | blobData : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
94 | return self.wBlobLen.value;
95 | })})
96 | };
97 |
98 | return new type.Component(self);
99 | }
100 |
101 | /**
102 | * Error message in license PDU automata
103 | * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
104 | * @param opt {object} type options
105 | * @returns {type.Component}
106 | */
107 | function licensingErrorMessage(opt) {
108 | var self = {
109 | __TYPE__ : MessageType.ERROR_ALERT,
110 | dwErrorCode : new type.UInt32Le(),
111 | dwStateTransition : new type.UInt32Le(),
112 | blob : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB)
113 | };
114 |
115 | return new type.Component(self, opt);
116 | }
117 |
118 | /**
119 | * License product informations
120 | * @see http://msdn.microsoft.com/en-us/library/cc241915.aspx
121 | * @returns {type.Component}
122 | */
123 | function productInformation() {
124 | var self = {
125 | dwVersion : new type.UInt32Le(),
126 | cbCompanyName : new type.UInt32Le(function() {
127 | return self.pbCompanyName.size();
128 | }),
129 | // may contain "Microsoft Corporation" from server microsoft
130 | pbCompanyName : new type.BinaryString(new Buffer('Microsoft Corporation', 'ucs2'), { readLength : new type.CallableValue(function() {
131 | return self.cbCompanyName.value;
132 | })}),
133 | cbProductId : new type.UInt32Le(function() {
134 | return self.pbProductId.size();
135 | }),
136 | // may contain "A02" from microsoft license server
137 | pbProductId : new type.BinaryString(new Buffer('A02', 'ucs2'), { readLength : new type.CallableValue(function() {
138 | return self.cbProductId.value;
139 | })})
140 | };
141 |
142 | return new type.Component(self);
143 | }
144 |
145 | /**
146 | * Use in license negotiation
147 | * @see http://msdn.microsoft.com/en-us/library/cc241917.aspx
148 | * @returns {type.Component}
149 | */
150 | function scope() {
151 | var self = {
152 | scope : licenseBinaryBlob(BinaryBlobType.BB_SCOPE_BLOB)
153 | };
154 |
155 | return new type.Component(self);
156 | }
157 |
158 | /**
159 | * @see http://msdn.microsoft.com/en-us/library/cc241916.aspx
160 | * @returns {type.Component}
161 | */
162 | function scopeList() {
163 | var self = {
164 | scopeCount : new type.UInt32Le(function() {
165 | return self.scopeArray.length;
166 | }),
167 | scopeArray : new type.Factory(function(s) {
168 | self.scopeArray = new type.Component([]);
169 | for(var i = 0; i < self.scopeCount.value; i++) {
170 | self.scopeArray.obj.push(scope().read(s));
171 | }
172 | })
173 | };
174 |
175 | return new type.Component(self);
176 | }
177 |
178 | /**
179 | * @see http://msdn.microsoft.com/en-us/library/cc241914.aspx
180 | * @param opt {object} type options
181 | * @returns {type.Component}
182 | */
183 | function serverLicenseRequest(opt) {
184 | var self = {
185 | __TYPE__ : MessageType.LICENSE_REQUEST,
186 | serverRandom : new type.BinaryString(new Buffer(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) } ),
187 | productInfo : productInformation(),
188 | keyExchangeList : licenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB),
189 | serverCertificate : licenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB),
190 | scopeList : scopeList()
191 | };
192 |
193 | return new type.Component(self, opt);
194 | }
195 |
196 | /**
197 | * @see http://msdn.microsoft.com/en-us/library/cc241918.aspx
198 | * @param opt {object} type options
199 | * @returns {type.Component}
200 | */
201 | function clientNewLicenseRequest(opt) {
202 | var self = {
203 | __TYPE__ : MessageType.NEW_LICENSE_REQUEST,
204 | preferredKeyExchangeAlg : new type.UInt32Le(0x00000001, { constant : true }),
205 | // pure microsoft client ;-)
206 | // http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
207 | platformId : new type.UInt32Le(0x04000000 | 0x00010000),
208 | clientRandom : new type.BinaryString(new Buffer(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) }),
209 | encryptedPreMasterSecret : licenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB),
210 | ClientUserName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB),
211 | ClientMachineName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB)
212 | };
213 |
214 | return new type.Component(self, opt);
215 | }
216 |
217 | /**
218 | * @see http://msdn.microsoft.com/en-us/library/cc241921.aspx
219 | * @param opt {object} type options
220 | * @returns {type.Component}
221 | */
222 | function serverPlatformChallenge(opt) {
223 | var self = {
224 | __TYPE__ : MessageType.PLATFORM_CHALLENGE,
225 | connectFlags : new type.UInt32Le(),
226 | encryptedPlatformChallenge : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB),
227 | MACData : new type.BinaryString(new Buffer(Array(16 + 1).join('\x00')), { readLength : new type.CallableValue(16) })
228 | };
229 |
230 | return new type.Component(self, opt);
231 | }
232 |
233 | /**
234 | * @see http://msdn.microsoft.com/en-us/library/cc241922.aspx
235 | * @param opt {object} type options
236 | * @returns {type.Component}
237 | */
238 | function clientPLatformChallengeResponse(opt) {
239 | var self = {
240 | __TYPE__ : MessageType.PLATFORM_CHALLENGE_RESPONSE,
241 | encryptedPlatformChallengeResponse : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB),
242 | encryptedHWID : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB),
243 | MACData : new type.BinaryString(new Buffer(Array(16 + 1).join('\x00'), 'binary'), { readLength : new type.CallableValue(16) })
244 | };
245 |
246 | return new type.Component(self, opt);
247 | };
248 |
249 | /**
250 | * Global license packet
251 | * @param packet {type.* | null} send packet
252 | * @returns {type.Component}
253 | */
254 | function licensePacket(message) {
255 | var self = {
256 | bMsgtype : new type.UInt8(function() {
257 | return self.licensingMessage.obj.__TYPE__;
258 | }),
259 | flag : new type.UInt8(Preambule.PREAMBLE_VERSION_3_0),
260 | wMsgSize : new type.UInt16Le(function() {
261 | return new type.Component(self).size();
262 | }),
263 | licensingMessage : message || new type.Factory(function(s) {
264 | switch(self.bMsgtype.value) {
265 | case MessageType.ERROR_ALERT:
266 | self.licensingMessage = licensingErrorMessage({ readLength : new type.CallableValue(function() {
267 | return self.wMsgSize.value - 4;
268 | })}).read(s);
269 | break;
270 | case MessageType.LICENSE_REQUEST:
271 | self.licensingMessage = serverLicenseRequest({ readLength : new type.CallableValue(function() {
272 | return self.wMsgSize.value - 4;
273 | })}).read(s);
274 | break;
275 | case MessageType.NEW_LICENSE_REQUEST:
276 | self.licensingMessage = clientNewLicenseRequest({ readLength : new type.CallableValue(function() {
277 | return self.wMsgSize.value - 4;
278 | })}).read(s);
279 | break;
280 | case MessageType.PLATFORM_CHALLENGE:
281 | self.licensingMessage = serverPlatformChallenge({ readLength : new type.CallableValue(function() {
282 | return self.wMsgSize.value - 4;
283 | })}).read(s);
284 | break;
285 | case MessageType.PLATFORM_CHALLENGE_RESPONSE:
286 | self.licensingMessage = clientPLatformChallengeResponse({ readLength : new type.CallableValue(function() {
287 | return self.wMsgSize.value - 4;
288 | })}).read(s);
289 | break;
290 | default:
291 | log.error('unknown license message type ' + self.bMsgtype.value);
292 | }
293 | })
294 | };
295 |
296 | return new type.Component(self);
297 | }
298 |
299 | /**
300 | * Module exports
301 | */
302 | module.exports = {
303 | MessageType : MessageType,
304 | ErrorCode : ErrorCode,
305 | StateTransition : StateTransition,
306 | licensePacket : licensePacket,
307 | clientNewLicenseRequest : clientNewLicenseRequest,
308 | clientPLatformChallengeResponse : clientPLatformChallengeResponse
309 | };
--------------------------------------------------------------------------------
/lib/protocol/pdu/sec.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var crypto = require('crypto');
22 | var events = require('events');
23 | var type = require('../../core').type;
24 | var error = require('../../core').error;
25 | var log = require('../../core').log;
26 | var gcc = require('../t125/gcc');
27 | var lic = require('./lic');
28 | var cert = require('../cert');
29 | var rsa = require('../../security').rsa;
30 |
31 | /**
32 | * @see http://msdn.microsoft.com/en-us/library/cc240579.aspx
33 | */
34 | var SecurityFlag = {
35 | SEC_EXCHANGE_PKT : 0x0001,
36 | SEC_TRANSPORT_REQ : 0x0002,
37 | RDP_SEC_TRANSPORT_RSP : 0x0004,
38 | SEC_ENCRYPT : 0x0008,
39 | SEC_RESET_SEQNO : 0x0010,
40 | SEC_IGNORE_SEQNO : 0x0020,
41 | SEC_INFO_PKT : 0x0040,
42 | SEC_LICENSE_PKT : 0x0080,
43 | SEC_LICENSE_ENCRYPT_CS : 0x0200,
44 | SEC_LICENSE_ENCRYPT_SC : 0x0200,
45 | SEC_REDIRECTION_PKT : 0x0400,
46 | SEC_SECURE_CHECKSUM : 0x0800,
47 | SEC_AUTODETECT_REQ : 0x1000,
48 | SEC_AUTODETECT_RSP : 0x2000,
49 | SEC_HEARTBEAT : 0x4000,
50 | SEC_FLAGSHI_VALID : 0x8000
51 | };
52 |
53 | /**
54 | * @see https://msdn.microsoft.com/en-us/library/cc240475.aspx
55 | */
56 | var InfoFlag = {
57 | INFO_MOUSE : 0x00000001,
58 | INFO_DISABLECTRLALTDEL : 0x00000002,
59 | INFO_AUTOLOGON : 0x00000008,
60 | INFO_UNICODE : 0x00000010,
61 | INFO_MAXIMIZESHELL : 0x00000020,
62 | INFO_LOGONNOTIFY : 0x00000040,
63 | INFO_COMPRESSION : 0x00000080,
64 | INFO_ENABLEWINDOWSKEY : 0x00000100,
65 | INFO_REMOTECONSOLEAUDIO : 0x00002000,
66 | INFO_FORCE_ENCRYPTED_CS_PDU : 0x00004000,
67 | INFO_RAIL : 0x00008000,
68 | INFO_LOGONERRORS : 0x00010000,
69 | INFO_MOUSE_HAS_WHEEL : 0x00020000,
70 | INFO_PASSWORD_IS_SC_PIN : 0x00040000,
71 | INFO_NOAUDIOPLAYBACK : 0x00080000,
72 | INFO_USING_SAVED_CREDS : 0x00100000,
73 | INFO_AUDIOCAPTURE : 0x00200000,
74 | INFO_VIDEO_DISABLE : 0x00400000,
75 | INFO_CompressionTypeMask : 0x00001E00
76 | };
77 |
78 | /**
79 | * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
80 | */
81 | var AfInet = {
82 | AfInet : 0x00002,
83 | AF_INET6 : 0x0017
84 | };
85 |
86 | /**
87 | * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
88 | */
89 | var PerfFlag = {
90 | PERF_DISABLE_WALLPAPER : 0x00000001,
91 | PERF_DISABLE_FULLWINDOWDRAG : 0x00000002,
92 | PERF_DISABLE_MENUANIMATIONS : 0x00000004,
93 | PERF_DISABLE_THEMING : 0x00000008,
94 | PERF_DISABLE_CURSOR_SHADOW : 0x00000020,
95 | PERF_DISABLE_CURSORSETTINGS : 0x00000040,
96 | PERF_ENABLE_FONT_SMOOTHING : 0x00000080,
97 | PERF_ENABLE_DESKTOP_COMPOSITION : 0x00000100
98 | };
99 |
100 | /**
101 | * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
102 | * @param input {Buffer} Binary data
103 | * @param salt {Buffer} salt for context call
104 | * @param salt1 {Buffer} another salt (ex : client random)
105 | * @param salt2 {Buffer} another salt (ex : server random)
106 | * @return {Buffer}
107 | */
108 | function saltedHash(input, salt, salt1, salt2) {
109 | var sha1Digest = crypto.createHash('sha1');
110 | sha1Digest.update(input);
111 | sha1Digest.update(salt.slice(0, 48));
112 | sha1Digest.update(salt1);
113 | sha1Digest.update(salt2);
114 |
115 | var sha1Sig = sha1Digest.digest();
116 |
117 | var md5Digest = crypto.createHash('md5');
118 | md5Digest.update(salt.slice(0, 48));
119 | md5Digest.update(sha1Sig);
120 | return md5Digest.digest();
121 | }
122 |
123 | /**
124 | * @param key {Buffer} secret
125 | * @param random1 {Buffer} client random
126 | * @param random2 {Buffer} server random
127 | * @returns {Buffer}
128 | */
129 | function finalHash (key, random1, random2) {
130 | var md5Digest = crypto.createHash('md5');
131 | md5Digest.update(key);
132 | md5Digest.update(random1);
133 | md5Digest.update(random2);
134 | return md5Digest.digest();
135 | }
136 |
137 | /**
138 | * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
139 | * @param secret {Buffer} secret
140 | * @param random1 {Buffer} client random
141 | * @param random2 {Buffer} server random
142 | * @returns {Buffer}
143 | */
144 | function masterSecret (secret, random1, random2) {
145 | var sh1 = saltedHash(new Buffer('A'), secret, random1, random2);
146 | var sh2 = saltedHash(new Buffer('BB'), secret, random1, random2);
147 | var sh3 = saltedHash(new Buffer('CCC'), secret, random1, random2);
148 |
149 | var ms = new Buffer(sh1.length + sh2.length + sh3.length);
150 | sh1.copy(ms);
151 | sh2.copy(ms, sh1.length);
152 | sh3.copy(ms, sh1.length + sh2.length);
153 | return ms;
154 | }
155 |
156 | /**
157 | * @see http://msdn.microsoft.com/en-us/library/cc241995.aspx
158 | * @param macSaltKey {Buffer} key
159 | * @param data {Buffer} data
160 | * @returns {Buffer}
161 | */
162 | function macData(macSaltKey, data) {
163 | var salt1 = new Buffer(40);
164 | salt1.fill(0x36);
165 |
166 | var salt2 = new Buffer(48);
167 | salt2.fill(0x5c);
168 |
169 | var dataLength = new type.UInt32Le(data.length).toStream().buffer;
170 |
171 | var sha1 = crypto.createHash('sha1');
172 | sha1.update(macSaltKey);
173 | sha1.update(salt1);
174 | sha1.update(dataLength);
175 | sha1.update(data);
176 | var sha1Digest = sha1.digest();
177 |
178 | var md5 = crypto.createHash('md5');
179 | md5.update(macSaltKey);
180 | md5.update(salt2);
181 | md5.update(sha1Digest);
182 |
183 | return md5.digest();
184 | }
185 |
186 | /**
187 | * RDP client informations
188 | * @param extendedInfoConditional {boolean} true if RDP5+
189 | * @returns {type.Component}
190 | */
191 | function rdpInfos(extendedInfoConditional) {
192 | var self = {
193 | codePage : new type.UInt32Le(),
194 | flag : new type.UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL | InfoFlag.INFO_ENABLEWINDOWSKEY),
195 | cbDomain : new type.UInt16Le(function() {
196 | return self.domain.size() - 2;
197 | }),
198 | cbUserName : new type.UInt16Le(function() {
199 | return self.userName.size() - 2;
200 | }),
201 | cbPassword : new type.UInt16Le(function() {
202 | return self.password.size() - 2;
203 | }),
204 | cbAlternateShell : new type.UInt16Le(function() {
205 | return self.alternateShell.size() - 2;
206 | }),
207 | cbWorkingDir : new type.UInt16Le(function() {
208 | return self.workingDir.size() - 2;
209 | }),
210 | domain : new type.BinaryString(new Buffer('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() {
211 | return self.cbDomain.value + 2;
212 | })}),
213 | userName : new type.BinaryString(new Buffer('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
214 | return self.cbUserName.value + 2;
215 | })}),
216 | password : new type.BinaryString(new Buffer('\x00', 'ucs2'), { readLength : new type.CallableValue(function () {
217 | return self.cbPassword.value + 2;
218 | })}),
219 | alternateShell : new type.BinaryString(new Buffer('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
220 | return self.cbAlternateShell.value + 2;
221 | })}),
222 | workingDir : new type.BinaryString(new Buffer('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
223 | return self.cbWorkingDir.value + 2;
224 | })}),
225 | extendedInfo : rdpExtendedInfos({ conditional : extendedInfoConditional })
226 | };
227 |
228 | return new type.Component(self);
229 | }
230 |
231 | /**
232 | * RDP client extended informations present in RDP5+
233 | * @param opt
234 | * @returns {type.Component}
235 | */
236 | function rdpExtendedInfos(opt) {
237 | var self = {
238 | clientAddressFamily : new type.UInt16Le(AfInet.AfInet),
239 | cbClientAddress : new type.UInt16Le(function() {
240 | return self.clientAddress.size();
241 | }),
242 | clientAddress : new type.BinaryString(new Buffer('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() {
243 | return self.cbClientAddress;
244 | }) }),
245 | cbClientDir : new type.UInt16Le(function() {
246 | return self.clientDir.size();
247 | }),
248 | clientDir : new type.BinaryString(new Buffer('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
249 | return self.cbClientDir;
250 | }) }),
251 | clientTimeZone : new type.BinaryString(new Buffer(Array(172 + 1).join("\x00"))),
252 | clientSessionId : new type.UInt32Le(),
253 | performanceFlags : new type.UInt32Le()
254 | };
255 | return new type.Component(self, opt);
256 | }
257 |
258 | /**
259 | * Header of security header
260 | * @returns {type.Component}
261 | */
262 | function securityHeader() {
263 | var self = {
264 | securityFlag : new type.UInt16Le(),
265 | securityFlagHi : new type.UInt16Le()
266 | };
267 |
268 | return new type.Component(self);
269 | }
270 |
271 | /**
272 | * Security layer
273 | * @param transport {events.EventEmitter}
274 | */
275 | function Sec(transport, fastPathTransport) {
276 | this.transport = transport;
277 | this.fastPathTransport = fastPathTransport;
278 | // init at connect event from transport layer
279 | this.gccClient = null;
280 | this.gccServer = null;
281 | var self = this;
282 | this.infos = rdpInfos(function() {
283 | return self.gccClient.core.rdpVersion.value === gcc.VERSION.RDP_VERSION_5_PLUS;
284 | });
285 | this.machineName = '';
286 |
287 |
288 | // basic encryption
289 | this.enableEncryption = false;
290 |
291 | if (this.fastPathTransport) {
292 | this.fastPathTransport.on('fastPathData', function (secFlag, s) {
293 | self.recvFastPath(secFlag, s);
294 | });
295 | }
296 | };
297 |
298 | //inherit from Layer
299 | inherits(Sec, events.EventEmitter);
300 |
301 | /**
302 | * Send message with security header
303 | * @param flag {integer} security flag
304 | * @param data {type.*} message
305 | */
306 | Sec.prototype.sendFlagged = function(flag, data) {
307 | this.transport.send('global', new type.Component([
308 | new type.UInt16Le(flag),
309 | new type.UInt16Le(),
310 | data
311 | ]));
312 | };
313 |
314 | /**
315 | * Main send function
316 | * @param message {type.*} message to send
317 | */
318 | Sec.prototype.send = function(message) {
319 | if (this.enableEncryption) {
320 | throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED');
321 | }
322 | this.transport.send('global', message);
323 | };
324 |
325 | /**
326 | * Main receive function
327 | * @param s {type.Stream}
328 | */
329 | Sec.prototype.recv = function(s) {
330 | if (this.enableEncryption) {
331 | throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED');
332 | }
333 | // not support yet basic RDP security layer
334 | this.emit('data', s);
335 | };
336 |
337 | /**
338 | * Receive fast path data
339 | * @param secFlag {integer} security flag
340 | * @param s {type.Stream}
341 | */
342 | Sec.prototype.recvFastPath = function (secFlag, s) {
343 | // transparent because basic RDP security layer not implemented
344 | this.emit('fastPathData', secFlag, s);
345 | };
346 |
347 | /**
348 | * Client security layer
349 | * @param transport {events.EventEmitter}
350 | */
351 | function Client(transport, fastPathTransport) {
352 | Sec.call(this, transport, fastPathTransport);
353 | // for basic RDP layer (in futur)
354 | this.enableSecureCheckSum = false;
355 | var self = this;
356 | this.transport.on('connect', function(gccClient, gccServer, userId, channels) {
357 | self.connect(gccClient, gccServer, userId, channels);
358 | }).on('close', function() {
359 | self.emit('close');
360 | }).on('error', function (err) {
361 | self.emit('error', err);
362 | });
363 | };
364 |
365 | //inherit from Layer
366 | inherits(Client, Sec);
367 |
368 | /**
369 | * Connect event
370 | */
371 | Client.prototype.connect = function(gccClient, gccServer, userId, channels) {
372 | //init gcc information
373 | this.gccClient = gccClient;
374 | this.gccServer = gccServer;
375 | this.userId = userId;
376 | this.channelId = channels.find(function(e) {
377 | if(e.name === 'global') return true;
378 | }).id;
379 | this.sendInfoPkt();
380 | };
381 |
382 | /**
383 | * close stack
384 | */
385 | Client.prototype.close = function() {
386 | this.transport.close();
387 | };
388 |
389 | /**
390 | * Send main information packet
391 | * VIP (very important packet) because contain credentials
392 | */
393 | Client.prototype.sendInfoPkt = function() {
394 | this.sendFlagged(SecurityFlag.SEC_INFO_PKT, this.infos);
395 | var self = this;
396 | this.transport.once('global', function(s) {
397 | self.recvLicense(s);
398 | });
399 | };
400 |
401 | function reverse(buffer) {
402 | var result = new Buffer(buffer.length);
403 | for(var i = 0; i < buffer.length; i++) {
404 | result.writeUInt8(buffer.readUInt8(buffer.length - 1 - i), i);
405 | }
406 | return result;
407 | }
408 |
409 | /**
410 | * Send a valid license request
411 | * @param licenseRequest {object(lic.serverLicenseRequest)} license requets infos
412 | */
413 | Client.prototype.sendClientNewLicenseRequest = function(licenseRequest) {
414 | log.debug('new license request');
415 | var serverRandom = licenseRequest.serverRandom.value;
416 |
417 | // read server certificate
418 | var s = new type.Stream(licenseRequest.serverCertificate.obj.blobData.value);
419 | var certificate = cert.certificate().read(s).obj;
420 | var publicKey = certificate.certData.obj.getPublicKey();
421 |
422 | var clientRandom = crypto.randomBytes(32);
423 | var preMasterSecret = crypto.randomBytes(48);
424 | var mSecret = masterSecret(preMasterSecret, clientRandom, serverRandom);
425 | var sessionKeyBlob = masterSecret(mSecret, serverRandom, clientRandom);
426 |
427 | this.licenseMacSalt = sessionKeyBlob.slice(0, 16)
428 | this.licenseKey = finalHash(sessionKeyBlob.slice(16, 32), clientRandom, serverRandom);
429 |
430 | var request = lic.clientNewLicenseRequest();
431 | request.obj.clientRandom.value = clientRandom;
432 |
433 | var preMasterSecretEncrypted = reverse(rsa.encrypt(reverse(preMasterSecret), publicKey));
434 | var preMasterSecretEncryptedPadded = new Buffer(preMasterSecretEncrypted.length + 8);
435 | preMasterSecretEncryptedPadded.fill(0);
436 | preMasterSecretEncrypted.copy(preMasterSecretEncryptedPadded);
437 | request.obj.encryptedPreMasterSecret.obj.blobData.value = preMasterSecretEncryptedPadded;
438 |
439 | request.obj.ClientMachineName.obj.blobData.value = this.infos.obj.userName.value;
440 | request.obj.ClientUserName.obj.blobData.value = new Buffer(this.machineName + '\x00');
441 |
442 | this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(request));
443 | };
444 |
445 | /**
446 | * Send a valid license request
447 | * @param platformChallenge {object(lic.serverPlatformChallenge)} platform challenge
448 | */
449 | Client.prototype.sendClientChallengeResponse = function(platformChallenge) {
450 | log.debug('challenge license');
451 | var serverEncryptedChallenge = platformChallenge.encryptedPlatformChallenge.obj.blobData.value;
452 | var serverChallenge = crypto.createDecipheriv('rc4', this.licenseKey, '').update(serverEncryptedChallenge);
453 | if (serverChallenge.toString('ucs2') !== 'TEST\x00') {
454 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_INVALID_LICENSE_CHALLENGE');
455 | }
456 |
457 | var hwid = new type.Component([new type.UInt32Le(2), new type.BinaryString(crypto.randomBytes(16))]).toStream().buffer;
458 |
459 | var response = lic.clientPLatformChallengeResponse();
460 | response.obj.encryptedPlatformChallengeResponse.obj.blobData.value = serverEncryptedChallenge;
461 | response.obj.encryptedHWID.obj.blobData.value = crypto.createCipheriv('rc4', this.licenseKey, '').update(hwid);
462 |
463 | var sig = new Buffer(serverChallenge.length + hwid.length);
464 | serverChallenge.copy(sig);
465 | hwid.copy(sig, serverChallenge.length);
466 | response.obj.MACData.value = macData(this.licenseMacSalt, sig);
467 |
468 | this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(response));
469 | };
470 |
471 | /**
472 | * Receive license informations
473 | * @param s {type.Stream}
474 | */
475 | Sec.prototype.recvLicense = function(s) {
476 | var header = securityHeader().read(s).obj;
477 | if (!(header.securityFlag.value & SecurityFlag.SEC_LICENSE_PKT)) {
478 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER');
479 | }
480 |
481 | var message = lic.licensePacket().read(s).obj;
482 | // i'm accepted
483 | if (message.bMsgtype.value === lic.MessageType.NEW_LICENSE ||
484 | (message.bMsgtype.value === lic.MessageType.ERROR_ALERT
485 | && message.licensingMessage.obj.dwErrorCode.value === lic.ErrorCode.STATUS_VALID_CLIENT
486 | && message.licensingMessage.obj.dwStateTransition.value === lic.StateTransition.ST_NO_TRANSITION)) {
487 | this.emit('connect', this.gccClient.core, this.userId, this.channelId);
488 | var self = this;
489 | this.transport.on('global', function(s) {
490 | self.recv(s);
491 | });
492 | return;
493 | }
494 |
495 | // server ask license request
496 | if (message.bMsgtype.value === lic.MessageType.LICENSE_REQUEST) {
497 | this.sendClientNewLicenseRequest(message.licensingMessage.obj);
498 | }
499 |
500 | // server send challenge
501 | if (message.bMsgtype.value === lic.MessageType.PLATFORM_CHALLENGE) {
502 | this.sendClientChallengeResponse(message.licensingMessage.obj);
503 | }
504 |
505 | var self = this;
506 | this.emit('connect', this.gccClient.core);
507 | this.transport.once('global', function (s) {
508 | self.recvLicense(s);
509 | });
510 | };
511 |
512 | /**
513 | * Module exports
514 | */
515 | module.exports = {
516 | PerfFlag : PerfFlag,
517 | InfoFlag : InfoFlag,
518 | Client : Client
519 | };
--------------------------------------------------------------------------------
/lib/protocol/rdp.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var net = require('net');
21 | var inherits = require('util').inherits;
22 | var events = require('events');
23 | var layer = require('../core').layer;
24 | var error = require('../core').error;
25 | var rle = require('../core').rle;
26 | var log = require('../core').log;
27 | var TPKT = require('./tpkt');
28 | var x224 = require('./x224');
29 | var t125 = require('./t125');
30 | var pdu = require('./pdu');
31 |
32 | /**
33 | * decompress bitmap from RLE algorithm
34 | * @param bitmap {object} bitmap object of bitmap event of node-rdpjs
35 | */
36 | function decompress (bitmap) {
37 | var fName = null;
38 | switch (bitmap.bitsPerPixel.value) {
39 | case 15:
40 | fName = 'bitmap_decompress_15';
41 | break;
42 | case 16:
43 | fName = 'bitmap_decompress_16';
44 | break;
45 | case 24:
46 | fName = 'bitmap_decompress_24';
47 | break;
48 | case 32:
49 | fName = 'bitmap_decompress_32';
50 | break;
51 | default:
52 | throw 'invalid bitmap data format';
53 | }
54 |
55 | var input = new Uint8Array(bitmap.bitmapDataStream.value);
56 | var inputPtr = rle._malloc(input.length);
57 | var inputHeap = new Uint8Array(rle.HEAPU8.buffer, inputPtr, input.length);
58 | inputHeap.set(input);
59 |
60 | var ouputSize = bitmap.width.value * bitmap.height.value * 4;
61 | var outputPtr = rle._malloc(ouputSize);
62 |
63 | var outputHeap = new Uint8Array(rle.HEAPU8.buffer, outputPtr, ouputSize);
64 |
65 | var res = rle.ccall(fName,
66 | 'number',
67 | ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'],
68 | [outputHeap.byteOffset, bitmap.width.value, bitmap.height.value, bitmap.width.value, bitmap.height.value, inputHeap.byteOffset, input.length]
69 | );
70 |
71 | var output = new Uint8ClampedArray(outputHeap.buffer, outputHeap.byteOffset, ouputSize);
72 |
73 | rle._free(inputPtr);
74 | rle._free(outputPtr);
75 |
76 | return output;
77 | }
78 |
79 | /**
80 | * Main RDP module
81 | */
82 | function RdpClient(config) {
83 | config = config || {};
84 | this.connected = false;
85 | this.bufferLayer = new layer.BufferLayer(new net.Socket());
86 | this.tpkt = new TPKT(this.bufferLayer);
87 | this.x224 = new x224.Client(this.tpkt);
88 | this.mcs = new t125.mcs.Client(this.x224);
89 | this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
90 | this.global = new pdu.global.Client(this.sec, this.sec);
91 |
92 | // config log level
93 | log.level = log.Levels[config.logLevel || 'INFO'] || log.Levels.INFO;
94 |
95 | // credentials
96 | if (config.domain) {
97 | this.sec.infos.obj.domain.value = new Buffer(config.domain + '\x00', 'ucs2');
98 | }
99 | if (config.userName) {
100 | this.sec.infos.obj.userName.value = new Buffer(config.userName + '\x00', 'ucs2');
101 | }
102 | if (config.password) {
103 | this.sec.infos.obj.password.value = new Buffer(config.password + '\x00', 'ucs2');
104 | }
105 | if(config.workingDir) {
106 | this.sec.infos.obj.workingDir.value = new Buffer(config.workingDir + '\x00', 'ucs2');
107 | }
108 | if(config.alternateShell) {
109 | this.sec.infos.obj.alternateShell.value = new Buffer(config.alternateShell + '\x00', 'ucs2');
110 | }
111 |
112 | if (config.enablePerf) {
113 | this.sec.infos.obj.extendedInfo.obj.performanceFlags.value =
114 | pdu.sec.PerfFlag.PERF_DISABLE_WALLPAPER
115 | | pdu.sec.PerfFlag.PERF_DISABLE_MENUANIMATIONS
116 | | pdu.sec.PerfFlag.PERF_DISABLE_CURSOR_SHADOW
117 | | pdu.sec.PerfFlag.PERF_DISABLE_THEMING
118 | | pdu.sec.PerfFlag.PERF_DISABLE_FULLWINDOWDRAG;
119 | }
120 |
121 | if (config.autoLogin) {
122 | this.sec.infos.obj.flag.value |= pdu.sec.InfoFlag.INFO_AUTOLOGON;
123 | }
124 |
125 | if (config.screen && config.screen.width && config.screen.height) {
126 | this.mcs.clientCoreData.obj.desktopWidth.value = config.screen.width;
127 | this.mcs.clientCoreData.obj.desktopHeight.value = config.screen.height;
128 | }
129 |
130 | log.debug('screen ' + this.mcs.clientCoreData.obj.desktopWidth.value + 'x' + this.mcs.clientCoreData.obj.desktopHeight.value);
131 |
132 | // config keyboard layout
133 | switch (config.locale) {
134 | case 'fr':
135 | log.debug('french keyboard layout');
136 | this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.FRENCH;
137 | break;
138 | case 'en':
139 | default:
140 | log.debug('english keyboard layout');
141 | this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
142 | }
143 |
144 |
145 | //bind all events
146 | var self = this;
147 | this.global.on('connect', function () {
148 | self.connected = true;
149 | self.emit('connect');
150 | }).on('session', function () {
151 | self.emit('session');
152 | }).on('close', function () {
153 | self.connected = false;
154 | self.emit('close');
155 | }).on('bitmap', function (bitmaps) {
156 | for(var bitmap in bitmaps) {
157 | var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
158 | var isCompress = bitmaps[bitmap].obj.flags.value & pdu.data.BitmapFlag.BITMAP_COMPRESSION;
159 |
160 | if (isCompress && config.decompress) {
161 | bitmapData = decompress(bitmaps[bitmap].obj);
162 | isCompress = false;
163 | }
164 |
165 | self.emit('bitmap', {
166 | destTop : bitmaps[bitmap].obj.destTop.value,
167 | destLeft : bitmaps[bitmap].obj.destLeft.value,
168 | destBottom : bitmaps[bitmap].obj.destBottom.value,
169 | destRight : bitmaps[bitmap].obj.destRight.value,
170 | width : bitmaps[bitmap].obj.width.value,
171 | height : bitmaps[bitmap].obj.height.value,
172 | bitsPerPixel : bitmaps[bitmap].obj.bitsPerPixel.value,
173 | isCompress : isCompress,
174 | data : bitmapData
175 | });
176 | }
177 | }).on('error', function (err) {
178 | log.warn(err.code + '(' + err.message + ')\n' + err.stack);
179 | if (err instanceof error.FatalError) {
180 | throw err;
181 | }
182 | else {
183 | self.emit('error', err);
184 | }
185 | });
186 | }
187 |
188 | inherits(RdpClient, events.EventEmitter);
189 |
190 | /**
191 | * Connect RDP client
192 | * @param host {string} destination host
193 | * @param port {integer} destination port
194 | */
195 | RdpClient.prototype.connect = function (host, port) {
196 | log.debug('connect to ' + host + ':' + port);
197 | var self = this;
198 | this.bufferLayer.socket.connect(port, host, function () {
199 | // in client mode connection start from x224 layer
200 | self.x224.connect();
201 | });
202 | return this;
203 | };
204 |
205 | /**
206 | * Close RDP client
207 | */
208 | RdpClient.prototype.close = function () {
209 | if(this.connected) {
210 | this.global.close();
211 | }
212 | this.connected = false;
213 | return this;
214 | };
215 |
216 | /**
217 | * Send pointer event to server
218 | * @param x {integer} mouse x position
219 | * @param y {integer} mouse y position
220 | * @param button {integer} button number of mouse
221 | * @param isPressed {boolean} state of button
222 | */
223 | RdpClient.prototype.sendPointerEvent = function (x, y, button, isPressed) {
224 | if (!this.connected)
225 | return;
226 |
227 | var event = pdu.data.pointerEvent();
228 | if (isPressed) {
229 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN;
230 | }
231 |
232 | switch(button) {
233 | case 1:
234 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1;
235 | break;
236 | case 2:
237 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2;
238 | break;
239 | case 3:
240 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
241 | break;
242 | default:
243 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE;
244 | }
245 |
246 | event.obj.xPos.value = x;
247 | event.obj.yPos.value = y;
248 |
249 | this.global.sendInputEvents([event]);
250 | };
251 |
252 | /**
253 | * send scancode event
254 | * @param code {integer}
255 | * @param isPressed {boolean}
256 | * @param extended {boolenan} extended keys
257 | */
258 | RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended) {
259 | if (!this.connected)
260 | return;
261 | extended = extended || false;
262 | var event = pdu.data.scancodeKeyEvent();
263 | event.obj.keyCode.value = code;
264 |
265 | if (!isPressed) {
266 | event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
267 | }
268 |
269 | if (extended) {
270 | event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED;
271 | }
272 |
273 | this.global.sendInputEvents([event]);
274 | };
275 |
276 | /**
277 | * Send key event as unicode
278 | * @param code {integer}
279 | * @param isPressed {boolean}
280 | */
281 | RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) {
282 | if (!this.connected)
283 | return;
284 |
285 | var event = pdu.data.unicodeKeyEvent();
286 | event.obj.unicode.value = code;
287 |
288 | if (!isPressed) {
289 | event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
290 | }
291 | this.global.sendInputEvents([event]);
292 | }
293 |
294 | /**
295 | * Wheel mouse event
296 | * @param x {integer} mouse x position
297 | * @param y {integer} mouse y position
298 | * @param step {integer} wheel step
299 | * @param isNegative {boolean}
300 | * @param isHorizontal {boolean}
301 | */
302 | RdpClient.prototype.sendWheelEvent = function (x, y, step, isNegative, isHorizontal) {
303 | if (!this.connected)
304 | return;
305 |
306 | var event = pdu.data.pointerEvent();
307 | if (isHorizontal) {
308 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_HWHEEL;
309 | }
310 | else {
311 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL;
312 | }
313 |
314 |
315 | if (isNegative) {
316 | event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL_NEGATIVE;
317 | }
318 |
319 | event.obj.pointerFlags.value |= (step & pdu.data.PointerFlag.WheelRotationMask)
320 |
321 | event.obj.xPos.value = x;
322 | event.obj.yPos.value = y;
323 |
324 | this.global.sendInputEvents([event]);
325 | }
326 |
327 | function createClient(config) {
328 | return new RdpClient(config);
329 | };
330 |
331 | /**
332 | * RDP server side protocol
333 | * @param config {object} configuration
334 | * @param socket {net.Socket}
335 | */
336 | function RdpServer(config, socket) {
337 | if (!(config.key && config.cert)) {
338 | throw new error.FatalError('NODE_RDP_PROTOCOL_RDP_SERVER_CONFIG_MISSING', 'missing cryptographic tools')
339 | }
340 | this.connected = false;
341 | this.bufferLayer = new layer.BufferLayer(socket);
342 | this.tpkt = new TPKT(this.bufferLayer);
343 | this.x224 = new x224.Server(this.tpkt, config.key, config.cert);
344 | this.mcs = new t125.mcs.Server(this.x224);
345 | };
346 |
347 | inherits(RdpServer, events.EventEmitter);
348 |
349 | function createServer (config, next) {
350 | return net.createServer(function (socket) {
351 | next(new RdpServer(config, socket));
352 | });
353 | };
354 |
355 | /**
356 | * Module exports
357 | */
358 | module.exports = {
359 | createClient : createClient,
360 | createServer : createServer
361 | };
--------------------------------------------------------------------------------
/lib/protocol/t125/gcc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../../core').type;
21 | var log = require('../../core').log;
22 | var error = require('../../core').error;
23 | var per = require('./per');
24 |
25 |
26 | var t124_02_98_oid = [ 0, 0, 20, 124, 0, 1 ];
27 | var h221_cs_key = "Duca";
28 | var h221_sc_key = "McDn";
29 |
30 |
31 | /**
32 | * @see http://msdn.microsoft.com/en-us/library/cc240509.aspx
33 | */
34 | var MessageType = {
35 | //server -> client
36 | SC_CORE : 0x0C01,
37 | SC_SECURITY : 0x0C02,
38 | SC_NET : 0x0C03,
39 | //client -> server
40 | CS_CORE : 0xC001,
41 | CS_SECURITY : 0xC002,
42 | CS_NET : 0xC003,
43 | CS_CLUSTER : 0xC004,
44 | CS_MONITOR : 0xC005
45 | };
46 |
47 | /**
48 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
49 | */
50 | var ColorDepth = {
51 | RNS_UD_COLOR_8BPP : 0xCA01,
52 | RNS_UD_COLOR_16BPP_555 : 0xCA02,
53 | RNS_UD_COLOR_16BPP_565 : 0xCA03,
54 | RNS_UD_COLOR_24BPP : 0xCA04
55 | };
56 |
57 | /**
58 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
59 | */
60 | var HighColor = {
61 | HIGH_COLOR_4BPP : 0x0004,
62 | HIGH_COLOR_8BPP : 0x0008,
63 | HIGH_COLOR_15BPP : 0x000f,
64 | HIGH_COLOR_16BPP : 0x0010,
65 | HIGH_COLOR_24BPP : 0x0018
66 | };
67 |
68 | /**
69 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
70 | */
71 | var Support = {
72 | RNS_UD_24BPP_SUPPORT : 0x0001,
73 | RNS_UD_16BPP_SUPPORT : 0x0002,
74 | RNS_UD_15BPP_SUPPORT : 0x0004,
75 | RNS_UD_32BPP_SUPPORT : 0x0008
76 | };
77 |
78 | /**
79 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
80 | */
81 | var CapabilityFlag = {
82 | RNS_UD_CS_SUPPORT_ERRINFO_PDU : 0x0001,
83 | RNS_UD_CS_WANT_32BPP_SESSION : 0x0002,
84 | RNS_UD_CS_SUPPORT_STATUSINFO_PDU : 0x0004,
85 | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS : 0x0008,
86 | RNS_UD_CS_UNUSED : 0x0010,
87 | RNS_UD_CS_VALID_CONNECTION_TYPE : 0x0020,
88 | RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU : 0x0040,
89 | RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT : 0x0080,
90 | RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL : 0x0100,
91 | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE : 0x0200,
92 | RNS_UD_CS_SUPPORT_HEARTBEAT_PDU : 0x0400
93 | };
94 |
95 | /**
96 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
97 | */
98 | var ConnectionType = {
99 | CONNECTION_TYPE_MODEM : 0x01,
100 | CONNECTION_TYPE_BROADBAND_LOW : 0x02,
101 | CONNECTION_TYPE_SATELLITE : 0x03,
102 | CONNECTION_TYPE_BROADBAND_HIGH : 0x04,
103 | CONNECTION_TYPE_WAN : 0x05,
104 | CONNECTION_TYPE_LAN : 0x06,
105 | CONNECTION_TYPE_AUTODETECT : 0x07
106 | };
107 |
108 | /**
109 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
110 | */
111 | var VERSION = {
112 | RDP_VERSION_4 : 0x00080001,
113 | RDP_VERSION_5_PLUS : 0x00080004
114 | };
115 |
116 | var Sequence = {
117 | RNS_UD_SAS_DEL : 0xAA03
118 | };
119 |
120 | /**
121 | * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
122 | */
123 | var EncryptionMethod = {
124 | ENCRYPTION_FLAG_40BIT : 0x00000001,
125 | ENCRYPTION_FLAG_128BIT : 0x00000002,
126 | ENCRYPTION_FLAG_56BIT : 0x00000008,
127 | FIPS_ENCRYPTION_FLAG : 0x00000010
128 | };
129 |
130 | /**
131 | * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
132 | */
133 | var EncryptionLevel = {
134 | ENCRYPTION_LEVEL_NONE : 0x00000000,
135 | ENCRYPTION_LEVEL_LOW : 0x00000001,
136 | ENCRYPTION_LEVEL_CLIENT_COMPATIBLE : 0x00000002,
137 | ENCRYPTION_LEVEL_HIGH : 0x00000003,
138 | ENCRYPTION_LEVEL_FIPS : 0x00000004
139 | };
140 |
141 | /**
142 | * @see http://msdn.microsoft.com/en-us/library/cc240513.aspx
143 | */
144 | var ChannelOptions = {
145 | CHANNEL_OPTION_INITIALIZED : 0x80000000,
146 | CHANNEL_OPTION_ENCRYPT_RDP : 0x40000000,
147 | CHANNEL_OPTION_ENCRYPT_SC : 0x20000000,
148 | CHANNEL_OPTION_ENCRYPT_CS : 0x10000000,
149 | CHANNEL_OPTION_PRI_HIGH : 0x08000000,
150 | CHANNEL_OPTION_PRI_MED : 0x04000000,
151 | CHANNEL_OPTION_PRI_LOW : 0x02000000,
152 | CHANNEL_OPTION_COMPRESS_RDP : 0x00800000,
153 | CHANNEL_OPTION_COMPRESS : 0x00400000,
154 | CHANNEL_OPTION_SHOW_PROTOCOL : 0x00200000,
155 | REMOTE_CONTROL_PERSISTENT : 0x00100000
156 | };
157 |
158 | /**
159 | * IBM_101_102_KEYS is the most common keyboard type
160 | */
161 | var KeyboardType = {
162 | IBM_PC_XT_83_KEY : 0x00000001,
163 | OLIVETTI : 0x00000002,
164 | IBM_PC_AT_84_KEY : 0x00000003,
165 | IBM_101_102_KEYS : 0x00000004,
166 | NOKIA_1050 : 0x00000005,
167 | NOKIA_9140 : 0x00000006,
168 | JAPANESE : 0x00000007
169 | };
170 |
171 | /**
172 | * @see http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
173 | */
174 | var KeyboardLayout = {
175 | ARABIC : 0x00000401,
176 | BULGARIAN : 0x00000402,
177 | CHINESE_US_KEYBOARD : 0x00000404,
178 | CZECH : 0x00000405,
179 | DANISH : 0x00000406,
180 | GERMAN : 0x00000407,
181 | GREEK : 0x00000408,
182 | US : 0x00000409,
183 | SPANISH : 0x0000040a,
184 | FINNISH : 0x0000040b,
185 | FRENCH : 0x0000040c,
186 | HEBREW : 0x0000040d,
187 | HUNGARIAN : 0x0000040e,
188 | ICELANDIC : 0x0000040f,
189 | ITALIAN : 0x00000410,
190 | JAPANESE : 0x00000411,
191 | KOREAN : 0x00000412,
192 | DUTCH : 0x00000413,
193 | NORWEGIAN : 0x00000414
194 | };
195 |
196 | /**
197 | * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
198 | */
199 | var CertificateType = {
200 | CERT_CHAIN_VERSION_1 : 0x00000001,
201 | CERT_CHAIN_VERSION_2 : 0x00000002
202 | };
203 |
204 | /**
205 | * @param {type.Type} data
206 | * @returns {type.Component}
207 | */
208 | function block(data) {
209 | var self = {
210 | // type of data block
211 | type : new type.UInt16Le(function() {
212 | return self.data.obj.__TYPE__;
213 | }),
214 | // length of entire packet
215 | length : new type.UInt16Le(function() {
216 | return new type.Component(self).size();
217 | }),
218 | // data block
219 | data : data || new type.Factory(function(s){
220 | var options = {
221 | readLength : new type.CallableValue( function () {
222 | return self.length.value - 4;
223 | })
224 | };
225 | switch(self.type.value) {
226 | case MessageType.SC_CORE:
227 | self.data = serverCoreData(options).read(s);
228 | break;
229 | case MessageType.SC_SECURITY:
230 | self.data = serverSecurityData(options).read(s);
231 | break;
232 | case MessageType.SC_NET:
233 | self.data = serverNetworkData(null, options).read(s);
234 | break;
235 | case MessageType.CS_CORE:
236 | self.data = clientCoreData(options).read(s);
237 | break;
238 | case MessageType.CS_SECURITY:
239 | self.data = clientSecurityData(options).read(s);
240 | break;
241 | case MessageType.CS_NET:
242 | self.data = clientNetworkData(null, options).read(s);
243 | break;
244 | default:
245 | log.debug("unknown gcc block type " + self.type.value);
246 | self.data = new type.BinaryString(null, options).read(s);
247 | }
248 | })
249 | };
250 |
251 | return new type.Component(self);
252 | }
253 |
254 | /**
255 | * Main client informations
256 | * keyboard
257 | * screen definition
258 | * color depth
259 | * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
260 | * @param opt {object} Classic type options
261 | * @returns {type.Component}
262 | */
263 | function clientCoreData(opt) {
264 | var self = {
265 | __TYPE__ : MessageType.CS_CORE,
266 | rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS),
267 | desktopWidth : new type.UInt16Le(1280),
268 | desktopHeight : new type.UInt16Le(800),
269 | colorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP),
270 | sasSequence : new type.UInt16Le(Sequence.RNS_UD_SAS_DEL),
271 | kbdLayout : new type.UInt32Le(KeyboardLayout.FRENCH),
272 | clientBuild : new type.UInt32Le(3790),
273 | clientName : new type.BinaryString(new Buffer('node-rdpjs\x00\x00\x00\x00\x00\x00', 'ucs2'), { readLength : new type.CallableValue(32) }),
274 | keyboardType : new type.UInt32Le(KeyboardType.IBM_101_102_KEYS),
275 | keyboardSubType : new type.UInt32Le(0),
276 | keyboardFnKeys : new type.UInt32Le(12),
277 | imeFileName : new type.BinaryString(new Buffer(Array(64 + 1).join('\x00')), { readLength : new type.CallableValue(64), optional : true }),
278 | postBeta2ColorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, { optional : true }),
279 | clientProductId : new type.UInt16Le(1, { optional : true }),
280 | serialNumber : new type.UInt32Le(0, { optional : true }),
281 | highColorDepth : new type.UInt16Le(HighColor.HIGH_COLOR_24BPP, { optional : true }),
282 | supportedColorDepths : new type.UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, { optional : true }),
283 | earlyCapabilityFlags : new type.UInt16Le(CapabilityFlag.RNS_UD_CS_SUPPORT_ERRINFO_PDU, { optional : true }),
284 | clientDigProductId : new type.BinaryString(new Buffer(Array(64 + 1).join('\x00')), { optional : true, readLength : new type.CallableValue(64) }),
285 | connectionType : new type.UInt8(0, { optional : true }),
286 | pad1octet : new type.UInt8(0, { optional : true }),
287 | serverSelectedProtocol : new type.UInt32Le(0, { optional : true })
288 | };
289 |
290 | return new type.Component(self, opt);
291 | }
292 |
293 | /**
294 | * @see http://msdn.microsoft.com/en-us/library/cc240517.aspx
295 | * @param opt {object} Classic type options
296 | * @returns {type.Component}
297 | */
298 | function serverCoreData(opt) {
299 | var self = {
300 | __TYPE__ : MessageType.SC_CORE,
301 | rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS),
302 | clientRequestedProtocol : new type.UInt32Le(null, { optional : true }),
303 | earlyCapabilityFlags : new type.UInt32Le(null, { optional : true })
304 | };
305 |
306 | return new type.Component(self, opt);
307 | }
308 |
309 | /**
310 | * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
311 | * @param opt {object} Classic type options
312 | * @returns {type.Component}
313 | */
314 | function clientSecurityData(opt) {
315 | var self = {
316 | __TYPE__ : MessageType.CS_SECURITY,
317 | encryptionMethods : new type.UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT),
318 | extEncryptionMethods : new type.UInt32Le()
319 | };
320 |
321 | return new type.Component(self, opt);
322 | }
323 |
324 | /**
325 | * Only use for SSL (RDP security layer TODO)
326 | * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
327 | * @param opt {object} Classic type options
328 | * @returns {type.Component}
329 | */
330 | function serverSecurityData(opt) {
331 | var self = {
332 | __TYPE__ : MessageType.SC_SECURITY,
333 | encryptionMethod : new type.UInt32Le(),
334 | encryptionLevel : new type.UInt32Le()
335 | };
336 |
337 | return new type.Component(self, opt);
338 | }
339 |
340 | /**
341 | * Channel definition
342 | * @param opt {object} Classic type options
343 | * @returns {type.Component}
344 | */
345 | function channelDef (opt) {
346 | var self = {
347 | name : new type.BinaryString(null, { readLength : new type.CallableValue(8) }),
348 | options : new type.UInt32Le()
349 | };
350 |
351 | return new type.Component(self, opt);
352 | }
353 |
354 | /**
355 | * Optional channel requests (sound, clipboard ...)
356 | * @param opt {object} Classic type options
357 | * @returns {type.Component}
358 | */
359 | function clientNetworkData(channelDefArray, opt) {
360 | var self = {
361 | __TYPE__ : MessageType.CS_NET,
362 | channelCount : new type.UInt32Le( function () {
363 | return self.channelDefArray.obj.length;
364 | }),
365 | channelDefArray : channelDefArray || new type.Factory( function (s) {
366 | self.channelDefArray = new type.Component([]);
367 |
368 | for (var i = 0; i < self.channelCount.value; i++) {
369 | self.channelDefArray.obj.push(channelDef().read(s));
370 | }
371 | })
372 | };
373 |
374 | return new type.Component(self, opt);
375 | }
376 |
377 | /**
378 | * @param channelIds {type.Component} list of available channels
379 | * @param opt {object} Classic type options
380 | * @returns {type.Component}
381 | */
382 | function serverNetworkData (channelIds, opt) {
383 | var self = {
384 | __TYPE__ : MessageType.SC_NET,
385 | MCSChannelId : new type.UInt16Le(1003, { constant : true }),
386 | channelCount : new type.UInt16Le(function () {
387 | return self.channelIdArray.obj.length;
388 | }),
389 | channelIdArray : channelIds || new type.Factory( function (s) {
390 | self.channelIdArray = new type.Component([]);
391 | for (var i = 0; i < self.channelCount.value; i++) {
392 | self.channelIdArray.obj.push(new type.UInt16Le().read(s));
393 | }
394 | }),
395 | pad : new type.UInt16Le(null, { conditional : function () {
396 | return (self.channelCount.value % 2) === 1;
397 | }})
398 | };
399 |
400 | return new type.Component(self, opt);
401 | }
402 |
403 | /**
404 | * Client or server GCC settings block
405 | * @param blocks {type.Component} array of gcc blocks
406 | * @param opt {object} options to component type
407 | * @returns {type.Component}
408 | */
409 | function settings(blocks, opt) {
410 | var self = {
411 | blocks : blocks || new type.Factory(function(s) {
412 | self.blocks = new type.Component([]);
413 | // read until end of stream
414 | while(s.availableLength() > 0) {
415 | self.blocks.obj.push(block().read(s));
416 | }
417 | }),
418 | };
419 |
420 | return new type.Component(self, opt);
421 | }
422 |
423 | /**
424 | * Read GCC response from server
425 | * @param s {type.Stream} current stream
426 | * @returns {Array(type.Component)} list of server block
427 | */
428 | function readConferenceCreateResponse(s) {
429 | per.readChoice(s);
430 |
431 | if(!per.readObjectIdentifier(s, t124_02_98_oid)) {
432 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_OBJECT_IDENTIFIER_T124');
433 | }
434 |
435 | per.readLength(s);
436 | per.readChoice(s);
437 | per.readInteger16(s, 1001);
438 | per.readInteger(s);
439 | per.readEnumerates(s);
440 | per.readNumberOfSet(s);
441 | per.readChoice(s);
442 |
443 | if (!per.readOctetStream(s, h221_sc_key, 4)) {
444 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY');
445 | }
446 |
447 | length = per.readLength(s);
448 | serverSettings = settings(null, { readLength : new type.CallableValue(length) });
449 |
450 | // Object magic
451 | return serverSettings.read(s).obj.blocks.obj.map(function(e) {
452 | return e.obj.data;
453 | });
454 | }
455 |
456 | /**
457 | * Read GCC request
458 | * @param s {type.Stream}
459 | * @returns {Array(type.Component)} list of client block
460 | */
461 | function readConferenceCreateRequest (s) {
462 | per.readChoice(s);
463 | if (!per.readObjectIdentifier(s, t124_02_98_oid)) {
464 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY');
465 | }
466 | per.readLength(s);
467 | per.readChoice(s);
468 | per.readSelection(s);
469 | per.readNumericString(s, 1);
470 | per.readPadding(s, 1);
471 |
472 | if (per.readNumberOfSet(s) !== 1) {
473 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_SET');
474 | }
475 |
476 | if (per.readChoice(s) !== 0xc0) {
477 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_CHOICE');
478 | }
479 |
480 | per.readOctetStream(s, h221_cs_key, 4);
481 |
482 | length = per.readLength(s);
483 | var clientSettings = settings(null, { readLength : new type.CallableValue(length) });
484 |
485 | // Object magic
486 | return clientSettings.read(s).obj.blocks.obj.map(function(e) {
487 | return e.obj.data;
488 | });
489 | }
490 |
491 | /**
492 | * Built {type.Componen} from gcc user data
493 | * @param userData {type.Component} GCC data from client
494 | * @returns {type.Component} GCC encoded client user data
495 | */
496 | function writeConferenceCreateRequest (userData) {
497 | var userDataStream = new type.Stream(userData.size());
498 | userData.write(userDataStream);
499 |
500 | return new type.Component([
501 | per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
502 | per.writeLength(userData.size() + 14), per.writeChoice(0),
503 | per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1),
504 | per.writeNumberOfSet(1), per.writeChoice(0xc0),
505 | per.writeOctetStream(new Buffer(h221_cs_key), 4), per.writeOctetStream(userDataStream.getValue())
506 | ]);
507 | }
508 |
509 | function writeConferenceCreateResponse (userData) {
510 | var userDataStream = new type.Stream(userData.size());
511 | userData.write(userDataStream);
512 |
513 | return new type.Component([
514 | per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
515 | per.writeLength(userData.size() + 14), per.writeChoice(0x14),
516 | per.writeInteger16(0x79F3, 1001), per.writeInteger(1), per.writeEnumerates(0),
517 | per.writeNumberOfSet(1), per.writeChoice(0xc0),
518 | per.writeOctetStream(new Buffer(h221_sc_key), 4), per.writeOctetStream(userDataStream.getValue())
519 | ]);
520 | }
521 |
522 | /**
523 | * Module exports
524 | */
525 | module.exports = {
526 | MessageType : MessageType,
527 | VERSION : VERSION,
528 | KeyboardLayout : KeyboardLayout,
529 | block : block,
530 | clientCoreData : clientCoreData,
531 | clientNetworkData : clientNetworkData,
532 | clientSecurityData : clientSecurityData,
533 | serverCoreData : serverCoreData,
534 | serverSecurityData : serverSecurityData,
535 | serverNetworkData : serverNetworkData,
536 | readConferenceCreateResponse : readConferenceCreateResponse,
537 | readConferenceCreateRequest : readConferenceCreateRequest,
538 | writeConferenceCreateRequest : writeConferenceCreateRequest,
539 | writeConferenceCreateResponse : writeConferenceCreateResponse
540 | };
--------------------------------------------------------------------------------
/lib/protocol/t125/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var mcs = require('./mcs');
21 | var gcc = require('./gcc');
22 |
23 | module.exports = {
24 | mcs : mcs,
25 | gcc : gcc
26 | };
27 |
--------------------------------------------------------------------------------
/lib/protocol/t125/mcs.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var events = require('events');
22 | var type = require('../../core').type;
23 | var log = require('../../core').log;
24 | var error = require('../../core').error;
25 | var gcc = require('./gcc');
26 | var per = require('./per');
27 | var asn1 = require('../../asn1');
28 |
29 | var Message = {
30 | MCS_TYPE_CONNECT_INITIAL : 0x65,
31 | MCS_TYPE_CONNECT_RESPONSE : 0x66
32 | };
33 |
34 | var DomainMCSPDU = {
35 | ERECT_DOMAIN_REQUEST : 1,
36 | DISCONNECT_PROVIDER_ULTIMATUM : 8,
37 | ATTACH_USER_REQUEST : 10,
38 | ATTACH_USER_CONFIRM : 11,
39 | CHANNEL_JOIN_REQUEST : 14,
40 | CHANNEL_JOIN_CONFIRM : 15,
41 | SEND_DATA_REQUEST : 25,
42 | SEND_DATA_INDICATION : 26
43 | };
44 |
45 | var Channel = {
46 | MCS_GLOBAL_CHANNEL : 1003,
47 | MCS_USERCHANNEL_BASE : 1001
48 | };
49 |
50 | /**
51 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
52 | * @returns {asn1.univ.Sequence}
53 | */
54 | function DomainParameters(maxChannelIds, maxUserIds, maxTokenIds,
55 | numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion) {
56 | return new asn1.univ.Sequence({
57 | maxChannelIds : new asn1.univ.Integer(maxChannelIds),
58 | maxUserIds : new asn1.univ.Integer(maxUserIds),
59 | maxTokenIds : new asn1.univ.Integer(maxTokenIds),
60 | numPriorities : new asn1.univ.Integer(numPriorities),
61 | minThoughput : new asn1.univ.Integer(minThoughput),
62 | maxHeight : new asn1.univ.Integer(maxHeight),
63 | maxMCSPDUsize : new asn1.univ.Integer(maxMCSPDUsize),
64 | protocolVersion : new asn1.univ.Integer(protocolVersion)
65 | });
66 | }
67 |
68 | /**
69 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
70 | * @param userData {Buffer}
71 | * @returns {asn1.univ.Sequence}
72 | */
73 | function ConnectInitial (userData) {
74 | return new asn1.univ.Sequence({
75 | callingDomainSelector : new asn1.univ.OctetString(new Buffer('\x01', 'binary')),
76 | calledDomainSelector : new asn1.univ.OctetString(new Buffer('\x01', 'binary')),
77 | upwardFlag : new asn1.univ.Boolean(true),
78 | targetParameters : DomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2),
79 | minimumParameters : DomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2),
80 | maximumParameters : DomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2),
81 | userData : new asn1.univ.OctetString(userData)
82 | }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 101));
83 | }
84 |
85 | /**
86 | * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
87 | * @returns {asn1.univ.Sequence}
88 | */
89 | function ConnectResponse (userData) {
90 | return new asn1.univ.Sequence({
91 | result : new asn1.univ.Enumerate(0),
92 | calledConnectId : new asn1.univ.Integer(0),
93 | domainParameters : DomainParameters(22, 3, 0, 1, 0, 1,0xfff8, 2),
94 | userData : new asn1.univ.OctetString(userData)
95 | }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 102));
96 | }
97 |
98 | /**
99 | * Format MCS PDU header packet
100 | * @param mcsPdu {integer}
101 | * @param options {integer}
102 | * @returns {type.UInt8} headers
103 | */
104 | function writeMCSPDUHeader(mcsPdu, options) {
105 | options = options || 0;
106 | return new type.UInt8((mcsPdu << 2) | options);
107 | }
108 |
109 | /**
110 | * Read MCS PDU header
111 | * @param opcode
112 | * @param mcsPdu
113 | * @returns {Boolean}
114 | */
115 | function readMCSPDUHeader(opcode, mcsPdu) {
116 | return (opcode >> 2) === mcsPdu;
117 | }
118 |
119 | /**
120 | * Multi-Channel Services
121 | * @param transport {events.EventEmitter} transport layer listen (connect, data) events
122 | * @param recvOpCode {DomainMCSPDU} opcode use in receive automata
123 | * @param sendOpCode {DomainMCSPDU} opcode use to send message
124 | */
125 | function MCS(transport, recvOpCode, sendOpCode) {
126 | this.transport = transport;
127 | this.recvOpCode = recvOpCode;
128 | this.sendOpCode = sendOpCode;
129 | this.channels = [{id : Channel.MCS_GLOBAL_CHANNEL, name : 'global'}];
130 | this.channels.find = function(callback) {
131 | for(var i in this) {
132 | if(callback(this[i])) return this[i];
133 | };
134 | };
135 |
136 | // bind events
137 | var self = this;
138 | this.transport.on('close', function () {
139 | self.emit('close');
140 | }).on('error', function (err) {
141 | self.emit('error', err);
142 | });
143 | }
144 |
145 | //inherit from Layer
146 | inherits(MCS, events.EventEmitter);
147 |
148 | /**
149 | * Send message to a specific channel
150 | * @param channelName {string} name of channel
151 | * @param data {type.*} message to send
152 | */
153 | MCS.prototype.send = function(channelName, data) {
154 | var channelId = this.channels.find(function(element) {
155 | if (element.name === channelName) return true;
156 | }).id;
157 |
158 | this.transport.send(new type.Component([
159 | writeMCSPDUHeader(this.sendOpCode),
160 | per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
161 | per.writeInteger16(channelId),
162 | new type.UInt8(0x70),
163 | per.writeLength(data.size()),
164 | data
165 | ]));
166 | };
167 |
168 | /**
169 | * Main receive function
170 | * @param s {type.Stream}
171 | */
172 | MCS.prototype.recv = function(s) {
173 | opcode = new type.UInt8().read(s).value;
174 |
175 | if (readMCSPDUHeader(opcode, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM)) {
176 | log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM");
177 | this.transport.close();
178 | return
179 | }
180 | else if(!readMCSPDUHeader(opcode, this.recvOpCode)) {
181 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_RECEIVE_OPCODE');
182 | }
183 |
184 | per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
185 |
186 | var channelId = per.readInteger16(s);
187 |
188 | per.readEnumerates(s);
189 | per.readLength(s);
190 |
191 | var channelName = this.channels.find(function(e) {
192 | if (e.id === channelId) return true;
193 | }).name;
194 |
195 | this.emit(channelName, s);
196 | };
197 |
198 | /**
199 | * Only main channels handle actually
200 | * @param transport {event.EventEmitter} bind connect and data events
201 | * @returns
202 | */
203 | function Client(transport) {
204 | MCS.call(this, transport, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST);
205 |
206 | // channel context automata
207 | this.channelsConnected = 0;
208 |
209 | // init gcc information
210 | this.clientCoreData = gcc.clientCoreData();
211 | this.clientNetworkData = gcc.clientNetworkData(new type.Component([]));
212 | this.clientSecurityData = gcc.clientSecurityData();
213 |
214 | // must be readed from protocol
215 | this.serverCoreData = null;
216 | this.serverSecurityData = null;
217 | this.serverNetworkData = null;
218 |
219 | var self = this;
220 | this.transport.on('connect', function(s) {
221 | self.connect(s);
222 | });
223 | }
224 |
225 | inherits(Client, MCS);
226 |
227 | /**
228 | * Connect event layer
229 | */
230 | Client.prototype.connect = function(selectedProtocol) {
231 | this.clientCoreData.obj.serverSelectedProtocol.value = selectedProtocol;
232 | this.sendConnectInitial();
233 | };
234 |
235 | /**
236 | * close stack
237 | */
238 | Client.prototype.close = function() {
239 | this.transport.close();
240 | };
241 |
242 | /**
243 | * MCS connect response (server->client)
244 | * @param s {type.Stream}
245 | */
246 | Client.prototype.recvConnectResponse = function(s) {
247 | var userData = new type.Stream(ConnectResponse().decode(s, asn1.ber).value.userData.value);
248 | var serverSettings = gcc.readConferenceCreateResponse(userData);
249 | // record server gcc block
250 | for(var i in serverSettings) {
251 | if(!serverSettings[i].obj) {
252 | continue;
253 | }
254 | switch(serverSettings[i].obj.__TYPE__) {
255 | case gcc.MessageType.SC_CORE:
256 | this.serverCoreData = serverSettings[i];
257 | break;
258 | case gcc.MessageType.SC_SECURITY:
259 | this.serverSecurityData = serverSettings[i];
260 | break;
261 | case gcc.MessageType.SC_NET:
262 | this.serverNetworkData = serverSettings[i];
263 | break;
264 | default:
265 | log.warn('unhandle server gcc block : ' + serverSettings[i].obj.__TYPE__);
266 | }
267 | }
268 |
269 | // send domain request
270 | this.sendErectDomainRequest();
271 | // send attach user request
272 | this.sendAttachUserRequest();
273 | // now wait user confirm from server
274 | var self = this;
275 | this.transport.once('data', function(s) {
276 | self.recvAttachUserConfirm(s);
277 | });
278 | };
279 |
280 | /**
281 | * MCS connection automata step
282 | * @param s {type.Stream}
283 | */
284 | Client.prototype.recvAttachUserConfirm = function(s) {
285 | if (!readMCSPDUHeader(new type.UInt8().read(s).value, DomainMCSPDU.ATTACH_USER_CONFIRM)) {
286 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER');
287 | }
288 |
289 | if (per.readEnumerates(s) !== 0) {
290 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER');
291 | }
292 |
293 | this.userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
294 | //ask channel for specific user
295 | this.channels.push({ id : this.userId, name : 'user' });
296 | // channel connect automata
297 | this.connectChannels();
298 | };
299 |
300 | /**
301 | * Last state in channel connection automata
302 | * @param s {type.Stream}
303 | */
304 | Client.prototype.recvChannelJoinConfirm = function(s) {
305 | var opcode = new type.UInt8().read(s).value;
306 |
307 | if (!readMCSPDUHeader(opcode, DomainMCSPDU.CHANNEL_JOIN_CONFIRM)) {
308 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM');
309 | }
310 |
311 | var confirm = per.readEnumerates(s);
312 |
313 | var userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
314 | if (this.userId !== userId) {
315 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID');
316 | }
317 |
318 | var channelId = per.readInteger16(s);
319 |
320 | if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
321 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL');
322 | }
323 |
324 | this.connectChannels();
325 | };
326 |
327 | /**
328 | * First MCS message
329 | */
330 | Client.prototype.sendConnectInitial = function() {
331 |
332 | var ccReq = gcc.writeConferenceCreateRequest(new type.Component([
333 | gcc.block(this.clientCoreData),
334 | gcc.block(this.clientNetworkData),
335 | gcc.block(this.clientSecurityData)
336 | ])).toStream().getValue();
337 |
338 | this.transport.send(ConnectInitial(ccReq).encode(asn1.ber));
339 |
340 | // next event is connect response
341 | var self = this;
342 | this.transport.once('data', function(s) {
343 | self.recvConnectResponse(s);
344 | });
345 | };
346 |
347 | /**
348 | * MCS connection automata step
349 | */
350 | Client.prototype.sendErectDomainRequest = function() {
351 | this.transport.send(new type.Component([
352 | writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST),
353 | per.writeInteger(0),
354 | per.writeInteger(0)
355 | ]));
356 | };
357 |
358 | /**
359 | * MCS connection automata step
360 | */
361 | Client.prototype.sendAttachUserRequest = function() {
362 | this.transport.send(writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST));
363 | };
364 |
365 | /**
366 | * Send a channel join request
367 | * @param channelId {integer} channel id
368 | */
369 | Client.prototype.sendChannelJoinRequest = function(channelId) {
370 | this.transport.send(new type.Component([
371 | writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST),
372 | per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
373 | per.writeInteger16(channelId)
374 | ]));
375 | };
376 |
377 | /**
378 | * Connect channels automata
379 | * @param s {type.Stream}
380 | */
381 | Client.prototype.connectChannels = function(s) {
382 | if(this.channelsConnected == this.channels.length) {
383 | var self = this;
384 | this.transport.on('data', function(s) {
385 | self.recv(s);
386 | });
387 |
388 | // send client and sever gcc informations
389 | this.emit('connect',
390 | {
391 | core : this.clientCoreData.obj,
392 | security : this.clientSecurityData.obj,
393 | net : this.clientNetworkData.obj
394 | },
395 | {
396 | core : this.serverCoreData.obj,
397 | security : this.serverSecurityData.obj
398 | }, this.userId, this.channels);
399 | return;
400 | }
401 |
402 | this.sendChannelJoinRequest(this.channels[this.channelsConnected++].id);
403 |
404 | var self = this;
405 | this.transport.once('data', function(s) {
406 | self.recvChannelJoinConfirm(s);
407 | });
408 | };
409 |
410 | /**
411 | * Server side of MCS layer
412 | * @param transport
413 | */
414 | function Server (transport) {
415 | MCS.call(this, transport, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION);
416 |
417 | // must be readed from protocol
418 | this.clientCoreData = null;
419 | this.clientNetworkData = null;
420 | this.clientSecurityData = null;
421 |
422 | // init gcc information
423 | this.serverCoreData = gcc.serverCoreData();
424 | this.serverSecurityData = gcc.serverSecurityData();
425 | this.serverNetworkData = gcc.serverNetworkData(new type.Component([]));
426 |
427 | var self = this;
428 | this.transport.on('connect', function (selectedProtocol) {
429 | self.serverCoreData.obj.clientRequestedProtocol.value = selectedProtocol;
430 | }).once('data', function (s) {
431 | self.recvConnectInitial(s);
432 | });
433 | }
434 |
435 | inherits(Server, MCS);
436 |
437 | /**
438 | * First state of server automata
439 | * @param s {type.Stream}
440 | */
441 | Server.prototype.recvConnectInitial = function (s) {
442 | var userData = new type.Stream(ConnectInitial().decode(s, asn1.ber).value.userData.value);
443 | var clientSettings = gcc.readConferenceCreateRequest(userData);
444 | // record server gcc block
445 | for(var i in clientSettings) {
446 | if(!clientSettings[i].obj) {
447 | continue;
448 | }
449 | switch(clientSettings[i].obj.__TYPE__) {
450 | case gcc.MessageType.CS_CORE:
451 | this.clientCoreData = clientSettings[i];
452 | break;
453 | case gcc.MessageType.CS_SECURITY:
454 | this.clientSecurityData = clientSettings[i];
455 | break;
456 | case gcc.MessageType.CS_NET:
457 | this.clientNetworkData = clientSettings[i];
458 | for (var i = 0; i < this.clientNetworkData.obj.channelCount.value; i++) {
459 | this.serverNetworkData.obj.channelIdArray.obj.push(new type.UInt16Le( i + 1 + Channel.MCS_GLOBAL_CHANNEL));
460 | }
461 | break;
462 | default:
463 | log.debug('unhandle client gcc block : ' + clientSettings[i].obj.__TYPE__);
464 | }
465 | }
466 |
467 | this.sendConnectResponse();
468 | };
469 |
470 | /**
471 | * State 2 in mcs server connetion automata
472 | */
473 | Server.prototype.sendConnectResponse = function () {
474 | var ccReq = gcc.writeConferenceCreateResponse(new type.Component([
475 | gcc.block(this.serverCoreData),
476 | gcc.block(this.serverSecurityData),
477 | gcc.block(this.serverNetworkData),
478 | ])).toStream().getValue();
479 |
480 | this.transport.send(ConnectResponse(ccReq).encode(asn1.ber));
481 |
482 | };
483 |
484 | /**
485 | * Module exports
486 | */
487 | module.exports = {
488 | Client : Client,
489 | Server : Server
490 | };
491 |
--------------------------------------------------------------------------------
/lib/protocol/t125/per.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var type = require('../../core').type;
21 | var error = require('../../core').error;
22 |
23 | /**
24 | * @param s {type.Stream} read value from stream
25 | * @returns read length from per format
26 | */
27 | function readLength(s) {
28 | var byte = new type.UInt8().read(s).value;
29 | var size = 0;
30 | if(byte & 0x80) {
31 | byte &= ~0x80;
32 | size = byte << 8;
33 | size += new type.UInt8().read(s).value;
34 | }
35 | else {
36 | size = byte;
37 | }
38 | return size;
39 | }
40 |
41 | /**
42 | * @param value {raw} value to convert to per format
43 | * @returns type objects per encoding value
44 | */
45 | function writeLength(value) {
46 | if(value > 0x7f) {
47 | return new type.UInt16Be(value | 0x8000);
48 | }
49 | else {
50 | return new type.UInt8(value);
51 | }
52 | }
53 |
54 | /**
55 | * @param s {type.Stream}
56 | * @returns {integer} choice decoding from per encoding
57 | */
58 | function readChoice(s) {
59 | return new type.UInt8().read(s).value;
60 | }
61 |
62 | /**
63 | * @param choice {integer}
64 | * @returns {type.UInt8} choice per encoded
65 | */
66 | function writeChoice(choice) {
67 | return new type.UInt8(choice);
68 | }
69 |
70 | /**
71 | * @param s {type.Stream}
72 | * @returns {integer} number represent selection
73 | */
74 | function readSelection(s) {
75 | return new type.UInt8().read(s).value;
76 | }
77 |
78 | /**
79 | * @param selection {integer}
80 | * @returns {type.UInt8} per encoded selection
81 | */
82 | function writeSelection(selection) {
83 | return new type.UInt8(selection);
84 | }
85 |
86 | /**
87 | * @param s {type.Stream}
88 | * @returns {integer} number of sets
89 | */
90 | function readNumberOfSet(s) {
91 | return new type.UInt8().read(s).value;
92 | }
93 |
94 | /**
95 | * @param numberOfSet {integer}
96 | * @returns {type.UInt8} per encoded nuimber of sets
97 | */
98 | function writeNumberOfSet(numberOfSet) {
99 | return new type.UInt8(numberOfSet);
100 | }
101 |
102 | /**
103 | * @param s {type.Stream}
104 | * @returns {integer} enumerates number
105 | */
106 | function readEnumerates(s) {
107 | return new type.UInt8().read(s).value;
108 | }
109 |
110 | /**
111 | * @param enumerate {integer}
112 | * @returns {type.UInt8} per encoded enumerate
113 | */
114 | function writeEnumerates(enumerate) {
115 | return new type.UInt8(enumerate);
116 | }
117 |
118 | /**
119 | * @param s {type.Stream}
120 | * @returns {integer} integer per decoded
121 | */
122 | function readInteger(s) {
123 | var result;
124 | var size = readLength(s);
125 | switch(size) {
126 | case 1:
127 | result = new type.UInt8();
128 | break;
129 | case 2:
130 | result = new type.UInt16Be();
131 | break;
132 | case 4:
133 | result = new type.UInt32Be();
134 | break;
135 | default:
136 | throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_PER_BAD_INTEGER_LENGTH');
137 | }
138 | return result.read(s).value;
139 | }
140 |
141 | /**
142 | * @param value {integer}
143 | * @returns {type.Component} per encoded integer
144 | */
145 | function writeInteger(value) {
146 | if(value <= 0xff) {
147 | return new type.Component([writeLength(1), new type.UInt8(value)]);
148 | }
149 | else if(value < 0xffff) {
150 | return new type.Component([writeLength(2), new type.UInt16Be(value)]);
151 | }
152 | else {
153 | return new type.Component([writeLength(4), new type.UInt32Be(value)]);
154 | }
155 | }
156 |
157 | /**
158 | * @param s {type.Stream}
159 | * @param minimum {integer} increment (default 0)
160 | * @returns {integer} per decoded integer 16 bits
161 | */
162 | function readInteger16(s, minimum) {
163 | return new type.UInt16Be().read(s).value + (minimum || 0);
164 | }
165 |
166 | /**
167 | * @param value {integer}
168 | * @param minimum {integer} decrement (default 0)
169 | * @returns {type.UInt16Be} per encoded integer 16 bits
170 | */
171 | function writeInteger16(value, minimum) {
172 | return new type.UInt16Be(value - (minimum || 0));
173 | }
174 |
175 | /**
176 | * Check object identifier
177 | * @param s {type.Stream}
178 | * @param oid {array} object identifier to check
179 | */
180 | function readObjectIdentifier(s, oid) {
181 | var size = readLength(s);
182 | if(size !== 5) {
183 | return false;
184 | }
185 |
186 | var a_oid = [0, 0, 0, 0, 0, 0];
187 | var t12 = new type.UInt8().read(s).value;
188 | a_oid[0] = t12 >> 4;
189 | a_oid[1] = t12 & 0x0f;
190 | a_oid[2] = new type.UInt8().read(s).value;
191 | a_oid[3] = new type.UInt8().read(s).value;
192 | a_oid[4] = new type.UInt8().read(s).value;
193 | a_oid[5] = new type.UInt8().read(s).value;
194 |
195 | for(var i in oid) {
196 | if(oid[i] !== a_oid[i]) return false;
197 | }
198 |
199 | return true;
200 | }
201 |
202 | /**
203 | * @param oid {array} oid to write
204 | * @returns {type.Component} per encoded object identifier
205 | */
206 | function writeObjectIdentifier(oid) {
207 | return new type.Component([new type.UInt8(5), new type.UInt8((oid[0] << 4) & (oid[1] & 0x0f)), new type.UInt8(oid[2]), new type.UInt8(oid[3]), new type.UInt8(oid[4]), new type.UInt8(oid[5])]);
208 | }
209 |
210 | /**
211 | * Read as padding...
212 | * @param s {type.Stream}
213 | * @param minValue
214 | */
215 | function readNumericString(s, minValue) {
216 | var length = readLength(s);
217 | length = (length + minValue + 1) / 2;
218 | s.readPadding(length);
219 | }
220 |
221 | /**
222 | * @param nStr {String}
223 | * @param minValue {integer}
224 | * @returns {type.Component} per encoded numeric string
225 | */
226 | function writeNumericString(nStr, minValue) {
227 | var length = nStr.length;
228 | var mlength = minValue;
229 | if(length - minValue >= 0) {
230 | mlength = length - minValue;
231 | }
232 |
233 | var result = [];
234 |
235 | for(var i = 0; i < length; i += 2) {
236 | var c1 = nStr.charCodeAt(i);
237 | var c2 = 0;
238 | if(i + 1 < length) {
239 | c2 = nStr.charCodeAt(i + 1);
240 | }
241 | else {
242 | c2 = 0x30;
243 | }
244 | c1 = (c1 - 0x30) % 10;
245 | c2 = (c2 - 0x30) % 10;
246 |
247 | result[result.length] = new type.UInt8((c1 << 4) | c2);
248 | }
249 |
250 | return new type.Component([writeLength(mlength), new type.Component(result)]);
251 | }
252 |
253 | /**
254 | * @param s {type.Stream}
255 | * @param length {integer} length of padding
256 | */
257 | function readPadding(s, length) {
258 | s.readPadding(length);
259 | }
260 |
261 | /**
262 | * @param length {integer} length of padding
263 | * @returns {type.BinaryString} per encoded padding
264 | */
265 | function writePadding(length) {
266 | return new type.BinaryString(new Buffer(Array(length + 1).join("\x00")));
267 | }
268 |
269 | /**
270 | * @param s {type.Stream}
271 | * @param octetStream {String}
272 | * @param minValue {integer} default 0
273 | * @returns {Boolean} true if read octectStream is equal to octetStream
274 | */
275 | function readOctetStream(s, octetStream, minValue) {
276 | var size = readLength(s) + (minValue || 0);
277 | if(size !== octetStream.length) {
278 | return false;
279 | }
280 | for(var i = 0; i < size; i++) {
281 | var c = new type.UInt8().read(s);
282 | if(octetStream.charCodeAt(i) !== c.value) {
283 | return false;
284 | }
285 | }
286 |
287 | return true;
288 | }
289 |
290 | /**
291 | * @param oStr {String}
292 | * @param minValue {integer} default 0
293 | * @returns {type.Component} per encoded octet stream
294 | */
295 | function writeOctetStream(oStr, minValue) {
296 | minValue = minValue || 0;
297 | var length = oStr.length;
298 | var mlength = minValue;
299 |
300 | if(length - minValue >= 0) {
301 | mlength = length - minValue;
302 | }
303 |
304 | result = [];
305 | for(var i = 0; i < length; i++) {
306 | result[result.length] = new type.UInt8(oStr[i]);
307 | }
308 |
309 | return new type.Component([writeLength(mlength), new type.Component(result)]);
310 | }
311 |
312 | /**
313 | * Module exports
314 | */
315 | module.exports = {
316 | readLength : readLength,
317 | writeLength : writeLength,
318 | readChoice : readChoice,
319 | writeChoice : writeChoice,
320 | readSelection : readSelection,
321 | writeSelection : writeSelection,
322 | readNumberOfSet : readNumberOfSet,
323 | writeNumberOfSet : writeNumberOfSet,
324 | readEnumerates : readEnumerates,
325 | writeEnumerates : writeEnumerates,
326 | readInteger : readInteger,
327 | writeInteger : writeInteger,
328 | readInteger16 : readInteger16,
329 | writeInteger16 : writeInteger16,
330 | readObjectIdentifier : readObjectIdentifier,
331 | writeObjectIdentifier : writeObjectIdentifier,
332 | readNumericString : readNumericString,
333 | writeNumericString : writeNumericString,
334 | readPadding : readPadding,
335 | writePadding : writePadding,
336 | readOctetStream : readOctetStream,
337 | writeOctetStream : writeOctetStream
338 | };
--------------------------------------------------------------------------------
/lib/protocol/tpkt.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var type = require('../core').type;
22 | var events = require('events');
23 |
24 | /**
25 | * Type of tpkt packet
26 | * Fastpath is use to shortcut RDP stack
27 | * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
28 | * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx
29 | */
30 | var Action = {
31 | FASTPATH_ACTION_FASTPATH : 0x0,
32 | FASTPATH_ACTION_X224 : 0x3
33 | };
34 |
35 | /**
36 | * TPKT layer of rdp stack
37 | */
38 | function TPKT(transport) {
39 | this.transport = transport;
40 | // wait 2 bytes
41 | this.transport.expect(2);
42 | // next state is receive header
43 | var self = this;
44 | this.transport.once('data', function(s) {
45 | self.recvHeader(s);
46 | }).on('close', function() {
47 | self.emit('close');
48 | }).on('error', function (err) {
49 | self.emit('error', err);
50 | });
51 | }
52 |
53 | /**
54 | * inherit from a packet layer
55 | */
56 | inherits(TPKT, events.EventEmitter);
57 |
58 | /**
59 | * Receive correct packet as expected
60 | * @param s {type.Stream}
61 | */
62 | TPKT.prototype.recvHeader = function(s) {
63 | var version = new type.UInt8().read(s).value;
64 | var self = this;
65 | if(version === Action.FASTPATH_ACTION_X224) {
66 | new type.UInt8().read(s);
67 |
68 | this.transport.expect(2);
69 | this.transport.once('data', function(s) {
70 | self.recvExtendedHeader(s);
71 | });
72 | }
73 | else {
74 | this.secFlag = ((version >> 6) & 0x3);
75 | var length = new type.UInt8().read(s).value;
76 | if (length & 0x80) {
77 | this.transport.expect(1);
78 | this.transport.once('data', function(s) {
79 | self.recvExtendedFastPathHeader(s, length);
80 | });
81 | }
82 | else {
83 | this.transport.expect(length - 2);
84 | this.transport.once('data', function(s) {
85 | self.recvFastPath(s);
86 | });
87 | }
88 | }
89 | };
90 |
91 | /**
92 | * Receive second part of header packet
93 | * @param s {type.Stream}
94 | */
95 | TPKT.prototype.recvExtendedHeader = function(s) {
96 | var size = new type.UInt16Be().read(s);
97 | this.transport.expect(size.value - 4);
98 | //next state receive packet
99 | var self = this;
100 | this.transport.once('data', function(s) {
101 | self.recvData(s);
102 | });
103 | };
104 |
105 | /**
106 | * Receive data available for presentation layer
107 | * @param s {type.Stream}
108 | */
109 | TPKT.prototype.recvData = function(s) {
110 | this.emit('data', s);
111 | this.transport.expect(2);
112 | //next state receive header
113 | var self = this;
114 | this.transport.once('data', function(s) {
115 | self.recvHeader(s);
116 | });
117 | };
118 |
119 | /**
120 | * Read extended fastpath header
121 | * @param s {type.Stream}
122 | */
123 | TPKT.prototype.recvExtendedFastPathHeader = function (s, length) {
124 | var rightPart = new type.UInt8().read(s).value;
125 | var leftPart = length & ~0x80;
126 | var packetSize = (leftPart << 8) + rightPart;
127 |
128 | var self = this;
129 | this.transport.expect(packetSize - 3);
130 | this.transport.once('data', function(s) {
131 | self.recvFastPath(s);
132 | });
133 | };
134 |
135 | /**
136 | * Read fast path data
137 | * @param s {type.Stream}
138 | */
139 | TPKT.prototype.recvFastPath = function (s) {
140 | this.emit('fastPathData', this.secFlag, s);
141 | var self = this;
142 | this.transport.expect(2);
143 | this.transport.once('data', function(s) {
144 | self.recvHeader(s);
145 | });
146 | };
147 |
148 | /**
149 | * Send message throught TPKT layer
150 | * @param message {type.*}
151 | */
152 | TPKT.prototype.send = function(message) {
153 | this.transport.send(new type.Component([
154 | new type.UInt8(Action.FASTPATH_ACTION_X224),
155 | new type.UInt8(0),
156 | new type.UInt16Be(message.size() + 4),
157 | message
158 | ]));
159 | };
160 |
161 | /**
162 | * close stack
163 | */
164 | TPKT.prototype.close = function() {
165 | this.transport.close();
166 | };
167 |
168 | /**
169 | * Module exports
170 | */
171 | module.exports = TPKT;
172 |
173 |
--------------------------------------------------------------------------------
/lib/protocol/x224.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var inherits = require('util').inherits;
21 | var events = require('events');
22 | var type = require('../core').type;
23 | var log = require('../core').log;
24 | var error = require('../core').error;
25 |
26 | /**
27 | * Message type present in X224 packet header
28 | */
29 | var MessageType = {
30 | X224_TPDU_CONNECTION_REQUEST : 0xE0,
31 | X224_TPDU_CONNECTION_CONFIRM : 0xD0,
32 | X224_TPDU_DISCONNECT_REQUEST : 0x80,
33 | X224_TPDU_DATA : 0xF0,
34 | X224_TPDU_ERROR : 0x70
35 | };
36 |
37 | /**
38 | * Type of negotiation present in negotiation packet
39 | */
40 | var NegotiationType = {
41 | TYPE_RDP_NEG_REQ : 0x01,
42 | TYPE_RDP_NEG_RSP : 0x02,
43 | TYPE_RDP_NEG_FAILURE : 0x03
44 | };
45 |
46 | /**
47 | * Protocols available for x224 layer
48 | */
49 | var Protocols = {
50 | PROTOCOL_RDP : 0x00000000,
51 | PROTOCOL_SSL : 0x00000001,
52 | PROTOCOL_HYBRID : 0x00000002,
53 | PROTOCOL_HYBRID_EX : 0x00000008
54 | };
55 |
56 | /**
57 | * Use to negotiate security layer of RDP stack
58 | * In node-rdpjs only ssl is available
59 | * @param opt {object} component type options
60 | * @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
61 | * @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
62 | * @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
63 | */
64 | function negotiation(opt) {
65 | var self = {
66 | type : new type.UInt8(),
67 | flag : new type.UInt8(),
68 | length : new type.UInt16Le(0x0008, { constant : true }),
69 | result : new type.UInt32Le()
70 | };
71 | return new type.Component(self, opt);
72 | }
73 |
74 | /**
75 | * X224 client connection request
76 | * @param opt {object} component type options
77 | * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
78 | */
79 | function clientConnectionRequestPDU(opt, cookie) {
80 | var self = {
81 | len : new type.UInt8(function() {
82 | return new type.Component(self).size() - 1;
83 | }),
84 | code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, { constant : true }),
85 | padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]),
86 | cookie : cookie || new type.Factory( function (s) {
87 | var offset = 0;
88 | while (true) {
89 | var token = s.buffer.readUInt16LE(s.offset + offset);
90 | if (token === 0x0a0d) {
91 | self.cookie = new type.BinaryString(null, { readLength : new type.CallableValue(offset + 2) }).read(s);
92 | return;
93 | }
94 | else {
95 | offset += 1;
96 | }
97 | }
98 | }, { conditional : function () {
99 | return self.len.value > 14;
100 | }}),
101 | protocolNeg : negotiation({ optional : true })
102 | };
103 |
104 | return new type.Component(self, opt);
105 | }
106 |
107 | /**
108 | * X224 Server connection confirm
109 | * @param opt {object} component type options
110 | * @see http://msdn.microsoft.com/en-us/library/cc240506.aspx
111 | */
112 | function serverConnectionConfirm(opt) {
113 | var self = {
114 | len : new type.UInt8(function() {
115 | return new type.Component(self).size() - 1;
116 | }),
117 | code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_CONFIRM, { constant : true }),
118 | padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]),
119 | protocolNeg : negotiation({ optional : true })
120 | };
121 |
122 | return new type.Component(self, opt);
123 | }
124 |
125 | /**
126 | * Header of each data message from x224 layer
127 | * @returns {type.Component}
128 | */
129 | function x224DataHeader() {
130 | var self = {
131 | header : new type.UInt8(2),
132 | messageType : new type.UInt8(MessageType.X224_TPDU_DATA, { constant : true }),
133 | separator : new type.UInt8(0x80, { constant : true })
134 | };
135 | return new type.Component(self);
136 | }
137 |
138 | /**
139 | * Common X224 Automata
140 | * @param presentation {Layer} presentation layer
141 | */
142 | function X224(transport) {
143 | this.transport = transport;
144 | this.requestedProtocol = Protocols.PROTOCOL_SSL;
145 | this.selectedProtocol = Protocols.PROTOCOL_SSL;
146 |
147 | var self = this;
148 | this.transport.on('close', function() {
149 | self.emit('close');
150 | }).on('error', function (err) {
151 | self.emit('error', err);
152 | });
153 | }
154 |
155 | //inherit from Layer
156 | inherits(X224, events.EventEmitter);
157 |
158 | /**
159 | * Main data received function
160 | * after connection sequence
161 | * @param s {type.Stream} stream formated from transport layer
162 | */
163 | X224.prototype.recvData = function(s) {
164 | // check header
165 | x224DataHeader().read(s);
166 | this.emit('data', s);
167 | };
168 |
169 | /**
170 | * Format message from x224 layer to transport layer
171 | * @param message {type}
172 | * @returns {type.Component} x224 formated message
173 | */
174 | X224.prototype.send = function(message) {
175 | this.transport.send(new type.Component([x224DataHeader(), message]));
176 | };
177 |
178 | /**
179 | * Client x224 automata
180 | * @param transport {events.EventEmitter} (bind data events)
181 | */
182 | function Client(transport) {
183 | X224.call(this, transport);
184 |
185 | }
186 |
187 | //inherit from X224 automata
188 | inherits(Client, X224);
189 |
190 | /**
191 | * Client automata connect event
192 | */
193 | Client.prototype.connect = function() {
194 | var message = clientConnectionRequestPDU(null, new type.BinaryString());
195 | message.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_REQ;
196 | message.obj.protocolNeg.obj.result.value = this.requestedProtocol;
197 | this.transport.send(message);
198 |
199 | // next state wait connection confirm packet
200 | var self = this;
201 | this.transport.once('data', function(s) {
202 | self.recvConnectionConfirm(s);
203 | });
204 | };
205 |
206 | /**
207 | * close stack
208 | */
209 | Client.prototype.close = function() {
210 | this.transport.close();
211 | };
212 |
213 | /**
214 | * Receive connection from server
215 | * @param s {Stream}
216 | */
217 | Client.prototype.recvConnectionConfirm = function(s) {
218 | var message = serverConnectionConfirm().read(s);
219 |
220 | if(message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_FAILURE) {
221 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NEG_FAILURE',
222 | 'Failure code:' + message.obj.protocolNeg.obj.result.value + " (see https://msdn.microsoft.com/en-us/library/cc240507.aspx)");
223 | }
224 |
225 | if(message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_RSP) {
226 | this.selectedProtocol = message.obj.protocolNeg.obj.result.value;
227 | }
228 |
229 | if([Protocols.PROTOCOL_HYBRID, Protocols.PROTOCOL_HYBRID_EX].indexOf(this.selectedProtocol) !== -1) {
230 | throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED');
231 | }
232 |
233 | if(this.selectedProtocol == Protocols.PROTOCOL_RDP) {
234 | log.debug("RDP standard security selected");
235 | return;
236 | }
237 |
238 | // finish connection sequence
239 | var self = this;
240 | this.transport.on('data', function(s) {
241 | self.recvData(s);
242 | });
243 |
244 | if(this.selectedProtocol == Protocols.PROTOCOL_SSL) {
245 | log.debug("SSL standard security selected");
246 | this.transport.transport.startTLS(function() {
247 | self.emit('connect', self.selectedProtocol);
248 | });
249 | return;
250 | }
251 | };
252 |
253 | /**
254 | * Server x224 automata
255 | */
256 | function Server(transport, keyFilePath, crtFilePath) {
257 | X224.call(this, transport);
258 | this.keyFilePath = keyFilePath;
259 | this.crtFilePath = crtFilePath;
260 | var self = this;
261 | this.transport.once('data', function (s) {
262 | self.recvConnectionRequest(s);
263 | });
264 | }
265 |
266 | //inherit from X224 automata
267 | inherits(Server, X224);
268 |
269 | /**
270 | * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
271 | * @param s {type.Stream}
272 | */
273 | Server.prototype.recvConnectionRequest = function (s) {
274 | var request = clientConnectionRequestPDU().read(s);
275 | if (!request.obj.protocolNeg.isReaded) {
276 | throw new Error('NODE_RDP_PROTOCOL_X224_NO_BASIC_SECURITY_LAYER');
277 | }
278 |
279 | this.requestedProtocol = request.obj.protocolNeg.obj.result.value;
280 | this.selectedProtocol = this.requestedProtocol & Protocols.PROTOCOL_SSL;
281 |
282 | if (!(this.selectedProtocol & Protocols.PROTOCOL_SSL)) {
283 | var confirm = serverConnectionConfirm();
284 | confirm.obj.protocolNeg.obj.type.value = NegociationType.TYPE_RDP_NEG_FAILURE;
285 | confirm.obj.protocolNeg.obj.result.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER;
286 | this.transport.send(confirm);
287 | this.close();
288 | }
289 | else {
290 | this.sendConnectionConfirm();
291 | }
292 | };
293 |
294 | /**
295 | * Start SSL connection if needed
296 | * @see http://msdn.microsoft.com/en-us/library/cc240501.aspx
297 | */
298 | Server.prototype.sendConnectionConfirm = function () {
299 | var confirm = serverConnectionConfirm();
300 | confirm.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_RSP;
301 | confirm.obj.protocolNeg.obj.result.value = this.selectedProtocol;
302 | this.transport.send(confirm);
303 |
304 | // finish connection sequence
305 | var self = this;
306 | this.transport.on('data', function(s) {
307 | self.recvData(s);
308 | });
309 |
310 | this.transport.transport.listenTLS(this.keyFilePath, this.crtFilePath, function() {
311 | log.debug('start SSL connection');
312 | self.emit('connect', self.requestedProtocol);
313 | });
314 | };
315 |
316 | /**
317 | * Module exports
318 | */
319 | module.exports = {
320 | Client : Client,
321 | Server : Server
322 | };
323 |
--------------------------------------------------------------------------------
/lib/security/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var x509 = require('./x509');
21 | var rsa = require('./rsa');
22 |
23 | module.exports = {
24 | x509 : x509,
25 | rsa : rsa
26 | };
27 |
--------------------------------------------------------------------------------
/lib/security/rsa.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | var BigInteger = require('./jsbn');
21 |
22 | /**
23 | * @param modulus {Buffer}
24 | * @param pubExp {integer}
25 | */
26 | function publicKey(modulus, pubExp) {
27 | return {
28 | n : modulus,
29 | e : pubExp
30 | }
31 | }
32 |
33 | function encrypt(data, publicKey) {
34 | return new BigInteger(data).modPowInt(publicKey.e, new BigInteger(publicKey.n)).toBuffer();
35 | }
36 |
37 | /**
38 | * Module Export
39 | */
40 | module.exports = {
41 | publicKey : publicKey,
42 | encrypt : encrypt
43 | };
--------------------------------------------------------------------------------
/lib/security/x509.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 | *
4 | * This file is part of node-rdpjs.
5 | *
6 | * node-rdpjs 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 3 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, see .
18 | */
19 |
20 | // https://tools.ietf.org/html/rfc5280
21 |
22 | var asn1 = require('../asn1');
23 |
24 | /**
25 | * @see https://tools.ietf.org/html/rfc5280 page 20
26 | * @returns {asn1.univ.Choice}
27 | */
28 | function DirectoryString() {
29 | return new asn1.univ.Choice({
30 | teletexString : new asn1.univ.T61String(),
31 | printableString : new asn1.univ.PrintableString(),
32 | universalString : new asn1.univ.UniversalString(),
33 | utf8String : new asn1.univ.UTF8String(),
34 | bmpString : new asn1.univ.BMPString(),
35 | ia5String : new asn1.univ.IA5String()
36 | });
37 | }
38 |
39 | /**
40 | * https://tools.ietf.org/html/rfc5280 page 20
41 | * @returns {asn1.univ.Choice}
42 | */
43 | function AttributeValue() {
44 | return DirectoryString();
45 | }
46 |
47 | /**
48 | * @see https://tools.ietf.org/html/rfc5280 page 20
49 | * @returns {asn1.univ.ObjectIdentifier}
50 | */
51 | function AttributeType() {
52 | return new asn1.univ.ObjectIdentifier();
53 | }
54 |
55 | /**
56 | * @see https://tools.ietf.org/html/rfc5280 page 20
57 | * @returns {asn1.univ.Sequence}
58 | */
59 | function AttributeTypeAndValue() {
60 | return new asn1.univ.Sequence({
61 | type : AttributeType(),
62 | value : AttributeValue()
63 | });
64 | }
65 |
66 | /**
67 | * https://tools.ietf.org/html/rfc5280 page 116
68 | * @returns {asn1.univ.SetOf}
69 | */
70 | function RelativeDistinguishedName() {
71 | return new asn1.univ.SetOf(AttributeTypeAndValue);
72 | }
73 |
74 | /**
75 | * https://tools.ietf.org/html/rfc5280 page 116
76 | * @returns {asn1.univ.SequenceOf}
77 | */
78 | function RDNSequence() {
79 | return new asn1.univ.SequenceOf(RelativeDistinguishedName);
80 | }
81 |
82 | /**
83 | * @see https://tools.ietf.org/html/rfc5280 page 116
84 | * @returns {asn1.univ.Choice}
85 | */
86 | function Name() {
87 | return new asn1.univ.Choice({
88 | rdnSequence : RDNSequence()
89 | });
90 | }
91 |
92 | /**
93 | * @see https://tools.ietf.org/html/rfc5280 page 18
94 | * @returns {asn1.univ.Sequence}
95 | */
96 | function AlgorithmIdentifier() {
97 | return new asn1.univ.Sequence({
98 | algorithm : new asn1.univ.ObjectIdentifier(),
99 | parameters : new asn1.univ.Null()
100 | });
101 | }
102 |
103 | /**
104 | * @see https://tools.ietf.org/html/rfc5280 page 117
105 | * @returns {asn1.univ.Sequence}
106 | */
107 | function Extension() {
108 | return new asn1.univ.Sequence({
109 | extnID : new asn1.univ.ObjectIdentifier(),
110 | critical : new asn1.univ.Boolean(),
111 | extnValue : new asn1.univ.OctetString()
112 | });
113 | }
114 |
115 | /**
116 | * @see https://tools.ietf.org/html/rfc5280 page 117
117 | * @returns {asn1.univ.SequenceOf}
118 | */
119 | function Extensions() {
120 | return new asn1.univ.SequenceOf(Extension);
121 | }
122 |
123 | /**
124 | * @see https://tools.ietf.org/html/rfc5280 page 117
125 | * @returns {asn1.univ.Choice}
126 | */
127 | function Time() {
128 | return new asn1.univ.Choice({
129 | utcTime : new asn1.univ.UTCTime(),
130 | generalTime : new asn1.univ.GeneralizedTime()
131 | });
132 | }
133 |
134 | /**
135 | * @see https://tools.ietf.org/html/rfc5280 page 117
136 | * @returns {asn1.univ.Sequence}
137 | */
138 | function Validity() {
139 | return new asn1.univ.Sequence({
140 | notBefore : Time(),
141 | notAfter : Time()
142 | });
143 | }
144 |
145 | /**
146 | * @see https://tools.ietf.org/html/rfc5280 page 117
147 | * @returns {asn1.univ.Integer}
148 | */
149 | function CertificateSerialNumber() {
150 | return new asn1.univ.Integer();
151 | }
152 |
153 | /**
154 | * @see https://tools.ietf.org/html/rfc5280 page 117
155 | * @returns {asn1.univ.Sequence}
156 | */
157 | function SubjectPublicKeyInfo() {
158 | return new asn1.univ.Sequence({
159 | algorithm : AlgorithmIdentifier(),
160 | subjectPublicKey : new asn1.univ.BitString()
161 | });
162 | }
163 |
164 | /**
165 | * @see https://tools.ietf.org/html/rfc5280 page 117
166 | * @returns {asn1.univ.BitString}
167 | */
168 | function UniqueIdentifier() {
169 | return new asn1.univ.BitString();
170 | }
171 |
172 | /**
173 | * @see https://tools.ietf.org/html/rfc5280 page 117
174 | * @returns {asn1.univ.Sequence}
175 | */
176 | function TbsCertificate() {
177 | return new asn1.univ.Sequence({
178 | version : CertificateSerialNumber().explicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Constructed, 0)),
179 | serialNumber : new asn1.univ.Integer(),
180 | signature : AlgorithmIdentifier(),
181 | issuer : Name(),
182 | validity : Validity(),
183 | subject : Name(),
184 | subjectPublicKeyInfo : SubjectPublicKeyInfo(),
185 | issuerUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 1).optional(),
186 | subjectUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 2).optional(),
187 | extensions : Extensions().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 3).optional()
188 | });
189 | }
190 |
191 | /**
192 | * @see https://tools.ietf.org/html/rfc5280 page 117
193 | * @returns {asn1.univ.Sequence}
194 | */
195 | function X509Certificate() {
196 | return new asn1.univ.Sequence({
197 | tbsCertificate : TbsCertificate(),
198 | signatureAlgorithm : AlgorithmIdentifier(),
199 | signatureValue : new asn1.univ.BitString()
200 | });
201 | }
202 |
203 | function RSAPublicKey() {
204 | return new asn1.univ.Sequence({
205 | modulus : new asn1.univ.Integer(),
206 | publicExponent : new asn1.univ.Integer()
207 | });
208 | }
209 |
210 | /**
211 | * Module Export
212 | */
213 | module.exports = {
214 | X509Certificate : X509Certificate,
215 | RSAPublicKey : RSAPublicKey
216 | };
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-rdpjs",
3 | "version": "0.3.3",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "balanced-match": {
8 | "version": "1.0.2",
9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
10 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
11 | "optional": true
12 | },
13 | "brace-expansion": {
14 | "version": "1.1.11",
15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
16 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
17 | "optional": true,
18 | "requires": {
19 | "balanced-match": "^1.0.0",
20 | "concat-map": "0.0.1"
21 | }
22 | },
23 | "bunyan": {
24 | "version": "1.8.15",
25 | "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
26 | "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
27 | "requires": {
28 | "dtrace-provider": "~0.8",
29 | "moment": "^2.19.3",
30 | "mv": "~2",
31 | "safe-json-stringify": "~1"
32 | }
33 | },
34 | "concat-map": {
35 | "version": "0.0.1",
36 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
37 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
38 | "optional": true
39 | },
40 | "dtrace-provider": {
41 | "version": "0.8.8",
42 | "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
43 | "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
44 | "optional": true,
45 | "requires": {
46 | "nan": "^2.14.0"
47 | }
48 | },
49 | "glob": {
50 | "version": "6.0.4",
51 | "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
52 | "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
53 | "optional": true,
54 | "requires": {
55 | "inflight": "^1.0.4",
56 | "inherits": "2",
57 | "minimatch": "2 || 3",
58 | "once": "^1.3.0",
59 | "path-is-absolute": "^1.0.0"
60 | }
61 | },
62 | "inflight": {
63 | "version": "1.0.6",
64 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
65 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
66 | "optional": true,
67 | "requires": {
68 | "once": "^1.3.0",
69 | "wrappy": "1"
70 | }
71 | },
72 | "inherits": {
73 | "version": "2.0.4",
74 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
75 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
76 | "optional": true
77 | },
78 | "lodash.isnumber": {
79 | "version": "3.0.3",
80 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
81 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
82 | },
83 | "minimatch": {
84 | "version": "3.1.2",
85 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
86 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
87 | "optional": true,
88 | "requires": {
89 | "brace-expansion": "^1.1.7"
90 | }
91 | },
92 | "minimist": {
93 | "version": "1.2.7",
94 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
95 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
96 | "optional": true
97 | },
98 | "mkdirp": {
99 | "version": "0.5.6",
100 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
101 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
102 | "optional": true,
103 | "requires": {
104 | "minimist": "^1.2.6"
105 | }
106 | },
107 | "moment": {
108 | "version": "2.29.4",
109 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
110 | "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
111 | "optional": true
112 | },
113 | "mv": {
114 | "version": "2.1.1",
115 | "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
116 | "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
117 | "optional": true,
118 | "requires": {
119 | "mkdirp": "~0.5.1",
120 | "ncp": "~2.0.0",
121 | "rimraf": "~2.4.0"
122 | }
123 | },
124 | "nan": {
125 | "version": "2.17.0",
126 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
127 | "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==",
128 | "optional": true
129 | },
130 | "ncp": {
131 | "version": "2.0.0",
132 | "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
133 | "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
134 | "optional": true
135 | },
136 | "once": {
137 | "version": "1.4.0",
138 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
139 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
140 | "optional": true,
141 | "requires": {
142 | "wrappy": "1"
143 | }
144 | },
145 | "path-is-absolute": {
146 | "version": "1.0.1",
147 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
148 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
149 | "optional": true
150 | },
151 | "rimraf": {
152 | "version": "2.4.5",
153 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
154 | "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
155 | "optional": true,
156 | "requires": {
157 | "glob": "^6.0.1"
158 | }
159 | },
160 | "safe-json-stringify": {
161 | "version": "1.2.0",
162 | "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
163 | "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
164 | "optional": true
165 | },
166 | "wrappy": {
167 | "version": "1.0.2",
168 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
169 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
170 | "optional": true
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-rdpjs",
3 | "author": "Sylvain Peyrefitte",
4 | "version": "0.3.3",
5 | "engines": {
6 | "node": ">=8.5.0"
7 | },
8 | "description": "Remote Desktop Protocol in Node.js",
9 | "license": "AGPL-3.0",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/citronneur/node-rdpjs"
13 | },
14 | "main": "lib/index.js",
15 | "dependencies": {
16 | "bunyan": "^1.8.15",
17 | "lodash.isnumber": "^3.0.3"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------