Skip to content

Updater signature validation - format incompatible w/RFC8017 #6201

Closed
@qistoph

Description

@qistoph

Basic Infos

  • This issue complies with the issue POLICY doc.
  • I have read the documentation at readthedocs and the issue is not addressed there.
  • I have tested that the issue is present in current master branch (aka latest git).
  • I have searched the issue tracker for a similar issue.
  • If there is a stack dump, I have decoded it.
  • I have filled out all fields below.

Platform

  • Hardware: ESP8285 device
  • Core Version: 2.5.2
  • Development Env: Arduino IDE
  • Operating System: Ubuntu

Settings in IDE (although not relevant imho)

  • Module: LOLIN(WEMOS) D1 D2 & mini
  • Flash Mode: unknown
  • Flash Size: 4MB
  • lwip Variant: v2 Lower Memory
  • Reset Method: unknown
  • Flash Frequency: 40Mhz
  • CPU Frequency: 80Mhz
  • Upload Using: SERIAL
  • Upload Speed: 921600

Problem Description

The signed updates code (#5213) does not correctly implement PKCS#1. This makes it harder to verify the updates in other applications, like a python script.

According to the RFC 8017 section 9.2 step 2:

Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo with the DER.

Currently the signed data looks like this:

00000000  00 01 ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000050  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000070  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000080  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000090  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000a0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000b0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000c0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000d0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff 00  |................|
000000e0  3c 10 ae 9a e8 d3 e6 42  bf c2 a9 c5 71 3f d3 2d  |<......B....q?.-|
000000f0  a5 d3 1d 12 b5 bb dd 86  1b 0a 30 60 4a 2e a2 bd  |..........0`J...|

RFC 8017 step 5 says the encoded message is a concatenation of:
EM = 0x00 || 0x01 || PS || 0x00 || T

T should be the DER of DigestInfo. In this case the DigestInfo should look like:

    0:d=0  hl=2 l=  49 cons: SEQUENCE          
    2:d=1  hl=2 l=  13 cons:  SEQUENCE          
    4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
   15:d=2  hl=2 l=   0 prim:   NULL              
   17:d=1  hl=2 l=  32 prim:  OCTET STRING      [HEX DUMP]:3C10AE9AE8D3E642BFC2A9C5713FD32DA5D31D12B5BBDD861B0A30604A2EA2BD

That would encode to EM:

00000000  00 01 ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000050  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000070  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000080  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000090  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000a0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000b0  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
000000c0  ff ff ff ff ff ff ff ff  ff ff ff ff 00 30 31 30  |.............010|
000000d0  0d 06 09 60 86 48 01 65  03 04 02 01 05 00 04 20  |...`.H.e....... |
000000e0  3c 10 ae 9a e8 d3 e6 42  bf c2 a9 c5 71 3f d3 2d  |<......B....q?.-|
000000f0  a5 d3 1d 12 b5 bb dd 86  1b 0a 30 60 4a 2e a2 bd  |..........0`J...|

The currently used version of BearSSL seems to support proper PKCS#1 signatures, with an OID.

The signing.py is executing:
openssl rsautl -sign -inkey <privatekey> on a pre-computed hash.
To create a signature with a valid PKCS#1 padded signature it should use openssl dgst -sha256 -sign <privatekey> on the raw binary.

Changing this might require additional effort to make it backwards compatible. Old firmware will most likely not accept these new signatures. Intermediate firmware might be required that checks for the new signature format, but is signed with the old method. This might be challenging for users, though since signing updates is relatively new (Oct 2018) it is probably better to do as soon as possible, before even more people are affected.

I'm willing to look into writing a PR for this, but would first like to check if that's appreciated and what the requirements would be.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions