mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Implement static cert verification correctly
This commit is contained in:
parent
0dc6211a7d
commit
74180bc4cd
6 changed files with 49 additions and 75 deletions
|
@ -459,9 +459,7 @@ void EntityServer::startDynamicDomainVerification() {
|
|||
EntityItemPointer entity = tree->findEntityByEntityItemID(i.value());
|
||||
|
||||
if (entity) {
|
||||
// ZRF FIXME!!!
|
||||
//if (!entity->verifyStaticCertificateProperties()) {
|
||||
if (false) {
|
||||
if (!entity->verifyStaticCertificateProperties()) {
|
||||
qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed"
|
||||
<< "static certificate verification.";
|
||||
// Delete the entity if it doesn't pass static certificate verification
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <QtEndian>
|
||||
#include <QJsonDocument>
|
||||
#include <openssl/rsa.h> // see comments for DEBUG_CERT
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
|
@ -41,6 +45,7 @@ int entityItemPointernMetaTypeId = qRegisterMetaType<EntityItemPointer>();
|
|||
|
||||
int EntityItem::_maxActionsDataSize = 800;
|
||||
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
|
||||
QString EntityItem::_marketplacePublicKey;
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||
SpatiallyNestable(NestableType::Entity, entityItemID)
|
||||
|
@ -1588,16 +1593,16 @@ QByteArray EntityItem::getStaticCertificateJSON() const {
|
|||
// It is important that this be reproducible in the same order each time. Since we also generate these on the server, we do it alphabetically
|
||||
// to help maintainence in two different code bases.
|
||||
if (!propertySet.getAnimation().getURL().isEmpty()) {
|
||||
json["animation.url"] = propertySet.getAnimation().getURL();
|
||||
json["animationURL"] = propertySet.getAnimation().getURL();
|
||||
}
|
||||
ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL);
|
||||
ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL);
|
||||
ADD_INT_PROPERTY(editionNumber, EditionNumber);
|
||||
ADD_INT_PROPERTY(entityInstanceNumber, EntityInstanceNumber);
|
||||
ADD_INT_PROPERTY(instanceNumber, EntityInstanceNumber);
|
||||
ADD_STRING_PROPERTY(itemArtist, ItemArtist);
|
||||
ADD_STRING_PROPERTY(itemCategories, ItemCategories);
|
||||
ADD_STRING_PROPERTY(itemDescription, ItemDescription);
|
||||
ADD_STRING_PROPERTY(itemLicense, ItemLicense);
|
||||
ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense);
|
||||
ADD_STRING_PROPERTY(itemName, ItemName);
|
||||
ADD_INT_PROPERTY(limitedRun, LimitedRun);
|
||||
ADD_STRING_PROPERTY(marketplaceID, MarketplaceID);
|
||||
|
@ -1612,39 +1617,6 @@ QByteArray EntityItem::getStaticCertificateHash() const {
|
|||
return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CERT
|
||||
QString EntityItem::computeCertificateID() {
|
||||
// Until the marketplace generates it, compute and answer the certificateID here.
|
||||
// Does not set it, as that will have to be done from script engine in order to update server, etc.
|
||||
const auto hash = getStaticCertificateHash();
|
||||
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
|
||||
const unsigned int textLength = hash.length();
|
||||
|
||||
const char privateKey[] = "-----BEGIN RSA PRIVATE KEY-----\n\
|
||||
MIIBOQIBAAJBALCoBiDAZOClO26tC5pd7JikBL61WIgpAqbcNnrV/TcG6LPI7Zbi\n\
|
||||
MjdUixmTNvYMRZH3Wlqtl2IKG1W68y3stKECAwEAAQJABvOlwhYwIhL+gr12jm2R\n\
|
||||
yPPzZ9nVEQ6kFxLlZfIT09119fd6OU1X5d4sHWfMfSIEgjwQIDS3ZU1kY3XKo87X\n\
|
||||
zQIhAOPHlYa1OC7BLhaTouy68qIU2vCKLP8mt4S31/TT0UOnAiEAxor6gU6yupTQ\n\
|
||||
yuyV3yHvr5LkZKBGqhjmOTmDfgtX7ncCIChGbgX3nQuHVOLhD/nTxHssPNozVGl5\n\
|
||||
KxHof+LmYSYZAiB4U+yEh9SsXdq40W/3fpLMPuNq1PRezJ5jGidGMcvF+wIgUNec\n\
|
||||
3Kg2U+CVZr8/bDT/vXRrsKj1zfobYuvbfVH02QY=\n\
|
||||
-----END RSA PRIVATE KEY-----";
|
||||
BIO* bio = BIO_new_mem_buf((void*)privateKey, sizeof(privateKey));
|
||||
RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
|
||||
|
||||
QByteArray signature(RSA_size(rsa), 0);
|
||||
unsigned int signatureLength = 0;
|
||||
const int signOK = RSA_sign(NID_sha256, text, textLength, reinterpret_cast<unsigned char*>(signature.data()), &signatureLength, rsa);
|
||||
BIO_free(bio);
|
||||
RSA_free(rsa);
|
||||
if (!signOK) {
|
||||
qCWarning(entities) << "Unable to compute signature for" << getName() << getEntityItemID();
|
||||
return "";
|
||||
}
|
||||
return signature.toBase64();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EntityItem::verifyStaticCertificateProperties() {
|
||||
// True IIF a non-empty certificateID matches the static certificate json.
|
||||
// I.e., if we can verify that the certificateID was produced by High Fidelity signing the static certificate hash.
|
||||
|
@ -1659,13 +1631,8 @@ bool EntityItem::verifyStaticCertificateProperties() {
|
|||
const auto hash = getStaticCertificateHash();
|
||||
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
|
||||
const unsigned int textLength = hash.length();
|
||||
|
||||
// After DEBUG_CERT ends, we will get/cache this once from the marketplace when needed, and it likely won't be RSA.
|
||||
const char publicKey[] = "-----BEGIN PUBLIC KEY-----\n\
|
||||
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALCoBiDAZOClO26tC5pd7JikBL61WIgp\n\
|
||||
AqbcNnrV/TcG6LPI7ZbiMjdUixmTNvYMRZH3Wlqtl2IKG1W68y3stKECAwEAAQ==\n\
|
||||
-----END PUBLIC KEY-----";
|
||||
BIO *bio = BIO_new_mem_buf((void*)publicKey, sizeof(publicKey));
|
||||
|
||||
BIO *bio = BIO_new_mem_buf((void*)qPrintable(EntityItem::_marketplacePublicKey), -1);
|
||||
EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||
RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
|
||||
bool answer = RSA_verify(NID_sha256, text, textLength, signature, signatureLength, rsa);
|
||||
|
@ -3006,3 +2973,34 @@ void EntityItem::somethingChangedNotification() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::retrieveMarketplacePublicKey() {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
requestURL.setPath("/api/v1/commerce/marketplace_key");
|
||||
QJsonObject request;
|
||||
networkRequest.setUrl(requestURL);
|
||||
|
||||
QNetworkReply* networkReply = NULL;
|
||||
networkReply = networkAccessManager.get(networkRequest);
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, [=]() {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
||||
jsonObject = jsonObject["data"].toObject();
|
||||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (!jsonObject["public_key"].toString().isEmpty()) {
|
||||
EntityItem::_marketplacePublicKey = jsonObject["public_key"].toString();
|
||||
qCWarning(entities) << "Marketplace public key has been set to" << _marketplacePublicKey;
|
||||
} else {
|
||||
qCWarning(entities) << "Marketplace public key is empty!";
|
||||
}
|
||||
} else {
|
||||
qCWarning(entities) << "Call to" << networkRequest.url() << "failed! Error:" << networkReply->error();
|
||||
}
|
||||
|
||||
networkReply->deleteLater();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,9 +36,6 @@
|
|||
#include "SimulationFlags.h"
|
||||
#include "EntityDynamicInterface.h"
|
||||
|
||||
// FIXME: The server-side marketplace will soon create the certificateID. At that point, all of the DEBUG_CERT stuff will go away.
|
||||
#define DEBUG_CERT 1
|
||||
|
||||
class EntitySimulation;
|
||||
class EntityTreeElement;
|
||||
class EntityTreeElementExtraEncodeData;
|
||||
|
@ -331,9 +328,6 @@ public:
|
|||
QByteArray getStaticCertificateJSON() const;
|
||||
QByteArray getStaticCertificateHash() const;
|
||||
bool verifyStaticCertificateProperties();
|
||||
#ifdef DEBUG_CERT
|
||||
QString computeCertificateID();
|
||||
#endif
|
||||
|
||||
// TODO: get rid of users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
@ -484,6 +478,9 @@ public:
|
|||
ChangeHandlerId registerChangeHandler(const ChangeHandlerCallback& handler);
|
||||
void deregisterChangeHandler(const ChangeHandlerId& changeHandlerId);
|
||||
|
||||
static QString _marketplacePublicKey;
|
||||
static void retrieveMarketplacePublicKey();
|
||||
|
||||
protected:
|
||||
QHash<ChangeHandlerId, ChangeHandlerCallback> _changeHandlers;
|
||||
|
||||
|
@ -635,7 +632,6 @@ protected:
|
|||
quint64 _lastUpdatedVelocityTimestamp { 0 };
|
||||
quint64 _lastUpdatedAngularVelocityTimestamp { 0 };
|
||||
quint64 _lastUpdatedAccelerationTimestamp { 0 };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -1778,18 +1778,3 @@ bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& en
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CERT
|
||||
QString EntityScriptingInterface::computeCertificateID(const QUuid& entityID) {
|
||||
QString result { "" };
|
||||
if (_entityTree) {
|
||||
_entityTree->withReadLock([&] {
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
|
||||
if (entity) {
|
||||
result = entity->computeCertificateID();
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
|
@ -387,9 +387,6 @@ public slots:
|
|||
Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID);
|
||||
|
||||
Q_INVOKABLE bool verifyStaticCertificateProperties(const QUuid& entityID);
|
||||
#ifdef DEBUG_CERT
|
||||
Q_INVOKABLE QString computeCertificateID(const QUuid& entityID);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
|
|
|
@ -71,6 +71,8 @@ EntityTree::EntityTree(bool shouldReaverage) :
|
|||
Octree(shouldReaverage)
|
||||
{
|
||||
resetClientEditStats();
|
||||
|
||||
EntityItem::retrieveMarketplacePublicKey();
|
||||
}
|
||||
|
||||
EntityTree::~EntityTree() {
|
||||
|
@ -1523,9 +1525,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c
|
|||
_totalCreates++;
|
||||
|
||||
if (newEntity && isCertified && getIsServer()) {
|
||||
// ZRF FIXME!!!
|
||||
//if (!newEntity->verifyStaticCertificateProperties()) {
|
||||
if (false) {
|
||||
if (!newEntity->verifyStaticCertificateProperties()) {
|
||||
qCDebug(entities) << "User" << senderNode->getUUID()
|
||||
<< "attempted to add a certified entity with ID" << entityItemID << "which failed"
|
||||
<< "static certificate verification.";
|
||||
|
|
Loading…
Reference in a new issue