From 74180bc4cd3026eb331c751014578e1ba2a29f3c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 19 Oct 2017 15:30:49 -0700 Subject: [PATCH] Implement static cert verification correctly --- .../src/entities/EntityServer.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 86 +++++++++---------- libraries/entities/src/EntityItem.h | 10 +-- .../entities/src/EntityScriptingInterface.cpp | 15 ---- .../entities/src/EntityScriptingInterface.h | 3 - libraries/entities/src/EntityTree.cpp | 6 +- 6 files changed, 49 insertions(+), 75 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 75bdb469a4..1351220714 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -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 diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 58b8dd22bf..3074bd275b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -14,9 +14,13 @@ #include #include #include -#include // see comments for DEBUG_CERT +#include #include #include +#include +#include +#include +#include #include @@ -41,6 +45,7 @@ int entityItemPointernMetaTypeId = qRegisterMetaType(); 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(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(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(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(); + }); +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c26f1694a9..ce39bbce8e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -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 _changeHandlers; @@ -635,7 +632,6 @@ protected: quint64 _lastUpdatedVelocityTimestamp { 0 }; quint64 _lastUpdatedAngularVelocityTimestamp { 0 }; quint64 _lastUpdatedAccelerationTimestamp { 0 }; - }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f5117dddc0..66a64db15e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -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 \ No newline at end of file diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 989d3dd89d..2dc31dbe7d 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -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); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba92947a2e..f8db876728 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -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.";