/** * 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 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; } }
/** * 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; }