mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Sign manifest with ephemeral and master keys (RIPD-1083)
This commit is contained in:
committed by
Edward Hennis
parent
7d46d153c6
commit
b55edfa8f0
@@ -42,7 +42,8 @@ make_Manifest (std::string s)
|
||||
auto const opt_spk = get<PublicKey>(st, sfSigningPubKey);
|
||||
auto const opt_seq = get (st, sfSequence);
|
||||
auto const opt_sig = get (st, sfSignature);
|
||||
if (!opt_pk || !opt_spk || !opt_seq || !opt_sig)
|
||||
auto const opt_msig = get (st, sfMasterSignature);
|
||||
if (!opt_pk || !opt_spk || !opt_seq || !opt_sig || !opt_msig)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
@@ -99,7 +100,11 @@ bool Manifest::verify () const
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
return ripple::verify (st, HashPrefix::manifest, masterKey, true);
|
||||
if (! ripple::verify (st, HashPrefix::manifest, signingKey, true))
|
||||
return false;
|
||||
|
||||
return ripple::verify (
|
||||
st, HashPrefix::manifest, masterKey, true, sfMasterSignature);
|
||||
}
|
||||
|
||||
uint256 Manifest::hash () const
|
||||
@@ -127,6 +132,14 @@ Blob Manifest::getSignature () const
|
||||
return st.getFieldVL (sfSignature);
|
||||
}
|
||||
|
||||
Blob Manifest::getMasterSignature () const
|
||||
{
|
||||
STObject st (sfGeneric);
|
||||
SerialIter sit (serialized.data (), serialized.size ());
|
||||
st.set (sit);
|
||||
return st.getFieldVL (sfMasterSignature);
|
||||
}
|
||||
|
||||
bool
|
||||
ManifestCache::loadValidatorKeys(
|
||||
Section const& keys,
|
||||
@@ -415,7 +428,9 @@ void ManifestCache::load (
|
||||
{
|
||||
if (!mo->verify())
|
||||
{
|
||||
Throw<std::runtime_error> ("Unverifiable manifest in db");
|
||||
JLOG(journal.warn())
|
||||
<< "Unverifiable manifest in db";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trusted(mo->masterKey) || unl.trusted(mo->masterKey))
|
||||
@@ -444,13 +459,15 @@ void ManifestCache::save (DatabaseCon& dbCon) const
|
||||
*db << "DELETE FROM ValidatorManifests";
|
||||
static const char* const sql =
|
||||
"INSERT INTO ValidatorManifests (RawData) VALUES (:rawData);";
|
||||
// soci does not support bulk insertion of blob data
|
||||
soci::blob rawData(*db);
|
||||
for (auto const& v : map_)
|
||||
{
|
||||
if (!v.second.m)
|
||||
continue;
|
||||
|
||||
// soci does not support bulk insertion of blob data
|
||||
// Do not reuse blob because manifest ecdsa signatures vary in length
|
||||
// but blob write length is expected to be >= the last write
|
||||
soci::blob rawData(*db);
|
||||
convert (v.second.m->serialized, rawData);
|
||||
*db << sql,
|
||||
soci::use (rawData);
|
||||
|
||||
@@ -99,6 +99,9 @@ struct Manifest
|
||||
uint256 hash () const;
|
||||
bool revoked () const;
|
||||
Blob getSignature () const;
|
||||
|
||||
/// Returns manifest master key signature
|
||||
Blob getMasterSignature () const;
|
||||
};
|
||||
|
||||
boost::optional<Manifest> make_Manifest(std::string s);
|
||||
|
||||
@@ -441,6 +441,7 @@ JSS ( validated_ledger ); // out: NetworkOPs
|
||||
JSS ( validated_ledgers ); // out: NetworkOPs
|
||||
JSS ( validation_key ); // out: ValidationCreate, ValidationSeed
|
||||
JSS ( validation_manifest ); // out: NetworkOPs
|
||||
JSS ( validation_private_key ); // out: ValidationCreate
|
||||
JSS ( validation_public_key ); // out: ValidationCreate, ValidationSeed
|
||||
JSS ( validation_quorum ); // out: NetworkOPs
|
||||
JSS ( validation_seed ); // out: ValidationCreate, ValidationSeed
|
||||
|
||||
@@ -447,6 +447,7 @@ extern SF_Blob const sfCreateCode;
|
||||
extern SF_Blob const sfMemoType;
|
||||
extern SF_Blob const sfMemoData;
|
||||
extern SF_Blob const sfMemoFormat;
|
||||
extern SF_Blob const sfMasterSignature;
|
||||
|
||||
// variable length (uncommon)
|
||||
extern SF_Blob const sfProof;
|
||||
|
||||
@@ -28,23 +28,34 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Sign a STObject using any secret key.
|
||||
The signature is placed in sfSignature. If
|
||||
a signature already exists, it is overwritten.
|
||||
/** Sign an STObject
|
||||
|
||||
@param st Object to sign
|
||||
@param prefix Prefix to insert before serialized object when hashing
|
||||
@param type Signing key type used to derive public key
|
||||
@param sk Signing secret key
|
||||
@param sigField Field in which to store the signature on the object.
|
||||
If not specified the value defaults to `sfSignature`.
|
||||
|
||||
@note If a signature already exists, it is overwritten.
|
||||
*/
|
||||
void
|
||||
sign (STObject& st,
|
||||
HashPrefix const& prefix,
|
||||
KeyType type, SecretKey const& sk);
|
||||
sign (STObject& st, HashPrefix const& prefix,
|
||||
KeyType type, SecretKey const& sk,
|
||||
SF_Blob const& sigField = sfSignature);
|
||||
|
||||
/** Verify the signature on a STObject.
|
||||
The signature must be contained in sfSignature.
|
||||
/** Returns `true` if STObject contains valid signature
|
||||
|
||||
@param st Signed object
|
||||
@param prefix Prefix inserted before serialized object when hashing
|
||||
@param pk Public key for verifying signature
|
||||
@param sigField Object's field containing the signature.
|
||||
If not specified the value defaults to `sfSignature`.
|
||||
*/
|
||||
bool
|
||||
verify (STObject const& st,
|
||||
HashPrefix const& prefix,
|
||||
PublicKey const& pk,
|
||||
bool mustBeFullyCanonical);
|
||||
verify (STObject const& st, HashPrefix const& prefix,
|
||||
PublicKey const& pk, bool mustBeFullyCanonical,
|
||||
SF_Blob const& sigField = sfSignature);
|
||||
|
||||
/** Return a Serializer suitable for computing a multisigning TxnSignature. */
|
||||
Serializer
|
||||
|
||||
@@ -199,9 +199,11 @@ SF_Blob const sfMemoType = make::one<SF_Blob::type>(&sfMemoType, STI
|
||||
SF_Blob const sfMemoData = make::one<SF_Blob::type>(&sfMemoData, STI_VL, 13, "MemoData");
|
||||
SF_Blob const sfMemoFormat = make::one<SF_Blob::type>(&sfMemoFormat, STI_VL, 14, "MemoFormat");
|
||||
|
||||
|
||||
// variable length (uncommon)
|
||||
// 16 has not been used yet...
|
||||
SF_Blob const sfProof = make::one<SF_Blob::type>(&sfProof, STI_VL, 17, "Proof");
|
||||
SF_Blob const sfProof = make::one<SF_Blob::type>(&sfProof, STI_VL, 17, "Proof");
|
||||
SF_Blob const sfMasterSignature = make::one<SF_Blob::type>(&sfMasterSignature, STI_VL, 18, "MasterSignature", SField::sMD_Default, SField::notSigning);
|
||||
|
||||
// account
|
||||
SF_Account const sfAccount = make::one<SF_Account::type>(&sfAccount, STI_ACCOUNT, 1, "Account");
|
||||
|
||||
@@ -24,22 +24,22 @@ namespace ripple {
|
||||
|
||||
void
|
||||
sign (STObject& st, HashPrefix const& prefix,
|
||||
KeyType type, SecretKey const& sk)
|
||||
KeyType type, SecretKey const& sk,
|
||||
SF_Blob const& sigField)
|
||||
{
|
||||
Serializer ss;
|
||||
ss.add32(prefix);
|
||||
st.addWithoutSigningFields(ss);
|
||||
set(st, sfSignature,
|
||||
set(st, sigField,
|
||||
sign(type, sk, ss.slice()));
|
||||
}
|
||||
|
||||
bool
|
||||
verify (STObject const& st,
|
||||
HashPrefix const& prefix,
|
||||
PublicKey const& pk,
|
||||
bool mustBeFullyCanonical)
|
||||
verify (STObject const& st, HashPrefix const& prefix,
|
||||
PublicKey const& pk, bool mustBeFullyCanonical,
|
||||
SF_Blob const& sigField)
|
||||
{
|
||||
auto const sig = get(st, sfSignature);
|
||||
auto const sig = get(st, sigField);
|
||||
if (! sig)
|
||||
return false;
|
||||
Serializer ss;
|
||||
|
||||
@@ -52,11 +52,14 @@ Json::Value doValidationCreate (RPC::Context& context)
|
||||
if (!seed)
|
||||
return rpcError (rpcBAD_SEED);
|
||||
|
||||
auto const private_key = generateSecretKey (KeyType::secp256k1, *seed);
|
||||
|
||||
obj[jss::validation_public_key] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PUBLIC,
|
||||
derivePublicKey (
|
||||
KeyType::secp256k1,
|
||||
generateSecretKey (KeyType::secp256k1, *seed)));
|
||||
derivePublicKey (KeyType::secp256k1, private_key));
|
||||
|
||||
obj[jss::validation_private_key] = toBase58 (
|
||||
TokenType::TOKEN_NODE_PRIVATE, private_key);
|
||||
|
||||
obj[jss::validation_seed] = toBase58 (*seed);
|
||||
obj[jss::validation_key] = seedAs1751 (*seed);
|
||||
|
||||
@@ -102,18 +102,23 @@ public:
|
||||
|
||||
Manifest
|
||||
make_Manifest
|
||||
(KeyType type, SecretKey const& sk, PublicKey const& spk, int seq,
|
||||
bool broken = false)
|
||||
(SecretKey const& sk, KeyType type, SecretKey const& ssk, KeyType stype,
|
||||
int seq, bool broken = false)
|
||||
{
|
||||
auto const pk = derivePublicKey(type, sk);
|
||||
auto const spk = derivePublicKey(stype, ssk);
|
||||
|
||||
STObject st(sfGeneric);
|
||||
st[sfSequence] = seq;
|
||||
st[sfPublicKey] = pk;
|
||||
st[sfSigningPubKey] = spk;
|
||||
|
||||
sign(st, HashPrefix::manifest, type, sk);
|
||||
BEAST_EXPECT(verify(st, HashPrefix::manifest, pk, true));
|
||||
sign(st, HashPrefix::manifest, stype, ssk);
|
||||
BEAST_EXPECT(verify(st, HashPrefix::manifest, spk, true));
|
||||
|
||||
sign(st, HashPrefix::manifest, type, sk, sfMasterSignature);
|
||||
BEAST_EXPECT(verify(
|
||||
st, HashPrefix::manifest, pk, true, sfMasterSignature));
|
||||
|
||||
if (broken)
|
||||
{
|
||||
@@ -227,7 +232,8 @@ public:
|
||||
|
||||
auto const sk = randomSecretKey();
|
||||
auto const kp = randomKeyPair(KeyType::secp256k1);
|
||||
auto const m = make_Manifest (KeyType::ed25519, sk, kp.first, 0);
|
||||
auto const m = make_Manifest (
|
||||
sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
|
||||
|
||||
cache.configManifest (clone (m), *unl, journal);
|
||||
BEAST_EXPECT(cache.trusted (m.masterKey));
|
||||
@@ -330,7 +336,8 @@ public:
|
||||
auto const sk = randomSecretKey();
|
||||
auto const pk = derivePublicKey(KeyType::ed25519, sk);
|
||||
auto const kp = randomKeyPair(KeyType::secp256k1);
|
||||
auto const m = make_Manifest (KeyType::ed25519, sk, kp.first, 0);
|
||||
auto const m = make_Manifest (
|
||||
sk, KeyType::ed25519, kp.second, KeyType::secp256k1, 0);
|
||||
|
||||
STObject st(sfGeneric);
|
||||
st[sfSequence] = 0;
|
||||
@@ -339,9 +346,11 @@ public:
|
||||
Serializer ss;
|
||||
ss.add32(HashPrefix::manifest);
|
||||
st.addWithoutSigningFields(ss);
|
||||
auto const sig = sign(KeyType::ed25519, sk, ss.slice());
|
||||
|
||||
auto const sig = sign(KeyType::secp256k1, kp.second, ss.slice());
|
||||
BEAST_EXPECT(strHex(sig) == strHex(m.getSignature()));
|
||||
|
||||
auto const masterSig = sign(KeyType::ed25519, sk, ss.slice());
|
||||
BEAST_EXPECT(strHex(masterSig) == strHex(m.getMasterSignature()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -360,16 +369,21 @@ public:
|
||||
auto const sk_a = randomSecretKey();
|
||||
auto const pk_a = derivePublicKey(KeyType::ed25519, sk_a);
|
||||
auto const kp_a = randomKeyPair(KeyType::secp256k1);
|
||||
auto const s_a0 = make_Manifest (KeyType::ed25519, sk_a, kp_a.first, 0);
|
||||
auto const s_a1 = make_Manifest (KeyType::ed25519, sk_a, kp_a.first, 1);
|
||||
auto const s_a0 = make_Manifest (
|
||||
sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 0);
|
||||
auto const s_a1 = make_Manifest (
|
||||
sk_a, KeyType::ed25519, kp_a.second, KeyType::secp256k1, 1);
|
||||
|
||||
auto const sk_b = randomSecretKey();
|
||||
auto const pk_b = derivePublicKey(KeyType::ed25519, sk_b);
|
||||
auto const kp_b = randomKeyPair(KeyType::secp256k1);
|
||||
auto const s_b0 = make_Manifest (KeyType::ed25519, sk_b, kp_b.first, 0);
|
||||
auto const s_b1 = make_Manifest (KeyType::ed25519, sk_b, kp_b.first, 1);
|
||||
auto const s_b2 =
|
||||
make_Manifest (KeyType::ed25519, sk_b, kp_b.first, 2, true); // broken
|
||||
auto const s_b0 = make_Manifest (
|
||||
sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 0);
|
||||
auto const s_b1 = make_Manifest (
|
||||
sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 1);
|
||||
auto const s_b2 = make_Manifest (
|
||||
sk_b, KeyType::ed25519, kp_b.second, KeyType::secp256k1, 2,
|
||||
true); // broken
|
||||
auto const fake = s_b1.serialized + '\0';
|
||||
|
||||
BEAST_EXPECT(cache.applyManifest (clone (s_a0), *unl, journal) == untrusted);
|
||||
@@ -395,7 +409,8 @@ public:
|
||||
auto const sk_c = randomSecretKey();
|
||||
auto const pk_c = derivePublicKey(KeyType::ed25519, sk_c);
|
||||
auto const kp_c = randomKeyPair(KeyType::secp256k1);
|
||||
auto const s_c0 = make_Manifest (KeyType::ed25519, sk_c, kp_c.first, 0);
|
||||
auto const s_c0 = make_Manifest (
|
||||
sk_c, KeyType::ed25519, kp_c.second, KeyType::secp256k1, 0);
|
||||
BEAST_EXPECT(unl->insertPermanentKey(pk_c, "trusted key"));
|
||||
BEAST_EXPECT(unl->trusted(pk_c));
|
||||
BEAST_EXPECT(!cache.trusted(pk_c));
|
||||
|
||||
@@ -31,15 +31,15 @@ namespace test {
|
||||
namespace validator {
|
||||
static auto const seed = "ss7t3J9dYentEFgKdPA3q6eyxtrLB";
|
||||
static auto const master_key =
|
||||
"nHU4LxxrSQsRTKy5uZbX95eYowoamUEPCcWraxoiCNbtDaUr1V34";
|
||||
"nHUYwQk8AyQ8pW9p4SvrWC2hosvaoii9X54uGLDYGBtEFwWFHsJK";
|
||||
static auto const signing_key =
|
||||
"n9LHPLA36SBky1YjbaVEApQQ3s9XcpazCgfAG7jsqBb1ugDAosbm";
|
||||
// Format manifest string to test trim()
|
||||
static auto const manifest =
|
||||
" JAAAAAFxIe2FwblmJwz4pVYXHLJSzSBgIK7mpQuHNQ88CxW\n"
|
||||
" \tjIN7q4nMhAuUTyasIhvj2KPfNRbmmIBnqNUzidgkKb244eP \n"
|
||||
"\t794ZpMdkC+8l5n3R/CHP6SAwhYDOaqub0Cs2NjjewBnp1mf\n"
|
||||
"\t 23rhAzdcjRuWzm0IT12eduZ0DwcF5Ng8rAelaYP1iT93ScE\t \t";
|
||||
" JAAAAAFxIe2cDLvm5IqpeGFlMTD98HCqv7+GE54anRD/zbvGNYtOsXMhAuUTyasIhvj2KPfN\n"
|
||||
" \tRbmmIBnqNUzidgkKb244eP794ZpMdkYwRAIgNVq8SYP7js0C/GAGMKVYXiCGUTIL7OKPSBLS \n"
|
||||
"\t7LTyrL4CIE+s4Tsn/FrrYj0nMEV1Mvf7PMRYCxtEERD3PG/etTJ3cBJAbwWWofHqg9IACoYV\n"
|
||||
"\t +n9ulZHSVRajo55EkZYw0XUXDw8zcI4gD58suOSLZTG/dXtZp17huIyHgxHbR2YeYjQpCw==\t \t";
|
||||
static auto sequence = 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user