示例#1
0
boost::optional<PublicKey>
parseBase58 (TokenType type, std::string const& s)
{
    auto const result = decodeBase58Token(s, type);
    auto const pks = makeSlice(result);
    if (!publicKeyType(pks))
        return boost::none;
    return PublicKey(pks);
}
示例#2
0
boost::optional<PublicKey>
parseBase58 (TokenType type, std::string const& s)
{
    auto const result =
        decodeBase58Token(s, type);
    if (result.empty())
        return boost::none;
    if (result.size() != 33)
        return boost::none;
    return PublicKey(makeSlice(result));
}
示例#3
0
PublicKey PublicKey::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
{
	QString pem;
	if(!stringFromFile(fileName, &pem))
	{
		if(result)
			*result = ErrorFile;
		return PublicKey();
	}
	return fromPEM(pem, result, provider);
}
示例#4
0
boost::optional<Manifest>
Manifest::make_Manifest (std::string s)
{
    try
    {
        STObject st (sfGeneric);
        SerialIter sit (s.data (), s.size ());
        st.set (sit);
        auto const pk = st.getFieldVL (sfPublicKey);
        if (! publicKeyType (makeSlice(pk)))
            return boost::none;

        auto const opt_seq = get (st, sfSequence);
        auto const opt_msig = get (st, sfMasterSignature);
        if (!opt_seq || !opt_msig)
            return boost::none;

        // Signing key and signature are not required for
        // master key revocations
        if (*opt_seq != std::numeric_limits<std::uint32_t>::max ())
        {
            auto const spk = st.getFieldVL (sfSigningPubKey);
            if (! publicKeyType (makeSlice(spk)))
                return boost::none;
            auto const opt_sig = get (st, sfSignature);
            if (! opt_sig)
                return boost::none;

            return Manifest (std::move (s), PublicKey (makeSlice(pk)),
                PublicKey (makeSlice(spk)), *opt_seq);
        }

        return Manifest (std::move (s), PublicKey (makeSlice(pk)),
            PublicKey(), *opt_seq);
    }
    catch (std::exception const&)
    {
        return boost::none;
    }
}
示例#5
0
	QCA::PGPKey GlooxAccount::GetEntryKey (QObject *entryObj) const
	{
		ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj);
		if (!entry)
		{
			qWarning () << Q_FUNC_INFO
					<< entryObj
					<< "doesn't implement ICLEntry";
			return QCA::PGPKey ();
		}

		auto mgr = ClientConnection_->GetCryptHandler ()->GetPGPManager ();
		return mgr->PublicKey (entry->GetHumanReadableID ());
	}
示例#6
0
STValidation::STValidation (SerialIter& sit, bool checkSignature)
    : STObject (getFormat (), sit, sfValidation)
{
    mNodeID = calcNodeID(
        PublicKey(makeSlice (getFieldVL (sfSigningPubKey))));
    assert (mNodeID.isNonZero ());

    if  (checkSignature && !isValid ())
    {
        JLOG (debugLog().error())
            << "Invalid validation" << getJson (0);
        Throw<std::runtime_error> ("Invalid validation");
    }
}
示例#7
0
NotTEC
Transactor::checkSingleSign (PreclaimContext const& ctx)
{
    auto const id = ctx.tx.getAccountID(sfAccount);

    auto const sle = ctx.view.read(
        keylet::account(id));
    auto const hasAuthKey     = sle->isFieldPresent (sfRegularKey);

    // Consistency: Check signature & verify the transaction's signing
    // public key is authorized for signing.
    auto const spk = ctx.tx.getSigningPubKey();
    if (!publicKeyType (makeSlice (spk)))
    {
        JLOG(ctx.j.trace()) <<
            "checkSingleSign: signing public key type is unknown";
        return tefBAD_AUTH; // FIXME: should be better error!
    }

    auto const pkAccount = calcAccountID (
        PublicKey (makeSlice (spk)));

    if (pkAccount == id)
    {
        // Authorized to continue.
        if (sle->isFlag(lsfDisableMaster))
            return tefMASTER_DISABLED;
    }
    else if (hasAuthKey &&
        (pkAccount == sle->getAccountID (sfRegularKey)))
    {
        // Authorized to continue.
    }
    else if (hasAuthKey)
    {
        JLOG(ctx.j.trace()) <<
            "checkSingleSign: Not authorized to use account.";
        return tefBAD_AUTH;
    }
    else
    {
        JLOG(ctx.j.trace()) <<
            "checkSingleSign: Not authorized to use account.";
        return tefBAD_AUTH_MASTER;
    }

    return tesSUCCESS;
}
示例#8
0
IPTransportInfo::IPTransportInfo(ITransportConnectionInfoPtr connectionInfo)
    : GenericTransportInfo(connectionInfo->getServerType(), ProtocolMetaData())
{
    if (!connectionInfo || connectionInfo->getConnectionInfo().empty()) {
        KAA_LOG_ERROR("Failed to create IP transport data: bad input data");
        throw KaaException("Bad connection data");
    }

    serverType_ = connectionInfo->getServerType();
    connectionData_ = connectionInfo->getConnectionInfo();
    accessPointId_ = connectionInfo->getAccessPointId();
    protocolId_ = connectionInfo->getTransportId();

    std::uint8_t *data = connectionData_.data();
    std::int32_t publicKeyLength = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data));
    data += sizeof(std::int32_t);

    publicKey_ = PublicKey(data, publicKeyLength);
    data += publicKeyLength;

    std::int32_t hostLength = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data));
    data += sizeof(std::int32_t);
    host_.assign(data, data + hostLength);
    data += hostLength;

    port_ = boost::asio::detail::socket_ops::network_to_host_long(*((int32_t *)data));

    std::ostringstream ss;
    ss << "http://" << host_ << ":" << port_;
    url_.assign(ss.str());

    if ((3 * sizeof(std::int32_t) + publicKeyLength + hostLength) > connectionData_.size()) {
        KAA_LOG_ERROR("Failed to create IP transport data: less size of input data than needed");
        throw KaaException("Bad connection data");
    }

    KAA_LOG_TRACE(boost::format("Create IP transport data: host=%1%, port=%2%, publicKeyLength=%3%") % host_% port_ % publicKey_.size());
}
示例#9
0
	bool PgpManager::handleStanza (const QDomElement& stanza)
	{
		const auto& tagName = stanza.tagName ();
		if ("message" != tagName && "presence" != tagName)
			return false;

		const auto& from = stanza.attribute ("from");

		// Case 1: signed presence|message
		const auto& x_element = stanza.firstChildElement ("x");
		if (x_element.namespaceURI () == NsSigned)
		{
			const auto& status = stanza.firstChildElement ("status");
			const auto& message = status.text ();
			const auto& signature = x_element.text ();

			const QCA::PGPKey key = PublicKey (from);

			if (!IsValidSignature (key, message.toUtf8 (), signature.toLatin1 ()))
				emit invalidSignatureReceived (from);
			else if (tagName == "message")
				emit signedMessageReceived (from);
			else if (tagName == "presence")
				emit signedPresenceReceived (from);
		}

		// Case 2: encrypted message
		if (x_element.namespaceURI () == NsEncrypted)
		{
			const auto& encryptedBodyStr = x_element.text ();
			const auto& encryptedBody = encryptedBodyStr.toLatin1 ();
			const auto& decryptedBody = DecryptBody (encryptedBody);
			if (!decryptedBody.isEmpty ())
				emit encryptedMessageReceived (from, QString::fromUtf8 (decryptedBody));
		}

		return false;
	}
示例#10
0
std::uint64_t
SetRegularKey::calculateBaseFee (
    PreclaimContext const& ctx)
{
    auto const id = ctx.tx.getAccountID(sfAccount);
    auto const spk = ctx.tx.getSigningPubKey();

    if (publicKeyType (makeSlice (spk)))
    {
        if (calcAccountID(PublicKey (makeSlice(spk))) == id)
        {
            auto const sle = ctx.view.read(keylet::account(id));

            if (sle && (! (sle->getFlags () & lsfPasswordSpent)))
            {
                // flag is armed and they signed with the right account
                return 0;
            }
        }
    }

    return Transactor::calculateBaseFee (ctx);
}
示例#11
0
std::pair<bool, std::string> STTx::checkSingleSign () const
{
    // We don't allow both a non-empty sfSigningPubKey and an sfSigners.
    // That would allow the transaction to be signed two ways.  So if both
    // fields are present the signature is invalid.
    if (isFieldPresent (sfSigners))
        return {false, "Cannot both single- and multi-sign."};

    bool validSig = false;
    try
    {
        bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig);
        auto const spk = getFieldVL (sfSigningPubKey);

        if (publicKeyType (makeSlice(spk)))
        {
            Blob const signature = getFieldVL (sfTxnSignature);
            Blob const data = getSigningData (*this);

            validSig = verify (
                PublicKey (makeSlice(spk)),
                makeSlice(data),
                makeSlice(signature),
                fullyCanonical);
        }
    }
    catch (std::exception const&)
    {
        // Assume it was a signature failure.
        validSig = false;
    }
    if (validSig == false)
        return {false, "Invalid signature."};

    return {true, ""};
}
示例#12
0
int wmain(
	_In_ int argc, 
	_In_ wchar_t* argv[])
{
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
int main(int argc, char *argv[])
{
#endif

#if defined(ENABLE_LIBSODIUM)
//Libsodium initialization
	if (sodium_init() != EXIT_SUCCESS)
	{
		wprintf_s(L"Libsodium initialization error\n");
#if defined(PLATFORM_WIN)
		system("Pause");
#endif

		return EXIT_FAILURE;
	}

	FILE *Output = nullptr;
//Output.
#if defined(PLATFORM_WIN)
	_wfopen_s(&Output, L"KeyPair.txt", L"w+,ccs=UTF-8");
#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
	Output = fopen("KeyPair.txt", "w+");
#endif
	if (Output != nullptr)
	{
	//Initialization and make keypair.
		size_t Index = 0;
		std::shared_ptr<char> Buffer(new char[KEYPAIR_MESSAGE_LEN]());
		std::shared_ptr<uint8_t> PublicKey(new uint8_t[crypto_box_PUBLICKEYBYTES]()), SecretKey(new uint8_t[crypto_box_SECRETKEYBYTES]());
		memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN);
		memset(PublicKey.get(), 0, crypto_box_PUBLICKEYBYTES);
		memset(SecretKey.get(), 0, crypto_box_SECRETKEYBYTES);
		crypto_box_keypair(PublicKey.get(), SecretKey.get());

	//Write public key.
		memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN);
		if (sodium_bin2hex(Buffer.get(), KEYPAIR_MESSAGE_LEN, PublicKey.get(), crypto_box_PUBLICKEYBYTES) == nullptr)
			wprintf_s(L"Create ramdom key pair failed, please try again.\n");
		CaseConvert(true, Buffer.get(), KEYPAIR_MESSAGE_LEN);
		fwprintf_s(Output, L"Client Public Key = ");
		for (Index = 0;Index < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN);++Index)
		{
			if (Index > 0 && Index % KEYPAIR_INTERVAL == 0 && Index + 1U < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN))
				fwprintf_s(Output, L":");

			fwprintf_s(Output, L"%c", Buffer.get()[Index]);
		}
		memset(Buffer.get(), 0, KEYPAIR_MESSAGE_LEN);
		fwprintf_s(Output, L"\n");

	//Write secret key.
		if (sodium_bin2hex(Buffer.get(), KEYPAIR_MESSAGE_LEN, SecretKey.get(), crypto_box_SECRETKEYBYTES) == nullptr)
			wprintf_s(L"Create ramdom key pair failed, please try again.\n");
		CaseConvert(true, Buffer.get(), KEYPAIR_MESSAGE_LEN);
		fwprintf_s(Output, L"Client Secret Key = ");
		for (Index = 0;Index < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN);++Index)
		{
			if (Index > 0 && Index % KEYPAIR_INTERVAL == 0 && Index + 1U < strnlen_s(Buffer.get(), KEYPAIR_MESSAGE_LEN))
				fwprintf_s(Output, L":");

			fwprintf_s(Output, L"%c", Buffer.get()[Index]);
		}
		fwprintf_s(Output, L"\n");

	//Close file.
		fclose(Output);
	}
	else {
		wprintf_s(L"Cannot create target file(KeyPair.txt)\n");
	#if defined(PLATFORM_WIN)
		system("Pause");
	#endif

		return EXIT_FAILURE;
	}

	wprintf_s(L"Create ramdom key pair success, please check KeyPair.txt.\n\n");
#if defined(PLATFORM_WIN)
	system("Pause");
#endif
#else
	#if defined(PLATFORM_WIN)
		wprintf_s(L"LibSodium is disable.\n\n");
		system("Pause");
	#elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX))
		wprintf(L"LibSodium is disable.\n\n");
	#endif
#endif

	return EXIT_SUCCESS;
}

//Convert lowercase/uppercase words to uppercase/lowercase words(Character version)
#if defined(ENABLE_LIBSODIUM)
void __fastcall CaseConvert(
	_In_ const bool IsLowerToUpper, 
	_Inout_ char *Buffer, 
	_In_ const size_t Length)
{
	for (size_t Index = 0;Index < Length;++Index)
	{
	//Lowercase to uppercase
		if (IsLowerToUpper)
			Buffer[Index] = (char)toupper(Buffer[Index]);
	//Uppercase to lowercase
		else 
			Buffer[Index] = (char)tolower(Buffer[Index]);
	}

	return;
}
示例#13
0
	PublicKey getPublicKey() const
	{
		return PublicKey(encryptExponent, modulus);
	}
示例#14
0
void ServerConfiguration::createTemplateConfigurationFile(QString const& filename) {
	ServerConfiguration sc("localhost", 12345, PublicKey(), "https://localhost/identity/%1", "OpenMittsu/1.0A", "", "https://localhost/%1", "https://localhost/%1/done", "https://localhost/upload", "OpenMittsu/1.0A", "");
	sc.toFile(filename);
}
示例#15
0
NotTEC
Transactor::checkMultiSign (PreclaimContext const& ctx)
{
    auto const id = ctx.tx.getAccountID(sfAccount);
    // Get mTxnAccountID's SignerList and Quorum.
    std::shared_ptr<STLedgerEntry const> sleAccountSigners =
        ctx.view.read (keylet::signers(id));
    // If the signer list doesn't exist the account is not multi-signing.
    if (!sleAccountSigners)
    {
        JLOG(ctx.j.trace()) <<
            "applyTransaction: Invalid: Not a multi-signing account.";
        return tefNOT_MULTI_SIGNING;
    }

    // We have plans to support multiple SignerLists in the future.  The
    // presence and defaulted value of the SignerListID field will enable that.
    assert (sleAccountSigners->isFieldPresent (sfSignerListID));
    assert (sleAccountSigners->getFieldU32 (sfSignerListID) == 0);

    auto accountSigners =
        SignerEntries::deserialize (*sleAccountSigners, ctx.j, "ledger");
    if (accountSigners.second != tesSUCCESS)
        return accountSigners.second;

    // Get the array of transaction signers.
    STArray const& txSigners (ctx.tx.getFieldArray (sfSigners));

    // Walk the accountSigners performing a variety of checks and see if
    // the quorum is met.

    // Both the multiSigners and accountSigners are sorted by account.  So
    // matching multi-signers to account signers should be a simple
    // linear walk.  *All* signers must be valid or the transaction fails.
    std::uint32_t weightSum = 0;
    auto iter = accountSigners.first.begin ();
    for (auto const& txSigner : txSigners)
    {
        AccountID const txSignerAcctID = txSigner.getAccountID (sfAccount);

        // Attempt to match the SignerEntry with a Signer;
        while (iter->account < txSignerAcctID)
        {
            if (++iter == accountSigners.first.end ())
            {
                JLOG(ctx.j.trace()) <<
                    "applyTransaction: Invalid SigningAccount.Account.";
                return tefBAD_SIGNATURE;
            }
        }
        if (iter->account != txSignerAcctID)
        {
            // The SigningAccount is not in the SignerEntries.
            JLOG(ctx.j.trace()) <<
                "applyTransaction: Invalid SigningAccount.Account.";
            return tefBAD_SIGNATURE;
        }

        // We found the SigningAccount in the list of valid signers.  Now we
        // need to compute the accountID that is associated with the signer's
        // public key.
        auto const spk = txSigner.getFieldVL (sfSigningPubKey);

        if (!publicKeyType (makeSlice(spk)))
        {
            JLOG(ctx.j.trace()) <<
                "checkMultiSign: signing public key type is unknown";
            return tefBAD_SIGNATURE;
        }

        AccountID const signingAcctIDFromPubKey =
            calcAccountID(PublicKey (makeSlice(spk)));

        // Verify that the signingAcctID and the signingAcctIDFromPubKey
        // belong together.  Here is are the rules:
        //
        //   1. "Phantom account": an account that is not in the ledger
        //      A. If signingAcctID == signingAcctIDFromPubKey and the
        //         signingAcctID is not in the ledger then we have a phantom
        //         account.
        //      B. Phantom accounts are always allowed as multi-signers.
        //
        //   2. "Master Key"
        //      A. signingAcctID == signingAcctIDFromPubKey, and signingAcctID
        //         is in the ledger.
        //      B. If the signingAcctID in the ledger does not have the
        //         asfDisableMaster flag set, then the signature is allowed.
        //
        //   3. "Regular Key"
        //      A. signingAcctID != signingAcctIDFromPubKey, and signingAcctID
        //         is in the ledger.
        //      B. If signingAcctIDFromPubKey == signingAcctID.RegularKey (from
        //         ledger) then the signature is allowed.
        //
        // No other signatures are allowed.  (January 2015)

        // In any of these cases we need to know whether the account is in
        // the ledger.  Determine that now.
        auto sleTxSignerRoot =
            ctx.view.read (keylet::account(txSignerAcctID));

        if (signingAcctIDFromPubKey == txSignerAcctID)
        {
            // Either Phantom or Master.  Phantoms automatically pass.
            if (sleTxSignerRoot)
            {
                // Master Key.  Account may not have asfDisableMaster set.
                std::uint32_t const signerAccountFlags =
                    sleTxSignerRoot->getFieldU32 (sfFlags);

                if (signerAccountFlags & lsfDisableMaster)
                {
                    JLOG(ctx.j.trace()) <<
                        "applyTransaction: Signer:Account lsfDisableMaster.";
                    return tefMASTER_DISABLED;
                }
            }
        }
        else
        {
            // May be a Regular Key.  Let's find out.
            // Public key must hash to the account's regular key.
            if (!sleTxSignerRoot)
            {
                JLOG(ctx.j.trace()) <<
                    "applyTransaction: Non-phantom signer lacks account root.";
                return tefBAD_SIGNATURE;
            }

            if (!sleTxSignerRoot->isFieldPresent (sfRegularKey))
            {
                JLOG(ctx.j.trace()) <<
                    "applyTransaction: Account lacks RegularKey.";
                return tefBAD_SIGNATURE;
            }
            if (signingAcctIDFromPubKey !=
                sleTxSignerRoot->getAccountID (sfRegularKey))
            {
                JLOG(ctx.j.trace()) <<
                    "applyTransaction: Account doesn't match RegularKey.";
                return tefBAD_SIGNATURE;
            }
        }
        // The signer is legitimate.  Add their weight toward the quorum.
        weightSum += iter->weight;
    }

    // Cannot perform transaction if quorum is not met.
    if (weightSum < sleAccountSigners->getFieldU32 (sfSignerQuorum))
    {
        JLOG(ctx.j.trace()) <<
            "applyTransaction: Signers failed to meet quorum.";
        return tefBAD_QUORUM;
    }

    // Met the quorum.  Continue.
    return tesSUCCESS;
}
示例#16
0
PublicKey STValidation::getSignerPublic () const
{
    return PublicKey(makeSlice (getFieldVL (sfSigningPubKey)));
}
示例#17
0
ListDisposition
ValidatorList::applyList (
    std::string const& manifest,
    std::string const& blob,
    std::string const& signature,
    std::uint32_t version)
{
    if (version != requiredListVersion)
        return ListDisposition::unsupported_version;

    boost::unique_lock<boost::shared_mutex> lock{mutex_};

    Json::Value list;
    PublicKey pubKey;
    auto const result = verify (list, pubKey, manifest, blob, signature);
    if (result != ListDisposition::accepted)
        return result;

    // Update publisher's list
    Json::Value const& newList = list["validators"];
    publisherLists_[pubKey].available = true;
    publisherLists_[pubKey].sequence = list["sequence"].asUInt ();
    publisherLists_[pubKey].expiration = TimeKeeper::time_point{
        TimeKeeper::duration{list["expiration"].asUInt()}};
    std::vector<PublicKey>& publisherList = publisherLists_[pubKey].list;

    std::vector<PublicKey> oldList = publisherList;
    publisherList.clear ();
    publisherList.reserve (newList.size ());
    std::vector<std::string> manifests;
    for (auto const& val : newList)
    {
        if (val.isObject () &&
            val.isMember ("validation_public_key") &&
            val["validation_public_key"].isString ())
        {
            std::pair<Blob, bool> ret (strUnHex (
                val["validation_public_key"].asString ()));

            if (! ret.second || ! ret.first.size ())
            {
                JLOG (j_.error()) <<
                    "Invalid node identity: " <<
                    val["validation_public_key"].asString ();
            }
            else
            {
                publisherList.push_back (
                    PublicKey(Slice{ ret.first.data (), ret.first.size() }));
            }

            if (val.isMember ("manifest") && val["manifest"].isString ())
                manifests.push_back(val["manifest"].asString ());
        }
    }

    // Update keyListings_ for added and removed keys
    std::sort (
        publisherList.begin (),
        publisherList.end ());

    auto iNew = publisherList.begin ();
    auto iOld = oldList.begin ();
    while (iNew != publisherList.end () ||
        iOld != oldList.end ())
    {
        if (iOld == oldList.end () ||
            (iNew != publisherList.end () &&
            *iNew < *iOld))
        {
            // Increment list count for added keys
            ++keyListings_[*iNew];
            ++iNew;
        }
        else if (iNew == publisherList.end () ||
            (iOld != oldList.end () && *iOld < *iNew))
        {
            // Decrement list count for removed keys
            if (keyListings_[*iOld] <= 1)
                keyListings_.erase (*iOld);
            else
                --keyListings_[*iOld];
            ++iOld;
        }
        else
        {
            ++iNew;
            ++iOld;
        }
    }

    if (publisherList.empty())
    {
        JLOG (j_.warn()) <<
            "No validator keys included in valid list";
    }

    for (auto const& valManifest : manifests)
    {
        auto m = Manifest::make_Manifest (
            beast::detail::base64_decode(valManifest));

        if (! m || ! keyListings_.count (m->masterKey))
        {
            JLOG (j_.warn()) <<
                "List for " << strHex(pubKey) <<
                " contained untrusted validator manifest";
            continue;
        }

        auto const result = validatorManifests_.applyManifest (std::move(*m));
        if (result == ManifestDisposition::invalid)
        {
            JLOG (j_.warn()) <<
                "List for " << strHex(pubKey) <<
                " contained invalid validator manifest";
        }
    }

    return ListDisposition::accepted;
}
示例#18
0
std::pair<bool, std::string> STTx::checkMultiSign () const
{
    // Make sure the MultiSigners are present.  Otherwise they are not
    // attempting multi-signing and we just have a bad SigningPubKey.
    if (!isFieldPresent (sfSigners))
        return {false, "Empty SigningPubKey."};

    // We don't allow both an sfSigners and an sfTxnSignature.  Both fields
    // being present would indicate that the transaction is signed both ways.
    if (isFieldPresent (sfTxnSignature))
        return {false, "Cannot both single- and multi-sign."};

    STArray const& signers {getFieldArray (sfSigners)};

    // There are well known bounds that the number of signers must be within.
    if (signers.size() < minMultiSigners || signers.size() > maxMultiSigners)
        return {false, "Invalid Signers array size."};

    // We can ease the computational load inside the loop a bit by
    // pre-constructing part of the data that we hash.  Fill a Serializer
    // with the stuff that stays constant from signature to signature.
    Serializer const dataStart {startMultiSigningData (*this)};

    // We also use the sfAccount field inside the loop.  Get it once.
    auto const txnAccountID = getAccountID (sfAccount);

    // Determine whether signatures must be full canonical.
    bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig);

    // Signers must be in sorted order by AccountID.
    AccountID lastAccountID (beast::zero);

    for (auto const& signer : signers)
    {
        auto const accountID = signer.getAccountID (sfAccount);

        // The account owner may not multisign for themselves.
        if (accountID == txnAccountID)
            return {false, "Invalid multisigner."};

        // No duplicate signers allowed.
        if (lastAccountID == accountID)
            return {false, "Duplicate Signers not allowed."};

        // Accounts must be in order by account ID.  No duplicates allowed.
        if (lastAccountID > accountID)
            return {false, "Unsorted Signers array."};

        // The next signature must be greater than this one.
        lastAccountID = accountID;

        // Verify the signature.
        bool validSig = false;
        try
        {
            Serializer s = dataStart;
            finishMultiSigningData (accountID, s);

            auto spk = signer.getFieldVL (sfSigningPubKey);

            if (publicKeyType (makeSlice(spk)))
            {
                Blob const signature =
                    signer.getFieldVL (sfTxnSignature);

                validSig = verify (
                    PublicKey (makeSlice(spk)),
                    s.slice(),
                    makeSlice(signature),
                    fullyCanonical);
            }
        }
        catch (std::exception const&)
        {
            // We assume any problem lies with the signature.
            validSig = false;
        }
        if (!validSig)
            return {false, std::string("Invalid signature on account ") +
                toBase58(accountID)  + "."};
    }

    // All signatures verified.
    return {true, ""};
}
示例#19
0
bool
ValidatorList::load (
    PublicKey const& localSigningKey,
    std::vector<std::string> const& configKeys,
    std::vector<std::string> const& publisherKeys)
{
    static boost::regex const re (
        "[[:space:]]*"            // skip leading whitespace
        "([[:alnum:]]+)"          // node identity
        "(?:"                     // begin optional comment block
        "[[:space:]]+"            // (skip all leading whitespace)
        "(?:"                     // begin optional comment
        "(.*[^[:space:]]+)"       // the comment
        "[[:space:]]*"            // (skip all trailing whitespace)
        ")?"                      // end optional comment
        ")?"                      // end optional comment block
    );

    boost::unique_lock<boost::shared_mutex> read_lock{mutex_};

    JLOG (j_.debug()) <<
        "Loading configured trusted validator list publisher keys";

    std::size_t count = 0;
    for (auto key : publisherKeys)
    {
        JLOG (j_.trace()) <<
            "Processing '" << key << "'";

        auto const ret = strUnHex (key);

        if (! ret.second || ! ret.first.size ())
        {
            JLOG (j_.error()) <<
                "Invalid validator list publisher key: " << key;
            return false;
        }

        auto id = PublicKey(Slice{ ret.first.data (), ret.first.size() });

        if (validatorManifests_.revoked (id))
        {
            JLOG (j_.warn()) <<
                "Configured validator list publisher key is revoked: " << key;
            continue;
        }

        if (publisherLists_.count(id))
        {
            JLOG (j_.warn()) <<
                "Duplicate validator list publisher key: " << key;
            continue;
        }

        publisherLists_[id].available = false;
        ++count;
    }

    JLOG (j_.debug()) <<
        "Loaded " << count << " keys";

    localPubKey_ = validatorManifests_.getMasterKey (localSigningKey);

    // Treat local validator key as though it was listed in the config
    if (localPubKey_.size())
        keyListings_.insert ({ localPubKey_, 1 });

    JLOG (j_.debug()) <<
        "Loading configured validator keys";

    count = 0;
    PublicKey local;
    for (auto const& n : configKeys)
    {
        JLOG (j_.trace()) <<
            "Processing '" << n << "'";

        boost::smatch match;

        if (!boost::regex_match (n, match, re))
        {
            JLOG (j_.error()) <<
                "Malformed entry: '" << n << "'";
            return false;
        }

        auto const id = parseBase58<PublicKey>(
            TokenType::TOKEN_NODE_PUBLIC, match[1]);

        if (!id)
        {
            JLOG (j_.error()) << "Invalid node identity: " << match[1];
            return false;
        }

        // Skip local key which was already added
        if (*id == localPubKey_ || *id == localSigningKey)
            continue;

        auto ret = keyListings_.insert ({*id, 1});
        if (! ret.second)
        {
            JLOG (j_.warn()) << "Duplicate node identity: " << match[1];
            continue;
        }
        auto it = publisherLists_.emplace(
            std::piecewise_construct,
            std::forward_as_tuple(local),
            std::forward_as_tuple());
        // Config listed keys never expire
        if (it.second)
            it.first->second.expiration = TimeKeeper::time_point::max();
        it.first->second.list.emplace_back(std::move(*id));
        it.first->second.available = true;
        ++count;
    }

    JLOG (j_.debug()) <<
        "Loaded " << count << " entries";

    return true;
}