To debug RSA padding error

This commit is contained in:
bwent 2015-08-03 14:02:57 -07:00
parent af293ec6dd
commit 54dd5da64c
4 changed files with 36 additions and 31 deletions

View file

@ -285,7 +285,6 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
packetReceiver.registerListener(PacketType::DomainConnectRequest, this, "processConnectRequestPacket"); packetReceiver.registerListener(PacketType::DomainConnectRequest, this, "processConnectRequestPacket");
packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket"); packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket");
packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket"); packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket");
packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processConnectRequestPacket");
packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket"); packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket");
@ -578,6 +577,7 @@ const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
<< NodeType::AvatarMixer << NodeType::EntityServer; << NodeType::AvatarMixer << NodeType::EntityServer;
void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet) { void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet) {
NodeType_t nodeType; NodeType_t nodeType;
HifiSockAddr publicSockAddr, localSockAddr; HifiSockAddr publicSockAddr, localSockAddr;
@ -638,23 +638,22 @@ void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet)
if (packet->bytesLeftToRead() > 0) { if (packet->bytesLeftToRead() > 0) {
// try to verify username and usernameSignature // try to verify username and usernameSignature
packetStream >> username >> 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()) { if(connectionToken.isNull()) {
// set up the connection token packet // set up the connection token packet
static auto connectionTokenPacket = NLPacket::create(PacketType::DomainServerConnectionToken, NUM_BYTES_RFC4122_UUID); connectionToken = QUuid::createUuid();
connectionTokenPacket.reset();
connectionTokenPacket->write(connectionToken.toRfc4122());
nodeList->sendUnreliablePacket(connectionToken, packet->getSenderSockAddr());
return;
} else {
// reset existing packet
//connectionTokenPacket.reset();
} }
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; QString reason;
@ -793,9 +792,8 @@ bool DomainServer::verifyUserSignature(const QString& username,
const QByteArray& usernameSignature, const QByteArray& usernameSignature,
QString& reasonReturn) { QString& reasonReturn) {
// it's possible this user can be allowed to connect, but we need to check their username signature // it's possible this user can be allowed to connect, but we need to check their username signature
QByteArray publicKeyArray = _userPublicKeys.value(username); QByteArray publicKeyArray = _userPublicKeys.value(username);
QUuid connectionToken = _connectionTokenHash.value(username);
if (!publicKeyArray.isEmpty()) { if (!publicKeyArray.isEmpty()) {
// if we do have a public key for the user, check for a signature match // 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 // first load up the public key into an RSA struct
RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size()); RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, publicKeyArray.size());
if (rsaPublicKey) { if (rsaPublicKey) {
QByteArray decryptedArray(RSA_size(rsaPublicKey), 0); QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
int decryptResult = int decryptResult =
@ -813,10 +812,13 @@ bool DomainServer::verifyUserSignature(const QString& username,
rsaPublicKey, RSA_PKCS1_PADDING); rsaPublicKey, RSA_PKCS1_PADDING);
QByteArray lowercaseUsername = username.toLower().toUtf8(); QByteArray lowercaseUsername = username.toLower().toUtf8();
QUuid connectionToken = _connectionTokenHash[username]; QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), QCryptographicHash::Sha256);
QByteArray usernameWithToken = lowercaseUsername.append(connectionToken.toRfc4122());
int err = ERR_get_error();
qDebug() << "Error: " << err;
if (decryptResult != -1) { if (decryptResult != -1) {
if (usernameWithToken == decryptedArray) { if (usernameWithToken == decryptedArray) {
qDebug() << "Username signature matches for" << username << "- allowing connection."; qDebug() << "Username signature matches for" << username << "- allowing connection.";
@ -834,10 +836,13 @@ bool DomainServer::verifyUserSignature(const QString& username,
} else { } else {
qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection."; qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection.";
reasonReturn = "Couldn't decrypt user signature."; reasonReturn = "Couldn't decrypt user signature.";
} }
// free up the public key, we don't need it anymore // free up the public key, we don't need it anymore
RSA_free(rsaPublicKey); RSA_free(rsaPublicKey);
_connectionTokenHash.remove(username);
} else { } else {
// we can't let this user in since we couldn't convert their public key to an RSA key we could use // 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."; 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(); _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 // 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<LimitedNodeList>()->getLocalSockAddr().getAddress() // if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|| senderSockAddr.getAddress() == QHostAddress::LocalHost) { // || senderSockAddr.getAddress() == QHostAddress::LocalHost) {
return true; // return true;
} // }
if (isRestrictingAccess) { if (isRestrictingAccess) {

View file

@ -129,6 +129,7 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject
} }
QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) { QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) {
if (!_privateKey.isEmpty()) { if (!_privateKey.isEmpty()) {
const char* privateKeyData = _privateKey.constData(); const char* privateKeyData = _privateKey.constData();
RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL, RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
@ -136,16 +137,14 @@ QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionTo
_privateKey.size()); _privateKey.size());
if (rsaPrivateKey) { if (rsaPrivateKey) {
QByteArray lowercaseUsername = _username.toLower().toUtf8(); 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); QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0);
int encryptReturn = RSA_private_encrypt(lowercaseUsername.size(), int encryptReturn = RSA_private_encrypt(usernameWithToken.size(),
reinterpret_cast<const unsigned char*>(usernameWithToken.constData()), reinterpret_cast<const unsigned char*>(usernameWithToken.constData()),
reinterpret_cast<unsigned char*>(usernameSignature.data()), reinterpret_cast<unsigned char*>(usernameSignature.data()),
rsaPrivateKey, RSA_PKCS1_PADDING); rsaPrivateKey, RSA_PKCS1_PADDING);
// free the private key RSA struct now that we are done with it // free the private key RSA struct now that we are done with it
RSA_free(rsaPrivateKey); RSA_free(rsaPrivateKey);
@ -154,6 +153,7 @@ QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionTo
qCDebug(networking) << "Error encrypting username signature."; qCDebug(networking) << "Error encrypting username signature.";
qCDebug(networking) << "Will re-attempt on next domain-server check in."; qCDebug(networking) << "Will re-attempt on next domain-server check in.";
} else { } else {
qDebug(networking) << "Signing username with connectionUUID";
return usernameSignature; return usernameSignature;
} }

View file

@ -277,19 +277,20 @@ void NodeList::sendDomainServerCheckIn() {
// if this is a connect request, and we can present a username signature, send it along // if this is a connect request, and we can present a username signature, send it along
if (!_domainHandler.isConnected() ) { if (!_domainHandler.isConnected() ) {
DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo(); DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo();
packetStream << accountInfo.getUsername();
// get connection token from the domain-server // get connection token from the domain-server
const QUuid& connectionToken = _domainHandler.getConnectionToken(); const QUuid& connectionToken = _domainHandler.getConnectionToken();
if(!connectionToken.isNull()) { if(!connectionToken.isNull()) {
const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(connectionToken); const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(connectionToken);
if (!usernameSignature.isEmpty()) { if (!usernameSignature.isEmpty()) {
qCDebug(networking) << "Including username signature in domain connect request."; packetStream << accountInfo.getUsername() << usernameSignature;
packetStream << usernameSignature;
} }
} }
} }
@ -462,7 +463,6 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket>
// refuse to process this packet if we aren't currently connected to the DS // refuse to process this packet if we aren't currently connected to the DS
return; return;
} }
// read in the connection token from the packet, then send domain-server checkin // read in the connection token from the packet, then send domain-server checkin
_domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID))); _domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID)));
sendDomainServerCheckIn(); sendDomainServerCheckIn();

View file

@ -26,8 +26,8 @@ const QSet<PacketType::Value> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType::Value
const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>() const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>()
<< StunResponse << CreateAssignment << RequestAssignment << StunResponse << CreateAssignment << RequestAssignment
<< DomainServerRequireDTLS << DomainConnectRequest << DomainServerRequireDTLS << DomainConnectRequest << DomainServerConnectionToken
<< DomainList << DomainConnectionDenied << DomainServerConnectionToken << DomainList << DomainConnectionDenied
<< DomainServerPathQuery << DomainServerPathResponse << DomainServerPathQuery << DomainServerPathResponse
<< DomainServerAddedNode << DomainServerAddedNode
<< ICEServerPeerInformation << ICEServerQuery << ICEServerHeartbeat << ICEServerPeerInformation << ICEServerQuery << ICEServerHeartbeat