-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Description
Problem
Sometimes (but not always) when running the test code below on python 3.14 on Windows it fails with this very odd error:
Traceback (most recent call last):
File "C:\path\to\test_weirdness.py", line 136, in <module>
foo_int_ca = create_intermediate_certificate(
subject_name=x509.Name.from_rfc4514_string(
'C=GB,ST=England,O=Foo Ltd,CN=Foo Ltd Intermediate CA'),
issuer=foo_ca)
File "C:\path\to\test_weirdness.py", line 65, in create_intermediate_certificate
builder = prepare_certificate(subject_name, issuer.cert.subject, 730, public_key)
File "C:\path\to\test_weirdness.py", line 21, in prepare_certificate
builder = builder.not_valid_before(today - datetime.timedelta(days=math.floor(float(valid_days) * 0.3)))
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
OverflowError: cannot convert float infinity to integer
despite valid_days being 730 where of course we expect this simple maths to work just fine:
Python 3.14.2 (tags/v3.14.2:df79316, Dec 5 2025, 17:18:21) [MSC v.1944 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> valid_days = 730
>>> math.floor(float(valid_days) * 0.3)
219
This only seems to happen with certain cryptography versions, which is why I'm filing it here, despite the error occurring in a bit of basic python maths in a very strange way.
Environment
> python.exe -VV
Python 3.14.2 (tags/v3.14.2:df79316, Dec 5 2025, 17:18:21) [MSC v.1944 64 bit (AMD64)]
This repros on cryptography versions:
- 46.0.5 and all versions back to and including 46.0.0
- 45.0.7 (EDIT: and back to 45.0.5 but not before)
But cryptography==44.0.3 does not repro after many attempts.
Repro code
EDIT: see this comment for a slightly smaller repro script which loops until it breaks.
Original repro code
import datetime
import math
from collections import namedtuple
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
CertKeyPair = namedtuple('CertKeyPair', ['cert', 'key'])
CertificateDetails = namedtuple('CertificateDetails', 'pem thumbprint')
def prepare_certificate(subject_name: x509.Name, issuer_name: x509.Name, valid_days: int, public_key) -> x509.CertificateBuilder:
builder = x509.CertificateBuilder()
builder = builder.subject_name(subject_name)
builder = builder.issuer_name(issuer_name)
today = datetime.datetime.today()
# NOTE: this is the line which (sometimes) fails with `OverflowError: cannot convert float infinity to integer`
# despite `valid_days` being a normal integer (e.g. 730 or 365) as confirmed in pdb
builder = builder.not_valid_before(today - datetime.timedelta(days=math.floor(float(valid_days) * 0.3)))
builder = builder.not_valid_after(today + datetime.timedelta(days=math.ceil(float(valid_days) * 0.7)))
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(public_key)
return builder
def create_ca_certificate(subject_name: x509.Name) -> CertKeyPair:
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
builder = prepare_certificate(subject_name, subject_name, 3650, public_key)
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True,
)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
), critical=True,
)
subject_key_id = x509.SubjectKeyIdentifier.from_public_key(public_key)
builder = builder.add_extension(subject_key_id, critical=False)
builder = builder.add_extension(x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(subject_key_id), critical=False)
certificate = builder.sign(private_key=private_key, algorithm=hashes.SHA256())
return CertKeyPair(cert=certificate, key=private_key)
def create_intermediate_certificate(subject_name: x509.Name, issuer: CertKeyPair) -> CertKeyPair:
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
builder = prepare_certificate(subject_name, issuer.cert.subject, 730, public_key)
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=1), critical=True,
)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
), critical=True,
)
builder = builder.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
issuer.cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
), critical=False
)
certificate = builder.sign(private_key=private_key, algorithm=hashes.SHA256())
return CertKeyPair(cert=certificate, key=private_key)
def create_leaf_certificate(subject_name: x509.Name, issuer: CertKeyPair) -> CertKeyPair:
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
builder = prepare_certificate(subject_name, issuer.cert.subject, 365, public_key)
builder = builder.add_extension(
x509.BasicConstraints(ca=False, path_length=None), critical=True,
)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=True,
key_encipherment=True,
data_encipherment=False,
key_agreement=False,
key_cert_sign=False,
crl_sign=False,
encipher_only=False,
decipher_only=False
), critical=True,
)
builder = builder.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
issuer.cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
), critical=False
)
certificate = builder.sign(private_key=private_key, algorithm=hashes.SHA256())
return CertKeyPair(cert=certificate, key=private_key)
# Normally it fails in one of `create_intermediate_certificate` or `create_leaf_certificate`
# with an error in `prepare_certificate` like this:
# builder = builder.not_valid_before(today - datetime.timedelta(days=math.floor(float(valid_days) * 0.3)))
# ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
# OverflowError: cannot convert float infinity to integer
# though sometimes it runs successfully.
# This behaviour started since upgrading to cryptography==46.0.5
foo_ca = create_ca_certificate(
subject_name=x509.Name.from_rfc4514_string(
'C=GB,ST=England,O=Foo Ltd,CN=Foo Ltd CA'))
foo_int_ca = create_intermediate_certificate(
subject_name=x509.Name.from_rfc4514_string(
'C=GB,ST=England,O=Foo Ltd,CN=Foo Ltd Intermediate CA'),
issuer=foo_ca)
foo_signing_cert = create_leaf_certificate(
subject_name=x509.Name.from_rfc4514_string(
'C=GB,ST=England,O=Foo Ltd,CN=Foo Ltd Signing Certificate'),
issuer=foo_int_ca)Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels