David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 1 | # ECDSA signature format |
| 2 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 3 | When the ECDSA SECP256R1 (EC256) signature support was added to MCUboot, a |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 4 | shortcut was taken, and these signatures were padded to make them |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 5 | always a fixed length. Unfortunately, this padding was done in a way |
| 6 | that is not easily reversible. Some crypto libraries (specifically, Mbed |
| 7 | TLS) are fairly strict about the formatting of the ECDSA signature. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 8 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 9 | There are two ways to fix this: |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 10 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 11 | - Use a reversible padding scheme. This solution requires |
| 12 | at least one pad byte to always be added (to set the length). This |
| 13 | padding would be somewhat incompatible across versions (older |
| 14 | EC256 would work, while newer MCUboot code would reject old |
| 15 | signatures. The EC code would work reliably only in the new |
| 16 | combination). |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 17 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 18 | - Remove the padding entirely. Depending on the tool used, this solution |
| 19 | requires some rethinking of how TLV generation is implemented so |
| 20 | that the length does not need to be known until the signature is |
| 21 | generated. These tools are usually written in higher-level |
| 22 | languages, so this change should not be difficult. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 23 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 24 | However, this will also break compatibility with older versions, |
| 25 | because images generated with newer tools will not |
| 26 | work with older versions of MCUboot. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 27 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 28 | This document proposes a multi-stage approach to give a transition |
| 29 | period: |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 30 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 31 | 1. Add a `--no-pad-sig` argument to the sign command in |
| 32 | `imgtool.py`. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 33 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 34 | Without this argument, the images are padded with the |
| 35 | existing scheme. With this argument, the ECDSA is encoded |
| 36 | without any padding. The `--pad-sig` argument is also |
| 37 | accepted, but it is already the default. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 38 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 39 | 2. MCUboot will be modified to allow unpadded signatures right away. |
| 40 | The existing EC256 implementations will still work (with or |
| 41 | without padding), and the existing EC implementation will be able |
| 42 | to accept padded and unpadded signatures. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 43 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 44 | 3. An Mbed TLS implementation of EC256 can be added, but it will require |
| 45 | the `--no-pad-sig` signature to be able to boot all generated |
| 46 | images. Without the argument, 3 out of 4 images generated will have |
| 47 | padding and will be considered invalid. |
| 48 | |
| 49 | After one or more MCUboot release cycles and announcements in the |
David Brown | bf3a3a9 | 2019-12-17 16:08:33 -0700 | [diff] [blame] | 50 | relevant channels, the arguments to `imgtool.py` will change: |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 51 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 52 | - `--no-pad-sig` will still be accepted but will have no effect. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 53 | |
David Brown | 3639aca | 2019-12-17 16:10:49 -0700 | [diff] [blame] | 54 | - `--pad-sig` will now bring back the old padding behavior. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 55 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 56 | This will require an update to any scripts that will rely on the default |
| 57 | behavior, but will not specify a specific version of imgtool. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 58 | |
| 59 | The signature generation in the simulator can be changed at the same |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 60 | time the boot code begins to accept unpadded signatures. The simulator is |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 61 | always run out of the same tree as the MCUboot code, so there should |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 62 | not be any compatibility issues. |
| 63 | |
| 64 | ## Background |
| 65 | |
| 66 | ECDSA signatures are encoded as ASN.1, notably with the signature |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 67 | itself encoded as follows: |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 68 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 69 | ``` |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 70 | ECDSA-Sig-Value ::= SEQUENCE { |
| 71 | r INTEGER, |
| 72 | s INTEGER |
| 73 | } |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 74 | ``` |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 75 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 76 | Both `r` and `s` are 256-bit numbers. Because these are |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 77 | unsigned numbers that are being encoded in ASN.1 as signed values, if |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 78 | the high bit of the number is set, the DER-encoded representation will |
| 79 | require 33 bytes instead of 32. This means that the length of the |
| 80 | signature will vary by a couple of bytes, depending on whether one or |
| 81 | both of these numbers have the high bit set. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 82 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 83 | Originally, MCUboot added padding to the entire signature and just |
| 84 | removed any trailing 0 bytes from the data block. This turned out to be fine 255 out of 256 |
| 85 | times, each time the last byte of the signature was non-zero, but if the |
| 86 | signature ended in a zero, MCUboot would remove too many bytes and render the |
| 87 | signature invalid. |
David Brown | 8f057ca | 2019-12-12 16:19:55 -0700 | [diff] [blame] | 88 | |
Francesco Domenico Servidio | 5851150 | 2022-01-11 17:07:13 +0100 | [diff] [blame] | 89 | The correct approach here is to accept that ECDSA signatures are of |
| 90 | variable length, and to make sure that we can handle them as such. |