GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — SSLContext.load_verify_locations(cadata=...) does not accept CRLs (unlike cafile and capath) · Issue #149679 · python/cpython

SSLContext.load_verify_locations(cadata=...) does not accept CRLs (unlike cafile and capath) #149679

New issue
Copy link
New issue
Copy link
Open
Open
SSLContext.load_verify_locations(cadata=...) does not accept CRLs (unlike cafile and capath)#149679
Copy link
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-SSLtype-featureA feature request or enhancementA feature request or enhancement

Description

@uedvt359
uedvt359
opened on May 11, 2026
Issue body actions

Feature or enhancement

Proposal:

SSLContext.load_verify_locations can load CA certificates or CRLs to validate against. It provides three parameters: cafile, capath and cadata. While all three can be used to load certificates, only the first two can load revocation lists.

If I have the CRL already in memory (e.g. because some earlier code downloaded and inspected the CRL before use), it has to be written to a file in order to load it.

The following code does not work - it raises an exception:

crl = ... # DER-encoded CRL loaded previously
ctx = ssl.create_default_context()
ctx.load_verify_locations(cadata=crl)

Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    ctx.load_verify_locations(cadata=crl)
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
ssl.SSLError: not enough data: cadata does not contain a certificate (_ssl.c:4219)

This workaround works, but is a bit ugly:

crl = ...
ctx = ssl.create_default_context()
with tempfile.NamedTemporaryFile(buffering=0) as f:
    f.write(crl)
    f.flush()
    ctx.load_verify_locations(cafile=f.name)

Also, the documentation is not clear on this, currently: Above the description of the three parameters, it says, "This method can also load certification revocation lists (CRLs) in PEM or DER format". In the description of each parameter, only certificates (not CRLs) are mentioned, e.g. "The cafile string, if present, is the path to a file of concatenated CA certificates in PEM format".
There is also no indication that only cafile and capath can take CRLs, and that using cadata for this fails.

Has this already been discussed elsewhere?

This is a minor feature, which does not need previous discussion elsewhere

Links to previous discussion of this feature:

No response

Linked PRs

  • gh-149679: Document that cadata does not accept CRLs #155701

Activity

  1. uedvt359
    added
    type-featureA feature request or enhancementA feature request or enhancement
    on May 11, 2026
  2. picnixz commented on May 13, 2026

    @picnixz
    picnixz
    on May 13, 2026
    Member
    More actions

    For cadata:

    The cadata object, if present, is either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates.

    From your code, I assume that your CRL is a DER-encoded string, not a PEM-encoded string. If you want to supply a DER-encoded certificate, you need a bytes string instead.

  3. picnixz
    added
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    topic-SSL
    pendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
    on May 13, 2026
  4. uedvt359 commented on May 13, 2026

    @uedvt359
    uedvt359
    on May 13, 2026
    Author
    More actions

    If you want to supply a DER-encoded certificate, you need a bytes string instead.

    i have tried both der-encoded csrs as bytestrings, and pem-encoded csrs in both string types - none are accepted.

  5. picnixz commented on May 13, 2026

    @picnixz
    picnixz
    on May 13, 2026
    Member
    More actions

    You might want to use ssl.DER_cert_to_PEM_cert to convert them properly. If your DER encoded string is a real string, you should encode() it then decode it to PEM and then give it back (sorry I do not have ways to check it now).

    Otherwise, if this does not work, something else is happening and maybe cadata is not meant for CRLs at all (in which case we need to update the docs for cafile/capath to state that they support CRLs).

    Alternatively, one can assume that cadata is broken for CRLs and consider it as a bugfix. I need to know whether it was deliberate though so digging into the C code will be needed (I do not know when I will have time)

  6. picnixz
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    and removed
    pendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
    on May 13, 2026
  7. uedvt359 commented on May 13, 2026

    @uedvt359
    uedvt359
    on May 13, 2026
    Author
    More actions

    this is not an error in my csr handling - the code to load csrs from string/bytes is simly not there.

    here is the implementation:

    cpython/Modules/_ssl.c

    Lines 4836 to 4880 in cd60968

    if (cadata) {
    if (PyUnicode_Check(cadata)) {
    PyObject *cadata_ascii = PyUnicode_AsASCIIString(cadata);
    if (cadata_ascii == NULL) {
    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
    goto invalid_cadata;
    }
    goto error;
    }
    r = _add_ca_certs(self,
    PyBytes_AS_STRING(cadata_ascii),
    PyBytes_GET_SIZE(cadata_ascii),
    SSL_FILETYPE_PEM);
    Py_DECREF(cadata_ascii);
    if (r == -1) {
    goto error;
    }
    }
    else if (PyObject_CheckBuffer(cadata)) {
    Py_buffer buf;
    if (PyObject_GetBuffer(cadata, &buf, PyBUF_SIMPLE)) {
    goto error;
    }
    assert(PyBuffer_IsContiguous(&buf, 'C'));
    if (buf.ndim > 1) {
    PyBuffer_Release(&buf);
    PyErr_SetString(PyExc_TypeError,
    "cadata should be a contiguous buffer with "
    "a single dimension");
    goto error;
    }
    r = _add_ca_certs(self, buf.buf, buf.len, SSL_FILETYPE_ASN1);
    PyBuffer_Release(&buf);
    if (r == -1) {
    goto error;
    }
    }
    else {
    invalid_cadata:
    PyErr_SetString(PyExc_TypeError,
    "cadata should be an ASCII string or a "
    "bytes-like object");
    goto error;
    }
    }

    cadata is handled seperately from cafile/capath - and cadata is passed to _add_ca_certs(), which does not accept CSRs.

  8. picnixz commented on May 13, 2026

    @picnixz
    picnixz
    on May 13, 2026
    Member
    More actions

    Ah I see, thanks. Mmh, I think the best is to add yet another parameter to that or an alternative function. I would rather see it as an alternative function which takes crldata/crlfile/crlpath instead but I need to think about it more

  9. picnixz
    removed
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on May 13, 2026
  10. picnixz commented on May 13, 2026

    @picnixz
    picnixz
    on May 13, 2026
    Member
    More actions

    Note: we still need to update the docs though. At least cafile/capath work well with CRL only but cadata does not.

  11. uedvt359 commented on May 13, 2026

    @uedvt359
    uedvt359
    on May 13, 2026
    Author
    More actions

    Python's load_verify_locations seems to be modeled after OpenSSL's SSL_CTX_load_verify_locations (obviously).

    The OpenSSL version does not support loading from a buffer, only from file/path, so cadata was a Python extension to that. Loading CRLs with cafile/capath is a feature inherited from the underlying library that has not been implemented in the cadata extension.

    Given that, i would prefer all three arguments to work the same (instead of another argument or even function), but i understand when other factors outweigh that.

  12. mangrisano
    added a commit that references this issue on Aug 13, 2026

    pythongh-149679: Document that cadata does not accept CRLs

    9ba3edf
  13. mangrisano commented on Aug 13, 2026

    @mangrisano
    mangrisano
    on Aug 13, 2026
    Contributor
    More actions

    The docs half of this (CRLs load only through cafile/capath, not cadata) is covered by #155701. This is about the feature half: loading a CRL that's already in memory without a temp-file round-trip.

    I work with CRLs a fair amount, so a few notes on the two directions raised above.

    Extending cadata to also accept CRLs (parity with cafile/capath, @uedvt359's preference). This matches OpenSSL's own SSL_CTX_load_verify_locations, which loads certs and CRLs from the same file/dir; cadata was only ever the in-memory extension of that, so it restores parity. It's also the smallest change: _add_ca_certs() already iterates PEM/DER items, so it would additionally try d2i_X509_CRL_bio / PEM_read_bio_X509_CRL + X509_STORE_add_crl for items that aren't certificates. The downside is that cadata reads as "CA data" and today's error is literally "cadata does not contain a certificate"; accepting CRLs there is implicit and makes a precise error message harder when the blob is neither.

    A dedicated crl* API (your lean). A CRL is revocation data, not a trust anchor, so keeping it separate reads better and lets us raise a precise "does not contain a CRL" error. On shape, a new method is cleaner than adding crlfile/crlpath/crldata to load_verify_locations, which already juggles three interdependent cert inputs — e.g. SSLContext.load_crl(crlfile=None, crlpath=None, crldata=None). The fiddly part is crlpath: a directory of CRLs relies on OpenSSL's hashed-dir lookup, so it would mirror capath's lazy behaviour rather than eagerly loading, whereas crlfile/crldata are the straightforward eager cases (PEM_read_bio_X509_CRL / d2i_X509_CRL_bio + X509_STORE_add_crl).

    My preference is the dedicated method: explicit, clean diagnostics, and it keeps CA trust and revocation data conceptually separate — which matters when reasoning about verify_flags. But if minimising API surface and OpenSSL parity weigh more, extending cadata is the smaller change and I'm happy either way.

    If you can pick a direction, I'll put up a PR with tests.

    Reacted by uedvt359
  14. mangrisano
    added a commit that references this issue on Aug 13, 2026

    pythongh-149679: Document that cadata does not accept CRLs

    099c8e4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirC modules in the Modules dirtopic-SSLtype-featureA feature request or enhancementA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.