void NetInterface::handleConnectReject(const Address &address, BitStream *stream) { Nonce nonce; Nonce serverNonce; nonce.read(stream); serverNonce.read(stream); NetConnection *conn = findPendingConnection(address); if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse && conn->getConnectionState() != NetConnection::AwaitingConnectResponse)) return; ConnectionParameters &p = conn->getConnectionParameters(); if(p.mNonce != nonce || p.mServerNonce != serverNonce) return; NetConnection::TerminationReason reason = (NetConnection::TerminationReason) stream->readEnum(NetConnection::TerminationReasons); char reasonStr[256]; stream->readString(reasonStr); logprintf(LogConsumer::LogNetInterface, "Received Connect Reject - reason code %d (%s)", reason, reasonStr); // If the reason is a bad puzzle solution, try once more with a new nonce if(reason == NetConnection::ReasonPuzzle && !p.mPuzzleRetried) { p.mPuzzleRetried = true; conn->setConnectionState(NetConnection::AwaitingChallengeResponse); conn->mConnectSendCount = 0; p.mNonce.getRandom(); // Generate new nonce sendConnectChallengeRequest(conn); return; } conn->setConnectionState(NetConnection::ConnectRejected); conn->onConnectTerminated(reason, reasonStr); removePendingConnection(conn); }
void NetInterface::handleConnectReject(const Address &address, BitStream *stream) { Nonce nonce; Nonce serverNonce; nonce.read(stream); serverNonce.read(stream); NetConnection *conn = findPendingConnection(address); if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse && conn->getConnectionState() != NetConnection::AwaitingConnectResponse)) return; ConnectionParameters &p = conn->getConnectionParameters(); if(p.mNonce != nonce || p.mServerNonce != serverNonce) return; char reason[256]; stream->readString(reason); TNLLogMessageV(LogNetInterface, ("Received Connect Reject - reason %s", reason)); // if the reason is a bad puzzle solution, try once more with a // new nonce. if(!strcmp(reason, "Puzzle") && !p.mPuzzleRetried) { p.mPuzzleRetried = true; conn->setConnectionState(NetConnection::AwaitingChallengeResponse); conn->mConnectSendCount = 0; p.mNonce.getRandom(); sendConnectChallengeRequest(conn); return; } conn->setConnectionState(NetConnection::ConnectRejected); conn->onConnectTerminated(NetConnection::ReasonRemoteHostRejectedConnection, reason); removePendingConnection(conn); }
static void handlePing(Game *game, const Address &remoteAddress, Socket &socket, BitStream *stream, S32 clientId) { TNLAssert(game->isServer(), "Expected this to be a server!"); Nonce clientNonce; clientNonce.read(stream); U32 protocolVersion; stream->read(&protocolVersion); if(protocolVersion != CS_PROTOCOL_VERSION) // Ignore pings from incompatible versions return; U32 clientIdentityToken = computeSimpleToken(clientNonce); PacketStream pingResponse; pingResponse.write(U8(GameNetInterface::PingResponse)); clientNonce.write(&pingResponse); pingResponse.write(clientIdentityToken); pingResponse.write(clientId); // older 019 ignore this or won't read this pingResponse.sendto(socket, remoteAddress); }
TEST(HeaderField, Serialize) { std::list<HeaderField> list; std::list<Certificate> certificates; for (unsigned i = 0; i < 2; ++i) { auto rand_gen = random_byte_generator(i + 8 * 3); Certificate cert; HashedId8 cert_digest; std::generate(cert_digest.begin(), cert_digest.end(), rand_gen); cert.signer_info = cert_digest; cert.subject_info = { SubjectType::Enrollment_Credential, random_byte_sequence(28, i) }; cert.signature = create_random_ecdsa_signature(i + 8); certificates.push_back(cert); } list.push_back(SignerInfo { certificates }); list.push_back(Time64 { 983 }); Time64WithStandardDeviation time_dev; time_dev.log_std_dev = 1; time_dev.time64 = 2000; list.push_back(time_dev); list.push_back(Time32 { 434 }); ThreeDLocation loc; loc.latitude.from_value(838); loc.longitude.from_value(37); loc.elevation = {{ 83, 17 }}; list.push_back(loc); std::list<HashedId3> hashed; for (unsigned i = 0; i < 3; ++i) { HashedId3 id; std::generate(id.begin(), id.end(), random_byte_generator(i + 8943)); hashed.push_back(id); } list.push_back(hashed); list.push_back(IntX { 43 }); Nonce nonce; std::generate(nonce.begin(), nonce.end(), random_byte_generator(22)); list.push_back(EncryptionParameter { nonce }); std::list<RecipientInfo> recipients; for (unsigned i = 0; i < 2; ++i) { const std::size_t length = field_size(PublicKeyAlgorithm::ECIES_NISTP256); auto rand_gen = random_byte_generator(i + 93); RecipientInfo info; EciesEncryptedKey key; std::generate(info.cert_id.begin(), info.cert_id.end(), rand_gen); key.c = random_byte_sequence(field_size(SymmetricAlgorithm::AES128_CCM), rand_gen()); std::generate(key.t.begin(), key.t.end(), rand_gen); key.v = Uncompressed { random_byte_sequence(length, rand_gen()), random_byte_sequence(length, rand_gen()) }; info.enc_key = key; recipients.push_back(info); } list.push_back(recipients); check(list, serialize_roundtrip(list)); }
void NetInterface::handlePunch(const Address &theAddress, BitStream *stream) { S32 i, j; NetConnection *conn; Nonce firstNonce; firstNonce.read(stream); ByteBuffer b(firstNonce.data, Nonce::NonceSize); TNLLogMessageV(LogNetInterface, ("Received punch packet from %s - %s", theAddress.toString(), b.encodeBase64()->getBuffer())); for(i = 0; i < mPendingConnections.size(); i++) { conn = mPendingConnections[i]; ConnectionParameters &theParams = conn->getConnectionParameters(); if(conn->getConnectionState() != NetConnection::SendingPunchPackets) continue; if((theParams.mIsInitiator && firstNonce != theParams.mServerNonce) || (!theParams.mIsInitiator && firstNonce != theParams.mNonce)) continue; // first see if the address is in the possible addresses list: for(j = 0; j < theParams.mPossibleAddresses.size(); j++) if(theAddress == theParams.mPossibleAddresses[j]) break; // if there was an exact match, just exit the loop, or // continue on to the next pending if this is not an initiator: if(j != theParams.mPossibleAddresses.size()) { if(theParams.mIsInitiator) break; else continue; } // if there was no exact match, we may have a funny NAT in the // middle. But since a packet got through from the remote host // we'll want to send a punch to the address it came from, as long // as only the port is not an exact match: for(j = 0; j < theParams.mPossibleAddresses.size(); j++) if(theAddress.isEqualAddress(theParams.mPossibleAddresses[j])) break; // if the address wasn't even partially in the list, just exit out if(j == theParams.mPossibleAddresses.size()) continue; // otherwise, as long as we don't have too many ping addresses, // add this one to the list: if(theParams.mPossibleAddresses.size() < 5) theParams.mPossibleAddresses.push_back(theAddress); // if this is the initiator of the arranged connection, then // process the punch packet from the remote host by issueing a // connection request. if(theParams.mIsInitiator) break; } if(i == mPendingConnections.size()) return; ConnectionParameters &theParams = conn->getConnectionParameters(); SymmetricCipher theCipher(theParams.mArrangedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, stream->getBytePosition(), &theCipher)) return; Nonce nextNonce; nextNonce.read(stream); if(nextNonce != theParams.mNonce) return; // see if the connection needs to be authenticated or uses key exchange if(stream->readFlag()) { if(stream->readFlag()) { theParams.mCertificate = new Certificate(stream); if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true)) return; theParams.mPublicKey = theParams.mCertificate->getPublicKey(); } else { theParams.mPublicKey = new AsymmetricKey(stream); if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true)) return; } if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize()) { // we don't have a private key, so generate one for this connection theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize()); } else theParams.mPrivateKey = mPrivateKey; theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer()); Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize); theParams.mUsingCrypto = true; } conn->setNetAddress(theAddress); TNLLogMessageV(LogNetInterface, ("Punch from %s matched nonces - connecting...", theAddress.toString())); conn->setConnectionState(NetConnection::AwaitingConnectResponse); conn->mConnectSendCount = 0; conn->mConnectLastSendTime = getCurrentTime(); sendArrangedConnectRequest(conn); }
void NetInterface::handleConnectChallengeResponse(const Address &address, BitStream *stream) { NetConnection *conn = findPendingConnection(address); if(!conn || conn->getConnectionState() != NetConnection::AwaitingChallengeResponse) // Not expecting a connection, abort! return; Nonce theNonce; theNonce.read(stream); ConnectionParameters &theParams = conn->getConnectionParameters(); if(theNonce != theParams.mNonce) // Nonces don't match, abort! return; stream->read(&theParams.mClientIdentity); // See if the server wants us to solve a client puzzle theParams.mServerNonce.read(stream); stream->read(&theParams.mPuzzleDifficulty); if(theParams.mPuzzleDifficulty > ClientPuzzleManager::MaxPuzzleDifficulty) // Puzzle too hard, abort! return; // See if the connection needs to be authenticated or uses key exchange if(stream->readFlag()) { if(stream->readFlag()) { theParams.mCertificate = new Certificate(stream); if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true)) // Invalid cert, abort! return; theParams.mPublicKey = theParams.mCertificate->getPublicKey(); } else { theParams.mPublicKey = new AsymmetricKey(stream); if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true)) return; } if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize()) { // we don't have a private key, so generate one for this connection theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize()); } else theParams.mPrivateKey = mPrivateKey; theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer()); Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize); theParams.mUsingCrypto = true; } logprintf(LogConsumer::LogNetInterface, "Received Challenge Response: %8x", theParams.mClientIdentity); conn->setConnectionState(NetConnection::ComputingPuzzleSolution); conn->mConnectSendCount = 0; theParams.mPuzzleSolution = 0; conn->mConnectLastSendTime = getCurrentTime(); continuePuzzleSolution(conn); }