Subject: [dane] Feedback request: python3-dane (A pure-python DANE library for Python 3)

From: Jonas Wielicki <[email-masked]>
Date: Thu, 11 Dec 2014 11:51:56 +0100

Dear list,

I hope this is not too off-topic, but I guess those most well suited for
the task can be found at this list.

I recently started working on a python3 library[1] to support the
implementation of DANE in python3 based applications. I am looking for
some support in form of a second or third pair of eyes. As this is a
security sensitive topic, I would be glad if someone took the time to
look over the approx. 600 lines of python code or the user interface
documentation.

To make it clear what the scope of the library is: It is not a
validating resolver; that is expected to be handled by the application.
it is not a TLS stack or bound to a specific TLS stack. It provides
parsing and hashing of certificates (via the pyasn1 package), as well as
functions to validate a chain of certificates (provided by the
application) used for TLS against a TLSA RRset (provided by the
application) together with the information whether PKIX validation
succeeded (also provided by the application). For PKIX validation, it
provides a facility to extract and validate trust anchors from TLSA RRsets.

I would like a general review (or any kind of feedback for that matter),
but I also have a specific question: I am unsure about the
implementation of the "CA constraint" usage. Is it correct to allow a
"CA constraint" record to enable the use of an otherwise untrusted (but
not invalid, e.g. expired) CA certificate?

Please also take a look at the documentation (for your convenience also
available online at [2]), as it describes the workflow and interface for
developers using the library, which has impact on the achieved security.

If anyone wants to review or take a quick look to see whether I’m doing
the right thing, I would be happy if any issues or feedback to be
reported to me either off-list to this email address, in the github
bugtracker, or on-list if that is considered sufficiently on-topic for
the list. As the library has been published like just now, I assume that
noone has put trust into it yet, so security critical bugs do not need
to be handled privately. If you want to do that nevertheless, use the
GPG key found in the repository (not attaching as it is quite large).
The fingerprint is:

      Key fingerprint = AA5A 78FF 508D 8CF4 F355  F682 E5ED E5AC 679E 300F

thanks for your attention,
Jonas Wielicki

   [1]: https://github.com/horazont/python3-dane/
   [2]: https://docs.zombofant.net/python3-dane/devel/

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 11 Dec 2014 15:05:40 +0000

> look over the approx. 600 lines of python code or the user interface

Here's my advice.  I fully encourage you to experiment with this
code, as a productive learning exercise.  However, please *do not*
document this as something other than experimental code that you
used to develop your understanding of the various technologies.

Unfortunately, in the DANE space, we have too many "toy" libraries
that are wrong or incomplete, and too few that are correct and
comprehensive, and will be maintained in the long term.

My plan is to see DANE support incorporated into the OpenSSL toolkit,
at which point Python applications will be able to use Python's
OpenSSL support (sufficiently recent, ...) to do DANE validation.

A more valuable contribution would be Python code that locates the
right validated TLSA records for a host:port combination that deals
with CNAME expansion and all the requisite DNS error handling per
the OPs draft.  For extra points, code that does this indirectly
via SRV or MX records, and produces also the correct set of "reference
identifiers" that go along with the TLSA records for handling
certificate usages 0, 1 and 2. This should also handle conversion
of IDNA hostnames to A-label form for DNS lookups and certificate
reference identifier construction.

Then, users of future robust DANE validation libraries will be able
to pass the correct TLSA records and "reference identifiers"
(expected DNS subject names) to those libraries.

Please continue to grow your skills in this space, but learning
and development exercises need to be explicitly labeled as such.
Non-expert users have a hard time distinguishing reliable code from
experiments, and would benefit from fewer choices of higher quality.

As to your questions:

   * Usages PKIX-TA(0) and PKIX-EE(1) never accept chains that
     would fail PKIX validation in the absence of DANE (including
     name checks).  These only "constrain" which chains that pass
     PKIX validation should be accepted.

     Great care must be exercised here, for example, after PKIX
     validation succeeds, a naive request to OpenSSL for the peer's
     chain returns the list of wire certificates, not the validated
     chain.  Additional complications arise due to cross-signing,
     that make it difficult to validate a PKIX chain constructed
     in isolation from the DANE records.  Such a chain might use
     a trust-anchor "below" the one that matches the DANE records.

   * Usage DANE-TA(2) is the most difficult to support, and "toy"
     implementations neglect to perform chain construction and
     integrity checks or perform name checks, apply name constraints,
     depth constraints, handle IDNA conversion of hostnames, ...

   * Usage DANE-EE(3) is generally straight-forward, you just
     check that the peer's certificate or public key has
     the expercted digest.  Even here, integration with the
     TLS library is a good idea, because at some point one
     might want to negotiate the use of "raw public keys"
     when the TLSA records for the peer include records
     of the form "3 1 X", which means that the SSL library
     needs to be aware of the TLSA records *before* the
     handshake.

-- 
	Viktor.

---

From: Jonas Wielicki <[email-masked]>
Date: Fri, 12 Dec 2014 11:24:06 +0100

Dear Viktor,

On 11.12.2014 16:05, Viktor Dukhovni wrote:
>> I recently started working on a python3 library[1] to support
>> the implementation of DANE in python3 based applications. I am
>> looking for some support in form of a second or third pair of
>> eyes. As this is a security sensitive topic, I would be glad if
>> someone took the time to look over the approx. 600 lines of
>> python code or the user interface documentation.
> 

I understand your concerns and I have added a note to the README and a
huge red warning to the autogenerated docs.

> right validated TLSA records for a host:port combination that
> deals with CNAME expansion and all the requisite DNS error handling
> per the OPs draft.  For extra points, code that does this
> indirectly via SRV or MX records, and produces also the correct set
> of "reference identifiers" that go along with the TLSA records for
> handling certificate usages 0, 1 and 2. This should also handle
> conversion of IDNA hostnames to A-label form for DNS lookups and
> certificate reference identifier construction.

I agree that this indeed is also a field of problem. However, I
currently don’t dare to implement a DNSSEC validating resolver, which
would be required for this task (or, again, offload the burden of
ensuring such a resolver is present to the user, which is generally
error-prone). There is DNSPython, which has some DNSSEC utilities, but
as far as I know does not provide validation support.

Thank you for giving me the hint to the draft though. I did not know
that it existed and it provides valuable insights on the workings of DANE.

> * Usages PKIX-TA(0) and PKIX-EE(1) never accept chains that would
> fail PKIX validation in the absence of DANE (including name
> checks).  These only "constrain" which chains that pass PKIX
> validation should be accepted.

Thank you, that answers my question.

> chain.

But I assume that one can obtain the actually validated chain using
the verify_callback mechanism provided by OpenSSL?

> Additional complications arise due to cross-signing, that make it
> difficult to validate a PKIX chain constructed in isolation from
> the DANE records.  Such a chain might use a trust-anchor "below"
> the one that matches the DANE records.

I read about that in the draft. I think this is unfortunate, as it
really requires to meld the support into the PKIX validating library,
something I hoped could be avoided (or, alternatively, validate
yourself, as you appearantly did in the postfix DANE code).

> implementations neglect to perform chain construction and integrity
> checks or perform name checks, apply name constraints, depth
> constraints, handle IDNA conversion of hostnames, ...

I wonder whether adding certificates provided by DANE-TA records
(assuming we have a Cert+Full record) to the trusted store of the SSL
implementation (only for that particular connection) and check whether
these have been used after the fact would be sufficient?.

thank you for your input,
Jonas Wielicki

---

From: Viktor Dukhovni <[email-masked]>
Date: Fri, 12 Dec 2014 18:14:12 +0000

> the verify_callback mechanism provided by OpenSSL?

Yes with usage 0/1, with usage 2 the traditional chain building
code cannot be used as-is.

> these have been used after the fact would be sufficient?.

It is not "sufficient", as these are not necessarily self-signed,
and OpenSSL (before 1.0.2) does not have a way to validate chains
that start with trust-anchor that is not self-signed.  Postfix can
also verify chains via a "2 1 0 <public key>" TLSA record, even
when the chain does not include the associated certificate!

-- 
	Viktor.