Subject: [TLS] SHA-1 patch updated with Russ' suggestion

From: Martin Thomson <[email-masked]>
Date: Thu, 5 Nov 2015 18:47:51 +0900

Nitpicks accepted, pull requests preferred:

https://github.com/tlswg/tls13-spec/pull/317

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 5 Nov 2015 21:38:34 +0000

> https://github.com/tlswg/tls13-spec/pull/317

I am having a hard time figuring out what's changing.  Can you
summarize the proposal?

I'd like it to say:

    * The signature algorithms of self-signed certificates are
      not subject to any constraints on either the supplicant or
      the verifier.  They are not required to match the supported
      signature algorithms of the peer, are not required to avoid
      deprecated algorithms, and their self-signatures SHOULD NOT
      be checked.

    * A "compatible" certificate message (ideally a certificate
      chain) is one in which each certificate is either self-signed
      or else is signed with a supported signature algorithm
      advertised by the peer.

    * A "non-SHA1" certificate message is a certificate message in
      which each certificate is either self-signed or else is signed
      with a signature algorithm other than SHA-1.

    * A certificate message provided for verification to the peer
      MUST be compatible if at all possible.

    * A compatible certificate message MUST be "non-SHA1" if at
      at all possible.

    * When it is not possible to send a compatible certificate
      message, a suitable default certificate message, in which
      signature algorithms not known to be supported by the peer
      MAY be sent.  The onus of determining whether such a chain
      is trustworthy falls exclusively on the verifier.

    * If a verifier determines that the chain is not trustworthy
      it MAY elect to abort the hanshake with a corresponding fatal
      alert.  If the chain is not trusted because it depends on an
      unsupported signature algorithm, then the appropriate alert
      is unsupported_certificate(43).

Note that the pull request contains harmful text:

    Any endpoint receiving any certificate signed using any signature
    algorithm using an MD5 hash MUST send a "bad_certificate" alert
    message and close the connection.

This breaks peers that send the self-signed CAcert root CA as part
of their chain.  The correct language would be:

    Certificates signed with a signature algorithm based on the
    MD5 hash that are not self-signed MUST NOT be trusted, even if
    signed by a trusted issuer (and not expired, etc.).

I should note that the harmful text is at least on the correct side
of the supplicant/verifier divide.  We protect nobody by restricting
what legitimate supplicants can send, that just lulls verifiers
into a false sense of security (they might not check for conditions
that they are not typically exposed to).  We need to protect
verifiers from what malicious actors will send, and malicious actors
will not play nice by avoiding MD5 and SHA-1.

So the emphasis needs to be clearly on the responsibilities of the
verifier.  Furthermore, questions of whether the chain is trusted
or not trusted belong in the layer doing PKIX (5280) trust chain
construction, not the layer doing TLS protocol message processing.

I will make sure that OpenSSL's stack for TLS 1.3 does not accept
MD5 signatures as trusted and (by default) won't accept SHA-1 as
trusted either.  The simplest implementation is to delete all
non-leaf certificates from the received chain that use disabled or
unsupported algorithms and then construct the chain from what
remains.  

If no trusted chain can be built, succeed or fail accordingly.
Some peers will be opportunistic and go on regardless.  Some peers
will require a secure connection, but will complete the connection
and then gracefully disconnect at the application layer.  Other
peers will abort the handshake and close with a fatal alert.

The logic unequivocally belongs in the verifier as it always did.

The lower levels of the protocol MUST NOT get in the way.

-- 
	Viktor.

---

From: Dave Garrett <[email-masked]>
Date: Thu, 5 Nov 2015 16:59:18 -0500

>       deprecated algorithms, and their self-signatures SHOULD NOT

Why "SHOULD NOT be checked"? I don't think it needs to say anything about checking self-signatures here, one way or another.

Dave

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 5 Nov 2015 22:05:02 +0000

> Why "SHOULD NOT be checked"? I don't think it needs to say anything about checking self-signatures here, one way or another.

The verifier always has a trusted out-of-band copy of each
trust-anchor.  Checking the self-signature may needlessly run into
problems when its deprecated algorithm is no longer even implemented
in the crypto library.  And yet the trust-anchor is still fine.

If this is the only point on which I'm in the rough, so be it, but
as a starting position I think it makes to avoid needless breakage.

-- 
	Viktor.

---

From: Dave Garrett <[email-masked]>
Date: Thu, 5 Nov 2015 18:53:46 -0500

> in the crypto library.  And yet the trust-anchor is still fine.

Ideally, if the implementation is trusting certs as a whole, then it should be attempting to validate self-signatures upon addition to the trust store. If the cert received matches exactly, then it has been checked; redoing it isn't helpful. I note "attempt to validate" and agree that failing but still agreeing to trust the cert could be fine. Essentially, I'd rather it say something to the effect of: "Trusted self-signatures SHOULD be validated before adding to a trust store and SHOULD NOT be re-checked at runtime." But we're getting slightly out of scope here, which is why I'm thinking that elaborating on this topic exactly as suggested is not needed in the document.

Dave

---

From: Viktor Dukhovni <[email-masked]>
Date: Fri, 6 Nov 2015 00:29:42 +0000

On Thu, Nov 05, 2015 at 06:53:46PM -0500, Dave Garrett wrote:

> > > Why "SHOULD NOT be checked"? I don't think it needs to say anything
> > > about checking self-signatures here, one way or another.
> > 
> Ideally, if the implementation is trusting certs as a whole, then it should
> be attempting to validate self-signatures upon addition to the trust store.
> If the cert received matches exactly, then it has been checked; redoing
> it isn't helpful. I note "attempt to validate" and agree that failing but
> still agreeing to trust the cert could be fine. Essentially, I'd rather
> it say something to the effect of: "Trusted self-signatures SHOULD be
> validated before adding to a trust store and SHOULD NOT be re-checked at
> runtime." But we're getting slightly out of scope here, which is why I'm
> thinking that elaborating on this topic exactly as suggested is not needed
> in the document.

Good, we essentially agree on the preferred implementation behaviour,
what remains to quibble over is how explicit the text should be in
that direction.  And your more nuanced formulation is fine.

I think that some implementation guidance is reasonable, but it
can be weaker than "SHOULD".  Implementations need to be strict
where necessary, but being "strict" where unnecessary is bad,
because connections break or downgrade to cleartext in cases that
would otherwise just work.

Having seen both a considerable lack of necessary checks in many
implementations, *and* a considerable excess of counter-productive
unnecessary checks, I prefer to give implementation guidance where
there is non-negligible risk of either type of error.

This particular issue is one where Schannel, for example, is at
present not implemented correctly.  It aborts handshakes when
clients present CAcert.org issued certificates along with the issuer
root CA cert.  In SMTP to outlook.com this typically downgrades
STARTTLS to cleartext for senders configured with client certs as
described.

Yes, I still agree that this is not a major issue, and if the core
issues around client and server obligations are sorted, I can live
with silence on this question if it is felt that guidance of this
type detracts too much from the document.

-- 
	Viktor.

---

From: Russ Housley <[email-masked]>
Date: Thu, 5 Nov 2015 20:15:31 -0500

> https://github.com/tlswg/tls13-spec/pull/317

It might be useful to remind people about the difference between self-signed certificates and self-issued certificates.  RFC 5280 says:

   Self-signed certificates are self-issued certificates where the digital
   signature may be verified by the public key bound into the
   certificate.  Self-signed certificates are used to convey a public
   key for use to begin certification paths.
   Self-issued certificates are CA certificates in which
   the issuer and subject are the same entity.

Self-issued certificates can appear in the middle of a path when a CA is doing key rollover and is doing old-signed-by-new and new-signed-by-old.  The rollover approach is described in RFC 2510; look for "key update".

Self-signed certificates are one very popular way to distribute the public key and distinguished name for a trust anchor.  The certification path validation procedures in Section 6 of RFC 5280 do not validate the signature on such a sel-signed certificate.  It says:

   When the trust anchor is provided in the form of a self-signed
   certificate, this self-signed certificate is not included as part of
   the prospective certification path.

Russ

---

From: Viktor Dukhovni <[email-masked]>
Date: Fri, 6 Nov 2015 01:47:31 +0000

On Thu, Nov 05, 2015 at 08:15:31PM -0500, Russ Housley wrote:

> It might be useful to remind people about the difference between self-signed
> certificates and self-issued certificates.  RFC 5280 says:
> 
> Self-issued certificates can appear in the middle of a path when a CA is
> doing key rollover and is doing old-signed-by-new and new-signed-by-old.
> The rollover approach is described in RFC 2510; look for "key update".

Thanks, I tried to use the right term in this discussion, and by
luck or otherwise seem to have gotten it right.

> Self-signed certificates are one very popular way to distribute the public
> key and distinguished name for a trust anchor.  The certification path
> validation procedures in Section 6 of RFC 5280 do not validate the signature
> on such a sel-signed certificate.  It says:
> 

Which is I think consistent with a recommendation to not check the
self-signatures of trust anchors.

In OpenSSL the definition of self-issued is as you explained, while
self-signed requires all of the below.

    * Self-issued as a pre-requisite.

    * If an authority key id is present, it must match.

    * If keyUsage is present, it must permit certificate signing[0]

So for a CA, a self-issued certificate can avoid being self-signed
by having an authority key identifier that through its key id, or
serial number identifies some other certificate as the issuer.

-- 
	Viktor.

[0] The check of the keyUsage is a recent addition.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 12 Nov 2015 16:21:14 -0800

On 5 November 2015 at 15:53, Dave Garrett <[email-masked]> wrote:
> "Trusted self-signatures SHOULD be validated before adding to a trust store and SHOULD NOT be re-checked at runtime." But we're getting slightly out of scope here, which is why I'm thinking that elaborating on this topic exactly as suggested is not needed in the document.

A trust anchor is a container for a public key and maybe some
ancillary information.  You don't actually need to check the signature
because the process by which you determine that the information is
correct doesn't depend on the signature.

For example, the certificates that are in the Mozilla trust store all
rely on the fact that you downloaded a valid version of Firefox and
the mechanisms by which we safeguard that process.  The signatures on
trust anchors could be garbage and everything would still be fine.

The intent of the change is to point this out.  I'll rebase it and
maybe add the pointer Russ provided, then we can double check that
it's right.  Right now, it's all dependent on other PRs and hard to
follow.

---

From: Sean Turner <[email-masked]>
Date: Wed, 25 Nov 2015 14:39:27 -0500

After reviewing the list discussion, PR#317 (https://github.com/tlswg/tls13-spec/pull/317) is okay to merge. Initially, there was some confusion about exactly what changes were being proposed (PR#317 is built on PR#231) but that seems to have no be cleared up; text about not checking the signature on a self-signed certificates has been added in various places.

Thanks,

J&S

> On Nov 05, 2015, at 04:47, Martin Thomson <[email-masked]> wrote:
> 
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

---

From: Viktor Dukhovni <[email-masked]>
Date: Wed, 25 Nov 2015 20:29:45 +0000

On Wed, Nov 25, 2015 at 02:39:27PM -0500, Sean Turner wrote:

> After reviewing the list discussion, PR#317
> (https://github.com/tlswg/tls13-spec/pull/317) is okay to merge. Initially,
> there was some confusion about exactly what changes were being proposed
> (PR#317 is built on PR#231) but that seems to have no be cleared up; text
> about not checking the signature on a self-signed certificates has been
> added in various places.

It seems the below is the final text on server certificates and SHA-1:

    https://github.com/martinthomson/tls13-spec/commit/bd7d7058d43c946142a8628e7d9103bdf346470a

    +All certificates provided by the server MUST be signed by a
    +hash/signature algorithm pair that appears in the "signature_algorithms"
    +extension provided by the client, if they are able to provide such
    +a chain (see {{signature-algorithms}}).
    +If the server cannot produce a certificate chain that is signed only via the
    +indicated supported pairs, then it SHOULD continue the handshake by sending
    +the client a certificate chain of its choice that may include algorithms
    +that are not known to be supported by the client. This fallback chain MAY
    +use the deprecated SHA-1 hash algorithm.

No problem with that text.  The text for the receiving end could perhaps use
a bit of refinement:

    +As SHA-1 and SHA-224 are deprecated, support for them is NOT RECOMMENDED.
    +Endpoints that reject chains due to use of a deprecated hash MUST send
    +a fatal "bad_certificate" alert message before closing the connection.
    +All endpoints are RECOMMENDED to transition to SHA-256 or better as soon
    +as possible to maintain interoperability with implementations
    +currently in the process of phasing out SHA-1 support.

the point being that the layer that's deciding that the hash
algorithms in the chain are or are not satisfactory is often well
above the code that's responsible for low-level protocol message
processing and alert generation.  Weak signature algorithms will
often simply present as trust failures, and may be reported in
the same way as chains for which no suitable trust anchor is found.

One reason why a precise error may be difficult is that "path
construction" algorithms need not use the particular certificates
provided by the peer, and may have access to alternative certificates
with which to build the chain.  So when an untrusted digest is
encountered, the simplest approach is to ignore that certificate
(filter such certificates out of the peer's response) and try to
build a chain without it.  Which means that the final error may
not be related to that problem digest.

The main case in which one can reasonably expect that the problem
digest will be reported is if the weak signature is in the leaf
certificate, rather than in an intermediate CA.

Some applications don't abort the handshake when trust fails, they
continue and disconnect at the application layer.

So the upshot is that perhaps "MUST" above is stronger than possible.

On the other hand, I don't see implementations taking that MUST
too seriously if it does not comport with how certificate chain
construction and verification is done.  Mere presence of an
unsupported digest in the certificate message should not be a reason
to send the alert and abort, the certificate with the problem
digest might not be needed in the end.  So the decision will (or
at least should) generally be delayed until chain construction
and verification take place, where there's enough complexity
that the proposed MUST may not possible.

My recommendation would be to encourage implementations to not
reject peer certificate messages out of hand (prior to attempting
chain construction and verification) merely because they happen to
contain an element with an unsupported signature.  When chain
verification fails, the library will do its best to communicate
the reason, which may be that its best chain candidate had an
unsupported digest and a "bad_certificate" alert is then sent.  It
may also be that no candidate chain is constructed (the simpler
ignore unsupported intermediates approach), in which case the fatal
alert is more likely "certificate_unknown".

-- 
	Viktor.