Compatibility fix for PyCA cryptography 42.0.0

Cryptography 42.0.0 introduced two new abstract properties
`not_valid_before_utc` and `not_valid_after_utc`, which are non-naive UTC
variants of the `not_valid_before` and `not_valid_after` properties.

The old properties are deprecated. The changeset also modifies code and
tests to use the new `_utc` variants.

Fixes: https://pagure.io/freeipa/issue/9518
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
This commit is contained in:
Christian Heimes 2024-01-24 09:23:22 +01:00 committed by Florence Blanc-Renaud
parent e6014a5c19
commit a45a7a20d9
13 changed files with 61 additions and 31 deletions

View File

@ -1728,8 +1728,8 @@ def cert_summary(msg, certs, indent=' '):
for cert in certs: for cert in certs:
s += '%sSubject: %s\n' % (indent, DN(cert.subject)) s += '%sSubject: %s\n' % (indent, DN(cert.subject))
s += '%sIssuer: %s\n' % (indent, DN(cert.issuer)) s += '%sIssuer: %s\n' % (indent, DN(cert.issuer))
s += '%sValid From: %s\n' % (indent, cert.not_valid_before) s += '%sValid From: %s\n' % (indent, cert.not_valid_before_utc)
s += '%sValid Until: %s\n' % (indent, cert.not_valid_after) s += '%sValid Until: %s\n' % (indent, cert.not_valid_after_utc)
s += '\n' s += '\n'
s = s[:-1] s = s[:-1]

View File

@ -272,6 +272,28 @@ class IPACertificate(crypto_x509.Certificate):
def not_valid_after(self): def not_valid_after(self):
return self._cert.not_valid_after.replace(tzinfo=datetime.timezone.utc) return self._cert.not_valid_after.replace(tzinfo=datetime.timezone.utc)
if hasattr(crypto_x509.Certificate, "not_valid_before_utc"):
# added in python-cryptography 42.0.0
@property
def not_valid_before_utc(self):
return self._cert.not_valid_before_utc
@property
def not_valid_after_utc(self):
return self._cert.not_valid_after_utc
else:
@property
def not_valid_before_utc(self):
return self._cert.not_valid_before.replace(
tzinfo=datetime.timezone.utc
)
@property
def not_valid_after_utc(self):
return self._cert.not_valid_after.replace(
tzinfo=datetime.timezone.utc
)
@property @property
def tbs_certificate_bytes(self): def tbs_certificate_bytes(self):
return self._cert.tbs_certificate_bytes return self._cert.tbs_certificate_bytes

View File

@ -944,19 +944,20 @@ class NSSDatabase:
"""Common checks for cert validity """Common checks for cert validity
""" """
utcnow = datetime.datetime.now(tz=datetime.timezone.utc) utcnow = datetime.datetime.now(tz=datetime.timezone.utc)
if cert.not_valid_before > utcnow: if cert.not_valid_before_utc > utcnow:
raise ValueError( raise ValueError(
f"not valid before {cert.not_valid_before} UTC is in the " f"not valid before {cert.not_valid_before_utc} UTC is in "
"future." "the future."
) )
if cert.not_valid_after < utcnow: if cert.not_valid_after_utc < utcnow:
raise ValueError( raise ValueError(
f"has expired {cert.not_valid_after} UTC" f"has expired {cert.not_valid_after_utc} UTC"
) )
# make sure the cert does not expire during installation # make sure the cert does not expire during installation
if cert.not_valid_after + datetime.timedelta(hours=1) < utcnow: if cert.not_valid_after_utc + datetime.timedelta(hours=1) < utcnow:
raise ValueError( raise ValueError(
f"expires in less than one hour ({cert.not_valid_after} UTC)" f"expires in less than one hour ({cert.not_valid_after_utc} "
"UTC)"
) )
def verify_server_cert_validity(self, nickname, hostname): def verify_server_cert_validity(self, nickname, hostname):

View File

@ -558,7 +558,7 @@ class CACertManage(admintool.AdminTool):
now = datetime.datetime.now(tz=datetime.timezone.utc) now = datetime.datetime.now(tz=datetime.timezone.utc)
for ca_cert, ca_nickname, _ca_trust_flags in ca_certs: for ca_cert, ca_nickname, _ca_trust_flags in ca_certs:
if ca_cert.not_valid_after < now: if ca_cert.not_valid_after_utc < now:
expired_certs.append(ca_nickname) expired_certs.append(ca_nickname)

View File

@ -208,7 +208,7 @@ def expired_dogtag_certs(now):
except RuntimeError: except RuntimeError:
pass # unfortunately certdb doesn't give us a better exception pass # unfortunately certdb doesn't give us a better exception
else: else:
if cert.not_valid_after <= now: if cert.not_valid_after_utc <= now:
certs.append((certid, cert)) certs.append((certid, cert))
return certs return certs
@ -226,12 +226,12 @@ def expired_ipa_certs(now):
# IPA RA # IPA RA
cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM) cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
if cert.not_valid_after <= now: if cert.not_valid_after_utc <= now:
certs.append((IPACertType.IPARA, cert)) certs.append((IPACertType.IPARA, cert))
# Apache HTTPD # Apache HTTPD
cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE) cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
if cert.not_valid_after <= now: if cert.not_valid_after_utc <= now:
if not is_ipa_issued_cert(api, cert): if not is_ipa_issued_cert(api, cert):
non_renewed.append((IPACertType.HTTPS, cert)) non_renewed.append((IPACertType.HTTPS, cert))
else: else:
@ -244,7 +244,7 @@ def expired_ipa_certs(now):
ds_nickname = ds.get_server_cert_nickname(serverid) ds_nickname = ds.get_server_cert_nickname(serverid)
db = NSSDatabase(nssdir=ds_dbdir) db = NSSDatabase(nssdir=ds_dbdir)
cert = db.get_cert(ds_nickname) cert = db.get_cert(ds_nickname)
if cert.not_valid_after <= now: if cert.not_valid_after_utc <= now:
if not is_ipa_issued_cert(api, cert): if not is_ipa_issued_cert(api, cert):
non_renewed.append((IPACertType.LDAPS, cert)) non_renewed.append((IPACertType.LDAPS, cert))
else: else:
@ -252,7 +252,7 @@ def expired_ipa_certs(now):
# KDC # KDC
cert = x509.load_certificate_from_file(paths.KDC_CERT) cert = x509.load_certificate_from_file(paths.KDC_CERT)
if cert.not_valid_after <= now: if cert.not_valid_after_utc <= now:
if not is_ipa_issued_cert(api, cert): if not is_ipa_issued_cert(api, cert):
non_renewed.append((IPACertType.HTTPS, cert)) non_renewed.append((IPACertType.HTTPS, cert))
else: else:
@ -286,7 +286,7 @@ def print_cert_info(context, desc, cert):
print("{} {} certificate:".format(context, desc)) print("{} {} certificate:".format(context, desc))
print(" Subject: {}".format(DN(cert.subject))) print(" Subject: {}".format(DN(cert.subject)))
print(" Serial: {}".format(cert.serial_number)) print(" Serial: {}".format(cert.serial_number))
print(" Expires: {}".format(cert.not_valid_after)) print(" Expires: {}".format(cert.not_valid_after_utc))
print() print()

View File

@ -486,9 +486,9 @@ class BaseCertObject(Object):
obj['serial_number'] = str(cert.serial_number) obj['serial_number'] = str(cert.serial_number)
obj['serial_number_hex'] = '0x%X' % cert.serial_number obj['serial_number_hex'] = '0x%X' % cert.serial_number
obj['valid_not_before'] = x509.format_datetime( obj['valid_not_before'] = x509.format_datetime(
cert.not_valid_before) cert.not_valid_before_utc)
obj['valid_not_after'] = x509.format_datetime( obj['valid_not_after'] = x509.format_datetime(
cert.not_valid_after) cert.not_valid_after_utc)
if full: if full:
obj['sha1_fingerprint'] = x509.to_hex_with_colons( obj['sha1_fingerprint'] = x509.to_hex_with_colons(
cert.fingerprint(hashes.SHA1())) cert.fingerprint(hashes.SHA1()))

View File

@ -1475,14 +1475,14 @@ class ra(rabase.rabase, RestClient):
if issuer_dn: if issuer_dn:
response_request['issuer'] = issuer_dn response_request['issuer'] = issuer_dn
not_valid_before = cert.get('NotValidBefore') not_valid_before_utc = cert.get('NotValidBefore')
if not_valid_before: if not_valid_before_utc:
response_request['valid_not_before'] = ( response_request['valid_not_before'] = (
not_valid_before) not_valid_before_utc)
not_valid_after = cert.get('NotValidAfter') not_valid_after_utc = cert.get('NotValidAfter')
if not_valid_after: if not_valid_after_utc:
response_request['valid_not_after'] = (not_valid_after) response_request['valid_not_after'] = (not_valid_after_utc)
status = cert.get('Status') status = cert.get('Status')
if status: if status:

View File

@ -303,8 +303,9 @@ def set_certificate_attrs(entry_attrs):
entry_attrs['serial_number_hex'] = u'0x%X' % cert.serial_number entry_attrs['serial_number_hex'] = u'0x%X' % cert.serial_number
entry_attrs['issuer'] = unicode(DN(cert.issuer)) entry_attrs['issuer'] = unicode(DN(cert.issuer))
entry_attrs['valid_not_before'] = x509.format_datetime( entry_attrs['valid_not_before'] = x509.format_datetime(
cert.not_valid_before) cert.not_valid_before_utc)
entry_attrs['valid_not_after'] = x509.format_datetime(cert.not_valid_after) entry_attrs['valid_not_after'] = x509.format_datetime(
cert.not_valid_after_utc)
entry_attrs['sha1_fingerprint'] = x509.to_hex_with_colons( entry_attrs['sha1_fingerprint'] = x509.to_hex_with_colons(
cert.fingerprint(hashes.SHA1())) cert.fingerprint(hashes.SHA1()))
entry_attrs['sha256_fingerprint'] = x509.to_hex_with_colons( entry_attrs['sha256_fingerprint'] = x509.to_hex_with_colons(

View File

@ -670,7 +670,7 @@ class TestACMERenew(IntegrationTest):
f'/etc/letsencrypt/live/{self.clients[0].hostname}/cert.pem' f'/etc/letsencrypt/live/{self.clients[0].hostname}/cert.pem'
) )
cert = x509.load_pem_x509_certificate(data, backend=default_backend()) cert = x509.load_pem_x509_certificate(data, backend=default_backend())
initial_expiry = cert.not_valid_after initial_expiry = cert.not_valid_after_utc
self.clients[0].run_command(['certbot', 'renew']) self.clients[0].run_command(['certbot', 'renew'])
@ -678,7 +678,7 @@ class TestACMERenew(IntegrationTest):
f'/etc/letsencrypt/live/{self.clients[0].hostname}/cert.pem' f'/etc/letsencrypt/live/{self.clients[0].hostname}/cert.pem'
) )
cert = x509.load_pem_x509_certificate(data, backend=default_backend()) cert = x509.load_pem_x509_certificate(data, backend=default_backend())
renewed_expiry = cert.not_valid_after renewed_expiry = cert.not_valid_after_utc
assert initial_expiry != renewed_expiry assert initial_expiry != renewed_expiry

View File

@ -1565,7 +1565,7 @@ class TestKRAinstallAfterCertRenew(IntegrationTest):
certs = x509.load_certificate_list(cmd.stdout_text.encode('utf-8')) certs = x509.load_certificate_list(cmd.stdout_text.encode('utf-8'))
# get expiry date of agent cert # get expiry date of agent cert
cert_expiry = certs[0].not_valid_after cert_expiry = certs[0].not_valid_after_utc
# move date to grace period so that certs get renewed # move date to grace period so that certs get renewed
self.master.run_command(['systemctl', 'stop', 'chronyd']) self.master.run_command(['systemctl', 'stop', 'chronyd'])

View File

@ -92,7 +92,7 @@ def get_cert_expiry(host, nssdb_path, cert_nick):
]) ])
data = host.get_file_contents('/root/cert.pem') data = host.get_file_contents('/root/cert.pem')
cert = x509.load_pem_x509_certificate(data, backend=default_backend()) cert = x509.load_pem_x509_certificate(data, backend=default_backend())
return cert.not_valid_after return cert.not_valid_after_utc
@pytest.fixture @pytest.fixture

View File

@ -1595,7 +1595,7 @@ class TestIpaHealthCheck(IntegrationTest):
# Pick a cert to find the upcoming expiration # Pick a cert to find the upcoming expiration
certfile = self.master.get_file_contents(paths.RA_AGENT_PEM) certfile = self.master.get_file_contents(paths.RA_AGENT_PEM)
cert = x509.load_certificate_list(certfile) cert = x509.load_certificate_list(certfile)
cert_expiry = cert[0].not_valid_after cert_expiry = cert[0].not_valid_after_utc
# Stop chronyd so it doesn't freak out with time so off # Stop chronyd so it doesn't freak out with time so off
restart_service(self.master, 'chronyd') restart_service(self.master, 'chronyd')

View File

@ -246,6 +246,8 @@ class test_x509:
assert cert.serial_number == 1093 assert cert.serial_number == 1093
assert cert.not_valid_before == not_before assert cert.not_valid_before == not_before
assert cert.not_valid_after == not_after assert cert.not_valid_after == not_after
assert cert.not_valid_before_utc == not_before
assert cert.not_valid_after_utc == not_after
assert cert.san_general_names == [] assert cert.san_general_names == []
assert cert.san_a_label_dns_names == [] assert cert.san_a_label_dns_names == []
assert cert.extended_key_usage == {'1.3.6.1.5.5.7.3.1'} assert cert.extended_key_usage == {'1.3.6.1.5.5.7.3.1'}
@ -277,6 +279,8 @@ class test_x509:
# ensure the timezone doesn't mess with not_before and not_after # ensure the timezone doesn't mess with not_before and not_after
assert cert.not_valid_before == not_before assert cert.not_valid_before == not_before
assert cert.not_valid_after == not_after assert cert.not_valid_after == not_after
assert cert.not_valid_before_utc == not_before
assert cert.not_valid_after_utc == not_after
def test_load_pkcs7_pem(self): def test_load_pkcs7_pem(self):
certlist = x509.pkcs7_to_certs(good_pkcs7, datatype=x509.PEM) certlist = x509.pkcs7_to_certs(good_pkcs7, datatype=x509.PEM)
@ -312,6 +316,8 @@ class test_x509:
datetime.timezone.utc) datetime.timezone.utc)
assert cert.not_valid_before == not_before assert cert.not_valid_before == not_before
assert cert.not_valid_after == not_after assert cert.not_valid_after == not_after
assert cert.not_valid_before_utc == not_before
assert cert.not_valid_after_utc == not_after
assert cert.san_general_names == [DNSName('ipa.demo1.freeipa.org')] assert cert.san_general_names == [DNSName('ipa.demo1.freeipa.org')]
assert cert.san_a_label_dns_names == ['ipa.demo1.freeipa.org'] assert cert.san_a_label_dns_names == ['ipa.demo1.freeipa.org']
assert cert.extended_key_usage == { assert cert.extended_key_usage == {