From 3bf8fb5d954d3562e5d57e8935478acd58adaa56 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 12 Apr 2019 16:40:41 -0700 Subject: [PATCH 1/4] Case21707 - Wallet doesn't work if user has unicode characters in windows username --- interface/src/commerce/Wallet.cpp | 134 ++++++++++++++++-------------- 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 37f28960e5..e00cd44fa9 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -96,28 +96,32 @@ int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) { } } -EC_KEY* readKeys(const char* filename) { - FILE* fp; - EC_KEY *key = NULL; - if ((fp = fopen(filename, "rt"))) { +EC_KEY* readKeys(QString filename) { + QFile file(filename); + EC_KEY* key = NULL; + if (file.open(QFile::ReadOnly)) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) { + QByteArray pemKeyBytes = file.readAll(); + BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); + if ((key = PEM_read_bio_EC_PUBKEY(bufio, NULL, NULL, NULL))) { // now read private key qCDebug(commerce) << "read public key"; - if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) { + if (key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL)) { qCDebug(commerce) << "read private key"; - fclose(fp); - return key; + BIO_free(bufio); + file.close(); + } else { + qCDebug(commerce) << "failed to read private key"; } - qCDebug(commerce) << "failed to read private key"; } else { qCDebug(commerce) << "failed to read public key"; } - fclose(fp); + BIO_free(bufio); + file.close(); } else { qCDebug(commerce) << "failed to open key file" << filename; } @@ -131,8 +135,7 @@ bool Wallet::writeBackupInstructions() { QFile outputFile(outputFilename); bool retval = false; - if (getKeyFilePath().isEmpty()) - { + if (getKeyFilePath().isEmpty()) { return false; } @@ -152,7 +155,7 @@ bool Wallet::writeBackupInstructions() { outputFile.write(text.toUtf8()); // Close the output file - outputFile.close(); + outputFile.close(); retval = true; qCDebug(commerce) << "wrote html file successfully"; @@ -165,28 +168,35 @@ bool Wallet::writeBackupInstructions() { return retval; } -bool writeKeys(const char* filename, EC_KEY* keys) { - FILE* fp; +bool writeKeys(QString filename, EC_KEY* keys) { + BIO* bio = BIO_new(BIO_s_mem()); bool retval = false; - if ((fp = fopen(filename, "wt"))) { - if (!PEM_write_EC_PUBKEY(fp, keys)) { - fclose(fp); - qCCritical(commerce) << "failed to write public key"; - return retval; - } + if (!PEM_write_bio_EC_PUBKEY(bio, keys)) { + BIO_free(bio); + qCCritical(commerce) << "failed to write public key"; + return retval; + } - if (!PEM_write_ECPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { - fclose(fp); - qCCritical(commerce) << "failed to write private key"; - return retval; - } + if (!PEM_write_bio_ECPrivateKey(bio, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { + BIO_free(bio); + qCCritical(commerce) << "failed to write private key"; + return retval; + } + QFile file(filename); + if (!file.open(QIODevice::WriteOnly)) { + const char* bio_data; + long bio_size = BIO_get_mem_data(bio, &bio_data); + + QByteArray keyBytes(bio_data, bio_size); + file.write(keyBytes); retval = true; qCDebug(commerce) << "wrote keys successfully"; - fclose(fp); + file.close(); } else { qCDebug(commerce) << "failed to open key file" << filename; } + BIO_free(bio); return retval; } @@ -215,7 +225,6 @@ QByteArray Wallet::getWallet() { } QPair generateECKeypair() { - EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1); QPair retval{}; @@ -235,7 +244,6 @@ QPair generateECKeypair() { if (publicKeyLength <= 0 || privateKeyLength <= 0) { qCDebug(commerce) << "Error getting DER public or private key from EC struct -" << ERR_get_error(); - // cleanup the EC struct EC_KEY_free(keyPair); @@ -251,8 +259,7 @@ QPair generateECKeypair() { return retval; } - - if (!writeKeys(keyFilePath().toStdString().c_str(), keyPair)) { + if (!writeKeys(keyFilePath(), keyPair)) { qCDebug(commerce) << "couldn't save keys!"; return retval; } @@ -273,13 +280,18 @@ QPair generateECKeypair() { // END copied code (which will soon change) // the public key can just go into a byte array -QByteArray readPublicKey(const char* filename) { - FILE* fp; - EC_KEY* key = NULL; - if ((fp = fopen(filename, "r"))) { +QByteArray readPublicKey(QString filename) { + QByteArray retval; + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) { + + QByteArray pemKeyBytes = file.readAll(); + BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); + + EC_KEY* key = PEM_read_bio_EC_PUBKEY(bufio, NULL, NULL, NULL); + if (key) { // file read successfully unsigned char* publicKeyDER = NULL; int publicKeyLength = i2d_EC_PUBKEY(key, &publicKeyDER); @@ -287,32 +299,35 @@ QByteArray readPublicKey(const char* filename) { // cleanup EC_KEY_free(key); - fclose(fp); qCDebug(commerce) << "parsed public key file successfully"; - QByteArray retval((char*)publicKeyDER, publicKeyLength); + retval.setRawData((char*)publicKeyDER, publicKeyLength); OPENSSL_free(publicKeyDER); - return retval; } else { qCDebug(commerce) << "couldn't parse" << filename; } - fclose(fp); + BIO_free(bufio); + file.close(); } else { qCDebug(commerce) << "couldn't open" << filename; } - return QByteArray(); + return retval; } // the private key should be read/copied into heap memory. For now, we need the EC_KEY struct // so I'll return that. -EC_KEY* readPrivateKey(const char* filename) { - FILE* fp; +EC_KEY* readPrivateKey(QString filename) { + QFile file(filename); EC_KEY* key = NULL; - if ((fp = fopen(filename, "r"))) { + if (file.open(QIODevice::ReadOnly)) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) { + + QByteArray pemKeyBytes = file.readAll(); + BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); + + if ((key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL))) { qCDebug(commerce) << "parsed private key file successfully"; } else { @@ -320,7 +335,8 @@ EC_KEY* readPrivateKey(const char* filename) { // if the passphrase is wrong, then let's not cache it DependencyManager::get()->setPassphrase(""); } - fclose(fp); + BIO_free(bufio); + file.close(); } else { qCDebug(commerce) << "couldn't open" << filename; } @@ -361,7 +377,7 @@ Wallet::Wallet() { if (wallet->getKeyFilePath().isEmpty() || !wallet->getSecurityImage()) { if (keyStatus == "preexisting") { status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING; - } else{ + } else { status = (uint) WalletStatus::WALLET_STATUS_NOT_SET_UP; } } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { @@ -569,10 +585,10 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() { } // otherwise, we have a passphrase but no keys, so we have to check - auto publicKey = readPublicKey(keyFilePath().toStdString().c_str()); + auto publicKey = readPublicKey(keyFilePath()); if (publicKey.size() > 0) { - if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) { + if (auto key = readPrivateKey(keyFilePath())) { EC_KEY_free(key); // be sure to add the public key so we don't do this over and over @@ -631,8 +647,7 @@ QStringList Wallet::listPublicKeys() { QString Wallet::signWithKey(const QByteArray& text, const QString& key) { EC_KEY* ecPrivateKey = NULL; - auto keyFilePathString = keyFilePath().toStdString(); - if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) { + if (ecPrivateKey = readPrivateKey(keyFilePath())) { unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)]; unsigned int signatureBytes = 0; @@ -641,12 +656,8 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) { QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); - - int retrn = ECDSA_sign(0, - reinterpret_cast(hashedPlaintext.constData()), - hashedPlaintext.size(), - sig, - &signatureBytes, ecPrivateKey); + int retrn = ECDSA_sign(0, reinterpret_cast(hashedPlaintext.constData()), hashedPlaintext.size(), + sig, &signatureBytes, ecPrivateKey); EC_KEY_free(ecPrivateKey); QByteArray signature(reinterpret_cast(sig), signatureBytes); @@ -682,7 +693,6 @@ void Wallet::updateImageProvider() { } void Wallet::chooseSecurityImage(const QString& filename) { - if (_securityImage) { delete _securityImage; } @@ -754,7 +764,7 @@ QString Wallet::getKeyFilePath() { } bool Wallet::writeWallet(const QString& newPassphrase) { - EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str()); + EC_KEY* keys = readKeys(keyFilePath()); auto ledger = DependencyManager::get(); // Remove any existing locker, because it will be out of date. if (!_publicKeys.isEmpty() && !ledger->receiveAt(_publicKeys.first(), _publicKeys.first(), QByteArray())) { @@ -768,7 +778,7 @@ bool Wallet::writeWallet(const QString& newPassphrase) { setPassphrase(newPassphrase); } - if (writeKeys(tempFileName.toStdString().c_str(), keys)) { + if (writeKeys(tempFileName, keys)) { if (writeSecurityImage(_securityImage, tempFileName)) { // ok, now move the temp file to the correct spot QFile(QString(keyFilePath())).remove(); @@ -834,10 +844,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize); } - EC_KEY* ec = readKeys(keyFilePath().toStdString().c_str()); + EC_KEY* ec = readKeys(keyFilePath()); QString sig; - if (ec) { + if (ec) { ERR_clear_error(); 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; From e36a8fc6a2a4a6221e970a6947a1b56847f4d398 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 12 Apr 2019 18:36:14 -0700 Subject: [PATCH 2/4] Fix osx/ubuntu build error --- interface/src/commerce/Wallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index e00cd44fa9..e6f8491053 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -110,7 +110,7 @@ EC_KEY* readKeys(QString filename) { qCDebug(commerce) << "read public key"; - if (key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL)) { + if ((key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL))) { qCDebug(commerce) << "read private key"; BIO_free(bufio); file.close(); @@ -647,7 +647,7 @@ QStringList Wallet::listPublicKeys() { QString Wallet::signWithKey(const QByteArray& text, const QString& key) { EC_KEY* ecPrivateKey = NULL; - if (ecPrivateKey = readPrivateKey(keyFilePath())) { + if ((ecPrivateKey = readPrivateKey(keyFilePath()))) { unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)]; unsigned int signatureBytes = 0; From 8f9d8372d8ea9e85afdae870a497d00b2fab91c0 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 12 Apr 2019 20:30:03 -0700 Subject: [PATCH 3/4] Public Key was getting corrupted. --- interface/src/commerce/Wallet.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index e6f8491053..2054206f87 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -302,8 +302,11 @@ QByteArray readPublicKey(QString filename) { qCDebug(commerce) << "parsed public key file successfully"; - retval.setRawData((char*)publicKeyDER, publicKeyLength); + QByteArray retval((char*)publicKeyDER, publicKeyLength); OPENSSL_free(publicKeyDER); + BIO_free(bufio); + file.close(); + return retval; } else { qCDebug(commerce) << "couldn't parse" << filename; } @@ -312,7 +315,7 @@ QByteArray readPublicKey(QString filename) { } else { qCDebug(commerce) << "couldn't open" << filename; } - return retval; + return QByteArray(); } // the private key should be read/copied into heap memory. For now, we need the EC_KEY struct @@ -387,7 +390,7 @@ Wallet::Wallet() { } else { status = (uint) WalletStatus::WALLET_STATUS_READY; } - + qCDebug(commerce) << "WALLET STATUS:" + keyStatus + " " + status; walletScriptingInterface->setWalletStatus(status); }); From 3949ca26385a2803fd9a9a8fa1b30f682c9cd5fc Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 15 Apr 2019 12:35:36 -0700 Subject: [PATCH 4/4] Remove logging and bump build. --- interface/src/commerce/Wallet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 2054206f87..5644f9ea4c 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -390,7 +390,6 @@ Wallet::Wallet() { } else { status = (uint) WalletStatus::WALLET_STATUS_READY; } - qCDebug(commerce) << "WALLET STATUS:" + keyStatus + " " + status; walletScriptingInterface->setWalletStatus(status); });