seal: ECDSA signature r/s shorter than 32 bytes is written wrong (der_to_raw copies 32-len bytes), ~1 in 256 seals do not verify
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 72/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- c
- Ambito
- cryptography, security
Direzione di ricerca
Il bug si trova in der_to_raw() in bintool/mbedtls_wrapper.c, nei rami INTEGER corti vicino alle righe 169 e 179, dove la lunghezza della copia è 32 - b invece di b. Leggi quei rami e la gestione della lunghezza DER sopra di essi, poi verifica se la PR #358 riscrive già questa funzione prima di modificarla. È completato quando r e s sono allineati a destra con i byte corretti per gli interi DER corti e una firma con r o s accorciato da uno zero iniziale viene verificata rispetto all'hash dell'immagine.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
picotool seal --sign intermittently writes a SIGNATURE block item that does not verify. It happens whenever the DER encoding of ECDSA's r or s is shorter than 32 bytes, i.e. the 32-byte value has a leading zero byte and the next byte is below 0x80. For a random 256-bit value that is 1/512; with two values per signature about 1 seal in 256 is affected. The ECDSA nonce is random, so re-running the same seal command on the same input gives a different signature and the failure looks random.
The HASH_VALUE item is correct in every bad image; only the signature is wrong. An image sealed this way does not pass signature verification, so it will not boot on an RP2350 with secure boot enabled.
Version: picotool 2.3.0 (tag 2.3.0, 6f6458d). The same code is on master and develop today (bintool/mbedtls_wrapper.c lines 169 and 179 at ba3df40).
Repro
- Any RP2350 ELF and a secp256k1 private key in PEM form.
- Seal it repeatedly; each run draws a fresh nonce:
for i in $(seq 2000); do picotool seal --quiet in.elf out_$i.elf key.pem --sign --hash done - Verify each signature independently, e.g. with Python
cryptography: take the image's SHA-256 (the HASH_VALUE item, which is correct) and the 64-byter || sfrom the SIGNATURE item, and callpublic_key.verify(encode_dss_signature(r, s), digest, ec.ECDSA(Prehashed(SHA256()))).
Observed
Windows builds (GCC 16.1, mbedtls from pico-sdk 2.3.0 lib/mbedtls, 0bebf8b), same input ELF and key throughout:
| build | seals | fail verification |
|---|---|---|
| 2.3.0, built from source | 2000 | 9 (0.45%; expected 1/256 = 0.39%) |
| 2.3.0, pico-sdk-tools Windows release binary | 2000 | 7 |
develop at ba3df40, built from source |
2000 | 7 |
develop at ba3df40 + the fix below |
2000 | 0 |
An earlier independent run of 150 seals of 2.3.0 showed 2 failures.
Every failing signature has the same shape: one half is 00 XX followed by 30 zero bytes, e.g.
r = 007f000000000000000000000000000000000000000000000000000000000000
s = efc6bedd550f00ebc968cfbba229c34573a58cbb914fe7a27d304e8ac667eb1c
Root cause
der_to_raw() in bintool/mbedtls_wrapper.c, the branch for a DER INTEGER shorter than 32 bytes:
} else {
memset(r, 0, sizeof(r));
memcpy(r + (32 - b2), sig->der + 4, (32 - b2)); // copies 32-b2 bytes, should copy b2
}
...
} else {
memset(s, 0, sizeof(r));
memcpy(s + (32 - b3), sig->der + 6 + b2, (32 - b3)); // same, for s
}
The destination offset 32 - b is right (right-align, zero-pad on the left), but the length is 32 - b instead of b. For the usual short case b == 31 this copies one byte instead of 31, which produces exactly the 00 XX 00..00 pattern above.
A two-line fix PR follows. Note that #358 rewrites der_to_raw() with a read_der_integer() helper that copies len bytes, so it would also fix this in passing; the separate PR is the minimal standalone change in case a point release wants it on its own.
- Lingua principale
- C++
- Stelle
- 1k
- Fork
- 194
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di raspberrypi/picotool
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
raspberrypi/picotool#371 · 1 commento ·
-
partition create writes the wrong extra family count when a partition has two custom family IDsForse già presa @sebxt l’ha presa 13 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
raspberrypi/picotool#368 · 1 reazione ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
raspberrypi/picotool#347 ·
-
`--ser` with several RP2350s on USB sends PICOBOOT requests to the wrong interfaceForse già presa @will-v-pi l’ha presa 10 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
raspberrypi/picotool#370 · 2 commenti ·
-
`picotool config -s <field> 0` fails to write zero value to device.Forse già presa @will-v-pi l’ha presa 19 giorni fa. Aperta
raspberrypi/picotool#364 · 1 commento · 1 assegnatario ·
Tutte le issue di raspberrypi/picotool
Issue simili
-
artifact:simulation-scenario domain:physics good first issue help wanted role:validation testing
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 3 giorni
-
bug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
NVIDIA/accelerated-computing-hub#294 ·
I maintainer di solito rispondono entro 4 giorni
-
bug P3
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
area-System.IO untriaged
Difficoltà 2/5 Mezza giornata Idoneità per principianti 72/100
dotnet/runtime#136802 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno