Re: [jose] [COSE] HPKE PartyU / PartyV

Orie Steele <orie@transmute.industries> Thu, 29 February 2024 22:31 UTC

Return-Path: <orie@transmute.industries>
X-Original-To: jose@ietfa.amsl.com
Delivered-To: jose@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 7C788C14F69E for <jose@ietfa.amsl.com>; Thu, 29 Feb 2024 14:31:19 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -7.086
X-Spam-Level:
X-Spam-Status: No, score=-7.086 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_HI=-5, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_KAM_HTML_FONT_INVALID=0.01, T_REMOTE_IMAGE=0.01, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=unavailable autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=transmute.industries
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id o46PARiN66v2 for <jose@ietfa.amsl.com>; Thu, 29 Feb 2024 14:31:15 -0800 (PST)
Received: from mail-pg1-x530.google.com (mail-pg1-x530.google.com [IPv6:2607:f8b0:4864:20::530]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 1DB44C14F699 for <jose@ietf.org>; Thu, 29 Feb 2024 14:31:10 -0800 (PST)
Received: by mail-pg1-x530.google.com with SMTP id 41be03b00d2f7-5d42e7ab8a9so1091866a12.3 for <jose@ietf.org>; Thu, 29 Feb 2024 14:31:10 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=transmute.industries; s=google; t=1709245869; x=1709850669; darn=ietf.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=FGcAPZVuGS69yPG71Y7RtIF/qZlzw9FLgVnYsxeS4TU=; b=UBpfYn3fGlF5Sswq9AZIBqIhg4/7Mcij8p8PO7iy6lb1qHqM0FCvIBIRVZst8oxDRK oSZXmKXmVKsy/j1BNmZ503rQ2A108IBjRq1xfeASWKz1sVJYG/PHmTCdssKerhcWK2Iy SJ+M+d2EAxee4hesnE/50k1gByF3IA23lTY1HNRumU7kWuA2ivHXjn9pu/en4VBCOP6w GGTtGcDx9eTWtowntp8a8veGw5ofKqidnAadl5tREyEph9rIYahWoy7BfSsLkkNsj1xD PrUU3rh5h6CU50paYUMtfe2Tn/5KIuLQqiAx68BAT5FkvienRVqWCeU1nCmw/HZ0RTfT atpw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709245869; x=1709850669; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=FGcAPZVuGS69yPG71Y7RtIF/qZlzw9FLgVnYsxeS4TU=; b=KJXg1jkpLQrF2CUi6TxB3jBYYN9cJJAEn9AOVqAF+Ld5/xqKpx6c113aGbCv4nI770 +Ya+otwBLoD4EnVHGVN52DJu4xg3x21wCjMJZ2UKpmHtoiXQ4B6uphtv7khTsMn68EDO 6ThNUNNUudSDooCalKdvoyf+jGp+BXOkN0JJSQ6p9sSuB6BpVTG+cpjjGGEUBusR6K+7 /IWZ/bHhyGhX7SpxIuLlU+tnHJOmS3031Iq8R75RNL30y7nix305ZKyTA9vw5hVKUgJq DKmg68EIQmog5do7KuTz+qNPPXRaxUOiPCa1u9Q41O2JoTlhDV/T6EAp9lG6kg7FgMHV yDgw==
X-Gm-Message-State: AOJu0Ywk9naSAR/2wz2NLBYS0LSSYeYyxH6Reectq2gL12lb81qONXz7 Kx4UnYJxtt6jNl05/zbfaOkWesaLyCI0uln5JJduySA6MrPB388PZsr3vYhA3dRlqvDpVs5cnAz cmdPcJkIj0hBZPts2o9hxTDUv+n6UwPbvmNs+4kcZvhV+E0hTZ5NuQg==
X-Google-Smtp-Source: AGHT+IHSwv5GdeAYyNEIsBfXXG7vFwZj+RNZ4lFYWQJ1YcWaQwSao7K0s3ryh9fBCUe8zpKNE7pfXVYNm05ytNTw+po=
X-Received: by 2002:a17:90a:e7cc:b0:29b:2179:b1df with SMTP id kb12-20020a17090ae7cc00b0029b2179b1dfmr6484pjb.0.1709245869139; Thu, 29 Feb 2024 14:31:09 -0800 (PST)
MIME-Version: 1.0
References: <CAN8C-_LUMe09=WbkwT-RckhR8+LYCQMw8XWnwmDLE5riYjd7pg@mail.gmail.com> <Zd749IrwWC2hI6yX@LK-Perkele-VII2.locald> <CAN8C-_J+mMABCa2HPWv5zJ=u1HSb+saq_mn5kB0Wq5upWUyM9Q@mail.gmail.com> <Zd-NRA2kH4fc_d-X@LK-Perkele-VII2.locald> <CAN8C-_+tG9845bn986Anr89ObNpUCzOAuiEJMPh4KGK3ixB+uQ@mail.gmail.com> <Zd-colj_jF47gLQP@LK-Perkele-VII2.locald> <CAN8C-_Jw2J6OY6N7gRVepVuHiC5NqgH36dXQ6krZ1U-Spqq7fQ@mail.gmail.com> <ZeCZJK76cQNZp7q9@LK-Perkele-VII2.locald> <CAN8C-_+_nzGCWV6zNny1j_9TTikW8rBtw9388YB7UGzSwEzoTw@mail.gmail.com> <ZeDih4he5eZ1y3PO@LK-Perkele-VII2.locald>
In-Reply-To: <ZeDih4he5eZ1y3PO@LK-Perkele-VII2.locald>
From: Orie Steele <orie@transmute.industries>
Date: Thu, 29 Feb 2024 16:30:57 -0600
Message-ID: <CAN8C-_LpNbCfe3FDF=4nnGEAnZku3+z51J1VcfxuGVqQab=xZg@mail.gmail.com>
To: Ilari Liusvaara <ilariliusvaara@welho.com>
Cc: JOSE WG <jose@ietf.org>, cose <cose@ietf.org>
Content-Type: multipart/alternative; boundary="000000000000dd53f906128cd027"
Archived-At: <https://mailarchive.ietf.org/arch/msg/jose/JPQJv4d0941CA8QirHwBqv2cbv0>
Subject: Re: [jose] [COSE] HPKE PartyU / PartyV
X-BeenThere: jose@ietf.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: Javascript Object Signing and Encryption <jose.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/jose>, <mailto:jose-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/jose/>
List-Post: <mailto:jose@ietf.org>
List-Help: <mailto:jose-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/jose>, <mailto:jose-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 29 Feb 2024 22:31:19 -0000

Inline:

On Thu, Feb 29, 2024 at 2:03 PM Ilari Liusvaara <ilariliusvaara@welho.com>
wrote:

> On Thu, Feb 29, 2024 at 11:04:57AM -0600, Orie Steele wrote:
> > I think we actually agree here.
> >
> > The remaining point is just what to do in HPKE.
> >
> > 1. New header parameters, mandatory processing rules, mix
> > content encryption algorithm into the KDF (via HPKE INFO).
>
> HPKE does not allow using both INFO and AAD for one message (I do not
> know why), and INFO has a short length limit (because it is used in
> ways that pretty much require buffering).
>
> So only AAD can be used.
>
>
> > 2. New Enc_structure, (fix disconnected layers vulnerability), protect
> > "Enc_structure" with AAD (via HPKE AAD).
>
> impl MultiRecipientEncrypt
> {
>         pub fn new(alg: EncryptionAlgorithm, rng: &mut
> TemporaryRandomStream) ->
>                 Result<MultiRecipientEncrypt, String>
>         {
>                 //...
>         }
>         pub fn get_key(&self) -> &[u8] { &self.key }
>         pub fn add_recipient(&mut self, recipient: &[CBOR])
>         {
>                 //...
>

Here is where your recipient code checks the algorithm.
Constructs the Enc_Structure (either fixing, or not fixing the AES-CBC
issue).
Encrypts the content encryption key, using Enc_structure as AAD.
And sets the encrypted_key of the recipient structure.

IMO, it's a mistake to encrypt a symmetric key if you are not sure what it
will be used for...
especially if the attacker can change its use from AES-GCM to AES-CBC.

You can call refusing to encrypt a key without knowing the algorithm it
will be used with a layer violation.
... I call it a security oriented design improvement.


>         }
>         pub fn finish<M:MessageSink>(self, ad: &dyn EncryptAdditionalInfo,
> msg: &[u8], to: M) ->
>                 Result<<<M as MessageSink>::Buffer as
> MessageBuffer>::Residual, String>
>         {
>                 //...
>         }
> }
>
> Any current other-type recipient (which is pretty much anything that is
> not a Direct Encryption or Direct Key Agreement) can be supported via
> that interface.
>
> But it can not support anything that mixes layers. Hence mixing layers
> is a breaking change.
>

I don't get why it cannot, if it's because the protected header is not
known yet... You could refactor your code.

Why do all the "recipient work", only to figure out that AES-CBC is
requested and your library has decided to not implement it...
or is prohibited from implementing it... as is the case for JOSE.


>
> And COSE design clearly intends for the layers to be kept separate.
>
>
Then its design needs to account for attacks that exploit the layer
separation.

You can claim layer purity as a justification for handing out decryption
keys for private messages.

But I don't have to agree with you : )


>
> > What JWE allows, is based on the algorithms it relies on, and their
> > processing rules are algorithm specific, for example:
> >
> > https://datatracker.ietf.org/doc/html/rfc7518#section-4.6.1.2
>
> All those processing rules operate on the JOSE header. Which means no
> distinction between protected and unprotected.
>
> This allows interface analogous to the above to work in JOSE.


>
> > So both 1 and 2 can also work for JOSE, except that there is no
> > "Enc_structure", there is just the normative language regarding:
> >
> > "What to set for HPKE AAD in seal and open" and "What to set for HPKE
> > INFO"...
> >
> > If we are not going to create COSE_KDF_CONTEXT, then suggest we will also
> > not create ConcatKDF context in JOSE.
> >
> > So HPKE INFO, will be the same in both JOSE HPKE and COSE HPKE.
> >
> > The guidance that JOSE provides regarding using the protected header
> bytes
> > as aad, seems reasonable.
> >
> > https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.4.5
> >
> > """
> > Let the Additional Authenticated Data encryption parameter be
> > ASCII(BASE64URL(UTF8(JWE Protected Header)))
> > """
> >
> > When you apply this guidance to HPKE Direct / Integrated Encryption,
> there
> > is only the top level protected header to consider since there is only a
> > single recipient.
>
> Yes, as long as the HPKE enc is not in protected headers, that is
> completely reasonable thing to do.
>

I've implemented both HPKE modes in JOSE and COSE.

It's working fine in protected headers for me...

I don't think it needs to be in protected headers, but in compact JWE...
that's the only header, so that's where it goes... ( encrypted JWT ...
digital identity / credential use cases ).

This also lines up with traditional compact JWE encryption...

  const key1 = await jose.generateKeyPair('ECDH-ES+A128KW', { crv: 'P-256',
extractable: true })
  const jwe = await new jose.CompactEncrypt(
    new TextEncoder().encode('It’s a dangerous business, Frodo, going out
your door.'),
  )
    .setProtectedHeader({ alg: 'ECDH-ES+A128KW', enc: 'A128GCM' })
    .encrypt(key1.publicKey)
  const { plaintext, protectedHeader } = await jose.compactDecrypt(jwe,
key1.privateKey);
  expect(protectedHeader.alg).toBe('ECDH-ES+A128KW')
  expect(protectedHeader.enc).toBe('A128GCM')
  expect(protectedHeader.epk.kty).toBe('EC')
  expect(protectedHeader.epk.crv).toBe('P-256')
  // protected header also protects the epk.
  expect(new TextDecoder().decode(plaintext)).toBe('It’s a dangerous
business, Frodo, going out your door.')



>
>
> > When you apply this guidance to HPKE Key Encryption, in JOSE, you are
> > "mixing layers", but that's ok to do, because there is no way to
> understand
> > any of the HPKE algorithms in the context of JOSE without reading the RFC
> > that defines that behavior... which we are hopefully progressing through
> > these debates : )
>
> No, it is not ok.
>
> The "attack" you are trying to "fix" can never work against JWE.


I'm not trying to fix it for JWE, because those algorithms are prohibited
in JWE:

https://www.iana.org/assignments/jose/jose.xhtml

I am trying to make HPKE AAD take protected headers, because that's how
they are protected in JOSE.

I'm also trying to place "encapsulated keys" in protected and unprotected
headers, because that's where "epk" goes in JOSE.


> And JWE clearly intends an API analogous to the above COSE example to
> work. Again, it is broken by mixing layers. There is even a precedent on
> how AEAD-capable algorithm behaves: It does not mix layers.
>

counterpoint, see the JOSE examples above:

expect(protectedHeader.alg).toBe('ECDH-ES+A128KW')
expect(protectedHeader.enc).toBe('A128GCM')

If you set A128GCM AAD to be the protected header, your AEAD is providing
integrity for your key agreement and key wrapping algorithm identifier.

We know this is not required, because we also have JOSE protected headers
that look like this:
{
  "enc": "A128GCM",
  "epk": {
    "crv": "P-256",
    "kty": "EC",
    "x": "ticr_5a7x5Y4kWPRKIEjMV1ufG_AUW4Ud9Aapmx1uOY",
    "y": "eWboqDQfzcDOaGnNRXansvIG9QgeYrjhs3dh60vQA0M"
  }
}


>
>
> > The logic for COSE is the same, regarding proposals 1 and 2.
>
> With unfortunate difference that RFC 8152 (nor does RFC 9052) did not
> explicitly state a critical security requirement. And then some folks
> went ahead and added a thing that makes it insecure.
>
> (Bonus points for making a thing I can't figure out how to use
> correctly in any useful way...)
>

: )

And this is why we have 2 lists included on this thread.

We don't want to end up making JOSE vulnerable by following COSE advice,
or make COSE vulnerable by following JOSE advice... There are important
security differences.

We also don't want encapsulated keys treated differently in ways that make
security analysis difficult.

Part of the reason why is that we already have security analysis for "epk"
in both JOSE and COSE,
and that's conceptually what DHKems are outputting via "enc".


>
> > I like your comment regarding the fully specified algorithms draft...
> > considering the encryption use case for fully specified algorithms:
> >
> > https://www.rfc-editor.org/rfc/rfc7520#section-5.6.3
> >
> > {
> >      "alg": "dir",
> >      "kid": "77c7e2b8-6e13-45cf-8672-617b5b45243a",
> >      "enc": "A128GCM"
> > }
> >
> > {
> >      "alg": "dir",
> >      "kid": "77c7e2b8-6e13-45cf-8672-617b5b45243a",
> >      "enc": "HPKE-Base-P256-SHA256-AES128GCM"
> > }
> >
> > I would consider both of these cases "fully specified".
>
> >From draft-ietf-jose-fully-specified-algorithms, section 5.
>
> "So for instance, for JOSE, alg values and enc values MUST each be
> fully specified, and their behaviors MUST NOT depend upon one another."
>
> This means that legal enc and legal alg values can be freely combined.
>

I don't follow... is your point that:

{
     "alg": "Ed25519",
     "kid": "77c7e2b8-6e13-45cf-8672-617b5b45243a",
     "enc": "A128GCM"
}

Make no sense?...

I agree but that does not invalid that both "A128GCM" and
"HPKE-Base-P256-SHA256-AES128GCM" are fully specified.


>
>
> > One is fully specified by listing a single AEAD algorithm.
> >
> > The other is fully specified by listing an HPKE SUITE, that bundles KEM,
> > KDF and AEAD together.
>
> The problem is that once you have "enc", it will do its thing. Any
> interference from "alg" is prohibited.
>

I think that's an argument in favor of :

{
     "alg": "dir",
     "kid": "77c7e2b8-6e13-45cf-8672-617b5b45243a",
     "enc": "HPKE-Base-P256-SHA256-AES128GCM"
}

For direct / integrated encryption in JOSE?


> And once you have "alg", it will do its thing, any interference from
> "enc" is prohibited.
>

What do I do with "dir", if I can't look at "enc" ?


>
>
> > In the context of COSE, we don't have "enc", but we do have fully
> specified
> > algorithms for COSE HPKE.
>
> COSE has layers. And it is clear that those are not allowed to interfere
> with one another.
>
>
I'd say it's clear they interfered with each other in ways that produced
vulnerabilities.

That's ok, everyone makes mistakes.

https://datatracker.ietf.org/doc/html/rfc9459 (and it seems the IETF
agrees).

Let's return to the solution:

HPKE AAD = CBOR ( [ "Encrypt1", CBOR ( RecipientProtectedHeader ),  CBOR (
ProtectedHeader ), external_aad ])

If you think Encrypt1 should never have external aad, you don't need a new
structure, you can use Encrypt0 with the layer0 protected header AS
external AAD.

HPKE AAD = CBOR ( [ "Encrypt0", CBOR ( RecipientProtectedHeader ),  CBOR (
ProtectedHeader ) ])

Logically you are encrypting a content encryption key to a single
recipient... so this seems... not that terrible.

This won't stop an attacker from ignoring HPKE recipients and toggling
A128GCM to A128CBC...

But it will prevent HPKE recipients from accidentally handing out an
AES-GCM key 16 bytes at a time for content that might not be exclusively
encrypted to them...

I might not be able to convince my friend to use HPKE, but I don't have to
help an attacker decrypt our shared private content.


>
>
> -Ilari
>
> _______________________________________________
> COSE mailing list
> COSE@ietf.org
> https://www.ietf.org/mailman/listinfo/cose
>


-- 


ORIE STEELE
Chief Technology Officer
www.transmute.industries

<https://transmute.industries>