Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestX509StoreContext::test_verify_with_time FAILED #684

Open
PPed72 opened this issue Aug 17, 2017 · 10 comments
Open

TestX509StoreContext::test_verify_with_time FAILED #684

PPed72 opened this issue Aug 17, 2017 · 10 comments

Comments

@PPed72
Copy link

PPed72 commented Aug 17, 2017

Whenever I try to build pyopenssl-17.2.0 on my gentoo system I get the following test failure:

tests/test_crypto.py::TestX509StoreContext::test_verify_with_time FAILED
[...]
================================================================== FAILURES ==================================================================
_________________________________________________ TestX509StoreContext.test_verify_with_time _________________________________________________

self = <tests.test_crypto.TestX509StoreContext object at 0x00007f71d67b9360>

    def test_verify_with_time(self):
        """
            `verify_certificate` raises error when the verification time is
            set at notAfter.
            """
        store = X509Store()
        store.add_cert(self.root_cert)
        store.add_cert(self.intermediate_cert)
    
        expire_time = self.intermediate_server_cert.get_notAfter()
        expire_datetime = datetime.strptime(
            expire_time.decode('utf-8'), '%Y%m%d%H%M%SZ'
        )
        store.set_time(expire_datetime)
    
        store_ctx = X509StoreContext(store, self.intermediate_server_cert)
        with pytest.raises(X509StoreContextError) as exc:
>           store_ctx.verify_certificate()
E           Failed: DID NOT RAISE <class 'OpenSSL.crypto.X509StoreContextError'>

tests/test_crypto.py:3639: Failed
==================================================== 1 failed, 504 passed in 9.74 seconds ====================================================
 * ERROR: dev-python/pyopenssl-17.2.0::gentoo failed (test phase):

openssl version is 1.0.2l

It happens with any python implementation on my system (I have python-2.7, python-3.5, pypy and pypy3)

@hynek
Copy link
Contributor

hynek commented Nov 26, 2017

Could we just…you know give expire_datetime 13h of leeway? 😇

@PPed72
Copy link
Author

PPed72 commented Nov 27, 2017

c)

Run the whole test suite in UTC local, e.g. "TZ=UTC py.test -v"

This seems the most reasonable approach.

@Mno-hime
Copy link

c)
Run the whole test suite in UTC local, e.g. "TZ=UTC py.test -v"

This seems the most reasonable approach.

TZ=UTC worked for me on OpenIndiana 2019.04.

@orosam
Copy link
Contributor

orosam commented Oct 8, 2020

This appears to be a bug in X509Store.set_time(), caused by vfy_time.strftime("%s") (vfy_time is a datetime object) disregarding the timezone, therefore passing an incorrect timestamp to X509_VERIFY_PARAM_set_time().

The "%s" problem is a known python issue, see Issue 12750, but it's not very straightforward to fix here. On python >= 3.3, int(vfy_time.timestamp()) could be used instead of int(vfy_time.strftime("%s")), but that's not available on python 2.7.

On python 3, the issue can be verified easily:

>>> from datetime import datetime, timezone
>>> tn = datetime.strptime("19700101000000Z", "%Y%m%d%H%M%SZ")  # tn will be naive (timezone-unaware)
>>> tn.timestamp()
-3600.0  # I'm in CET, which is 1 hour after UTC on 1st January
>>> tn.strftime("%s")
'-3600'
>>> ta = tn.replace(tzinfo=timezone.utc)  # ta will be timezone-aware
>>> ta.timestamp()
0.0  # since ta is in UTC, the timestamp of 1970-01-01 00:00 UTC is zero
>>> ta.strftime("%s")
'-3600'  # but strftime("%s") disregards the timezone in ta, and always uses the local timezone

@orosam
Copy link
Contributor

orosam commented Oct 12, 2020

... and apparently I'm not the first to figure this out. I just bumped into #798, which is basically the same issue, and #907 fixing them.

@reaperhulk
Copy link
Member

@orosam thats another PR that needs rebasing sadly. 😬

@orosam
Copy link
Contributor

orosam commented Oct 12, 2020

I was playing with that a little 😄, strftime("%s") is evil... More about that at #798...

@orosam
Copy link
Contributor

orosam commented Oct 26, 2020

This issue is also fixed by #907, and documented in #952.

@mcepl
Copy link

mcepl commented Dec 11, 2020

Perhaps this issue has been fixed, but I have two more failures with this test.

This one is on 32bit i586 (OpenSUSE/Tumbleweed):

[   48s] __________________ TestX509StoreContext.test_verify_with_time __________________
[   48s] 
[   48s] self = <tests.test_crypto.TestX509StoreContext object at 0xf61d3f2c>
[   48s] 
[   48s]     def test_verify_with_time(self):
[   48s]         """
[   48s]         `verify_certificate` raises error when the verification time is
[   48s]         set at notAfter.
[   48s]         """
[   48s]         store = X509Store()
[   48s]         store.add_cert(self.root_cert)
[   48s]         store.add_cert(self.intermediate_cert)
[   48s]     
[   48s]         expire_time = self.intermediate_server_cert.get_notAfter()
[   48s]         expire_datetime = datetime.strptime(
[   48s]             expire_time.decode("utf-8"), "%Y%m%d%H%M%SZ"
[   48s]         )
[   48s] >       store.set_time(expire_datetime)
[   48s] 
[   48s] tests/test_crypto.py:4111: 
[   48s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   48s] 
[   48s] self = <OpenSSL.crypto.X509Store object at 0xf61d3fec>
[   48s] vfy_time = datetime.datetime(2047, 12, 20, 17, 11, 20)
[   48s] 
[   48s]     def set_time(self, vfy_time):
[   48s]         """
[   48s]         Set the time against which the certificates are verified.
[   48s]     
[   48s]         Normally the current time is used.
[   48s]     
[   48s]         .. note::
[   48s]     
[   48s]           For example, you can determine if a certificate was valid at a given
[   48s]           time.
[   48s]     
[   48s]         .. versionadded:: 17.0.0
[   48s]     
[   48s]         :param datetime vfy_time: The verification time to set on this store.
[   48s]         :return: ``None`` if the verification time was successfully set.
[   48s]         """
[   48s]         param = _lib.X509_VERIFY_PARAM_new()
[   48s]         param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free)
[   48s]     
[   48s]         _lib.X509_VERIFY_PARAM_set_time(
[   48s] >           param, calendar.timegm(vfy_time.timetuple())
[   48s]         )
[   48s] E       OverflowError: integer 2460474680 does not fit '32-bit int'
[   48s] 
[   48s] ../../BUILDROOT/python-pyOpenSSL-20.0.0-71.1.i386/usr/lib/python3.6/site-packages/OpenSSL/crypto.py:1680: OverflowError

@reaperhulk
Copy link
Member

On x86 (not x86_64) time_t is defined as a 32-bit value. Unfortunately this means verification past int32 max won't work. OpenSSL may have other APIs for this, but someone will need to do the research.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

7 participants
@hynek @reaperhulk @mcepl @PPed72 @Mno-hime @orosam and others