This commit is contained in:
howard-stearns 2017-11-22 16:29:56 -08:00
parent 899999a4c6
commit abf41300dd
4 changed files with 23 additions and 92 deletions

View file

@ -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<const unsigned char*>(marketplacePublicKeyByteArray.constData());
int marketplacePublicKeyLength = marketplacePublicKeyByteArray.length();
const unsigned char* key = reinterpret_cast<const unsigned char*>(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<const unsigned char*>(digestByteArray.constData());
int digestLength = digestByteArray.length();
const QByteArray signatureByteArray = QByteArray::fromBase64(getCertificateID().toUtf8());
const unsigned char* signature = reinterpret_cast<const unsigned char*>(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()));
}

View file

@ -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;

View file

@ -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<const unsigned char*>(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<const unsigned char*>(digestByteArray.constData());
int digestLength = digestByteArray.length();
const unsigned char* signature = reinterpret_cast<const unsigned char*>(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;

View file

@ -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<AvatarData> myAvatar) { _myAvatar = myAvatar; }