This service will be undergoing maintenance at 00:00 UTC, 2017-10-23 It is expected to last about 30 minutes
Bug 1300655 - OpenSSL: X509_verify_cert() fails to report error when check_trust() returns X509_TRUST_REJECTED
OpenSSL: X509_verify_cert() fails to report error when check_trust() returns ...
Status: CLOSED NOTABUG
Product: Security Response
Classification: Other
Component: vulnerability (Show other bugs)
unspecified
All Linux
medium Severity medium
: ---
: ---
Assigned To: Red Hat Product Security
impact=moderate,public=20160301,repor...
: Security
Depends On:
Blocks: 1300659 1301692
  Show dependency treegraph
 
Reported: 2016-01-21 06:20 EST by Adam Mariš
Modified: 2016-08-12 01:42 EDT (History)
25 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2016-08-11 02:21:37 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
Proposed patch (432 bytes, patch)
2016-01-21 06:23 EST, Adam Mariš
no flags Details | Diff
OpenSSL patch with test cases (84.57 KB, patch)
2016-01-25 06:17 EST, Christian Heimes
no flags Details | Diff
Proposed patch from upstream (7.54 KB, patch)
2016-02-15 11:06 EST, Adam Mariš
no flags Details | Diff

  None (edit)
Description Adam Mariš 2016-01-21 06:20:02 EST
It was reported that x509_cerify_cert() fails to report an error when check_trust() helper function returns X509_TRUST_REJECTED.
Internally trust settings are stored in ASN1_SEQUENCE(X509_CERT_AUX) on disk and in X509->aux member of X.509 certificates. By default certificates have no auxiliary data. Self-signed certificates without auxiliary trust data are considered as trustworthy. When a certificate has auxiliary data and is loaded with a proper function (e.g. PEM_read_bio_X509_AUX() or SSL_CTX_load_verify_locations()), trust settings are verified with X509_check_trust(). The actual trust depends on the purpose of a connection, e.g. NID_server_auth for a client that wants to verify a connection to a TLS web server. For TLS server and client connections, ssl_verify_cert_chain() calls X509_verify_cert() to verify the chain including trust settings. If X509_TRUST_REJECTED is returned by check_trust(), variable 'ok' is still set to 1 from previous call.
Comment 1 Adam Mariš 2016-01-21 06:23 EST
Created attachment 1116900 [details]
Proposed patch
Comment 3 Adam Mariš 2016-01-21 06:29:10 EST
Acknowledgments:

This issue was discovered by Christian Heimes of Red Hat.
Comment 4 Christian Heimes 2016-01-21 11:58:23 EST
I have some updates. It looks like OpenSSL 1.0.2 is broken since https://git.openssl.org/?p=openssl.git;a=commit;h=d65b8b2162f33ac0d53dace588a0847ed827626c


OpenSSL 1.0.0 is not affected. check_trust() returns ok flag.

https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_0-stable#l345
https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_0-stable#l631


OpenSSL 1.0.1 is not affected. check_trust() also returns ok flag.

https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_1-stable#l386
https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_1-stable#l670


OpenSSL 1.0.2 is buggy. check_trust() has been altered and now returns trust flags (X509_TRUST_TRUSTED, X509_TRUST_REJECTED or X509_TRUST_UNTRUSTED). X509_verify_cert() fails to set ok=0 for X509_TRUST_REJECTED. It might also handle X509_TRUST_UNTRUSTED wrong. My patch might be incomplete, I have to look into that case more closely. The X509_TRUST_UNTRUSTED case can occure for certs with e.g. '-addtrust clientAuth'. In that case a certificate is not explicitly distrusted for serverAuth but lacks the trust bit for serverAuth.

https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_2-stable#l363
https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/x509/x509_vfy.c;hb=refs/heads/OpenSSL_1_0_2-stable#l788


OpenSSL master (1.1.0 development) has a different trust and chain building code. It needs further investigation.
Comment 5 Christian Heimes 2016-01-25 06:17 EST
Created attachment 1117928 [details]
OpenSSL patch with test cases
Comment 7 Tomas Mraz 2016-01-25 09:54:37 EST
Our code does not diverge from upstream 1.0.1 branch in this regard so it is not vulnerable.
Comment 8 Adam Mariš 2016-01-27 04:45:46 EST
According to maintainer, the issue is addressed in master (1.1.0-dev) where the chain construction code has been completely rewritten. The 1.1.0-dev code not only avoids this problem, but also exercises explicit reject auxiliary data in the verify tests.
Comment 9 Adam Mariš 2016-02-15 11:06 EST
Created attachment 1127323 [details]
Proposed patch from upstream
Comment 12 Christian Heimes 2016-02-18 06:23:49 EST
Mark, this ticket is about a bug in the trust check code, not about BC / EKU. It's a bug in the trust verification code that was introduced in 2012, https://github.com/openssl/openssl/commit/d65b8b2162f33ac0d53dace588a0847ed827626c#diff-06463ef55f4d9d5411a243b09e66c06fL668


An attack scenario may look like this.

'Evil Country' has a CA called 'Evil CA' that is controlled by an autocratic government. 'Evil CA' has EKU for S/MIME and TLS web server auth. I don't fully trust 'Evil CA' because I know that it signs certs for TLS interception so the government can spy on users. But I still want to trust the CA for S/MIME signing because state officials sign emails.

With OpenSSL's trust feature I can modify the root anchor and make sure that 'Evil CA' is rejected for TLS server auth. After all the feature is documented in the man page of openssl x509. Due to a bug in OpenSSL my policy is silently ignored. 'Evil CA' is able to sign a cert for *.redhat.com and intercept all traffic with Red Hat.


About three years ago we wanted to use the feature in Python and PyOpenSSL. But we weren't able to make trust reject work. We thought it was a problem on our side and gave up. About a month ago I picked up my experiments again. This time I was able to find the bug -- not in my code but in OpenSSL. I don't know if anybody actually uses the feature. But we were almost using it in Python, PyOpenSSL, python-requests and python-cryptography. Just our rigorous unit testing policy prevented us from introducing a serious bug into the Python ecosystem.
Comment 14 Christian Heimes 2016-02-18 06:34:39 EST
I agree that the issue a low severity. As far as I know Red Hat based distros (RHEL, Fedora,...) are the only distros that ship a PEM bundle with TRUSTED CERTIFICATEs, too.

Are you sure that nobody uses /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt or /etc/pki/tls/certs/ca-bundle.trust.crt ?
Comment 16 Christian Heimes 2016-03-01 09:22:00 EST
You can release the embargo. The fix https://github.com/openssl/openssl/commit/a3baa171053547488475709c7197592c66e427cf is in today's OpenSSL 1.0.2g release. The bug wasn't mentioned in the changelog for 1.0.2g and hasn't got a CVE assigned to.

Note You need to log in before you can comment on or make changes to this bug.