/** * Intialise a packet at the Secure layer * * @param flags Encryption flags * @param length Length of packet * @return Intialised packet * @throws RdesktopException */ public RdpPacket_Localised init(int flags, int length) throws RdesktopException { int headerlength = 0; RdpPacket_Localised buffer; if (!this.licenceIssued) headerlength = ((flags & SEC_ENCRYPT) != 0) ? 12 : 4; else headerlength = ((flags & SEC_ENCRYPT) != 0) ? 12 : 0; buffer = McsLayer.init(length + headerlength); buffer.pushLayer(RdpPacket.SECURE_HEADER, headerlength); // buffer.setHeader(RdpPacket_Localised.SECURE_HEADER); // buffer.incrementPosition(headerlength); // buffer.setStart(buffer.getPosition()); return buffer; }
/** * Handle MCS info from server (server info, encryption info and channel information) * * @param mcs_data Data received from server */ public void processMcsData(RdpPacket_Localised mcs_data) throws RdesktopException, CryptoException { logger.debug("Secure.processMcsData"); int tag = 0, len = 0, length = 0, nexttag = 0; mcs_data.incrementPosition(21); // header (T.124 stuff, probably) len = mcs_data.get8(); if ((len & 0x00000080) != 0) { len = mcs_data.get8(); } while (mcs_data.getPosition() < mcs_data.getEnd()) { tag = mcs_data.getLittleEndian16(); length = mcs_data.getLittleEndian16(); if (length <= 4) return; nexttag = mcs_data.getPosition() + length - 4; switch (tag) { case (Secure.SEC_TAG_SRV_INFO): processSrvInfo(mcs_data); break; case (Secure.SEC_TAG_SRV_CRYPT): this.processCryptInfo(mcs_data); break; case (Secure.SEC_TAG_SRV_CHANNELS): /* * FIXME: We should parse this information and use it to map * RDP5 channels to MCS channels */ break; default: throw new RdesktopException("Not implemented! Tag:" + tag + "not recognized!"); } mcs_data.setPosition(nexttag); } }
/** * Read in a public key from a provided Secure layer PDU, and store in this.exponent and * this.modulus * * @param data Secure layer PDU containing key data * @return True if key successfully read * @throws RdesktopException */ public boolean parsePublicKey(RdpPacket_Localised data) throws RdesktopException { int magic = 0, modulus_length = 0; magic = data.getLittleEndian32(); if (magic != SEC_RSA_MAGIC) { throw new RdesktopException("Wrong magic! Expected" + SEC_RSA_MAGIC + "got:" + magic); } modulus_length = data.getLittleEndian32() - SEC_PADDING_SIZE; if (modulus_length < 64 || modulus_length > SEC_MAX_MODULUS_SIZE) { throw new RdesktopException( "Bad server public key size (" + (modulus_length * 8) + " bites)"); } data.incrementPosition(8); // unknown modulus bits this.exponent = new byte[SEC_EXPONENT_SIZE]; data.copyToByteArray(this.exponent, 0, data.getPosition(), SEC_EXPONENT_SIZE); data.incrementPosition(SEC_EXPONENT_SIZE); this.modulus = new byte[modulus_length]; data.copyToByteArray(this.modulus, 0, data.getPosition(), modulus_length); data.incrementPosition(modulus_length); data.incrementPosition(SEC_PADDING_SIZE); this.server_public_key_len = modulus_length; if (data.getPosition() <= data.getEnd()) { return true; } else { return false; } }
/** * Read encryption information from a Secure layer PDU, obtaining and storing level of encryption * and any keys received * * @param data Packet to read encryption information from * @return Size of RC4 key * @throws RdesktopException */ public int parseCryptInfo(RdpPacket_Localised data) throws RdesktopException { logger.debug("Secure.parseCryptInfo"); int encryption_level = 0, random_length = 0, RSA_info_length = 0; int tag = 0, length = 0; int next_tag = 0, end = 0; int rc4_key_size = 0; rc4_key_size = data.getLittleEndian32(); // 1 = 40-Bit 2 = 128 Bit encryption_level = data.getLittleEndian32(); // 1 = low, 2 = medium, // 3 = high if (encryption_level == 0) { // no encryption return 0; } random_length = data.getLittleEndian32(); RSA_info_length = data.getLittleEndian32(); if (random_length != SEC_RANDOM_SIZE) { throw new RdesktopException( "Wrong Size of Random! Got" + random_length + "expected" + SEC_RANDOM_SIZE); } this.server_random = new byte[random_length]; data.copyToByteArray(this.server_random, 0, data.getPosition(), random_length); data.incrementPosition(random_length); end = data.getPosition() + RSA_info_length; if (end > data.getEnd()) { logger.debug("Reached end of crypt info prematurely "); return 0; } // data.incrementPosition(12); // unknown bytes int flags = data.getLittleEndian32(); // in_uint32_le(s, flags); // 1 // = RDP4-style, 0x80000002 = // X.509 logger.debug("Flags = 0x" + Integer.toHexString(flags)); if ((flags & 1) != 0) { logger.debug(("We're going for the RDP4-style encryption")); data.incrementPosition(8); // in_uint8s(s, 8); // unknown while (data.getPosition() < data.getEnd()) { tag = data.getLittleEndian16(); length = data.getLittleEndian16(); next_tag = data.getPosition() + length; switch (tag) { case (Secure.SEC_TAG_PUBKEY): if (!parsePublicKey(data)) { return 0; } break; case (Secure.SEC_TAG_KEYSIG): // Microsoft issued a key but we don't care break; default: throw new RdesktopException("Unimplemented decrypt tag " + tag); } data.setPosition(next_tag); } if (data.getPosition() == data.getEnd()) { return rc4_key_size; } else { logger.warn("End not reached!"); return 0; } } else { logger.debug(("We're going for the RDP5-style encryption")); // data.incrementPosition(4); // number of certificates int num_certs = data.getLittleEndian32(); int cacert_len = data.getLittleEndian32(); data.incrementPosition(cacert_len); int cert_len = data.getLittleEndian32(); data.incrementPosition(cert_len); readCert = true; return rc4_key_size; } }
/** * Prepare data as a Secure PDU and pass down to the MCS layer * * @param sec_data Data to send * @param flags Encryption flags * @param channel Channel over which to send data * @throws RdesktopException * @throws IOException * @throws CryptoException */ public void send_to_channel(RdpPacket_Localised sec_data, int flags, int channel) throws RdesktopException, IOException, CryptoException { int datalength = 0; byte[] signature = null; byte[] data; byte[] buffer; sec_data.setPosition(sec_data.getHeader(RdpPacket.SECURE_HEADER)); if (this.licenceIssued == false || (flags & SEC_ENCRYPT) != 0) { sec_data.setLittleEndian32(flags); } if (Options.debug_hexdump) { int length = sec_data.getEnd() - sec_data.getPosition(); byte[] packet = new byte[length]; sec_data.copyToByteArray( packet, 0, sec_data.getPosition(), sec_data.getEnd() - sec_data.getPosition()); System.out.println("Sending packet:"); System.out.println(net.propero.rdp.tools.HexDump.dumpHexString(packet)); } if ((flags & SEC_ENCRYPT) != 0) { flags &= ~SEC_ENCRYPT; datalength = sec_data.getEnd() - sec_data.getPosition() - 8; data = new byte[datalength]; buffer = null; sec_data.copyToByteArray(data, 0, sec_data.getPosition() + 8, datalength); signature = this.sign(this.sec_sign_key, 8, this.keylength, data, datalength); buffer = this.encrypt(data, datalength); sec_data.copyFromByteArray(signature, 0, sec_data.getPosition(), 8); sec_data.copyFromByteArray(buffer, 0, sec_data.getPosition() + 8, datalength); } // McsLayer.send(sec_data); McsLayer.send_to_channel(sec_data, channel); }
public void establishKey() throws RdesktopException, IOException, CryptoException { RdpPacket_Localised buffer; int flags = SEC_CLIENT_RANDOM; if (readCert) { // RDP5-style encryption, use old code for now int length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE; buffer = this.init(flags, 76); buffer.setLittleEndian32(length); buffer.copyFromByteArray(this.sec_crypted_random, 0, buffer.getPosition(), SEC_MODULUS_SIZE); buffer.incrementPosition(SEC_MODULUS_SIZE); } else { int length = server_public_key_len + SEC_PADDING_SIZE; buffer = this.init(flags, length + 4); buffer.setLittleEndian32(length); buffer.copyFromByteArray( this.sec_crypted_random, 0, buffer.getPosition(), server_public_key_len); buffer.incrementPosition(server_public_key_len); } buffer.incrementPosition(SEC_PADDING_SIZE); buffer.markEnd(); this.send(buffer, flags); }
/** * Read server info from packet, specifically the RDP version of the server * * @param mcs_data Packet to read */ private void processSrvInfo(RdpPacket_Localised mcs_data) { Options.server_rdp_version = mcs_data.getLittleEndian16(); // in_uint16_le(s, // g_server_rdp_version); logger.debug(("Server RDP version is " + Options.server_rdp_version)); if (1 == Options.server_rdp_version) Options.use_rdp5 = false; }
/** * Construct MCS data, including channel, encryption and display options * * @return Packet populated with MCS data */ public RdpPacket_Localised sendMcsData() { logger.debug("Secure.sendMcsData"); RdpPacket_Localised buffer = new RdpPacket_Localised(512); int hostlen = 2 * (Options.hostname == null ? 0 : Options.hostname.length()); if (hostlen > 30) { hostlen = 30; } int length = 162 + 76 + 12 + 4; if (Options.use_rdp5 && (channels.num_channels() > 0)) length += channels.num_channels() * 12 + 8; buffer.setBigEndian16(5); /* unknown */ buffer.setBigEndian16(0x14); buffer.set8(0x7c); buffer.setBigEndian16(1); buffer.setBigEndian16(length | 0x8000); // remaining length buffer.setBigEndian16(8); // length? buffer.setBigEndian16(16); buffer.set8(0); buffer.setLittleEndian16(0xc001); buffer.set8(0); buffer.setLittleEndian32(0x61637544); // "Duca" ?! buffer.setBigEndian16(length - 14 | 0x8000); // remaining length // Client information buffer.setLittleEndian16(SEC_TAG_CLI_INFO); buffer.setLittleEndian16(216); // length buffer.setLittleEndian16(Options.use_rdp5 ? 4 : 1); buffer.setLittleEndian16(8); buffer.setLittleEndian16(Options.width); buffer.setLittleEndian16(Options.height); buffer.setLittleEndian16(0xca01); buffer.setLittleEndian16(0xaa03); buffer.setLittleEndian32(Options.keylayout); buffer.setLittleEndian32(2600); // or 0ece // // client // build? we // are 2600 // compatible // :-) /* Unicode name of client, padded to 32 bytes */ buffer.outUnicodeString(Options.hostname, hostlen); buffer.incrementPosition(30 - hostlen); buffer.setLittleEndian32(4); buffer.setLittleEndian32(0); buffer.setLittleEndian32(12); buffer.incrementPosition(64); /* reserved? 4 + 12 doublewords */ buffer.setLittleEndian16(0xca01); // out_uint16_le(s, 0xca01); buffer.setLittleEndian16(1); buffer.setLittleEndian32(0); // out_uint32(s, 0); buffer.set8(Options.server_bpp); // out_uint8(s, g_server_bpp); buffer.setLittleEndian16(0x0700); // out_uint16_le(s, 0x0700); buffer.set8(0); // out_uint8(s, 0); buffer.setLittleEndian32(1); // out_uint32_le(s, 1); buffer.incrementPosition(64); buffer.setLittleEndian32(0); // selected_protocol /* End of client info */ buffer.setLittleEndian16(SEC_TAG_CLI_4); // out_uint16_le(s, SEC_TAG_CLI_4); buffer.setLittleEndian16(12); // out_uint16_le(s, 12); int cluster_flags = 0; cluster_flags |= SEC_CC_REDIRECTION_SUPPORTED; cluster_flags |= (SEC_CC_REDIRECT_VERSION_3 << 2); if (Options.console_session) { cluster_flags |= SEC_CC_REDIRECT_SESSIONID_FIELD_VALID; } buffer.setLittleEndian32(cluster_flags); // out_uint32_le(s, buffer.setLittleEndian32(0); // redirect session id? // Client encryption settings // buffer.setLittleEndian16(SEC_TAG_CLI_CRYPT); buffer.setLittleEndian16(12); // length buffer.setLittleEndian32(Options.encryption ? 0x3 : 0); buffer.setLittleEndian32(0); // unknown if (Options.use_rdp5 && (channels.num_channels() > 0)) { logger.debug(("num_channels is " + channels.num_channels())); buffer.setLittleEndian16(SEC_TAG_CLI_CHANNELS); // out_uint16_le(s, // SEC_TAG_CLI_CHANNELS); buffer.setLittleEndian16(channels.num_channels() * 12 + 8); // out_uint16_le(s, buffer.setLittleEndian32(channels.num_channels()); // out_uint32_le(s, // g_num_channels); // // number of // virtual // channels for (int i = 0; i < channels.num_channels(); i++) { logger.debug(("Requesting channel " + channels.channel(i).name())); buffer.out_uint8p(channels.channel(i).name(), 8); // out_uint8a(s, // g_channels[i].name, // 8); buffer.setBigEndian32(channels.channel(i).flags()); // out_uint32_be(s, // g_channels[i].flags); } } buffer.markEnd(); return buffer; }
/** * Receive a Secure layer PDU from the MCS layer * * @return Packet representing received Secure PDU * @throws RdesktopException * @throws IOException * @throws CryptoException * @throws OrderException */ public RdpPacket_Localised receive() throws RdesktopException, IOException, CryptoException, OrderException { int sec_flags = 0; RdpPacket_Localised buffer = null; while (true) { int[] channel = new int[1]; buffer = McsLayer.receive(channel); if (buffer == null) return null; buffer.setHeader(RdpPacket.SECURE_HEADER); if (Constants.encryption || (!this.licenceIssued)) { sec_flags = buffer.getLittleEndian32(); if ((sec_flags & SEC_LICENCE_NEG) != 0) { licence.process(buffer); continue; } if ((sec_flags & SEC_ENCRYPT) != 0) { buffer.incrementPosition(8); // signature byte[] data = new byte[buffer.size() - buffer.getPosition()]; buffer.copyToByteArray(data, 0, buffer.getPosition(), data.length); byte[] packet = this.decrypt(data); buffer.copyFromByteArray(packet, 0, buffer.getPosition(), packet.length); // buffer.setStart(buffer.getPosition()); // return buffer; } } if (channel[0] != MCS.MCS_GLOBAL_CHANNEL) { channels.channel_process(buffer, channel[0]); continue; } buffer.setStart(buffer.getPosition()); return buffer; } }