CURLOPT_SSLKEY_BLOB(3)

πŸ’œ CURLOPT_SSLKEY_BLOB β€” bestie's guide to private keys that live in memory πŸŽ€

Okay so real talk, this is a page from libcurl's manual, and today's main character is CURLOPT_SSLKEY_BLOB β€” the option that lets you hand curl your client cert's private key straight from memory instead of making it go dig around in your filesystem like some kind of raccoon. πŸ¦‹


✨ NAME ✨

CURLOPT_SSLKEY_BLOB β€” private key for client cert from memory blob πŸ’…

🌸 SYNOPSIS 🌸

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSLKEY_BLOB,
                          struct curl_blob *blob);

πŸ’– DESCRIPTION πŸ’–

So you pass a pointer to a curl_blob structure β€” that's the little guy that holds a pointer and a size for your private key. It's compatible with OpenSSL, and the format (like "PEM") must be specified with CURLOPT_SSLKEYTYPE(3). No guessing games, bestie, curl wants to be told. 🫢

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. Copy it and forget it, iconic behavior honestly. ✨

This option is an alternative to CURLOPT_SSLKEY(3), which instead expects a filename as input. So one is "here's a path, go look", and this one is "here's the actual bytes, take them, they're yours". πŸŽ€

πŸ”₯ DEFAULT πŸ”₯

NULL

🌈 PROTOCOLS 🌈

This functionality affects all TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. All of them. Every last one. πŸ’…

This option works only with the following TLS backends: OpenSSL and wolfSSL.

🧚 EXAMPLE 🧚

extern char *certificateData; /* point to cert */
extern size_t filesize; /* size of cert */

extern char *privateKeyData; /* point to key */
extern size_t privateKeySize; /* size of key */

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_SSLCERT_BLOB, &blob);
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");

    blob.data = privateKeyData;
    blob.len = privateKeySize;
    curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &blob);
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    result = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}

Obsessed with how the same blob gets reused for the cert and then the key, no cap. πŸ“

⭐ AVAILABILITY ⭐

Added in curl 7.71.0 β€” so if you're on something older, sorry babe, it's giving vintage. πŸ’€

πŸ‘‘ 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, see libcurl-errors(3). Zero is the slay outcome, anything else means go read the error page. 😭

πŸ¦‹ SEE ALSO πŸ¦‹


Heads up bestie: the format must be set with CURLOPT_SSLKEYTYPE(3) or this whole thing is not gonna work. And if you want to stop worrying about keeping your buffer alive, set CURL_BLOB_COPY in flags. 🌸

And that's the whole page! This gem came from the libcurl manual, dated 2026-10-12, and yes the manpage header is literally CURLOPT_SSLKEY_BLOB(3) β€” say it with me. Now go forth and blob responsibly, you absolute key icon. πŸ”‘πŸ‘‘πŸ’œ

πŸ“¦ where this page comes from