From 54dd5da64cf0e43095873821ef7c44164e01aaec Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 3 Aug 2015 14:02:57 -0700 Subject: [PATCH] To debug RSA padding error --- domain-server/src/DomainServer.cpp | 47 ++++++++++--------- .../networking/src/DataServerAccountInfo.cpp | 8 ++-- libraries/networking/src/NodeList.cpp | 8 ++-- .../networking/src/udt/PacketHeaders.cpp | 4 +- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b9f7a293b3..324096c997 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -285,7 +285,6 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { packetReceiver.registerListener(PacketType::DomainConnectRequest, this, "processConnectRequestPacket"); packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket"); packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket"); - packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processConnectRequestPacket"); packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket"); packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket"); @@ -578,6 +577,7 @@ const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::EntityServer; void DomainServer::processConnectRequestPacket(QSharedPointer packet) { + NodeType_t nodeType; HifiSockAddr publicSockAddr, localSockAddr; @@ -638,23 +638,22 @@ void DomainServer::processConnectRequestPacket(QSharedPointer packet) if (packet->bytesLeftToRead() > 0) { // try to verify username and usernameSignature packetStream >> username >> usernameSignature; - } else { - QUuid connectionToken = _connectionTokenHash[username]; + } else { + // if user didn't include username and usernameSignature in connect request, send a connectionToken packet + QUuid& connectionToken = _connectionTokenHash[username]; if(connectionToken.isNull()) { // set up the connection token packet - static auto connectionTokenPacket = NLPacket::create(PacketType::DomainServerConnectionToken, NUM_BYTES_RFC4122_UUID); - connectionTokenPacket.reset(); - connectionTokenPacket->write(connectionToken.toRfc4122()); - nodeList->sendUnreliablePacket(connectionToken, packet->getSenderSockAddr()); - return; - } else { - // reset existing packet - - //connectionTokenPacket.reset(); + connectionToken = QUuid::createUuid(); } + static auto connectionTokenPacket = NLPacket::create(PacketType::DomainServerConnectionToken, NUM_BYTES_RFC4122_UUID); + connectionTokenPacket->reset(); + connectionTokenPacket->write(connectionToken.toRfc4122()); + limitedNodeList->sendUnreliablePacket(*connectionTokenPacket, packet->getSenderSockAddr()); + return; + } QString reason; @@ -793,9 +792,8 @@ bool DomainServer::verifyUserSignature(const QString& username, const QByteArray& usernameSignature, QString& reasonReturn) { // it's possible this user can be allowed to connect, but we need to check their username signature - - QByteArray publicKeyArray = _userPublicKeys.value(username); + QUuid connectionToken = _connectionTokenHash.value(username); if (!publicKeyArray.isEmpty()) { // if we do have a public key for the user, check for a signature match @@ -803,7 +801,8 @@ bool DomainServer::verifyUserSignature(const QString& username, // first load up the public key into an RSA struct RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size()); - + + if (rsaPublicKey) { QByteArray decryptedArray(RSA_size(rsaPublicKey), 0); int decryptResult = @@ -813,10 +812,13 @@ bool DomainServer::verifyUserSignature(const QString& username, rsaPublicKey, RSA_PKCS1_PADDING); QByteArray lowercaseUsername = username.toLower().toUtf8(); - QUuid connectionToken = _connectionTokenHash[username]; - QByteArray usernameWithToken = lowercaseUsername.append(connectionToken.toRfc4122()); + QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), QCryptographicHash::Sha256); + + int err = ERR_get_error(); + qDebug() << "Error: " << err; if (decryptResult != -1) { + if (usernameWithToken == decryptedArray) { qDebug() << "Username signature matches for" << username << "- allowing connection."; @@ -834,10 +836,13 @@ bool DomainServer::verifyUserSignature(const QString& username, } else { qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection."; reasonReturn = "Couldn't decrypt user signature."; + } // free up the public key, we don't need it anymore RSA_free(rsaPublicKey); + _connectionTokenHash.remove(username); + } else { // we can't let this user in since we couldn't convert their public key to an RSA key we could use qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection."; @@ -859,10 +864,10 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username, _settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool(); // we always let in a user who is sending a packet from our local socket or from the localhost address - if (senderSockAddr.getAddress() == DependencyManager::get()->getLocalSockAddr().getAddress() - || senderSockAddr.getAddress() == QHostAddress::LocalHost) { - return true; - } +// if (senderSockAddr.getAddress() == DependencyManager::get()->getLocalSockAddr().getAddress() +// || senderSockAddr.getAddress() == QHostAddress::LocalHost) { +// return true; +// } if (isRestrictingAccess) { diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index bdef718ff4..580a676ece 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -129,6 +129,7 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject } QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) { + if (!_privateKey.isEmpty()) { const char* privateKeyData = _privateKey.constData(); RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL, @@ -136,16 +137,14 @@ QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionTo _privateKey.size()); if (rsaPrivateKey) { QByteArray lowercaseUsername = _username.toLower().toUtf8(); - QByteArray usernameWithToken = lowercaseUsername.append(connectionToken.toRfc4122()); - + QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), QCryptographicHash::Sha256); QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0); - int encryptReturn = RSA_private_encrypt(lowercaseUsername.size(), + int encryptReturn = RSA_private_encrypt(usernameWithToken.size(), reinterpret_cast(usernameWithToken.constData()), reinterpret_cast(usernameSignature.data()), rsaPrivateKey, RSA_PKCS1_PADDING); - // free the private key RSA struct now that we are done with it RSA_free(rsaPrivateKey); @@ -154,6 +153,7 @@ QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionTo qCDebug(networking) << "Error encrypting username signature."; qCDebug(networking) << "Will re-attempt on next domain-server check in."; } else { + qDebug(networking) << "Signing username with connectionUUID"; return usernameSignature; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 1739285cba..d467fcfa13 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -277,19 +277,20 @@ void NodeList::sendDomainServerCheckIn() { // if this is a connect request, and we can present a username signature, send it along if (!_domainHandler.isConnected() ) { + DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo(); - packetStream << accountInfo.getUsername(); // get connection token from the domain-server const QUuid& connectionToken = _domainHandler.getConnectionToken(); if(!connectionToken.isNull()) { + const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(connectionToken); if (!usernameSignature.isEmpty()) { - qCDebug(networking) << "Including username signature in domain connect request."; - packetStream << usernameSignature; + packetStream << accountInfo.getUsername() << usernameSignature; } + } } @@ -462,7 +463,6 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer // refuse to process this packet if we aren't currently connected to the DS return; } - // read in the connection token from the packet, then send domain-server checkin _domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID))); sendDomainServerCheckIn(); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 90b4d57e05..f3f222f310 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -26,8 +26,8 @@ const QSet SEQUENCE_NUMBERED_PACKETS = QSet NON_SOURCED_PACKETS = QSet() << StunResponse << CreateAssignment << RequestAssignment - << DomainServerRequireDTLS << DomainConnectRequest - << DomainList << DomainConnectionDenied << DomainServerConnectionToken + << DomainServerRequireDTLS << DomainConnectRequest << DomainServerConnectionToken + << DomainList << DomainConnectionDenied << DomainServerPathQuery << DomainServerPathResponse << DomainServerAddedNode << ICEServerPeerInformation << ICEServerQuery << ICEServerHeartbeat