CURLOPT_ISSUERCERT_BLOB(3)

πŸ’… CURLOPT_ISSUERCERT_BLOB(3) β€” the libcurl manual page, but make it make sense

okay so bestie, welcome to the CURLOPT_ISSUERCERT_BLOB page πŸ’– this thing lives in the libcurl Library Functions Manual and it's literally about handing curl an issuer SSL certificate straight from memory. no files, no drama, just vibes and a blob. let's get into it πŸŽ€


✨ NAME ✨

CURLOPT_ISSUERCERT_BLOB β€” issuer SSL certificate from memory blob πŸ¦‹


✨ SYNOPSIS ✨

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ISSUERCERT_BLOB,
                          struct curl_blob *stblob);

✨ DESCRIPTION ✨

So what you're doing here is passing a pointer to a curl_blob structure β€” and that struct is literally just holding the pointer and the size of a memory block containing the binary data of a CA certificate in PEM format. cute, right? 🌸

If you set this option, an additional check gets run against the peer certificate to verify that the issuer really is the one associated with the certificate you provided through this option. and like… this extra check is genuinely useful in multi-level PKI situations where you need to enforce that the peer certificate comes from a specific branch of the tree. no cap, that's the whole point 🫢

bestie pls use this option together with the CURLOPT_SSL_VERIFYPEER(3) option. otherwise the result of the check is not considered a failure. it's giving "check ran but nobody cared" 😭

There's a specific error code β€” CURLE_SSL_ISSUER_ERROR β€” defined alongside this option, which is returned if setting up the SSL/TLS session failed because of a mismatch with the issuer of the peer certificate. (heads up: CURLOPT_SSL_VERIFYPEER(3) has to be set too for the check to actually fail.)

If the blob is initialized with the flags member of struct curl_blob set to CURL_BLOB_COPY, then the application does not have to keep the buffer around after setting this. the copy is handled for you, iconic πŸ’…

This option is an alternative to CURLOPT_ISSUERCERT(3), which instead expects a filename as input. same energy, different input type, iykyk ⭐


✨ DEFAULT ✨

NULL


✨ PROTOCOLS ✨

This functionality affects all TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. 🌈

This option works only with the following TLS backends: OpenSSL


✨ EXAMPLE ✨

extern char *certificateData;
extern size_t filesize;

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode result;
    struct curl_blob blob;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    blob.data = certificateData;
    blob.len = filesize;
    blob.flags = CURL_BLOB_COPY;
    curl_easy_setopt(curl, CURLOPT_ISSUERCERT_BLOB, &blob);
    result = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}

like look at that, the CURL_BLOB_COPY flag is right there doing its little job so you don't have to babysit the buffer afterward 🧚


✨ AVAILABILITY ✨

Added in curl 7.71.0 πŸŽ€


✨ RETURN VALUE ✨

curl_easy_setopt(3) returns a CURLcode indicating success or error.

CURLE_OK (0) means everything was OK, non-zero means an error occurred β€” go peek at libcurl-errors(3) for the deets πŸ”₯


✨ SEE ALSO ✨


and that's the whole page, bestie, you ate that πŸ“ this iconic little number comes from libcurl, dated 2026-10-12, and it's filed under CURLOPT_ISSUERCERT_BLOB(3). go forth and verify those issuers πŸ‘‘πŸ’œ

πŸ“¦ where this page comes from