From 928af0b4b714b33514bae8f46ad17be1ef36a166 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Tue, 17 Nov 2020 14:09:25 -0800 Subject: [PATCH 1/2] Update transaction malleability docs for RFCS - Update mentions of RequireFullyCanonicalSig to reflect that it's enabled now - De-emphasizes tfFullyCanonicalSig now that it has no effect - Rework the Transaction Malleability Exploit to reflect the multi-signing scenario, which is the only possible one now. --- .../transaction-malleability.md | 46 ++++++------------- .../transaction-common-fields.md | 6 +-- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/content/concepts/consensus-network/transaction-malleability.md b/content/concepts/consensus-network/transaction-malleability.md index e6d53fe937..2c0e89df97 100644 --- a/content/concepts/consensus-network/transaction-malleability.md +++ b/content/concepts/consensus-network/transaction-malleability.md @@ -4,17 +4,10 @@ A transaction is "malleable" if it can be changed in any way after being signed, If vulnerable software submits malleable transactions and assumes they can only execute under the original hash, it may lose track of transactions. In the worst case, malicious actors could take advantage of this to steal money from the vulnerable system. -There are two circumstances that could lead to transaction malleability: +On the XRP Ledger mainnet, only **multi-signed transactions** can be malleable, if they have more signatures than necessary, or if an authorized signer provides an additional signature beyond what is necessary. Good operational security can protect against these problems. See [Mitigations for Multi-Signature Malleability](#mitigations-for-multi-signature-malleability) for guidelines. -1. The transaction does not specify the `tfFullyCanonicalSig` flag on a transaction signed using the default signing algorithm (ECDSA with the secp256k1 curve). +Before 2014, single-signed transactions could be malleable due to properties of the default signing algorithm, ECDSA with the secp256k1 curve. For compatibility with legacy signing tools, it was possible to create and submit malleable single-signed transactions until the [RequireFullyCanonicalSig amendment][] became enabled on 2020-07-03. (Transactions [signed with Ed25519 keys](cryptographic-keys.html#signing-algorithms) were never vulnerable to this problem.) - **Use the [`tfFullyCanonicalSig` flag](transaction-common-fields.html#global-flags)** to guarantee that a transaction is not malleable in this way. Although transactions [signed with Ed25519 keys](cryptographic-keys.html#signing-algorithms) are not vulnerable to this problem, **there is no downside** to using this flag on _all_ transactions. - - If the [RequireFullyCanonicalSig amendment][] :not_enabled: is enabled, all transactions are protected against malleability regardless of the `tfFullyCanonicalSig` flag. - -2. The transaction is [multi-signed](multi-signing.html) and has more signatures than necessary. Even if the transaction originally did not have more signatures than necessary, it could be malleable if an authorized signer provides an additional signature. - - Good operational security can protect against these problems. See [Mitigations for Multi-Signature Malleability](#mitigations-for-multi-signature-malleability) for guidelines. ## Background @@ -41,18 +34,11 @@ Generally speaking, any standard ECDSA implementation handles these requirements An ECDSA signature consists of two integers, called R and S. The secp256k1 _group order_, called N, is a constant value for all secp256k1 signatures. Specifically, N is the value `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`. For any given signature `(R,S)`, the signature `(R, N-S)` (that is, using N minus S in place of S) is also valid. -Thus, to have _fully_ canonical signatures, one must choose which of the two possibilities is preferred and declare the other to be invalid. The creators of the XRP Ledger decided arbitrarily to prefer the _smaller_ of the two possible values, `S` or `N-S`. A transaction is considered _fully canonical_ if it uses the preferred (smaller) value of `S`, and follows all the normal rules for being canonical. +Thus, to have _fully_ canonical signatures, one must choose which of the two possibilities is preferred and declare the other to be invalid. The creators of the XRP Ledger decided arbitrarily to prefer the _smaller_ of the two possible values, `S` or `N-S`. A transaction is considered _fully canonical_ if it uses the preferred (smaller) value of `S`, and follows all the normal rules for being canonical. To calculate a fully-canonical ECDSA signature, one must compare S and N-S to determine which is smaller, then use that value in the `Signature` field of the transaction. -To maintain compatibility with older software that did not always generate fully canonical signatures, the XRP Ledger accepts transactions that are not fully canonical. To protect new users from exploits, the XRP Ledger has a flag on transactions called [**`tfFullyCanonicalSig`**](transaction-common-fields.html#global-flags), which requires that the transaction use a _fully-canonical_ signature to be valid. If the [RequireFullyCanonicalSig amendment][] :not_enabled: is enabled, all transactions require fully-canonical signatures regardless of the `tfFullyCanonicalSig` flag, and legacy software that makes non-fully-canonical signatures is no longer compatible. +With the [RequireFullyCanonicalSig amendment][] (enabled in 2020), all transactions must use _fully canonical_ signatures only. -To calculate a fully-canonical ECDSA signature, one must compare S and N-S to determine which is smaller, then use that value in the `Signature` field of the transaction. - -All XRP Ledger software that Ripple publishes (including `rippled`, and ripple-lib/RippleAPI) generates only fully-canonical signatures. To further protect users, Ripple has configured its code to enable the **`tfFullyCanonicalSig`** flag by default where possible. Ripple strongly encourages third-party implementations of XRP Ledger software to generate only fully-canonical signatures, and enable `tfFullyCanonicalSig` on transactions by default. - -There are two cases where Ripple's signing implementations for the XRP Ledger do not automatically enable the `tfFullyCanonicalSig` flag. Users should take care to set the flag in these situations: - -- When the user explicitly specifies the `Flags` field of the transaction. Use bitwise OR to apply `tfFullyCanonicalSig` _and_ any other desired flags. -- When the user provides a multi-signature for a transaction. Since different participants in a multi-signature must sign _exactly_ the same data, the signing code does not pre-process the transaction instructions to add the `tfFullyCanonicalSig` flag. For multi-signed transactions, always enable the `tfFullyCanonicalSig` flag explicitly. +Between 2014 and 2020, the XRP Ledger was compatible with legacy software that did not always generate fully canonical signatures, but used a flag on transactions called [**`tfFullyCanonicalSig`**](transaction-common-fields.html#global-flags) to protect compatible software from transaction malleability. This flag, which compatible signing software enables by default, required that the transaction use a _fully-canonical_ signature to be valid. Now that the [RequireFullyCanonicalSig amendment][] is enabled, the flag is no longer necessary, but there is no harm in enabling it anyway. ### Malleability with Multi-Signatures @@ -86,35 +72,29 @@ For greater security, these guidelines provide multiple layers of protection. If the software you use to interface with the XRP Ledger sends malleable transactions, a malicious actor may be able to trick your software into losing track of a transaction's final outcome and potentially (in the worst case) sending equivalent payments multiple times. -If you use single-signatures and always enable the `tfFullyCanonicalSig` flag, you are not vulnerable to this exploit. If you use multi-signatures, you may be vulnerable if you or your signers provide more signatures than necessary. +If you use single-signatures only, you are not vulnerable to this exploit. If you use multi-signatures, you may be vulnerable if you or your signers provide more signatures than necessary. ### Exploit Scenario Steps The process to exploit a vulnerable system follows a series of steps similar to the following: -1. The vulnerable system constructs and signs a transaction without enabling `tfFullyCanonicalSig`. +1. The vulnerable system constructs a multi-signed transaction and collects more than the necessary number of signatures. - Three ways that a transaction may not enable the `tfFullyCanonicalSig` flag are: - - - The system explicitly specifies a `Flags` field that does not have the `tfFullyCanonicalSig` bit enabled. - - The transaction is multi-signed and does not explicitly enable the `tfFullyCanonicalSig` flag. - - The system omits the `Flags` field from the transaction fields, but uses a non-standard implementation that does not automatically enable `tfFullyCanonicalSig` when signing. - - To be vulnerable, the transaction must be signed with an ECDSA key pair. If multi-signed, the transaction must be signed by at least one ECDSA key pair. - - Most likely, the vulnerable transaction uses a fully-canonical signature, but the flags indicate that the transaction would also be valid with a non-fully-canonical one. The transaction may also use `LastLedgerSequence` so that its final outcome is clear in a finite amount of time. + If an authorized signer is malicious or irresponsible, the transaction could also be vulnerable if that signer's signature is not included but could be added. 2. The system notes the identifying hash of the vulnerable transaction, submits it to the XRP Ledger network, then begins monitoring for that hash to be included in a validated ledger version. 3. A malicious actor sees the transaction propagating through the network before it becomes confirmed. -4. The malicious actor calculates the alternate signature for the vulnerable transaction. +4. The malicious actor calculates removes an extra signature from the vulnerable transaction. Unlike creating a signature for different transaction instructions, this does not require a large amount of computational work. It can be done in much less time than it takes to generate a signature in the first place. - The modified signature results in a different identifying hash. (You do not have to calculate the hash before you submit to the network, but knowing the hash makes it easier to check the transaction's status later.) + Alternatively, an authorized signer whose signature is not already part of the transaction could add their signature to the vulnerable transaction's list of signatures. Depending on the sender's multi-signing settings, this can be in addition to removing other signatures from the transaction. -5. The malicious actor submits the modified (likely non-fully-canonical) transaction to the network. + The modified list of signatures results in a different identifying hash. (You do not have to calculate the hash before you submit to the network, but knowing the hash makes it easier to check the transaction's status later.) + +5. The malicious actor submits the modified transaction to the network. This creates a "race" between the transaction as originally submitted and the modified version submitted by the malicious actor. The two transactions are mutually exclusive. Both are valid, but they have the same exact transaction data, including the `Sequence` number, so at most one of them can ever be included in a validated ledger. diff --git a/content/references/rippled-api/transaction-formats/transaction-common-fields.md b/content/references/rippled-api/transaction-formats/transaction-common-fields.md index e8b95820b0..b5178f8412 100644 --- a/content/references/rippled-api/transaction-formats/transaction-common-fields.md +++ b/content/references/rippled-api/transaction-formats/transaction-common-fields.md @@ -66,11 +66,11 @@ The only flag that applies globally to all transactions is as follows: | Flag Name | Hex Value | Decimal Value | Description | |:----------------------|:-----------|:--------------|:--------------------------| -| `tfFullyCanonicalSig` | `0x80000000` | 2147483648 | _(Strongly recommended)_ Require a fully-canonical signature. | +| `tfFullyCanonicalSig` | `0x80000000` | 2147483648 | **DEPRECATED** No effect. Require a fully-canonical signature. | -When using the [sign method][] (or [submit method][] in "sign-and-submit" mode), `rippled` adds a `Flags` field with `tfFullyCanonicalSig` enabled unless the `Flags` field is already present. The `tfFullyCanonicalSig` flag ***is not*** automatically enabled if `Flags` is explicitly specified. The flag ***is not*** automatically enabled when using the [sign_for method][] to add a signature to a multi-signed transaction. +When using the [sign method][] (or [submit method][] in "sign-and-submit" mode), `rippled` adds a `Flags` field with `tfFullyCanonicalSig` enabled unless the `Flags` field is already present. The `tfFullyCanonicalSig` flag is not automatically enabled if `Flags` is explicitly specified. The flag is not automatically enabled when using the [sign_for method][] to add a signature to a multi-signed transaction. -**Warning:** If you do not enable `tfFullyCanonicalSig`, it is theoretically possible for a malicious actor to modify your transaction signature so that the transaction may succeed with a different hash than expected. In the worst case, this could [trick your integration into submitting the same payment multiple times](transaction-malleability.html#exploit-with-malleable-transactions). To avoid this problem, enable the `tfFullyCanonicalSig` flag on all transactions you sign. If the [RequireFullyCanonicalSig amendment][] :not_enabled: is enabled, all single-signed transactions are protected regardless of the `tfFullyCanonicalSig` flag. +**Note:** The `tfFullyCanonicalSig` flag was used from 2014 until 2020 to protect against [transaction malleability](transaction-malleability.html) while maintaining compatibility with legacy signing software. The [RequireFullyCanonicalSig amendment][] ended compatibility with such legacy software and made the protections the default for all transactions. If you are using a [parallel network](parallel-networks.html) that does not have RequireFullyCanonicalSig enabled, you should always enable the `tfFullyCanonicalSig` flag to protect against transaction malleability. ### Flag Ranges From f480a43999f516b5a395f8bd286f4c5d9b3481c6 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Wed, 18 Nov 2020 11:12:34 -0800 Subject: [PATCH 2/2] Tx malleability: copy edits --- .../concepts/consensus-network/transaction-malleability.md | 4 ++-- .../transaction-formats/transaction-common-fields.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/concepts/consensus-network/transaction-malleability.md b/content/concepts/consensus-network/transaction-malleability.md index 2c0e89df97..ea8c68a1b1 100644 --- a/content/concepts/consensus-network/transaction-malleability.md +++ b/content/concepts/consensus-network/transaction-malleability.md @@ -86,11 +86,11 @@ The process to exploit a vulnerable system follows a series of steps similar to 3. A malicious actor sees the transaction propagating through the network before it becomes confirmed. -4. The malicious actor calculates removes an extra signature from the vulnerable transaction. +4. The malicious actor removes an extra signature from the vulnerable transaction. Unlike creating a signature for different transaction instructions, this does not require a large amount of computational work. It can be done in much less time than it takes to generate a signature in the first place. - Alternatively, an authorized signer whose signature is not already part of the transaction could add their signature to the vulnerable transaction's list of signatures. Depending on the sender's multi-signing settings, this can be in addition to removing other signatures from the transaction. + Alternatively, an authorized signer whose signature is not already part of the transaction could add their signature to the vulnerable transaction's list of signatures. Depending on the sender's multi-signing settings, this can be instead of or in addition to removing other signatures from the transaction. The modified list of signatures results in a different identifying hash. (You do not have to calculate the hash before you submit to the network, but knowing the hash makes it easier to check the transaction's status later.) diff --git a/content/references/rippled-api/transaction-formats/transaction-common-fields.md b/content/references/rippled-api/transaction-formats/transaction-common-fields.md index b5178f8412..2bab8701a3 100644 --- a/content/references/rippled-api/transaction-formats/transaction-common-fields.md +++ b/content/references/rippled-api/transaction-formats/transaction-common-fields.md @@ -66,7 +66,7 @@ The only flag that applies globally to all transactions is as follows: | Flag Name | Hex Value | Decimal Value | Description | |:----------------------|:-----------|:--------------|:--------------------------| -| `tfFullyCanonicalSig` | `0x80000000` | 2147483648 | **DEPRECATED** No effect. Require a fully-canonical signature. | +| `tfFullyCanonicalSig` | `0x80000000` | 2147483648 | **DEPRECATED** No effect. (If the [RequireFullyCanonicalSig amendment][] is not enabled, this flag enforces a [fully-canonical signature](transaction-malleability.html#alternate-secp256k1-signatures).) | When using the [sign method][] (or [submit method][] in "sign-and-submit" mode), `rippled` adds a `Flags` field with `tfFullyCanonicalSig` enabled unless the `Flags` field is already present. The `tfFullyCanonicalSig` flag is not automatically enabled if `Flags` is explicitly specified. The flag is not automatically enabled when using the [sign_for method][] to add a signature to a multi-signed transaction.