Skip to content

Commit

Permalink
Merge pull request #931 from mDuo13/rfcs_enabled
Browse files Browse the repository at this point in the history
Update transaction malleability docs for RFCS
  • Loading branch information
mDuo13 committed Nov 18, 2020
2 parents d553373 + f480a43 commit b2716c6
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 36 deletions.
46 changes: 13 additions & 33 deletions content/concepts/consensus-network/transaction-malleability.md
Expand Up @@ -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
Expand All @@ -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.

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.

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.
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.

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.
With the [RequireFullyCanonicalSig amendment][] (enabled in 2020), all transactions must use _fully canonical_ signatures only.

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
Expand Down Expand Up @@ -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`.

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.
1. The vulnerable system constructs a multi-signed transaction and collects more than the necessary number of signatures.

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 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 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.)

5. The malicious actor submits the modified (likely non-fully-canonical) transaction to the network.
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.

Expand Down
Expand Up @@ -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. (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.
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

Expand Down

0 comments on commit b2716c6

Please sign in to comment.