Subject: [TLS] Possible TLS 1.3 erratum

From: Peter Gutmann <[email-masked]>
Date: Thu, 15 Jul 2021 10:55:50 +0000

I've got some code that dumps TLS diagnostic info and realised it was
displaying garbage values for some signature_algorithms entries.  Section
4.2.3 of the RFC says:

      In TLS 1.2, the extension contained hash/signature pairs.  The
      pairs are encoded in two octets, so SignatureScheme values have
      been allocated to align with TLS 1.2's encoding.

However, they don't align with TLS 1.2's encoding (apart from being 16-bit
values), the values are encoded backwards compared to TLS 1.2, so where 1.2
uses { hash, sig } 1.3 uses values equivalent to { sig, hash }.  In particular
to decode them you need to know whether you're looking at a 1.2 value or a 1.3
value, and a 1.2-compliant decoder that's looking at what it thinks are
{ hash, sig } pairs will get very confused.

Should I submit an erratum changing the above text to point out that the
encoding is incompatible and signature_algorithms needs to be decoded
differently depending on whether it's coming from a 1.2 or 1.3 client?  At the
moment the text is misleading since it implies that it's possible to process
the extension with a 1.2-compliant decoder when in fact all the 1.3 ones can't
be decoded like that.

Peter.

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 15 Jul 2021 06:01:20 -0700

As we are currently working on a 8446-bis, the best thing to do would be to
file a PR at:
https://github.com/tlswg/tls13-spec

Thanks,
-Ekr

On Thu, Jul 15, 2021 at 3:56 AM Peter Gutmann <[email-masked]>
wrote:

> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: David Benjamin <[email-masked]>
Date: Thu, 15 Jul 2021 10:53:02 -0400

The SignatureScheme change was perhaps overly clever, but the intent is
that you can process them the same at both versions and backport
the single-enum interpretation. (That's what we do.) The key observation is
that TLS 1.3's allocations will never overlap with a defined TLS 1.2 hash
or signature value. So an old implementation will never send a value that
overlaps with TLS 1.3. More importantly, it will interpret any new TLS 1.3
value as {unknown hash, unknown algorithm} and ignore it, which is what we
want it to do anyway.

That means an old implementation will interop just fine with new values,
and we can freely recast the whole extension as SignatureSchemes in new
implementations.

On Thu, Jul 15, 2021 at 9:02 AM Eric Rescorla <[email-masked]> wrote:

> As we are currently working on a 8446-bis, the best thing to do would be
> to file a PR at:

---

From: Nick Harper <[email-masked]>
Date: Thu, 15 Jul 2021 12:48:16 -0700

Regarding
> so where 1.2 uses { hash, sig } 1.3 uses values equivalent to { sig, hash
}.

While some TLS 1.3 SignatureScheme enum values might appear to have the sig
in the upper octet and hash in the lower octet, that is not the case and
SignatureSchemes for TLS 1.3 only exist as combinations with all parameters
specified. (Some SignatureSchemes, e.g. ed25519 and ed448 don't decompose
into a separate sig and hash.) It does not make sense to think about
decomposing the on-the-wire representation of a SignatureScheme into a
separate sig and hash.

> differently depending on whether it's coming from a 1.2 or 1.3 client?

I don't think an erratum or PR is necessary. A TLS 1.2 server can process
the extension as specified in RFC 5246 (and the TLS 1.3 values will be
ignored as {unknown hash, unknown algorithm}). A TLS 1.3 server can process
the extension as values from the TLS 1.3 SignatureScheme enum, even if TLS
1.2 is negotiated. There's no incompatibility here.

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 16 Jul 2021 12:43:34 +0000

Eric Rescorla <[email-masked]> writes:

>file a PR at: https://github.com/tlswg/tls13-spec

Before I do that I thought I'd get some input on what to say, there's actually
two issues, the first being the one I mentioned.  I was thinking something
like:

  TLS 1.2 defined the entries in the "extension_data" as two eight-bit values
  constituting a { hash, signature } pair.  TLS 1.3 changes the definition to
  be a single 16-bit value constituting a cipher suite that encodes both the
  signature and hash algorithm into a single value.  Although some of the TLS
  1.3 values, in particular the rsa_pss_rsae_xxx ones, appear to follow the
  TLS 1.2 format, implementations SHOULD NOT treat them as { hash, signature }
  pairs but as a single cipher suite identifier.

The second one is the fact that there are two different cipher suites for RSA-
PSS, rsa_pss_rsae_xxx and rsa_pss_pss_xxx, with conditions for use that are
stated in a somewhat backwards form, "If the public key is carried in an
X.509 certificate, it MUST use the RSASSA-PSS OID".  Since the only reason
these exist AFAICT is to deal with rsaEncryption vs. RSA-PSS certs, it should
really be stated as something like "the RSA-PSS code point used depends on how
the key is carried in an X.509 certificate.  If the certificate OID is
rsaEncryption then the rsa_pss_rsae_xxx form MUST be used.  If the certificate
OID is RSASSA-PSS then the rsa_pss_pss_xxx form MUST be used".

And then add some explanation for why this is so and what'll go wrong if you
use the other one, since I can't see any reason why you can't just use
rsa_pss_rsae_xxx or rsa_pss_pss_xxx for everything.  What vulnerability is
this mitigating?

Peter.

---

From: Ilari Liusvaara <[email-masked]>
Date: Fri, 16 Jul 2021 17:01:41 +0300

>   pairs but as a single cipher suite identifier.

Actually, I think this is quite messy issue:

- Signature schemes 0x0403, 0x0503 and 0x0603 alias signature algoritm 3
  hash 4, 5 and 6. However, those two things are not the same, because
  the former have curve restriction, but the latter do not.
- The Ed25519 and Ed448 in TLS 1.2 are registered in messy way: It
  looks like signature algorithms 7 and 8 are registered for that.
  However, those are only valid for hash 8, so codepoints actually
  precisely overlap with corresponding TLS 1.3 signature schemes.
- There is even worse issue with GOST signatures in TLS 1.2. Those are
  signature algorithms 64 and 65, only valid for hash 8. Unfortunately,
  the corresponding schemes 0x0840 and 0x0841 are unallocated.
  Allocating those could cause issues.
- Signature algorithms 224 to 255 are reserved for private use. However,
  much of the schemes those alias are unallocated. Putting any standard
  allocations there could cause issues. No similar issue exists for hash
  algorithms in private use range, because any standard signatures one
  would use with those are reserved anyway.

So one algorithm one could use is:

- Handle anything with signature 0-3/224-255 and hash 0-6/224-255 as
  signature/hash pair.
- Display schemes 0x0840 and 0x0841 specially.
- Handle anything else as signature scheme. 

However, this would not be right for the three ECDSA codepoints, and it
would not be right if in future anything gets allocated to some
potentially troublesome scheme identifiers. It is not necressary to do
anything special with 0x0807 and 0x0808 because mapping those to schemes
gives correct result anyway.

> rsa_pss_rsae_xxx or rsa_pss_pss_xxx for everything.  What vulnerability is

It is not mitigating any vulnerability. The reason is that some TLS
implementations have very hard time supporting RSA-PSS certificates.
And I do not find the conditions to be backwards: There are two, both
scoped.

There is an edge case through: What if keys are not carried on X.509
certificate? In that case, it seems that both are allowed. In
practicular, are Raw Public Keys X.509 certificates? Those do have
RSAEncryption/RSA-PSS distinction like X.509 certificates do. And
then there was some certificate type for automotive applications,
and potentially more future certificate types ("CBOR compressed" is
particualrly fun one, considering those can expand to actual X.509
certificates, but might not do so.)

-Ilari

---

From: Peter Gutmann <[email-masked]>
Date: Mon, 19 Jul 2021 12:06:41 +0000

>Actually, I think this is quite messy issue:

It certainly is.

>Signature schemes 0x0403, 0x0503 and 0x0603 alias signature algoritm 3 hash
>4, 5 and 6. However, those two things are not the same, because the former
>have curve restriction, but the latter do not.

That and the 25519/448 values are definitely the weirdest of the lot.  In
particular the value 0x03 means P256 when used with SHA256, P384 when used
with SHA384, and P521 when used with SHA512.

>- Handle anything else as signature scheme.

I think an easier, meaning with less special cases, way to handle it is for a
TLS 1.2 implementation to treat the values defined in 5246 as { hash,
signature } pairs and for TLS 1.3 and newer implementations to treat all
values as 16-bit cipher suites, combined with a reworking of the definitions,
e.g. to define the "ed25519" suite in terms of the curve and hash algorithm,
not just "Ed25519 and you're supposed to know the rest".

>The reason is that some TLS implementations have very hard time supporting
>RSA-PSS certificates.

But why should the TLS layer care about what OID is used to represent an RSA
key in a certificate?  The signature at the TLS level is either a PSS
signature or it isn't, it doesn't matter which OID is used in the certificate
that carries the key.

More to the point, the TLS layer may have no way to determine which OID is
used in the certificate, it's either an RSA key or not, not "it's an RSA key
with OID A" or "it's an RSA key with OID B".

So I think for bis the text should rename rsa_pss_rsae_xxx to just rsa_pss_xxx
and drop rsa_pss_pss_xxx, which I assume has never been used anyway because I
don't know of any public CA that'll issue a certificate with a PSS OID.

Peter.

---

From: Hubert Kario <[email-masked]>
Date: Mon, 19 Jul 2021 15:25:47 +0200

> signature or it isn't, it doesn't matter which OID is used in 

It only doesn't matter if you don't want to verify the certificate...

It's one thing to be able to be able to verify an RSA-PSS signature on
TLS level, it's entirely another to be able to properly handle all the
different RSA-PSS limitations when using it in SPKI in X.509.

> don't know of any public CA that'll issue a certificate with a PSS OID.

That's because browsers don't have the code to handle RSA-PSS certificates.
But that doesn't mean that there is no code that can do that.
-- 
Regards,
Hubert Kario
Senior Quality Engineer, QE BaseOS Security team
Web: www.cz.redhat.com
Red Hat Czech s.r.o., Purkyňova 99/71, 612 45, Brno, Czech Republic

---

From: "Martin Thomson" <[email-masked]>
Date: Tue, 20 Jul 2021 00:09:03 +1000

> That's because browsers don't have the code to handle RSA-PSS certificates.

Not ALL the code, but we only have one small piece left in Firefox.  And we have plans to address the final small piece.  So maybe soon.

---

From: Peter Gutmann <[email-masked]>
Date: Mon, 19 Jul 2021 19:37:08 +0000

Hubert Kario <[email-masked]> writes:

>It's one thing to be able to be able to verify an RSA-PSS signature on TLS
>level, it's entirely another to be able to properly handle all the different
>RSA-PSS limitations when using it in SPKI in X.509.

Is there anything that's jumped through all the hoops to implement the complex
mess that is PSS but then not added the few lines of code you need do verify
it in certificates?  And if so, why?

In any case it's still encoding a minor implementation artefact of the
certificate library being used into the TLS protocol, where it has absolutely
no place.  You either do PSS or you don't, and the TLS layer doesn't need to
know what magic number you use to identify it in certificates.

More to the point, for a number of certificate libraries there's no way for
the TLS layer to know what magic number is used because it's a minor
implementation detail that isn't exposed in the API.

Peter.

---

From: Hubert Kario <[email-masked]>
Date: Tue, 20 Jul 2021 12:38:48 +0200

> it in certificates?  And if so, why?

I suggest you go back to the RFCs and check exactly what is needed for 
proper
handling of RSA-PSS Subject Public Key type in X.509. Specifically when the
"parameters" field is present.

You definitely won't be able to implement it in just "few lines".

> know what magic number you use to identify it in certificates.

1. It's not minor
2. "What certificates can peer accept" is totally within the purview of 
TLS.
   It's like that for Raw keys, it's like that for GPG certificates, it's
   like that for RSA vs ECDSA vs DSA certificates, and now it's also for
   RSA-PSS.
-- 
Regards,
Hubert Kario
Senior Quality Engineer, QE BaseOS Security team
Web: www.cz.redhat.com
Red Hat Czech s.r.o., Purkyňova 99/71, 612 45, Brno, Czech Republic

---

From: Peter Gutmann <[email-masked]>
Date: Tue, 20 Jul 2021 14:18:38 +0000

Hubert Kario <[email-masked]> writes:

>I suggest you go back to the RFCs and check exactly what is needed for proper

Looking at the code I'm using, it's four lines of extra code for PSS when
reading sigs and four lines extra when writing (OK, technically seven if you
include the "if" statement and curly braces lines).

>You definitely won't be able to implement it in just "few lines".

See above.

>2. "What certificates can peer accept" is totally within the purview of TLS.

Two things, firstly those values are used in two different extensions, only
one of which covers signatures in certificates, and secondly, what happens if
the client says rsa_pss_pss and the server only has an rsa_pss_rsae
certificate?  Does the server admin rush out and buy an rsa_pss_pss
certificate (or, at the moment, found a new public CA that will issue them an
rsa_pss_pss certificate) just to keep the client happy?  Or are they expected
to go out and buy two lots of every certificate that differ only in the RSA
OID used just to play along with the client's request?  This is exactly the
reason why CMS rejected special-case handling for this stuff, because it
doesn't make any sense.  And now TLS is doing the exact thing that CMS
rejected for not making any sense.

Since the next step in the exchange will be to send the client the
certificate, the only thing it could potentially do is save a single round
trip when the handshake is rejected by the server for lack of an
appropriately-OIDed cert rather than the client when it gets said cert.

Peter.

---

From: Ryan Sleevi <[email-masked]>
Date: Tue, 20 Jul 2021 11:17:55 -0400

> include the "if" statement and curly braces lines).

I'm very happy for you. I think other implementers' experiences vastly
differ from your experience, and I hope we can agree that both are valid of
consideration.

For example, the NSS library used by Mozilla has well exceeded a thousand
lines of code so far. I'm sure a thousand lines may not seem like much, in
the grand scheme of things, but not every line is "free or easy" - some
lines are harder to change, and reason about, due to the security
implications. For NSS, this is in part due to its layering design based on
PKCS#11 and its abstraction interfaces for certificates and verification.
It's also partly because as a security-critical library that affects
millions of users, a different standard is applied than might be applied a
hobbyist project.

For browsers like Chrome, used by over a billion users, there are indeed
practical concerns regarding the separation between the TLS layers and the
certificate layer. The "classic" late-90s view of "one library to do it
all" (TLS and PKI) is actually not that common in industry, at least not
those being used "at internet scale". From browsers to mobile devices to
the server room, it's not uncommon for TLS to be implemented by one layer
or library, while certificate verification to be handled by another. They
may share a cryptographic library (e.g. using NSS or JSSE), or they may not
(e.g. Chrome, which integrates with both BoringSSL and the OS libraries).
As such, it's not uncommon for there to be distinction in terms of
capabilities, whether due to abstractions in use or capabilities of the
library in use.

---

From: Peter Gutmann <[email-masked]>
Date: Tue, 20 Jul 2021 16:16:54 +0000

Ryan Sleevi <[email-masked]> writes:

>lines of code so far.

Is that purely to parse PSS in X.509, or for the overall PSS implementation?
I know PSS is a dog's breakfast of arbitrary parameters and values, but I'm a
bit suspicious of that line count just to to process the 'Parameters'
structure, particularly since it's shared with OAEP so already present if you
support OAEP.

Or are you supporting every single possible corner case and weird option
rather than just { SHA-2, MGF1, SHA-2, $SHA2-blocksize }?

>certificate layer. The "classic" late-90s view of "one library to do it all"
>(TLS and PKI) is actually not that common in industry, at least not those
>being used "at internet scale".

And that's exactly the point I'm making, the standard currently encodes low-
level internal details of the PKI implementation into the TLS implementation.
Unless you're using one library to do it all, the TLS layer has no idea what
OID the PKI layer is using to identify an RSA key in a certificate, and so it
has no idea whether it should be saying rsa_pss_rsae or rsa_pss_pss because
the PKI layer just presents a certificate with an RSA key.

All of this is currently hidden by the fact that you can't get PSS-OID certs
from any public CA that I know of so everyone can just hardcode rsa_pss_rsae
everywhere and ignore the issue, but at some point some CA may accidentally
issue a PSS-OID cert and then who knows what'll happen.  

For every single TLS implementation out there.

Peter.

---

From: Ryan Sleevi <[email-masked]>
Date: Tue, 20 Jul 2021 13:05:14 -0400

> Is that purely to parse PSS in X.509, or for the overall PSS

The overall PSS implementation. Parsing PSS w/o an implementation is
sillypants.

Like most modern libraries, NSS is decoupled through various concerns. For
example, one layer deals with parsing the DER and extracting a higher-level
symbolic value specific to the API.

> structure, particularly since it's shared with OAEP so already present if

Eh, say that again? PSS uses RSASSA-PSS-Params and that's a distinct type
than RSAES-OAEP-Params - saltLength/TrailerField vs pSourceAlgorithm.

But most APIs abstract things so folks aren't dealing directly in DER, but
in whatever language-specific representation with type-safety - e.g. a C
struct/Java class/etc

> rather than just { SHA-2, MGF1, SHA-2, $SHA2-blocksize }?

This is 100% part of the problem with PSS - that the parameters have
multiple combinations, rather than being either empty (encapsulated by the
OID to represent the combination) or being memcmp()able. However, both
cryptographic libraries and PKI libraries tend to deal with the abstract
specification.

> level internal details of the PKI implementation into the TLS

Others have pointed out, this was already true with prior versions of TLS
and signature_algorithms reflecting both the TLS parameters and the PKI
parameters. The only distinction here is TLS 1.3 allows them to be treated
separately - since from the TLS point of view, the PKI is *mostly* an
opaque black box. I say *mostly*, because there is the TLS-level constraint
on the keyUsage of the identity certificate.

> the PKI layer just presents a certificate with an RSA key.

No, this isn't really correct either. As mentioned above, since the first
version of TLS, there has been some coupling to the subject certificate
(the server certificate on the server, the client certificate for the
client). The server certificate's keyUsage has long affected the available
ciphersuites a TLS server can successfully negotiate - e.g. whether you're
using an ephemeral key exchange or not - and the subject key has equally
had an impact - e.g. you're not going to negotiate RSA with an EC key, full
stop.

So there's inherently a coupling at the subject certificate, but the
remainder, the certificate path building and verification part, is largely
left as an exercise to the reader. Netscape did this with SSL the IANA IPRA
of RFC 1422 never came about (and for good reason). It was left as a "TBD /
implementation defined" about the policy side, other than the requirements
on the leaf.

TLS 1.3 simply continues this abstraction. The TLS library knows what it
supports at the TLS layer, and still has to be able to parse certificates
and keys (but only its identity certificate), and can leave the
caller/consumer to provide the parameters about what its PKI library
supports.

> from any public CA that I know of

Yes, they're generally forbidden by browser policy, to avoid the
combinatorial compatibility explosion.

> so everyone can just hardcode rsa_pss_rsae

I'm not sure why you're posing it as "unknown" what will happen,
considering it's well-defined.

---

From: Hubert Kario <[email-masked]>
Date: Tue, 20 Jul 2021 21:37:32 +0200

> include the "if" statement and curly braces lines).

And that code will reject a SHA-512 signature if it was made by a 
certificate
with hash algorithm of SHA-256?
What about MGF? Salt length?

Will it reject PKCS#1 v1.5 signatures made with such a key?

It's one thing to be able to read a certificate with those parameters,
it's completely different to actually implement the standard.
-- 
Regards,
Hubert Kario
Senior Quality Engineer, QE BaseOS Security team
Web: www.cz.redhat.com
Red Hat Czech s.r.o., Purkyňova 99/71, 612 45, Brno, Czech Republic