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.
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 1d1e044..0a9bc53 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 @@
         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 1d483ac..55f5ddd 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -8,7 +8,6 @@
 import datetime
 import ipaddress
 import os
-import sys
 
 from asn1crypto.x509 import Certificate
 
@@ -1722,18 +1721,16 @@
                     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 @@
         ).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)