suit-wg / suit-firmware-encryption

Repo for draft-ietf-suit-firmware-encryption
1 stars 5 forks source link

Countersignature #9

Closed hannestschofenig closed 2 years ago

hannestschofenig commented 2 years ago

Marco suggested to explore the use of countersignatures to reduce the size of the signed signed and encrypted payload.

hannestschofenig commented 2 years ago

I have been thinking about the use of countersignatures for firmware encryption and COSE HPKE in particular.

Ideally, one would want to use COSE_Countersignature0 since it is efficient since it only carries the signature. Unfortunately, it also does not contain any algorithm or key id information. Currently there is no information in the payload that allows the recipient to identify the signature algorithm and the key id used by the sender. My conclusion is that COSE_Countersignature0 cannot be used for COSE HPKE.

The full counter signature could, however, be used since it carries additional information in the protected and the unprotected headers. Unfortunately, the full counter signature does not give benefits, as far as I can tell, over just applying the signature over the regular COSE_Encrypt/ COSE_Encrypt0 payload.

hannestschofenig commented 2 years ago

Marco responded by email:

I agree, and we were already suspecting this in Philadelphia. The recipients can't assume in advance who the signer is or the details about the signing process.

TLDR; Having a countersignature in the COSE Header of the Encrypt_0 object should still result in a small advantage, but it may be considered not worth it.

This started with a discussion on the SUIT Envelope in [1], i.e.,

SUIT_Envelope = {
     ...
     suit-protection-wrappers => bstr .cbor {
         *(int/str) => [+ SUIT_Encryption_Info]
     }
}

With reference to the HPKE case, my original question was about where and how to include the signature here, since authentication of the Encrypt_0 object is expected, see [2]. I think the conclusion was to consider something like this.

SUIT_Envelope = {
     ...
     suit-protection-wrappers => bstr .cbor {
         *(int/str) => [+ SUIT_Protection_Info]
     }
}

Where "SUIT_Protection_Info" can be COSE_Encrypt_Tagged (like in the AES Key Wrap case) or COSE_Signature / COSE_Sign1 (like in the HPKE case).

Then, the serialized CBOR map would have (at least) two entries, i.e.:

0 => [Encrypt_0_OBJ_1, Encrypt_0_OBJ_2 ...]
1 => [Sign_1_OBJ_1, Sign_0_OBJ_2 ...]

Where the i-th signature in the second array pertains to the i-th Encrypt_0 object of the first array. I think this would work fine already.

Then the follow-up question was if this can be improved by having the signatures embedded as countersignatures in the header of the Encrypt_0 objects.

Assuming that at most 23 Encrypt_0 objects are transferred, that would mean:

0 => [Encrypt_0_OBJ_1_with_CountSign, Encrypt_0_OBJ_2_with_CountSign ...]

That is:

Basically, this pays off (with 1 less byte of overhead) if you transfer only one Encrypt_0 object, which I thought would always be the case when using the HPKE construction.

However, if that's correct, then the overall "suit-protection-wrappers" can become as follows:

COSE_Encrypt_Tagged = #6.96(COSE_Encrypt)
SUIT_Encryption_Info = COSE_Encrypt_Tagged

SUIT_Protection_Info = COSE_Encrypt / COSE_Encrypt0 / SUIT_Encryption_Info

SUIT_Envelope = {
     ...
     ? suit-protection-wrappers => bstr .cbor {
         *(int/str) => SUIT_Protection_Info / [+ SUIT_Protection_Info]
     }
}

In the HPKE case, the serialized CBOR map in "suit-protection-wrappers" would have a single element with an HPKE-related registered label, i.e., the Encrypt_0 object including the countersignature in its COSE Header parameter. Since another CBOR array is gone, this yields a total gain of 2 bytes.

Clearly, it's a call of judgment if a gain of 2 bytes is overall worth it.