On Sat, Oct 25, 2025 at 09:27:06AM -0500, Orie wrote: > The purpose of these structures is to create application specific context > that can separate symmetric keys via kdf or cyphers via ahead aad. > > In JOSE there is no risk of being tricked to use non aead, but in COSE that > risk does exist. > > This only matters for key encryption. > > The desired feature is to have the 2 layers connected, such that a change > to one layer forces the other layer to fail closed, without revealing > anything. > > This can be accomplished by pulling the next layer into the info parameter, > as is done in concatKDF in JOSE via a context structure. > > The kdf is the earliest place to separate application context in HPKE, so I > assume it's the safest.
I would definitely not assume it is the safest. The problem is that info mismatches do not immediately stop the process the way aad mismatches do, and AEAD guarantees about wrong aad versus wrong key are very different (e.g., see "key commitment"). However, this is probably not going to be issue in practice (but there might be some pathological AEAD that has some nasty surprises). > But the problem is that this safety is eroaded when all you are encrypting > is a content encryption key, and the algorithm that is used with that key > can be controlled by the attacker. > > This is what motivates the need for a structure that binds between the hpke > encrypted content encryption key (per recipient) and the encrypted content > (shared by all recipients). > > The essential property is that when encrypting and decrypting the content > encryption key, you must know the next algorithm (and accept that it is > secure enough for your use case). However, that does not motivate including "protected" per-recipient attributes or per-recipient aad. And while such things are natural in COSE (e.g., any AEAD-class cipher), it is not natural in JOSE. > My original JOSE/COSE hpke implementations tried to solve this by just > pulling the symmetric layer protected header (including algorithm > identifiers) into the hpke aead aad. > > In COSE this doesn't work, because algorithms in protected headers are > optional. Ilari also pointed out other layering issues with this approach. > > To try to solve this for both JOSE and COSE, you need to pull the essential > parameters into a structure and then use that structure in the hpke > operation on the content encryption key. However, COSE and JOSE have some relevant differences here: - JOSE has exactly one global protected bucket, while COSE has protected bucket per layer with algorithm that supports one (in practice, one wants layer0 algorithm to give a global bucket). - JOSE does not have any true aad facility, whereas COSE does. In practice, the context should be bound to the whole message, so one wants the aad at layer0. > Here is an example: > > hpke_info_or_aad = [ > "hpke_key_encryption_context", > HPKE-0, > A128GCM, > private_info = "" > ] > > This reads out as: > > I'm using hpke-0 to encrypt a content encryption key for use with A128GCM > with optional private information mixed into the kdf or committed via ahead > aad. > > I don't see why we need canonicalization to solve this problem. We do not (but there is a subtle pitfall). The canonicalization is used for protecting per-recipient attributes, which I do not think should be used except when required by JWE itself. With JOSE-HPKE, the required stuff is "alg" and "ek". The latter is explicitly excluded, and "alg" is implicitly authenticated by HPKE anyway. So none of this stuff is useful in any way. The subtle pitfall is encoding JOSE algorithm names. Those are guaranteed to be ASCII, however even ASCII characters can be escaped in JSON (and some even require that). The KDF context solves this using binary encoding. COSE solves this using light canonicalization. > Use string concatenation in JOSE, and CBOR encoding in COSE. Be careful with naive concatenation. For separation, there are things like explicit lengths (which KDF context uses) and the Unicode 0xFF trick[1]. > Am I missing something essential that motivates the need for determinism in > arbitrary data structures to accomplish the security goal? AFAIK, no. [1] Encoding arbitrary sequence of Unicode Scalar Values using UTF-8 never produces 0xFF byte[2] (the same is true if encoding arbitrary sequence of Unicode Codepoints using WTF-8), so it can be used as a terminator. [2] The possible byte values are 0x00 to 0xBF inclusive, and 0xC2 to 0xF4 inclusive. 0xC0 and 0xC1 are impossible as those are invalid encodings of what would be ASCII, and 0xF5 and up would correspond to nonexistent planes (even extension to 32768 planes would only produce up to 0xFD). -Ilari _______________________________________________ jose mailing list -- [email protected] To unsubscribe send an email to [email protected]
