Subject: [jose] JSE/JWE algorithm factoring

From: "Jim Schaad" <[email-masked]>
Date: Sat, 21 Jul 2012 19:19:00 -0700

<personal>

Here is another proposal for the people who originally designed the system
to take pot shots at, but one which I think might clean up a few things.

If you look at signature algorithms, you need to specify the following
items:

1.  Where do you find the key to use
2.  What is the public key operation you are using, and
3.  What is the cryptographic hash function you are using.

We now normally combine items 2 and 3 together to make a single signature
algorithm.

If you look at a complete MAC and at encryption systems, you need to specify
a subset of the following items:

1.  Where is the key you need to  use.
2.  What is the public key operation you are using.
3.  What is the KDF function to go from the public key result to a symmetric
key.
4.  What is the key wrap algorithm to go from a symmetric key to a symmetric
key
5.  What is the content algorithm being used with the symmetric key.

For the purposes of this discussion, I am ignoring the issues with doing a
composite AEAD algorithm and assuming that is atomically specified.

If we then look at the different scenarios that need to be supported we do
the following:

a) Directly encrypt or MAC with a known symmetric key:  items 2, 3 and 4 are
omitted, item 5 is specified and item 1 is optionally specified.
b) Use known symmetric key and random CEK:  items 2 and 3 are omitted, items
4 and 5 are specified, item 1 is optionally specified
c)  Use a key agreement algorithm but not a random CEK:  Items 4 is omitted.
Items 2, 3, and 5 are specified, item 1 is optionally specified.
d) For a traditional key transport algorithm: items 3 and 4 are omitted.
Items 2 and 5 are specified and items 1 is optionally specified.
e) For RSA-KEM with a random CEK: Items 2, 3, 4 and 5 are specified and item
1 is optionally omitted.

You also need to look at the data fields that need to be provided.  For
signature algorithms, the output field is the signature value itself.  For
the complete MAC/Encryption  case you have three different fields:

1.  The encrypted content field
2.  The random CEK encrypted some how
3.  The authentication value to be used.

Using the same scenarios as above, the encrypted content is present for
encryption cases and not for MAC cases

a) Only field 3 is present
b) Both data fields 2 and 3 are present
c) Only field 3 is present
d) Both data fields 2 and 3 are present
e) There are two different versions of 2 present (one for a completely
random value and one for the random CEK) as well as field 3.

Ok - that is the background information, now for the proposal:

1)  We specify that if algorithm 2 requires an algorithm 3 then they will be
specified together as a single algorithm name
2)  Any algorithm name not required is omitted.  The steps of how to process
will deal with the case of an omitted name.  The only place where this
presents some interesting issues is when looking for a key to be used and
deciding what type of key is going to be needed.  There will be a couple of
extra steps over what is currently needed as more than one field will need
to be examined before you know if you are looking for a public key algorithm
or a symmetric key algorithm.
3)  Each of the algorithms 2, 4 and 5 will be specified as their own
distinct field names.  Algorithm name 2 will be overloaded by additionally
specifying a signature algorithm in this field.
4)  Algorithm 5 will specify both MAC and content encryption algorithm.  
5)  Any encryption/MAC algorithm which does not use a random CEK value is
not appropriate for use in cases where there is going to be more than one
recipient.
6)  How do I figure out if it is signed, MAC-ed or encrypted?  If content
algorithm is absent, then treat as signed.  If content algorithm field
contains a MAC algorithm treat as MAC-ed.  If content algorithm contains an
encryption algorithm treat as encrypted.  Otherwise treat as unknown object.

There is an issue that needs to be dealt with for the dot notation that is
currently being used.  If you have a full MAC item (with a random CEK) then
the current dot structure is insufficient to handle that case.  I can see a
couple of possible answers:

1)  Allow MACs to have either 2 or 3 dots depending on the situation.
2)  Allow the number of dotted fields to vary for all types depending on the
algorithms being used.  This means that there could be anywhere from 2 to 4
dots depending on the set of items selected.
3) Make all of them fixed at 3 dots and take the hit of the extra character
in some cases.
4) Leave signed at 2 dots, but make MAC and encryption always be 3 dots.

An example of each scenario above:

{"pkAlg":"RSAv1.5-SHA256"}
{"cAlg":"HMAC-SHA256"}
{"cAlg":"HMAC-SHA256", "cwAlg":"AES-WRAP-256"}
{"pkAlg":"ECDH-256-KDF1", "cAlg":"HMAC-SHA256"}
{"pkAlg":"ECDH-256-KDF1","cwAlg":"AES-WRAP-256","cAlg":"AES128"}
{"pkAlg":"RSAv1.5","cAlg":"AES128"}
{"pkAlg":"RSA-KEM-KDF1","cwAlg":"AES-WRAP-256","cAlg":"HMAC-SHA256"}

I am completely unwedded to the names of anything in the examples, I just
choose some simple short names that are representative and easy for me to
remember:
pkAlg - public key algorithm - either a signature algorithm, a key
agreement/key derivation pair or a key transport algorithm (also a key
transport + key derivation for RSA-KEM)
cwAlg - key wrap algorithm
cAlg - content algorithm - either an AEAD algorithm or a MAC algorithm

jim

---

From: "Jim Schaad" <[email-masked]>
Date: Sat, 21 Jul 2012 19:58:01 -0700

After having sent this message and while mowing my driveway, I did come up
with an additional option for the dotted notation question.  One could
restrict the use of MAC to a small subset of the scenarios below (basically
just the first) and the number of data fields would then be the same as the
current document since that is currently the only option that is permitted.

This would require a change in the algorithm descriptions, but not in the
dotted notation.

Jim

> -----Original Message-----
> From: [email-masked] [mailto:[email-masked]] On Behalf Of
> Jim Schaad
> Sent: Saturday, July 21, 2012 7:19 PM
> To: 'Mike Jones'; [email-masked]
> Subject: [jose] JSE/JWE algorithm factoring
> 
> <personal>
> 
> _______________________________________________
> jose mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/jose

---

From: "Manger, James H" <[email-masked]>
Date: Mon, 23 Jul 2012 12:09:57 +1000

Jim,

> Here is another proposal for the people who originally designed the
> system to take pot shots at, but one which I think might clean up a
> few things.
> …

So to process such a value, the recipient:
* Looks for the presence or absence of 3 header fields ("pkAlg", "cAlg", "cwAlg") — giving 8 possible combinations
* Determines if the "cAlg" value is a MAC or encryption algorithm or unrecognized — tripling the 4 combinations when "cAlg" is present

That gives 16 possible "modes". The code can now use a switch statement for the mode-specific processing. Better hope that future modes fit within this model: eg a checksum might have to pretend to be a MAC algorithm; mode that just compresses data (uhmm…).

Wouldn't it be simpler to have a specific field to indicate the mode? Each mode defines how many dot-separated segments there are, what they hold, and which other header fields indicate the algs the mode uses. If you don't recognize the mode you cannot process the message.

Examples:
{"t":"sig", "sig":"RSAv1.5-SHA256"}
{"t":"mac", "mac":"HMAC-SHA256"}
{"t":"wrap-mac", "mac":"HMAC-SHA256", "wrap":"AES-WRAP-256"}
{"t":"agree-mac", "kag":"ECDH-256-KDF1", "mac":"HMAC-SHA256"}
{"t":"agree-wrap-enc", "kag":"ECDH-256-KDF1", "wrap":"AES-WRAP-256", "enc":"AES128"}
{"t":"transport-enc", "kt":"RSAv1.5", "enc":"AES128"}
{"t":"transport-wrap-mac", "kt":"RSA-KEM-KDF1", "wrap":"AES-WRAP-256", "mac":"HMAC-SHA256"}

Want a mode that just compresses data? Define "t":"zip".
Want a MAC mode with the same structure as "t":"mac" but where unrecognized fields MUST be understood? Define "t":"mac!".

--
James Manger

---

From: "Jim Schaad" <[email-masked]>
Date: Sun, 22 Jul 2012 22:05:32 -0700

> From: Manger, James H [mailto:[email-masked]]
> Sent: Sunday, July 22, 2012 7:10 PM
> To: Jim Schaad; [email-masked]
> Subject: RE: [jose] JSE/JWE algorithm factoring
> 
> Jim,
> 
> * Looks for the presence or absence of 3 header fields ("pkAlg", "cAlg",
> "cwAlg")   giving 8 possible combinations
> * Determines if the "cAlg" value is a MAC or encryption algorithm or
> unrecognized   tripling the 4 combinations when "cAlg" is present
> 
> That gives 16 possible "modes". The code can now use a switch statement for
> the mode-specific processing. Better hope that future modes fit within this
> model: eg a checksum might have to pretend to be a MAC algorithm; mode
> that just compresses data (uhmm ).

If this is the way that you are going to define modes then you have vastly understated the number of modes that might exist.  
5 types of pkAlg (sig, key agree, key transport, RSA-KEM like, unknown, absent)
3 types of cwAlg (known, unknown, absent)
4 types of cAlg (encryption, mac, unknown, absent)
5 or 6 ways to retrieve the key information

Total = somewhere around 300?

However some of the things that you add are binary - either you understand and do it or you don't.  Adding Zip does not double the number of modes, just the number of test cases if you are being exhaustive in testing.  In practice however the number of test cases that need to be added is dependent on the number of code paths that are modified not on the complete possible tree of values.

> 
> Wouldn't it be simpler to have a specific field to indicate the mode? Each
> mode defines how many dot-separated segments there are, what they hold,
> and which other header fields indicate the algs the mode uses. If you don't
> recognize the mode you cannot process the message.

I agree that having modes can be useful, but I am not sure that it is going to help in this situation.  The code for dealing with the above is actually very simple logic

if (pkAlg exists) {
   if (pkAlg is a signature algorithm) do signature processing and return
  else if (pkAlg is a known algorithm) {
    find the key
    process the value
  }
 Else throw an error
}

If (cwAlg exists ) {
   If unknown algorithm throw error
    If no key  then find the key
   Process the value
}

If (cAlg exists) {
  If unknown alg then throw error
  If no key known then find the key
  If encryption alg then process as encryption and return
  If mac alg then process as mac and return
}

Throw an error

There are a large number of test cases, but that is different than modes.  Some of the modes currently make no sense.  Why have a cwAlg and no cAlg?  We are not currently in the business of transporting keys for later use.  It might make sense later but not now.  If the cAlg is unknown - who cares about the rest of the algs as you can't go anywhere with it anyway.

> {"t":"agree-wrap-enc", "kag":"ECDH-256-KDF1", "wrap":"AES-WRAP-256",
> "enc":"AES128"} {"t":"transport-enc", "kt":"RSAv1.5", "enc":"AES128"}
> Want a MAC mode with the same structure as "t":"mac" but where
> unrecognized fields MUST be understood? Define "t":"mac!".

And now you also start getting compounded modes - want a mode that is both agree-wrap-enc and zipped - then you start getting a huge number of possible strings to deal with. 

That is not to say that having some level of modes is not a good idea.  I would be more than willing to see the typ field become both mandatory and slightly more useful - i.e. encryption vs signature vs mac as the processing can be very different in the different cases.

Jim

---

From: "Manger, James H" <[email-masked]>
Date: Mon, 23 Jul 2012 16:19:07 +1000

> > Wouldn't it be simpler to have a specific field to indicate the mode?
> > Each mode defines how many dot-separated segments there are, what they
> > hold, and which other header fields indicate the algs the mode uses.
> > If you don't recognize the mode you cannot process the message.

> I agree that having modes can be useful, but I am not sure that it is
> going to help in this situation.  The code for dealing with the above
> is actually very simple logic
> 
> if (pkAlg exists) {

So let's say we publish JOSE v1; you implement this code; then 6 months later JOSE v2 adds the option to compress the data before signing it (by allowing "zip":"DEFLATE" in a JWS). Your code happily processes the message; verifies the signature; then returns DEFLATE gibberish instead of the expected content. Yuck.
A "MUST understand everything" rule (if specified and *IMPLEMENTED everywhere*) might save you by triggering an "unsupported field" error, but such a rule is wrong for lots of other reasons.
A better approach is for JOSE v2 to defines "t":"sig2". Processing is the same as "t":"sig" but if a "zip" field is present the content is compressed. Your old code looks at "t":"sig2" and immediately returns "unsupported mode".

Relying on the presence/absence and values of 3 fields (pkAlg, cwAlg, cAlg) is not extensible to new modes.

> And now you also start getting compounded modes - want a mode that is
> both agree-wrap-enc and zipped - then you start getting a huge number
> of possible strings to deal with.

Not in practice. One mode string can cover lots of "sub-modes" (eg zipped or not), as long as the sub-modes are specified when the mode string is defined. You only need a new mode string when you want something new that could otherwise be misinterpreted. Instead of every field (about the structure, about the keys, about revocation info, about key discovery options, metadata about the content…) needing to be "MUST understand", only the mode string needs to be understood.

We could pick mode strings corresponding to the top-level contentType in CMS (eg SignedData, EncryptedData, AuthenticatedData, AuthEnvelopedData, CompressedData, …).
Or we could be a bit more specific and pick mode strings that cover particular key establishment techniques (eg AuthEnvelopedData.KeyTransport, AuthEnvelopedData.KeyAgreement, AuthEnvelopedData.SymmetricKEK, AuthEnvelopedData.Password, AuthEnvelopedData.IBE, …). I prefer the latter (since we are only likely to specify a subset of key establishment techniques at first).

> That is not to say that having some level of modes is not a good idea.
> I would be more than willing to see the typ field become both mandatory
> and slightly more useful - i.e. encryption vs signature vs mac as the
> processing can be very different in the different cases.

--
James Manger

---

From: "Jim Schaad" <[email-masked]>
Date: Mon, 23 Jul 2012 22:12:11 -0700

> Sent: Sunday, July 22, 2012 11:19 PM
> > > Each mode defines how many dot-separated segments there are, what
> > > they hold, and which other header fields indicate the algs the mode uses.
> >   If mac alg then process as mac and return }
> >
> > Throw an error
> 
> 
> So let's say we publish JOSE v1; you implement this code; then 6 months later
> JOSE v2 adds the option to compress the data before signing it (by allowing
> "zip":"DEFLATE" in a JWS). Your code happily processes the message; verifies
> the signature; then returns DEFLATE gibberish instead of the expected
> content. Yuck.
> A "MUST understand everything" rule (if specified and *IMPLEMENTED
> everywhere*) might save you by triggering an "unsupported field" error, but
> such a rule is wrong for lots of other reasons.
> A better approach is for JOSE v2 to defines "t":"sig2". Processing is the same
> as "t":"sig" but if a "zip" field is present the content is compressed. Your old
> code looks at "t":"sig2" and immediately returns "unsupported mode".
> 

I am not trying to make it extensible to new "modes", I am trying to get a better way to do the current two modes that we have - signing, mac-ing and encrypting.  If we create a new Fudge mode then it needs to define its behavior and may or may not use these fields, just like in the current proposal.

> Not in practice. One mode string can cover lots of "sub-modes" (eg zipped or
> not), as long as the sub-modes are specified when the mode string is
> defined. You only need a new mode string when you want something new
> that could otherwise be misinterpreted. Instead of every field (about the
> structure, about the keys, about revocation info, about key discovery
> options, metadata about the content ) needing to be "MUST understand",
> only the mode string needs to be understood.

This is the same as for my proposal.

> 
> 
> We could pick mode strings corresponding to the top-level contentType in
> CMS (eg SignedData, EncryptedData, AuthenticatedData,
> AuthEnvelopedData, CompressedData,  ).
> Or we could be a bit more specific and pick mode strings that cover particular
> key establishment techniques (eg AuthEnvelopedData.KeyTransport,
> AuthEnvelopedData.KeyAgreement, AuthEnvelopedData.SymmetricKEK,
> AuthEnvelopedData.Password, AuthEnvelopedData.IBE,  ). I prefer the latter
> (since we are only likely to specify a subset of key establishment techniques
> at first).
> 
> 
> 
> > I would be more than willing to see the typ field become both
> > mandatory and slightly more useful - i.e. encryption vs signature vs
> > mac as the processing can be very different in the different cases.
> 
> --
> James Manger