Esempio n. 1
0
bool
ManifestCache::load (
    DatabaseCon& dbCon, std::string const& dbTable,
    std::string const& configManifest,
    std::vector<std::string> const& configRevocation)
{
    load (dbCon, dbTable);

    if (! configManifest.empty())
    {
        auto mo = Manifest::make_Manifest (
            beast::detail::base64_decode(configManifest));
        if (! mo)
        {
            JLOG (j_.error()) << "Malformed validator_token in config";
            return false;
        }

        if (mo->revoked())
        {
            JLOG (j_.warn()) <<
                "Configured manifest revokes public key";
        }

        if (applyManifest (std::move(*mo)) ==
            ManifestDisposition::invalid)
        {
            JLOG (j_.error()) << "Manifest in config was rejected";
            return false;
        }
    }

    if (! configRevocation.empty())
    {
        std::string revocationStr;
        revocationStr.reserve (
            std::accumulate (configRevocation.cbegin(), configRevocation.cend(), std::size_t(0),
                [] (std::size_t init, std::string const& s)
                {
                    return init + s.size();
                }));

        for (auto const& line : configRevocation)
            revocationStr += beast::rfc2616::trim(line);

        auto mo = Manifest::make_Manifest (
            beast::detail::base64_decode(revocationStr));

        if (! mo || ! mo->revoked() ||
            applyManifest (std::move(*mo)) == ManifestDisposition::invalid)
        {
            JLOG (j_.error()) << "Invalid validator key revocation in config";
            return false;
        }
    }

    return true;
}
Esempio n. 2
0
bool Manifest::verify () const
{
    STObject st (sfGeneric);
    SerialIter sit (serialized.data (), serialized.size ());
    st.set (sit);

    // Signing key and signature are not required for
    // master key revocations
    if (! revoked () && ! ripple::verify (st, HashPrefix::manifest, signingKey))
        return false;

    return ripple::verify (
        st, HashPrefix::manifest, masterKey, sfMasterSignature);
}
Esempio n. 3
0
PGPPublicKey revoke_with_cert(const PGPPublicKey & pub, PGPPublicKey & revoke){
    if (pub.get_ASCII_Armor() != 1){
        throw std::runtime_error("Error: A public key is required.");
    }

    if (revoke.get_ASCII_Armor() != 1){
        throw std::runtime_error("Error: A revocation signature is required.");
    }

    // only expects 1 signature packet
    if (!revoke.get_packets().size()){
        throw std::runtime_error("Error: No packets found in revocation key.");
    }
    if (revoke.get_packets().size() > 1){
        std::cerr << "Warning: Multiple packets found. Only reading first packet." << std::endl;
    }
    if (revoke.get_packets()[0] -> get_tag() != 2){
        throw std::runtime_error("Error: Packet is not a signature packet");
    }

    std::string raw = revoke.get_packets()[0] -> raw();
    Tag2::Ptr tag2 = std::make_shared<Tag2>(raw);

    if ((tag2 -> get_type() != 0x20) && (tag2 -> get_type() != 0x28)){
        std::stringstream s; s << static_cast <unsigned int> (tag2->get_type());
        throw std::runtime_error("Error: Invalid signature type found: " + s.str());
    }

    // which packet to look for
    uint8_t which = (tag2 -> get_type() == 0x20)?6:14;

    std::string r_keyid = tag2 -> get_keyid();
    std::string k_keyid = "";

    if (!r_keyid.size()){
        throw std::runtime_error("Error: No key id found.");
    }

    // find key with key id
    for(Packet::Ptr const & p: pub.get_packets()){
        if (p -> get_tag() == which){
            raw = p -> raw();
            Tag6 tag6(raw);
            k_keyid = tag6.get_keyid();
            break;
        }
    }

    if (r_keyid != k_keyid){
        throw std::runtime_error("Error: Revocation Certificate does not revoke this Public Key.");
    }

    if (!verify_revoke(pub, revoke)){
        throw std::runtime_error("Error: This revocation certificate was not signed by this key.");
    }

    // Create output key
    PGPPublicKey revoked(pub);
    std::vector <Packet::Ptr> old_packets = pub.get_packets_clone();
    std::vector <Packet::Ptr> new_packets;

    unsigned int i = 0;
    // push all packets up to and including revoked packet into new packets
    do{
        new_packets.push_back(old_packets[i]);
    }
    while ((i < old_packets.size()) && (old_packets[i++] -> get_tag() != which));

    // append revocation signature to key
    new_packets.push_back(tag2);
    // append rest of packets
    while (i < old_packets.size()){
        new_packets.push_back(old_packets[i++]);
    }
    revoked.set_packets(new_packets);

    // clear out data
    tag2.reset();
    old_packets.clear();
    new_packets.clear();

    return revoked;
}
Esempio n. 4
0
PGPPublicKey revoke_uid(PGPPublicKey & pub, PGPSecretKey & pri, const std::string passphrase, const uint8_t code, const std::string & reason){
    if (pub.get_ASCII_Armor() != 1){
        throw std::runtime_error("Error: A public key is required for the first argument.");
    }
    if (pri.get_ASCII_Armor() != 2){
        throw std::runtime_error("Error: A private key is required for the second argument.");
    }

    Tag5::Ptr signer = find_signing_key(pri, 5);
    if (!signer){
        throw std::runtime_error("Error: Private signing key not found");
    }

    // find subkey
    Tag7::Ptr key = nullptr;
    std::vector <Packet::Ptr> packets = pri.get_packets();
    for(Packet::Ptr const & p : packets){
        if (p -> get_tag() == 7){
            std::string data = p -> raw();
            key = std::make_shared<Tag7>(data);
            break;
        }
    }

    if (!key){
        throw std::runtime_error("Error: No Secret Subkey packet found.");
    }

    ID::Ptr uid = find_user_id(pri);
    if (!uid){
        throw std::runtime_error("Error: No User ID packet found.");
    }

    Tag2::Ptr sig = create_sig_packet(0x30, signer);

    // add revocation subpacket
    std::vector <Tag2Subpacket::Ptr> hashed_subpackets = sig -> get_hashed_subpackets_clone();
    Tag2Sub29::Ptr revoke = std::make_shared<Tag2Sub29>();
    revoke -> set_code(code);
    revoke -> set_reason(reason);
    hashed_subpackets.push_back(revoke);
    sig -> set_hashed_subpackets(hashed_subpackets);

    // set signature data
    std::string hashed_data = to_sign_30(key, uid, sig);
    sig -> set_left16(hashed_data.substr(0, 2));
    sig -> set_mpi(pka_sign(hashed_data, signer, passphrase, sig -> get_hash()));

    // Create output key
    PGPPublicKey revoked(pub);
    std::vector <Packet::Ptr> old_packets = pub.get_packets_clone();
    std::vector <Packet::Ptr> new_packets;

    unsigned int i = 0;
    // push all packets up to and including revoked packet into new packets
    do{
        new_packets.push_back(old_packets[i]);
    }
    while ((i < old_packets.size()) && (old_packets[i++] -> get_tag() != 13));

    // append revocation signature to key
    new_packets.push_back(sig);

    // append rest of packets
    while (i < old_packets.size()){
        new_packets.push_back(old_packets[i++]);
    }
    revoked.set_packets(new_packets);

    signer.reset();
    key.reset();
    uid.reset();
    sig.reset();

    return revoked;
}
Esempio n. 5
0
ListDisposition
ValidatorList::verify (
    Json::Value& list,
    PublicKey& pubKey,
    std::string const& manifest,
    std::string const& blob,
    std::string const& signature)
{
    auto m = Manifest::make_Manifest (beast::detail::base64_decode(manifest));

    if (! m || ! publisherLists_.count (m->masterKey))
        return ListDisposition::untrusted;

    pubKey = m->masterKey;
    auto const revoked = m->revoked();

    auto const result = publisherManifests_.applyManifest (
        std::move(*m));

    if (revoked && result == ManifestDisposition::accepted)
    {
        removePublisherList (pubKey);
        publisherLists_.erase (pubKey);
    }

    if (revoked || result == ManifestDisposition::invalid)
        return ListDisposition::untrusted;

    auto const sig = strUnHex(signature);
    auto const data = beast::detail::base64_decode (blob);
    if (! sig.second ||
        ! ripple::verify (
            publisherManifests_.getSigningKey(pubKey),
            makeSlice(data),
            makeSlice(sig.first)))
        return ListDisposition::invalid;

    Json::Reader r;
    if (! r.parse (data, list))
        return ListDisposition::invalid;

    if (list.isMember("sequence") && list["sequence"].isInt() &&
        list.isMember("expiration") && list["expiration"].isInt() &&
        list.isMember("validators") && list["validators"].isArray())
    {
        auto const sequence = list["sequence"].asUInt();
        auto const expiration = TimeKeeper::time_point{
            TimeKeeper::duration{list["expiration"].asUInt()}};
        if (sequence < publisherLists_[pubKey].sequence ||
            expiration <= timeKeeper_.now())
            return ListDisposition::stale;
        else if (sequence == publisherLists_[pubKey].sequence)
            return ListDisposition::same_sequence;
    }
    else
    {
        return ListDisposition::invalid;
    }

    return ListDisposition::accepted;
}
Esempio n. 6
0
   /**
    *  @pre producers must be sorted from lowest to highest
    *  @pre if proxy is set then no producers can be voted for
    *  @pre every listed producer or proxy must have been previously registered
    *  @pre voter must authorize this action
    *  @pre voter must have previously staked some EOS for voting
    */
   void system_contract::voteproducer( const account_name voter, const account_name proxy, const std::vector<account_name>& producers ) {
      require_auth( voter );

      //validate input
      if ( proxy ) {
         eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" );
         require_recipient( proxy );
      } else {
         eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" );
         for( size_t i = 1; i < producers.size(); ++i ) {
            eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" );
         }
      }

      voters_table voters_tbl( _self, _self );
      auto voter_it = voters_tbl.find( voter );

      eosio_assert( 0 <= voter_it->staked.amount, "negative stake" );
      eosio_assert( voter_it != voters_tbl.end() && ( 0 < voter_it->staked.amount || ( voter_it->is_proxy && 0 < voter_it->proxied_votes ) ), "no stake to vote" );
      if ( voter_it->is_proxy ) {
         eosio_assert( proxy == 0 , "account registered as a proxy is not allowed to use a proxy" );
      }

      //find old producers, update old proxy if needed
      const std::vector<account_name>* old_producers = nullptr;
      if( voter_it->proxy ) {
         if ( voter_it->proxy == proxy ) {
            return; // nothing changed
         }
         auto old_proxy = voters_tbl.find( voter_it->proxy );
         eosio_assert( old_proxy != voters_tbl.end(), "old proxy not found" ); //data corruption
         voters_tbl.modify( old_proxy, 0, [&](auto& a) { a.proxied_votes -= uint64_t(voter_it->staked.amount); } );
         if ( old_proxy->is_proxy ) { //if proxy stopped being a proxy, the votes were already taken back from producers by on( const unregister_proxy& )
            old_producers = &old_proxy->producers;
         }
      } else {
         old_producers = &voter_it->producers;
      }

      //find new producers, update new proxy if needed
      const std::vector<account_name>* new_producers = nullptr;
      if ( proxy ) {
         auto new_proxy = voters_tbl.find( proxy );
         eosio_assert( new_proxy != voters_tbl.end() && new_proxy->is_proxy, "proxy not found" );
         voters_tbl.modify( new_proxy, 0, [&](auto& a) { a.proxied_votes += uint64_t(voter_it->staked.amount); } );
         new_producers = &new_proxy->producers;
      } else {
         new_producers = &producers;
      }

      producers_table producers_tbl( _self, _self );
      uint128_t votes = uint64_t(voter_it->staked.amount);
      if ( voter_it->is_proxy ) {
         votes += voter_it->proxied_votes;
      }

      if ( old_producers ) { //old_producers == nullptr if proxy has stopped being a proxy and votes were taken back from the producers at that moment
         //revoke votes only from no longer elected
         std::vector<account_name> revoked( old_producers->size() );
         auto end_it = std::set_difference( old_producers->begin(), old_producers->end(), new_producers->begin(), new_producers->end(), revoked.begin() );
         for ( auto it = revoked.begin(); it != end_it; ++it ) {
            auto prod = producers_tbl.find( *it );
            eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption
            producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes -= votes; } );
         }
      }

      //update newly elected
      std::vector<account_name> elected( new_producers->size() );
      auto end_it = elected.begin();
      if( old_producers ) {
         end_it = std::set_difference( new_producers->begin(), new_producers->end(), old_producers->begin(), old_producers->end(), elected.begin() );
      } else {
         end_it = std::copy( new_producers->begin(), new_producers->end(), elected.begin() );
      }
      for ( auto it = elected.begin(); it != end_it; ++it ) {
         auto prod = producers_tbl.find( *it );
         eosio_assert( prod != producers_tbl.end(), "producer is not registered" );
         if ( proxy == 0 ) { //direct voting, in case of proxy voting update total_votes even for inactive producers
            eosio_assert( prod->active(), "producer is not currently registered" );
         }
         producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes += votes; } );
      }

      // save new values to the account itself
      voters_tbl.modify( voter_it, 0, [&](voter_info& a) {
            a.proxy = proxy;
            a.last_update = now();
            a.producers = producers;
         });
   }