STACK_OF(3)

πŸ“¦ version 4.1.0, in opensuse-leap 16.0

πŸ’… STACK_OF(3) β€” the OpenSSL "stacks" page, bestie edition

omg hi. so this is STACK_OF(3), a page from the Library Functions Manual, and honestly? it's a whole journey. buckle up πŸŽ€


🌸 NAME 🌸

STACK_OF β€” variable-sized arrays of pointers, called OpenSSL stacks

like, they're arrays. they're called stacks. it's giving "we named it wrong on purpose" πŸ’€


✨ SYNOPSIS ✨

#include <openssl/safestack.h>

STACK_OF(type);

that's it. that's the whole vibe. one include, one macro πŸ¦‹


πŸ’– DESCRIPTION πŸ’–

okay so the <openssl/safestack.h> header provides a fragile, unusually complicated system of macro-generated wrappers around the functions described in the OPENSSL_sk_new(3) manual page. fragile. unusually complicated. those are the man page's words, not mine, and I respect the honesty πŸ’€

the whole thing is intended to implement superficially type-safe variable-sized arrays of pointers β€” somewhat misleadingly called "stacks" by OpenSSL. (they're not stacks, bestie. they're arrays of pointers. but we're gonna call them stacks anyway because that's the ~lore~ 🫢)

and here's the thing: due to the excessive number of API functions, it is impossible to properly document this system. like, literally impossible. in particular, calling man(1) for any of the functions operating on stacks cannot yield any result. you'll just get nothing. a void. an empty terminal. πŸ™ˆ


unfortunately, application programs can hardly avoid using the concept because several important OpenSSL APIs rely on it β€” see the SEE ALSO section for examples. and even though both pages are more complicated than any manual page ought to be, using the concept safely requires a complete understanding of all the details in both this manual page and in OPENSSL_sk_new(3). both. no skimming. I'm sorry. 😭

The STACK_OF() macro takes a type name as its argument β€” typically the name of a type that has been defined as an alias for a specific struct type using a typedef declaration. it expands to an incomplete struct type which is intended to represent a "stack" of objects of the given type.

and here's the plot twist: that type does not actually exist πŸ’€ so it is not possible to define, for example, an automatic variable STACK_OF(X509) my_certificates β€” it is only possible to define pointers to stacks, like:

STACK_OF(X509) *my_certificates

the only way such pointers can ever be used is by wrapper functions casting them to the type _STACK * described in OPENSSL_sk_new(3). that's it. that's the only way. main character energy only ✨


for a considerable number of types, OpenSSL provides one wrapper function for each function described in OPENSSL_sk_new(3). the names of these wrapper functions are usually constructed by inserting the name of the type and an underscore after the sk_ prefix of the function name.

usually, where the real functions take void * arguments, the wrappers take pointers to the type in question, and where the real functions take _STACK * arguments, the wrappers take pointers to STACK_OF(type). same energy for return values. various exceptions to all this exist, but the above applies to all the types listed below πŸ‘‘


using the above may make sense for the following types because public API functions exist that take stacks of these types as arguments or return them:

ASN1_INTEGER, ASN1_OBJECT, ASN1_UTF8STRING, CMS_RecipientInfo, CMS_SignerInfo, CONF_VALUE, GENERAL_NAMES, GENERAL_SUBTREE, OPENSSL_STRING (which is just char * β€” yes really, that's all it is πŸ“), PKCS12_SAFEBAG, PKCS7, PKCS7_RECIP_INFO, PKCS7_SIGNER_INFO, POLICYQUALINFO, SRTP_PROTECTION_PROFILE, SSL_CIPHER, SSL_COMP, X509, X509_ALGOR, X509_ATTRIBUTE, X509_CRL, X509_EXTENSION, X509_INFO, X509_NAME, X509_OBJECT, X509_POLICY_NODE, X509_REVOKED.


additionally, some public API functions use the following types which are declared with typedef:

  • STACK_OF(ACCESS_DESCRIPTION) β†’ AUTHORITY_INFO_ACCESS
  • STACK_OF(ASN1_OBJECT) β†’ EXTENDED_KEY_USAGE
  • STACK_OF(ASN1_TYPE) β†’ ASN1_SEQUENCE_ANY
  • STACK_OF(DIST_POINT) β†’ CRL_DIST_POINTS
  • STACK_OF(GENERAL_NAME) β†’ GENERAL_NAMES
  • STACK_OF(IPAddressFamily) β†’ IPAddrBlocks
  • STACK_OF(POLICY_MAPPING) β†’ POLICY_MAPPINGS
  • STACK_OF(POLICYINFO) β†’ CERTIFICATEPOLICIES
  • STACK_OF(X509_ALGOR) β†’ X509_ALGORS
  • STACK_OF(X509_EXTENSION) β†’ X509_EXTENSIONS

⚠️ even though the OpenSSL headers declare wrapper functions for many more types, and even though the OpenSSL documentation says that users can declare their own stack types, using STACK_OF() with any type not listed here is strongly discouraged. for other types, there may be subtle, undocumented differences in syntax and semantics, and attempting to declare custom stack types is very error prone. using plain C arrays of pointers to the desired type is much simpler and less dangerous. like, just do that. please. for me. 🫢

πŸ”₯ EXAMPLES πŸ”₯

okay so the following program creates a certificate object, puts two pointers to it on a stack, and uses X509_free(3) to clean up properly. it's actually a cute little program, ngl:

#include <err.h>
#include <stdio.h>
#include <openssl/x509.h>

int
main(void)
{
        STACK_OF(X509)  *stack;
        X509            *x;

        if ((stack = sk_X509_new_null()) == NULL)
                err(1, NULL);
        if ((x = X509_new()) == NULL)
                err(1, NULL);
        if (sk_X509_push(stack, x) == 0)
                err(1, NULL);
        if (X509_up_ref(x) == 0)
                errx(1, "X509_up_ref failed");
        if (sk_X509_push(stack, x) == 0)
                err(1, NULL);
        printf("%d pointers: %p, %p\n", sk_X509_num(stack),
            sk_X509_value(stack, 0), sk_X509_value(stack, 1));
        sk_X509_pop_free(stack, X509_free);

        return 0;
}

and the output looks similar to:

2 pointers: 0x4693ff24c00, 0x4693ff24c00

(yes, both pointers are the same address β€” that's the whole point, we pushed the same x twice πŸ’…)


πŸ¦‹ SEE ALSO πŸ¦‹

crypto(3), OCSP_request_sign(3), OPENSSL_sk_new(3), PKCS12_parse(3), PKCS7_encrypt(3), SSL_CTX_set_client_CA_list(3), SSL_get_ciphers(3), SSL_get_peer_cert_chain(3), SSL_load_client_CA_file(3), X509_CRL_get_REVOKED(3), X509_STORE_CTX_get0_chain(3)

iykyk πŸ‘‘


🌈 HISTORY 🌈

the STACK_OF() macro first appeared in OpenSSL 0.9.3 and has been available since OpenBSD 2.6. an icon. an elder. a legend. 🧚


and that's the whole page, bestie! this one shipped from Debian, dated October 24, 2021, and it's literally STACK_OF(3) through and through β€” no cap πŸ’œβœ¨

πŸ“¦ where this page comes from