diff --git a/Reseed.cpp b/Reseed.cpp index fbf32fc4..c443a4fe 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #include #include "I2PEndian.h" #include "Reseed.h" @@ -497,7 +499,30 @@ namespace data LogPrint (eLogInfo, numCertificates, " certificates loaded"); } - TlsSession::TlsSession (const std::string& address) + std::string Reseeder::HttpsRequest (const std::string& address) + { + i2p::util::http::url u(address); + TlsSession session (u.host_, 443); + std::stringstream ss; + ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); + return ""; + } + + TlsSession::TlsSession (const std::string& host, int port): + m_Seqn (0) + { + m_Site.connect(host, boost::lexical_cast(port)); + if (m_Site.good ()) + { + Handshake (); + } + else + LogPrint (eLogError, "Can't connect to ", host, ":", port); + } + + void TlsSession::Handshake () { static uint8_t clientHello[] = { @@ -553,120 +578,112 @@ namespace data // 0x14 handshake type (finished) // 0x00, 0x00, 0x0C length of handshake payload // 12 bytes of verified data - }; - - i2p::util::http::url u(address); - boost::asio::ip::tcp::iostream site; - site.connect(u.host_, "443"); - if (site.good ()) - { - CryptoPP::SHA256 finishedHash; - // send ClientHello - site.write ((char *)clientHello, sizeof (clientHello)); - finishedHash.Update (clientHello + 5, sizeof (clientHello) - 5); - // read ServerHello - uint8_t type; - site.read ((char *)&type, 1); - uint16_t version; - site.read ((char *)&version, 2); - uint16_t length; - site.read ((char *)&length, 2); - length = be16toh (length); - char * serverHello = new char[length]; - site.read (serverHello, length); - finishedHash.Update ((uint8_t *)serverHello, length); - uint8_t serverRandom[32]; - if (serverHello[0] == 0x02) // handshake type server hello - memcpy (serverRandom, serverHello + 6, 32); - else - LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); - delete[] serverHello; - // read Certificate - site.read ((char *)&type, 1); - site.read ((char *)&version, 2); - site.read ((char *)&length, 2); - length = be16toh (length); - char * certificate = new char[length]; - site.read (certificate, length); - finishedHash.Update ((uint8_t *)certificate, length); - CryptoPP::RSA::PublicKey publicKey; - // 0 - handshake type - // 1 - 3 - handshake payload length - // 4 - 6 - length of array of certificates - // 7 - 9 - length of certificate - if (certificate[0] == 0x0B) // handshake type certificate - publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); - else - LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); - delete[] certificate; - // read ServerHelloDone - site.read ((char *)&type, 1); - site.read ((char *)&version, 2); - site.read ((char *)&length, 2); - length = be16toh (length); - char * serverHelloDone = new char[length]; - site.read (serverHelloDone, length); - finishedHash.Update ((uint8_t *)serverHelloDone, length); - if (serverHelloDone[0] != 0x0E) // handshake type hello done - LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); - delete[] serverHelloDone; - // our turn now - // generate secret key - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); - // encryptor.CiphertextLength (48); - uint8_t secret[48], encrypted[256]; - secret[0] = clientKeyExchange[1]; secret[1] = clientKeyExchange[2]; // version - m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes - encryptor.Encrypt (rnd, secret, 48, encrypted); - // send ClientKeyExchange - site.write ((char *)clientKeyExchange, sizeof (clientKeyExchange)); - site.write ((char *)encrypted, 256); - finishedHash.Update (clientKeyExchange + 5, sizeof (clientKeyExchange) - 5); - finishedHash.Update (encrypted, 256); - uint8_t masterSecret[48], random[64]; - memcpy (random, clientHello + 11, 32); - memcpy (random + 32, serverRandom, 32); - // send ChangeCipherSpecs - site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); - // calculate master secret - PRF (secret, "master secret", random, 64, 48, masterSecret); - // expand master secret - uint8_t keys[256]; // clientMACKey, serverMACKey, clientKey, serverKey - memcpy (random, serverRandom, 32); - memcpy (random + 32, clientHello + 11, 32); - PRF (masterSecret, "key expansion", random, 64, 256, keys); - memcpy (m_MacKey, keys, 32); - m_Encryption.SetKey (keys + 64); - m_Decryption.SetKey (keys + 96); - - // send finished - uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; - finishedPayload[0] = 0x14; // handshake type (finished) - finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes - finishedHash.Final (finishedHashDigest); - PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); - uint8_t mac[32]; - CalculateMAC (0x16, 0, finishedPayload, 16, mac); - Encrypt (finishedPayload, 16, mac, encryptedPayload); - site.write ((char *)finished, sizeof (finished)); - site.write ((char *)encryptedPayload, 80); - // read ChangeCipherSpecs - uint8_t changeCipherSpecs1[6]; - site.read ((char *)changeCipherSpecs1, 6); - // read finished - site.read ((char *)&type, 1); - site.read ((char *)&version, 2); - site.read ((char *)&length, 2); - length = be16toh (length); - char * finished1 = new char[length]; - site.read (finished1, length); - delete[] finished1; - } - else - LogPrint (eLogError, "Can't connect to ", address); - } + }; + CryptoPP::SHA256 finishedHash; + // send ClientHello + m_Site.write ((char *)clientHello, sizeof (clientHello)); + finishedHash.Update (clientHello + 5, sizeof (clientHello) - 5); + // read ServerHello + uint8_t type; + m_Site.read ((char *)&type, 1); + uint16_t version; + m_Site.read ((char *)&version, 2); + uint16_t length; + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * serverHello = new char[length]; + m_Site.read (serverHello, length); + finishedHash.Update ((uint8_t *)serverHello, length); + uint8_t serverRandom[32]; + if (serverHello[0] == 0x02) // handshake type server hello + memcpy (serverRandom, serverHello + 6, 32); + else + LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); + delete[] serverHello; + // read Certificate + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * certificate = new char[length]; + m_Site.read (certificate, length); + finishedHash.Update ((uint8_t *)certificate, length); + CryptoPP::RSA::PublicKey publicKey; + // 0 - handshake type + // 1 - 3 - handshake payload length + // 4 - 6 - length of array of certificates + // 7 - 9 - length of certificate + if (certificate[0] == 0x0B) // handshake type certificate + publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); + else + LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); + delete[] certificate; + // read ServerHelloDone + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * serverHelloDone = new char[length]; + m_Site.read (serverHelloDone, length); + finishedHash.Update ((uint8_t *)serverHelloDone, length); + if (serverHelloDone[0] != 0x0E) // handshake type hello done + LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); + delete[] serverHelloDone; + // our turn now + // generate secret key + CryptoPP::AutoSeededRandomPool rnd; + CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); + // encryptor.CiphertextLength (48); + uint8_t secret[48], encrypted[256]; + secret[0] = 3; secret[1] = 3; // version + m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes + encryptor.Encrypt (rnd, secret, 48, encrypted); + // send ClientKeyExchange + m_Site.write ((char *)clientKeyExchange, sizeof (clientKeyExchange)); + m_Site.write ((char *)encrypted, 256); + finishedHash.Update (clientKeyExchange + 5, sizeof (clientKeyExchange) - 5); + finishedHash.Update (encrypted, 256); + uint8_t masterSecret[48], random[64]; + memcpy (random, clientHello + 11, 32); + memcpy (random + 32, serverRandom, 32); + // send ChangeCipherSpecs + m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); + // calculate master secret + PRF (secret, "master secret", random, 64, 48, masterSecret); + // expand master secret + uint8_t keys[256]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32) + memcpy (random, serverRandom, 32); + memcpy (random + 32, clientHello + 11, 32); + PRF (masterSecret, "key expansion", random, 64, 256, keys); + memcpy (m_MacKey, keys, 32); + m_Encryption.SetKey (keys + 64); + m_Decryption.SetKey (keys + 96); + + // send finished + uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; + finishedPayload[0] = 0x14; // handshake type (finished) + finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes + finishedHash.Final (finishedHashDigest); + PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); + uint8_t mac[32]; + CalculateMAC (0x16, finishedPayload, 16, mac); + Encrypt (finishedPayload, 16, mac, encryptedPayload); + m_Site.write ((char *)finished, sizeof (finished)); + m_Site.write ((char *)encryptedPayload, 80); + // read ChangeCipherSpecs + uint8_t changeCipherSpecs1[6]; + m_Site.read ((char *)changeCipherSpecs1, 6); + // read finished + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + char * finished1 = new char[length]; + m_Site.read (finished1, length); + delete[] finished1; + } + void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, size_t len, uint8_t * buf) { @@ -710,24 +727,24 @@ namespace data return size; } - size_t TlsSession::Decrypt (uint8_t * in, size_t len, uint8_t * out) + size_t TlsSession::Decrypt (uint8_t * buf, size_t len) { - m_Decryption.SetIV (in); - m_Decryption.Decrypt (in + 16, len - 16, in + 16); - memcpy (out, in + 16, len - 48); // skip 32 bytes mac - return len - 48 - in[len -1] - 1; + m_Decryption.SetIV (buf); + m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); + return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding } - void TlsSession::CalculateMAC (uint8_t type, uint64_t seqn, const uint8_t * buf, size_t len, uint8_t * mac) + void TlsSession::CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) { uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) - htobe64buf (header, seqn); + htobe64buf (header, m_Seqn); header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 htobe16buf (header + 11, len); CryptoPP::HMAC hmac (m_MacKey, 32); hmac.Update (header, 13); hmac.Update (buf, len); hmac.Final (mac); + m_Seqn++; } CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) @@ -773,6 +790,34 @@ namespace data return ret; } + void TlsSession::Send (const uint8_t * buf, size_t len) + { + uint8_t * out = new uint8_t[len + 64 + 5]; // 64 = 32 mac + 16 iv + upto 16 padding, 5 = header + out[0] = 0x17; // application data + out[1] = 0x03; out[2] = 0x03; // version + uint8_t mac[32]; + CalculateMAC (0x17, buf, len, mac); + size_t encryptedLen = Encrypt (buf, len, mac, out); + htobe16buf (out + 3, encryptedLen); + m_Site.write ((char *)out, encryptedLen + 5); + delete[] out; + } + + std::string TlsSession::Receive () + { + if (m_Site.eof ()) return ""; + uint8_t type; uint16_t version, length; + m_Site.read ((char *)&type, 1); + m_Site.read ((char *)&version, 2); + m_Site.read ((char *)&length, 2); + length = be16toh (length); + uint8_t * buf = new uint8_t[length]; + m_Site.read ((char *)buf, length); + size_t decryptedLen = Decrypt (buf, length); + std::string str ((char *)buf + 16, decryptedLen); + delete[] buf; + return str; + } } } diff --git a/Reseed.h b/Reseed.h index 5b302044..a5a61366 100644 --- a/Reseed.h +++ b/Reseed.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "Identity.h" #include "aes.h" @@ -51,19 +51,24 @@ namespace data { public: - TlsSession (const std::string& address); + TlsSession (const std::string& host, int port); + void Send (const uint8_t * buf, size_t len); + std::string Receive (); private: + void Handshake (); CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, size_t len, uint8_t * buf); - void CalculateMAC (uint8_t type, uint64_t seqn, const uint8_t * buf, size_t len, uint8_t * mac); + void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac); size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out); - size_t Decrypt (uint8_t * in, size_t len, uint8_t * out); + size_t Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16 private: + uint64_t m_Seqn; + boost::asio::ip::tcp::iostream m_Site; CryptoPP::AutoSeededRandomPool m_Rnd; i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCDecryption m_Decryption;