diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 762e13d8a1..11b83e1052 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2505,28 +2505,25 @@ QByteArray EntityItemProperties::getStaticCertificateHash() const { return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256); } -bool EntityItemProperties::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. +// FIXME: This is largely copied from EntityItemProperties::verifyStaticCertificateProperties, which should be refactored to use this. +// I also don't like the nested-if style, but for this step I'm deliberately preserving the similarity. +bool EntityItemProperties::verifySignature(const QString& publicKey, const QByteArray& digestByteArray, const QByteArray& signatureByteArray) { - if (getCertificateID().isEmpty()) { + if (digestByteArray.isEmpty()) { return false; } - const QByteArray marketplacePublicKeyByteArray = EntityItem::_marketplacePublicKey.toUtf8(); - const unsigned char* marketplacePublicKey = reinterpret_cast(marketplacePublicKeyByteArray.constData()); - int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length(); + const unsigned char* key = reinterpret_cast(publicKey.toUtf8().constData()); + int keyLength = publicKey.length(); - BIO *bio = BIO_new_mem_buf((void*)marketplacePublicKey, marketplacePublicKeyLength); + BIO *bio = BIO_new_mem_buf((void*)key, keyLength); EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); if (evp_key) { EC_KEY* ec = EVP_PKEY_get1_EC_KEY(evp_key); if (ec) { - const QByteArray digestByteArray = getStaticCertificateHash(); const unsigned char* digest = reinterpret_cast(digestByteArray.constData()); int digestLength = digestByteArray.length(); - const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8()); const unsigned char* signature = reinterpret_cast(signatureByteArray.constData()); int signatureLength = signatureByteArray.length(); @@ -2543,9 +2540,8 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { long error = ERR_get_error(); if (error != 0) { const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "ERROR while verifying static certificate properties! EC error:" << error_str - << "\nStatic Cert JSON:" << getStaticCertificateJSON() - << "\nKey:" << EntityItem::_marketplacePublicKey << "\nKey Length:" << marketplacePublicKeyLength + qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str + << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength << "\nDigest:" << digest << "\nDigest Length:" << digestLength << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; } @@ -2557,7 +2553,8 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { EVP_PKEY_free(evp_key); } return answer; - } else { + } + else { if (bio) { BIO_free(bio); } @@ -2566,16 +2563,23 @@ bool EntityItemProperties::verifyStaticCertificateProperties() { } long error = ERR_get_error(); const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify static certificate properties! EC error:" << error_str; + qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC key error:" << error_str; return false; } - } else { + } + else { if (bio) { BIO_free(bio); } long error = ERR_get_error(); const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify static certificate properties! EC error:" << error_str; + qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC PEM error:" << error_str; return false; } } + +bool EntityItemProperties::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. + return verifySignature(EntityItem::_marketplacePublicKey, getStaticCertificateHash(), QByteArray::fromBase64(getCertificateID().toUtf8())); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 732dbdf69f..ec192d7c9f 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -339,6 +339,7 @@ public: QByteArray getStaticCertificateJSON() const; QByteArray getStaticCertificateHash() const; bool verifyStaticCertificateProperties(); + static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature); protected: QString getCollisionMaskAsString() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bd446ab332..fb27209de4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1190,7 +1190,7 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity } QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----"; - bool verificationSuccess = verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8()); + bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8()); if (verificationSuccess) { qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded."; @@ -1201,79 +1201,6 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity return verificationSuccess; } -// FIXME: This is largely copied from EntityItemProperties::verifyStaticCertificateProperties, which should be refactored to use this. -// I also don't like the nested-if style, but for this step I'm deliberately preserving the similarity. -bool EntityTree::verifySignature(const QString& publicKey, const QByteArray& digestByteArray, const QByteArray& signatureByteArray) { - - if (digestByteArray.isEmpty()) { - return false; - } - - const unsigned char* key = reinterpret_cast(publicKey.toUtf8().constData()); - int keyLength = publicKey.length(); - - BIO *bio = BIO_new_mem_buf((void*)key, keyLength); - EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (evp_key) { - EC_KEY* ec = EVP_PKEY_get1_EC_KEY(evp_key); - if (ec) { - const unsigned char* digest = reinterpret_cast(digestByteArray.constData()); - int digestLength = digestByteArray.length(); - - const unsigned char* signature = reinterpret_cast(signatureByteArray.constData()); - int signatureLength = signatureByteArray.length(); - - ERR_clear_error(); - // ECSDA verification prototype: note that type is currently ignored - // int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, - // const unsigned char *sig, int siglen, EC_KEY *eckey); - bool answer = ECDSA_verify(0, - digest, - digestLength, - signature, - signatureLength, - ec); - long error = ERR_get_error(); - if (error != 0) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str - << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength - << "\nDigest:" << digest << "\nDigest Length:" << digestLength - << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; - } - EC_KEY_free(ec); - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - return answer; - } - else { - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC key error:" << error_str; - return false; - } - } - else { - if (bio) { - BIO_free(bio); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC PEM error:" << error_str; - return false; - } -} - void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { int certIDByteArraySize; int textByteArraySize; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 747a73ebd7..11a747d624 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -277,7 +277,6 @@ public: QByteArray computeNonce(const QString& certID, const QString ownerKey); bool verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id); - static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature); void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; }