Skip to content

Commit ce32c41

Browse files
committed
fix aia encoding memory leak
1 parent 857d401 commit ce32c41

File tree

2 files changed

+74
-10
lines changed

2 files changed

+74
-10
lines changed

src/cryptography/hazmat/backends/openssl/encode_asn1.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -345,16 +345,22 @@ def _encode_authority_information_access(backend, authority_info_access):
345345
aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
346346
backend.openssl_assert(aia != backend._ffi.NULL)
347347
aia = backend._ffi.gc(
348-
aia, backend._lib.sk_ACCESS_DESCRIPTION_free
348+
aia,
349+
lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
350+
x, backend._ffi.addressof(
351+
backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
352+
)
353+
)
349354
)
350355
for access_description in authority_info_access:
351356
ad = backend._lib.ACCESS_DESCRIPTION_new()
352357
method = _txt2obj(
353358
backend, access_description.access_method.dotted_string
354359
)
355-
gn = _encode_general_name(backend, access_description.access_location)
360+
_encode_general_name_preallocated(
361+
backend, access_description.access_location, ad.location
362+
)
356363
ad.method = method
357-
ad.location = gn
358364
res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
359365
backend.openssl_assert(res >= 1)
360366

@@ -385,8 +391,12 @@ def _encode_subject_key_identifier(backend, ski):
385391

386392

387393
def _encode_general_name(backend, name):
394+
gn = backend._lib.GENERAL_NAME_new()
395+
return _encode_general_name_preallocated(backend, name, gn)
396+
397+
398+
def _encode_general_name_preallocated(backend, name, gn):
388399
if isinstance(name, x509.DNSName):
389-
gn = backend._lib.GENERAL_NAME_new()
390400
backend.openssl_assert(gn != backend._ffi.NULL)
391401
gn.type = backend._lib.GEN_DNS
392402

@@ -400,7 +410,6 @@ def _encode_general_name(backend, name):
400410
backend.openssl_assert(res == 1)
401411
gn.d.dNSName = ia5
402412
elif isinstance(name, x509.RegisteredID):
403-
gn = backend._lib.GENERAL_NAME_new()
404413
backend.openssl_assert(gn != backend._ffi.NULL)
405414
gn.type = backend._lib.GEN_RID
406415
obj = backend._lib.OBJ_txt2obj(
@@ -409,13 +418,11 @@ def _encode_general_name(backend, name):
409418
backend.openssl_assert(obj != backend._ffi.NULL)
410419
gn.d.registeredID = obj
411420
elif isinstance(name, x509.DirectoryName):
412-
gn = backend._lib.GENERAL_NAME_new()
413421
backend.openssl_assert(gn != backend._ffi.NULL)
414422
dir_name = _encode_name(backend, name.value)
415423
gn.type = backend._lib.GEN_DIRNAME
416424
gn.d.directoryName = dir_name
417425
elif isinstance(name, x509.IPAddress):
418-
gn = backend._lib.GENERAL_NAME_new()
419426
backend.openssl_assert(gn != backend._ffi.NULL)
420427
if isinstance(name.value, ipaddress.IPv4Network):
421428
packed = (
@@ -433,7 +440,6 @@ def _encode_general_name(backend, name):
433440
gn.type = backend._lib.GEN_IPADD
434441
gn.d.iPAddress = ipaddr
435442
elif isinstance(name, x509.OtherName):
436-
gn = backend._lib.GENERAL_NAME_new()
437443
backend.openssl_assert(gn != backend._ffi.NULL)
438444
other_name = backend._lib.OTHERNAME_new()
439445
backend.openssl_assert(other_name != backend._ffi.NULL)
@@ -456,7 +462,6 @@ def _encode_general_name(backend, name):
456462
gn.type = backend._lib.GEN_OTHERNAME
457463
gn.d.otherName = other_name
458464
elif isinstance(name, x509.RFC822Name):
459-
gn = backend._lib.GENERAL_NAME_new()
460465
backend.openssl_assert(gn != backend._ffi.NULL)
461466
# ia5strings are supposed to be ITU T.50 but to allow round-tripping
462467
# of broken certs that encode utf8 we'll encode utf8 here too.
@@ -465,7 +470,6 @@ def _encode_general_name(backend, name):
465470
gn.type = backend._lib.GEN_EMAIL
466471
gn.d.rfc822Name = asn1_str
467472
elif isinstance(name, x509.UniformResourceIdentifier):
468-
gn = backend._lib.GENERAL_NAME_new()
469473
backend.openssl_assert(gn != backend._ffi.NULL)
470474
# ia5strings are supposed to be ITU T.50 but to allow round-tripping
471475
# of broken certs that encode utf8 we'll encode utf8 here too.

tests/hazmat/backends/test_openssl_memleak.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,63 @@ def func():
389389
x509.IssuingDistributionPoint
390390
)
391391
"""))
392+
393+
def test_create_certificate_with_extensions(self):
394+
assert_no_memory_leaks(textwrap.dedent("""
395+
def func():
396+
import datetime
397+
398+
from cryptography import x509
399+
from cryptography.hazmat.backends.openssl import backend
400+
from cryptography.hazmat.primitives import hashes
401+
from cryptography.hazmat.primitives.asymmetric import ec
402+
from cryptography.x509.oid import (
403+
AuthorityInformationAccessOID, ExtendedKeyUsageOID, NameOID
404+
)
405+
406+
private_key = ec.generate_private_key(ec.SECP256R1(), backend)
407+
408+
not_valid_before = datetime.datetime.now()
409+
not_valid_after = not_valid_before + datetime.timedelta(days=365)
410+
411+
aia = x509.AuthorityInformationAccess([
412+
x509.AccessDescription(
413+
AuthorityInformationAccessOID.OCSP,
414+
x509.UniformResourceIdentifier(u"http://ocsp.domain.com")
415+
),
416+
x509.AccessDescription(
417+
AuthorityInformationAccessOID.CA_ISSUERS,
418+
x509.UniformResourceIdentifier(u"http://domain.com/ca.crt")
419+
)
420+
])
421+
sans = [u'*.example.org', u'foobar.example.net']
422+
san = x509.SubjectAlternativeName(list(map(x509.DNSName, sans)))
423+
424+
ski = x509.SubjectKeyIdentifier.from_public_key(
425+
private_key.public_key()
426+
)
427+
eku = x509.ExtendedKeyUsage([
428+
ExtendedKeyUsageOID.CLIENT_AUTH,
429+
ExtendedKeyUsageOID.SERVER_AUTH,
430+
ExtendedKeyUsageOID.CODE_SIGNING,
431+
])
432+
433+
builder = x509.CertificateBuilder().serial_number(
434+
777
435+
).issuer_name(x509.Name([
436+
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
437+
])).subject_name(x509.Name([
438+
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
439+
])).public_key(
440+
private_key.public_key()
441+
).add_extension(
442+
aia, critical=False
443+
).not_valid_before(
444+
not_valid_before
445+
).not_valid_after(
446+
not_valid_after
447+
)
448+
449+
cert = builder.sign(private_key, hashes.SHA256(), backend)
450+
cert.extensions
451+
"""))

0 commit comments

Comments
 (0)