Subject: [CFRG] RSA PSS Salt Length for HTTP Message Signatures

From: Justin Richer <[email-masked]>
Date: Wed, 26 May 2021 16:45:52 -0400

Hi everyone,

I’m one of the editors of the HTTP Message Signatures spec, and I’ve got a question that I was told this list might be a good place to find an answer for. The latest draft of the spec is here if you want to follow along:

https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html>

For some background, this spec defines methods for normalizing and signing HTTP messages (both request and response), along with ways to attach the results of that signature to the HTTP message. This is a draft of the HTTP WG. While applications can profile this with any algorithm that can take in the input string and output the byte array signature, we are defining a handful of general-use signature algorithm methods that can be signaled explicitly.

One of the methods we’re defining uses RSA PSS with SHA512 for a hash. What we’ve discovered in implementation is that it seems like there might be a couple other parameters that also need to be specified, specifically the “salt length”. I had been using one library that defaults this to 20, another library defaults it to (I think?) 32, and another library seems to vary it based on the SHA hash size. Is there a best practice here, or a way to determine what the correct salt length is? I couldn’t find anything in RFC8017 that suggests an appropriate value, so if I’m just missing it please point me to it. 

The current text from the signatures spec is the following, and I’d plan to just add “the salt length (sLen) value is (XX)” in both the sign and verify sections below:

To sign using this algorithm, the signer applies the RSASSA-PSS-SIGN (K, M) function [RFC8017 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC8017>] with the signer's private signing key (K) and the signature input string (M) (Section 2.5 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#create-sig-input>). The hash SHA-512 [RFC6234 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC6234>] is applied to the signature input string to create the digest content to which the digital signature is applied. The resulting signed content byte array (S) is the HTTP message signature output used in Section 3.1 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#sign>.

To verify using this algorithm, the verifier applies the RSASSA-PSS-VERIFY ((n, e), M, S) function [RFC8017 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC8017>] using the public key portion of the verification key material ((n, e)) and the signature input string (M) re-created as described in Section 3.2 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#verify>. The hash function SHA-512 [RFC6234 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC6234>] is applied to the signature input string to create the digest content to which the verification function is applied. The verifier extracts the HTTP message signature to be verified (S) as described in Section 3.2 <https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#verify>. The results of the verification function are compared to the http message signature to determine if the signature presented is valid.

Thank you so much for your help, and please be sure to CC me on replies as I am not subscribed to this list. 
 — Justin

---

From: Russ Housley <[email-masked]>
Date: Wed, 26 May 2021 17:38:29 -0400

RFC 4055 has this recommendation:

         The saltLength field is the octet length of the salt.  For a
         given hashAlgorithm, the recommended value of saltLength is the
         number of octets in the hash value.

Russ

> On May 26, 2021, at 4:45 PM, Justin Richer <[email-masked]> wrote:
> 
> Hi everyone,
> 
> _______________________________________________
> CFRG mailing list
> [email-masked]
> https://www.irtf.org/mailman/listinfo/cfrg

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 27 May 2021 01:51:29 +0000

Justin Richer <[email-masked]> writes:

>I had been using one library that defaults this to 20, another library
>defaults it to (I think?) 32, and another library seems to vary it based on
>the SHA hash size. Is there a best practice here, or a way to determine what
>the correct salt length is? I couldn’t find anything in RFC8017 that suggests
>an appropriate value, so if I’m just missing it please point me to it.

In theory the spec suggests using the hash size, but as you've found in
practice everyone seems to do whatever they feel like, and it's not just for
the salt size, since PSS leaves almost everything as a user-choice parameter
you'll find all sorts of weird unexpected stuff there, with endless weird
corner cases that you'd think no-one would ever implement until you find
something that does.  One thing to look out for is the leading-bits-trimming
that's required but very well disguised in the spec, since some
implementations do it and some don't.

A more general comment is that it'd make more sense to specify PKCS #1 with
encode-then-memcmp() rather than forcing people to guess how other
implementations of PSS work, it's just a huge implementation headache that'll
be repeated for everyone who has to do it.

Peter.

---

From: Justin Richer <[email-masked]>
Date: Thu, 27 May 2021 12:13:48 -0400

Thank you! That is clear guidance and we can use that to set a known value since we are fixing the hash size, in this specific case. 

 — Justin

> On May 26, 2021, at 5:38 PM, Russ Housley <[email-masked]> wrote:
> 
>> On May 26, 2021, at 4:45 PM, Justin Richer <[email-masked] <mailto:[email-masked]>> wrote:
>> 
>> Hi everyone,
>> 
>> [email-masked] <mailto:[email-masked]>

---

From: John Mattsson <[email-masked]>
Date: Thu, 27 May 2021 17:10:35 +0000

Don't forget to specify the mask generation function (MGF). That is another important input. RSA-PSS use two different hash functions that can be different. I have seen implementations of RSA-PSS with SHA2 that only support MGF‐1 with SHA‐1.

Modern standards like CAB Forum Baseline Requirement, JOSE, and COSE, RFC 8692 require use of the same hash algorith for both. CAB Forum Baseline Requirement calls it:

"RSASSA‐PSS with SHA‐512, MGF‐1 with SHA‐512, and a salt length of 64 bytes"

Cheers,
John

From: CFRG <[email-masked]> on behalf of Justin Richer <[email-masked]>
Date: Thursday, 27 May 2021 at 18:14
To: Russ Housley <[email-masked]>
Cc: IRTF CFRG <[email-masked]>
Subject: Re: [CFRG] RSA PSS Salt Length for HTTP Message Signatures
Thank you! That is clear guidance and we can use that to set a known value since we are fixing the hash size, in this specific case.

 — Justin

On May 26, 2021, at 5:38 PM, Russ Housley <[email-masked]<mailto:[email-masked]>> wrote:

Russ

On May 26, 2021, at 4:45 PM, Justin Richer <[email-masked]<mailto:[email-masked]>> wrote:

Hi everyone,

https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html

To sign using this algorithm, the signer applies the RSASSA-PSS-SIGN (K, M) function [RFC8017<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC8017>] with the signer's private signing key (K) and the signature input string (M) (Section 2.5<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#create-sig-input>). The hash SHA-512 [RFC6234<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC6234>] is applied to the signature input string to create the digest content to which the digital signature is applied. The resulting signed content byte array (S) is the HTTP message signature output used in Section 3.1<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#sign>.

To verify using this algorithm, the verifier applies the RSASSA-PSS-VERIFY ((n, e), M, S) function [RFC8017<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC8017>] using the public key portion of the verification key material ((n, e)) and the signature input string (M) re-created as described in Section 3.2<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#verify>. The hash function SHA-512 [RFC6234<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#RFC6234>] is applied to the signature input string to create the digest content to which the verification function is applied. The verifier extracts the HTTP message signature to be verified (S) as described in Section 3.2<https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-04.html#verify>. The results of the verification function are compared to the http message signature to determine if the signature presented is valid.

Thank you so much for your help, and please be sure to CC me on replies as I am not subscribed to this list.
 — Justin
_______________________________________________
CFRG mailing list
[email-masked]<mailto:[email-masked]>
https://www.irtf.org/mailman/listinfo/cfrg<https://protect2.fireeye.com/v1/url?k=0037cec6-5facf624-00378e5d-86073b36ea28-55e61acee15efdff&q=1&e=b4afe96e-fb2a-4ebe-bd17-1b9dd11b902a&u=https%3A%2F%2Fwww.irtf.org%2Fmailman%2Flistinfo%2Fcfrg>

---

From: Justin Richer <[email-masked]>
Date: Thu, 27 May 2021 15:08:04 -0400

Thank you for this follow up. When I was just updating my test vector implementation I saw this as another optional parameter alongside the salt length and so I was about to ask if this was important to specify. I see here that it is. :)

I will swing back around to this list once I have a PR on the HTTP document for feedback on the details of the specification text across the different algorithm types.

Thank you all again, this has been very helpful.
 — Justin

> On May 27, 2021, at 1:10 PM, John Mattsson <[email-masked]> wrote:
> 
> On May 26, 2021, at 5:38 PM, Russ Housley <[email-masked] <mailto:[email-masked]>> wrote:
>  
> https://www.irtf.org/mailman/listinfo/cfrg <https://protect2.fireeye.com/v1/url?k=0037cec6-5facf624-00378e5d-86073b36ea28-55e61acee15efdff&q=1&e=b4afe96e-fb2a-4ebe-bd17-1b9dd11b902a&u=https%3A%2F%2Fwww.irtf.org%2Fmailman%2Flistinfo%2Fcfrg>

---

From: Richard Outerbridge <[email-masked]>
Date: Thu, 27 May 2021 15:18:46 -0400

> On 2021-05-27 (147), at 15:08:04, Justin Richer <[email-masked]> wrote:
> 
>> On May 27, 2021, at 1:10 PM, John Mattsson <[email-masked] <mailto:[email-masked]>> wrote:
>> 
>> Don't forget to specify the mask generation function (MGF). 

Why is this still obscure rocket science?  Have we out done ourselves?  Is crypto still & set to remain the domain of arcane wizards?
__outer

---

From: Brian Smith <[email-masked]>
Date: Thu, 27 May 2021 16:15:32 -0700

>          number of octets in the hash value.

I recommend that you follow the example of TLS 1.3 [1], which is compatible
with that recommendation in RFC 4055:

      RSASSA-PSS [RFC8017
<https://datatracker.ietf.org/doc/html/rfc8017>] with mask generation
function 1.  The digest
      used in the mask generation function and the digest being signed
      are both the corresponding hash algorithm as defined in [SHS
<https://datatracker.ietf.org/doc/html/rfc8446#ref-SHS>].
      The length of the Salt MUST be equal to the length of the digest
      algorithm.  If the public key is carried in an X.509 certificate,
      it MUST use the RSASSA-PSS OID [RFC5756
<https://datatracker.ietf.org/doc/html/rfc5756>]. [...] The algorithm

      parameters MUST be DER encoded.  If the corresponding public key's

      parameters are present, then the parameters in the signature MUST

      be identical to those in the public key.

Some crypto libraries (e.g. mine) only support this exact form of PSS
signatures, both generating and verifying. I am not sure if the rationale
for TLS 1.3's strictness is given anywhere, but it underwent significant
discussion before the above strict form was agreed upon.

[1] https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.3

Cheers,
Brian

---

From: Benjamin Kaduk <[email-masked]>
Date: Thu, 27 May 2021 16:23:54 -0700

> [1] https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.3

The sentiment that comes through in the TLS list archives is that PSS has a
lot of parameters and that means places for implementations to mess up if
they're allowed to vary freely.  If you nail down as part of the protocol
that there is only one way to do things, correct (and testable)
implementation is much easier.

-Ben

---

From: "Martin Thomson" <[email-masked]>
Date: Fri, 28 May 2021 10:21:35 +1000

To add to what Brian and Ben said (listen to their advice), the CA/Browser Forum have also adopted a very narrow profile of PSS if you need further support for this view.

(BTW, I would would change a tiny thing in the TLS text: "the length of the digest algorithm" is generally understood to be the "natural" size of the algorithm's output.  If you look at SHA-2, it's not the block size, which is one measure of the "length" of the digest.  For SHA-2 it's 224, 256, 384, or 512 bits as appropriate.  And with the digest potentially being an XOF, like SHAKE, you have to be careful to avoid saying "output length" as that concept is not always directly applicable to an XOF.)

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 28 May 2021 03:10:37 +0000

Justin Richer <[email-masked]> writes:

>When I was just updating my test vector implementation I saw this as another
>optional parameter alongside the salt length and so I was about to ask if
>this was important to specify. I see here that it is. :)

I would recommend specifying a complete cipher suite that locks down every
single variable parameter to a fixed value, hashes, MGFs, data block sizes,
everything.  Without that you're always going to get some implementation that
creates fully standards-compliant signatures that, nevertheless, nothing else
can deal with.

Or, as I mentioned, use encode-then-memcmp() PKCS #1, since there's nothing to
get wrong in there.

Peter.

---

From: "Salz, Rich" <[email-masked]>
Date: Fri, 28 May 2021 13:05:18 +0000

Perhaps reconsider PSS.  https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html is excellent reading.

---

From: Justin Richer <[email-masked]>
Date: Fri, 28 May 2021 10:44:17 -0400

> Perhaps reconsider PSS.  https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html is excellent reading.

I appreciate the reference, thank you for that. It’s enlightening, but something to note: We aren’t :just: defining RSA-PSS, we’re also defining a flavor of RSA 1.5, a flavor of HMAC, and a flavor of ECDSA, each with fixed parameters including sizes and curves and the like. Which means that our own version of PSS is going to be a very strict and narrow selection tied to a single identifier, and if there’s enough of a draw from any community to define another set of parameters, it can be registered with a new label. The intent is to have zero variability here, which is why I’m reaching out to this group to help nail some of that down as best we can.

On top of that, the algorithm selection happens up at the application layer here, since this is all on top of HTTP. That means that if the two sides have their own way of figuring out which algorithm and parameters to use and they are configured with those, then they can just do that and it doesn’t affect the spec. There’s no expectation of interoperability or runtime negotiation if you’re doing a point solution like that, but for a lot of developers out there the point solution is safer and we can avoid the JOSE “alg: none” problem as a consequence. There are already communities that have their own underlying crypto systems and key management at the application level and they want to keep using that, and we want them to be able to do that using this spec right out of the box. We’re trying to be very careful in enumerating these requirements and expectations in the spec itself, including being much clearer about algorithm and key resolution strategies.

 — Justin

---

From: Brian Smith <[email-masked]>
Date: Fri, 28 May 2021 11:15:00 -0700

Salz, Rich <[email-masked]> wrote:

> Perhaps reconsider PSS.
> https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html
> is excellent reading.
>

I agree with most of the concerns in that document but it's too one-sided
against PSS. A lot of the noted concerns are addressed by following the
advice at the very end, by only using PSS with fixed parameters like TLS
1.3 does.

Note also that RFC 4055 says "For similar reasons, one RSA key pair
should always
be used with the same RSASSA-PSS parameters (except possibly for the salt
length)." The easiest way to follow that advice is to fix all the
parameters in the protocol.

Cheers,
Brian

---

From: "Blumenthal, Uri - 0553 - MITLL" <[email-masked]>
Date: Fri, 28 May 2021 19:51:31 +0000

>    Perhaps reconsider PSS.  https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html is excellent reading.

There is some reason in Peter's arguments - but if we start rejecting better crypto algorithms because it's possible to screw up their 
Implementation, it's unlikely that we end up in a good place. ;-)   

Brian Smith (and others) outlined a good strategy for this, and pretty much every other similar concern: fix the parameter set.

---

From: "Salz, Rich" <[email-masked]>
Date: Fri, 28 May 2021 21:23:24 +0000

> but something to note: We aren’t :just: defining RSA-PSS, we’re also defining a flavor of RSA 1.5, a flavor of HMAC, and a flavor of ECDSA, each with fixed parameters including sizes and curves and the like. Which means that our own version of PSS is going to be a very strict and narrow selection tied to a single identifier, and if there’s enough of a draw from any community to define another set of parameters, it can be registered with a new label. 

That makes a great deal of sense, and mitigates/removes the concerns in the link I posted.

Nice work.

---

From: denis bider <[email-masked]>
Date: Fri, 28 May 2021 20:49:55 -0500

> if we start rejecting better crypto algorithms because it's possible to
> screw up their Implementation, it's unlikely that we end up in a good
place.

The only argument I'm EVER seeing presented against PKCS#1 v1.5 is exactly
the one you refuse to admit against RSA-PSS: the likelihood of incorrect
implementation.

This is even though this thread has shown that PKCS#1 v1.5 is trivial to
implement correctly (encode then memcmp), whereas RSA-PSS is incredibly
hard.

denis

On Fri, May 28, 2021 at 2:52 PM Blumenthal, Uri - 0553 - MITLL <
[email-masked]> wrote:

> On 5/28/21, 09:21, "CFRG on behalf of Salz, Rich" <[email-masked]
> on behalf of rsalz=[email-masked]> wrote:
>
> >    Perhaps reconsider PSS.
> There is some reason in Peter's arguments - but if we start rejecting
> better crypto algorithms because it's possible to screw up their
> Brian Smith (and others) outlined a good strategy for this, and pretty
> much every other similar concern: fix the parameter set.

---

From: Neil Madden <[email-masked]>
Date: Sat, 29 May 2021 07:59:27 +0100

> On 28 May 2021, at 15:45, Justin Richer <[email-masked]> wrote:
> 
> I appreciate the reference, thank you for that. It’s enlightening, but something to note: We aren’t :just: defining RSA-PSS, we’re also defining a flavor of RSA 1.5, a flavor of HMAC, and a flavor of ECDSA, each with fixed parameters including sizes and curves and the like.

No EdDSA? RSA signatures are not very performant for this kind of sign-once-verify-once use-case, because the signing operation is comparatively very expensive for short messages. Although that cost is pushed out to the client, which is preferable, if that client is sending a lot of small API requests this can be a very large overhead. 

I have some serious reservations about the use of signatures for this use case at all. There is no privacy considerations section in the draft, but surely making user’s HTTP requests signed has serious implications for their privacy? Especially if the signing key may be unique to an individual. I think this will have similar privacy issues as DKIM [1].

If the intent of the draft is to provide “end-to-end integrity and authenticity” then IMO a MAC is more appropriate than a signature (which provides much stronger properties), perhaps in combination with an authenticated KEM like HPKE [2].

[1]: https://blog.cryptographyengineering.com/2020/11/16/ok-google-please-publish-your-dkim-secret-keys/ 

[2]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hpke#section-5.1.3

— Neil

---

From: Neil Madden <[email-masked]>
Date: Sat, 29 May 2021 10:14:04 +0100

> Or, as I mentioned, use encode-then-memcmp() PKCS #1, since there's nothing to

By this do you mean *constant-time* memcmp? Otherwise that seems something quite easy to get wrong. 

— Neil

---

From: Peter Gutmann <[email-masked]>
Date: Sat, 29 May 2021 09:21:54 +0000

>By this do you mean *constant-time* memcmp? Otherwise that seems something

You're doing a memcmp() on known, public data, there's nothing to leak so no
need for a constant-time memcmp().

Peter.

---

From: Neil Madden <[email-masked]>
Date: Sat, 29 May 2021 13:26:57 +0100

> need for a constant-time memcmp().

I was thinking of the fault attack mitigation technique where you sign twice and compare. I guess you’re talking about verification instead. 

— Neil