mirror of
https://github.com/overte-org/overte.git
synced 2025-04-24 05:53:29 +02:00
fix up dynamic ownership challenge
This commit is contained in:
parent
16d6d8a361
commit
899999a4c6
3 changed files with 91 additions and 31 deletions
|
@ -537,7 +537,7 @@ QStringList Wallet::listPublicKeys() {
|
|||
// the horror of code pages and so on (changing the bytes) by just returning a base64
|
||||
// encoded string representing the signature (suitable for http, etc...)
|
||||
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
|
||||
qCInfo(commerce) << "Signing text.";
|
||||
qCInfo(commerce) << "Signing text" << text << "with key" << key;
|
||||
EC_KEY* ecPrivateKey = NULL;
|
||||
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
|
||||
QByteArray signature(ECDSA_size(ecPrivateKey), 0);
|
||||
|
@ -727,7 +727,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
|
|||
|
||||
if (ec) {
|
||||
ERR_clear_error();
|
||||
sig = signWithKey(text, ""); // base64 signature, QByteArray cast (on return) to QString
|
||||
sig = signWithKey(text, ""); // base64 signature, QByteArray cast (on return) to QString FIXME should pass ec as string so we can tell which key to sign with
|
||||
status = 1;
|
||||
} else {
|
||||
qCDebug(commerce) << "During entity ownership challenge, creating the EC-signed nonce failed.";
|
||||
|
@ -740,7 +740,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
|
|||
|
||||
QByteArray textByteArray;
|
||||
if (status > -1) {
|
||||
textByteArray = QByteArray(sigChar, status);
|
||||
textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
|
||||
}
|
||||
textByteArraySize = textByteArray.size();
|
||||
int certIDSize = certID.size();
|
||||
|
@ -768,7 +768,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
|
|||
textPacket->write(certID);
|
||||
textPacket->write(textByteArray);
|
||||
|
||||
qCDebug(commerce) << "Sending ChallengeOwnership Packet containing signed text" << textByteArray << "for CertID" << certID;
|
||||
qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing signed text" << textByteArray << "for CertID" << certID;
|
||||
|
||||
nodeList->sendPacket(std::move(textPacket), *sendingNode);
|
||||
}
|
||||
|
|
|
@ -1166,29 +1166,13 @@ void EntityTree::startPendingTransferStatusTimer(const QString& certID, const En
|
|||
}
|
||||
|
||||
QByteArray EntityTree::computeNonce(const QString& certID, const QString ownerKey) {
|
||||
QString ownerKeyWithHeaders = ("-----BEGIN ECDSA PUBLIC KEY-----\n" + ownerKey + "\n-----END ECDSA PUBLIC KEY-----");
|
||||
BIO* bio = BIO_new_mem_buf((void*)ownerKeyWithHeaders.toUtf8().constData(), -1);
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); // NO NEWLINE
|
||||
EC_KEY* ec = PEM_read_bio_EC_PUBKEY(bio, NULL, NULL, NULL);
|
||||
QUuid nonce = QUuid::createUuid(); //random, 5-hex value, separated by "-"
|
||||
QByteArray nonceBytes = nonce.toByteArray();
|
||||
|
||||
if (ec) {
|
||||
QUuid nonce = QUuid::createUuid(); //random, 5-hex value, separated by "-"
|
||||
QByteArray nonceBytes = nonce.toByteArray();
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
_certNonceMap.insert(certID, QPair<QUuid, QString>(nonce, ownerKey));
|
||||
|
||||
if (bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
_certNonceMap.insert(certID, nonce);
|
||||
|
||||
return nonceBytes;
|
||||
} else {
|
||||
if (bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
return nonceBytes;
|
||||
}
|
||||
|
||||
bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, EntityItemID& id) {
|
||||
|
@ -1197,24 +1181,99 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity
|
|||
id = _entityCertificateIDMap.value(certID);
|
||||
}
|
||||
|
||||
QString actualNonce;
|
||||
QString actualNonce, key;
|
||||
{
|
||||
QWriteLocker locker(&_certNonceMapLock);
|
||||
actualNonce = _certNonceMap.take(certID).toString();
|
||||
QPair<QUuid, QString> sent = _certNonceMap.take(certID);
|
||||
actualNonce = sent.first.toString();
|
||||
key = sent.second;
|
||||
}
|
||||
|
||||
bool verificationSuccess = (actualNonce == nonce);
|
||||
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----";
|
||||
bool verificationSuccess = verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8());
|
||||
|
||||
if (verificationSuccess) {
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
|
||||
} else {
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed."
|
||||
<< "\nActual nonce:" << actualNonce << "\nonce:" << nonce;
|
||||
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -277,6 +277,7 @@ 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; }
|
||||
|
||||
|
@ -334,7 +335,7 @@ protected:
|
|||
QHash<QString, EntityItemID> _entityCertificateIDMap;
|
||||
|
||||
mutable QReadWriteLock _certNonceMapLock;
|
||||
QHash<QString, QUuid> _certNonceMap;
|
||||
QHash<QString, QPair<QUuid, QString>> _certNonceMap;
|
||||
|
||||
EntitySimulationPointer _simulation;
|
||||
|
||||
|
|
Loading…
Reference in a new issue