aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2019-01-21 22:36:25 -0600
committerAlex Gaynor <alex.gaynor@gmail.com>2019-01-21 23:36:25 -0500
commit767fa8511caade795457b23ea9d3d85af1ed12bb (patch)
tree917394e703ca72b35c82b2c9b06e1db22c0363a5
parent5b3e735253d4cc1c7f51dedc11c9ca5eeb6f451f (diff)
downloadplatform_external_python_cryptography-767fa8511caade795457b23ea9d3d85af1ed12bb.tar.gz
platform_external_python_cryptography-767fa8511caade795457b23ea9d3d85af1ed12bb.tar.bz2
platform_external_python_cryptography-767fa8511caade795457b23ea9d3d85af1ed12bb.zip
allow 32-bit platforms to encode certs with dates > unix epoch (#4727)
Previously we used unix timestamps, but now we are switching to using ASN1_TIME_set_string and automatically formatting the string based on the year. The rule is as follows: Per RFC 5280 (section 4.1.2.5.), the valid input time strings should be encoded with the following rules: 1. UTC: YYMMDDHHMMSSZ, if YY < 50 (20YY) --> UTC: YYMMDDHHMMSSZ 2. UTC: YYMMDDHHMMSSZ, if YY >= 50 (19YY) --> UTC: YYMMDDHHMMSSZ 3. G'd: YYYYMMDDHHMMSSZ, if YYYY >= 2050 --> G'd: YYYYMMDDHHMMSSZ 4. G'd: YYYYMMDDHHMMSSZ, if YYYY < 2050 --> UTC: YYMMDDHHMMSSZ Notably, Dates < 1950 are not valid UTCTime. At the moment we still reject dates < Jan 1, 1970 in all cases but a followup PR can fix that.
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py21
-rw-r--r--tests/x509/test_x509.py21
2 files changed, 19 insertions, 23 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 1d1e0446..0a9bc53a 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -5,7 +5,6 @@
from __future__ import absolute_import, division, print_function
import base64
-import calendar
import collections
import contextlib
import itertools
@@ -854,20 +853,12 @@ class Backend(object):
return _Certificate(self, x509_cert)
def _set_asn1_time(self, asn1_time, time):
- timestamp = calendar.timegm(time.timetuple())
- res = self._lib.ASN1_TIME_set(asn1_time, timestamp)
- if res == self._ffi.NULL:
- errors = self._consume_errors()
- self.openssl_assert(
- errors[0]._lib_reason_match(
- self._lib.ERR_LIB_ASN1,
- self._lib.ASN1_R_ERROR_GETTING_TIME
- )
- )
- raise ValueError(
- "Invalid time. This error can occur if you set a time too far "
- "in the future on Windows."
- )
+ if time.year >= 2050:
+ asn1_str = time.strftime('%Y%m%d%H%M%SZ').encode('ascii')
+ else:
+ asn1_str = time.strftime('%y%m%d%H%M%SZ').encode('ascii')
+ res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str)
+ self.openssl_assert(res == 1)
def _create_asn1_time(self, time):
asn1_time = self._lib.ASN1_TIME_new()
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
index 1d483ac2..55f5ddda 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -8,7 +8,6 @@ import binascii
import datetime
import ipaddress
import os
-import sys
from asn1crypto.x509 import Certificate
@@ -1722,18 +1721,16 @@ class TestCertificateBuilder(object):
oid
)[0]._type == asn1_type
- @pytest.mark.skipif(sys.platform != "win32", reason="Requires windows")
@pytest.mark.parametrize(
("not_valid_before", "not_valid_after"),
[
- [datetime.datetime(1999, 1, 1), datetime.datetime(9999, 1, 1)],
- [datetime.datetime(9999, 1, 1), datetime.datetime(9999, 12, 31)],
+ [datetime.datetime(1970, 2, 1), datetime.datetime(9999, 1, 1)],
+ [datetime.datetime(1970, 2, 1), datetime.datetime(9999, 12, 31)],
]
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)
- def test_invalid_time_windows(self, not_valid_before, not_valid_after,
- backend):
+ def test_extreme_times(self, not_valid_before, not_valid_after, backend):
private_key = RSA_KEY_2048.private_key(backend)
builder = x509.CertificateBuilder().subject_name(x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
@@ -1748,8 +1745,16 @@ class TestCertificateBuilder(object):
).not_valid_after(
not_valid_after
)
- with pytest.raises(ValueError):
- builder.sign(private_key, hashes.SHA256(), backend)
+ cert = builder.sign(private_key, hashes.SHA256(), backend)
+ assert cert.not_valid_before == not_valid_before
+ assert cert.not_valid_after == not_valid_after
+ parsed = Certificate.load(
+ cert.public_bytes(serialization.Encoding.DER)
+ )
+ not_before = parsed['tbs_certificate']['validity']['not_before']
+ not_after = parsed['tbs_certificate']['validity']['not_after']
+ assert not_before.chosen.tag == 23 # UTCTime
+ assert not_after.chosen.tag == 24 # GeneralizedTime
@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=X509Backend)