ASN1_EXTERN_FUNCS(3SSL)

πŸ’… ASN1_EXTERN_FUNCS β€” the OpenSSL manual page, bestie edition

okay so this is ASN1_EXTERN_FUNCS(3SSL), straight out of the OpenSSL manual, and we're gonna make it make sense. sit down, grab a strawberry, we're doing ASN.1 external function support 🌸


✨ NAME ✨

ASN1_EXTERN_FUNCS, ASN1_ex_d2i, ASN1_ex_d2i_ex, ASN1_ex_i2d, ASN1_ex_new_func, ASN1_ex_new_ex_func, ASN1_ex_free_func, ASN1_ex_print_func, IMPLEMENT_EXTERN_ASN1 β€” literally all of these are about ASN.1 external function support. that's the whole vibe. πŸ¦‹


πŸŽ€ SYNOPSIS πŸŽ€

#include <openssl/asn1t.h>

typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
                        const ASN1_ITEM *it, int tag, int aclass, char opt,
                        ASN1_TLC *ctx);
typedef int ASN1_ex_d2i_ex(ASN1_VALUE **pval, const unsigned char **in, long len,
                           const ASN1_ITEM *it, int tag, int aclass, char opt,
                           ASN1_TLC *ctx, OSSL_LIB_CTX *libctx,
                           const char *propq);
typedef int ASN1_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
                        const ASN1_ITEM *it, int tag, int aclass);
typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
typedef int ASN1_ex_new_ex_func(ASN1_VALUE **pval, const ASN1_ITEM *it,
                                OSSL_LIB_CTX *libctx, const char *propq);
typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
typedef int ASN1_ex_print_func(BIO *out, const ASN1_VALUE **pval,
                               int indent, const char *fname,
                               const ASN1_PCTX *pctx);

struct ASN1_EXTERN_FUNCS_st {
   void *app_data;
   ASN1_ex_new_func *asn1_ex_new;
   ASN1_ex_free_func *asn1_ex_free;
   ASN1_ex_free_func *asn1_ex_clear;
   ASN1_ex_d2i *asn1_ex_d2i;
   ASN1_ex_i2d *asn1_ex_i2d;
   ASN1_ex_print_func *asn1_ex_print;
   ASN1_ex_new_ex_func *asn1_ex_new_ex;
   ASN1_ex_d2i_ex *asn1_ex_d2i_ex;
};
typedef struct ASN1_EXTERN_FUNCS_st ASN1_EXTERN_FUNCS;

#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs)

no cap, that's a whole lot of function pointers and i'm obsessed with every single one of them πŸ”₯


🌈 DESCRIPTION 🌈

so normally, ASN.1 data structure templates get defined in OpenSSL using a parade of macros like ASN1_SEQUENCE(), ASN1_SEQUENCE_END() and friends. cute, right? but plot twist: you can also define templates based entirely on external functions. those external functions get called whenever OpenSSL needs to do stuff like making a fresh ASN1_VALUE, or turning an ASN1_VALUE to/from DER encoding. main character behaviour, honestly. ✨

the IMPLEMENT_EXTERN_ASN1() macro is how you build one of these externally defined structures. here's the tea on its parameters:

  • the name of the structure goes in the sname parameter
  • the tag for the structure goes in the tag parameter (typically V_ASN1_SEQUENCE, iykyk)
  • and a pointer to an ASN1_EXTERN_FUNCS structure goes in the fptrs parameter

then the ASN1_EXTERN_FUNCS structure itself has these entries. buckle up: πŸŽ€

the struct fields, one by one

  • app_data β€” just a pointer to whatever arbitrary application specific data you want. it's giving "miscellaneous pocket."
  • asn1_ex_new β€” the "new" function, and its whole job is constructing a brand new ASN1_VALUE object. the freshly built value should land in *pval. the it parameter is a pointer to the ASN1_ITEM template object, the one created via that IMPLEMENT_EXTERN_ASN1() macro.

returns a positive value on success, or 0 on error. no in-between, we don't do ambiguity here πŸ’…

  • asn1_ex_free β€” the "free" function. it frees the ASN1_VALUE passed in *pval, the one that was previously allocated via a "new" function. the it parameter is a pointer to the ASN1_ITEM template object created via the IMPLEMENT_EXTERN_ASN1() macro.
  • asn1_ex_clear β€” the "clear" function. it clears any data in the ASN1_VALUE passed in *pval and makes it suitable for reuse. (recycling era ♻️) the it parameter is a pointer to the ASN1_ITEM template object created via the IMPLEMENT_EXTERN_ASN1() macro.
  • asn1_ex_d2i β€” the "d2i" function, responsible for converting DER data with the tag tag and class class into an ASN1_VALUE. details, because details matter:
    • if *pval is non-NULL, then the ASN_VALUE it points to should be reused. otherwise a new ASN1_VALUE should be allocated and stored in *pval.
    • *in points to the DER data to be decoded, and len is the length of that data.
    • after decoding, *in should be updated to point at the next byte after the decoded data.
    • if the ASN1_VALUE is considered optional in this context, then opt will be nonzero. otherwise it will be zero.
    • the it parameter is a pointer to the ASN1_ITEM template object created via the IMPLEMENT_EXTERN_ASN1() macro.
    • a pointer to the current ASN1_TLC context (which may be required for other ASN1 function calls) is passed in the ctx parameter.

the asn1_ex_d2i entry may be NULL if asn1_ex_d2i_ex has been specified instead.

returns <= 0 on error, or a positive value on success.

  • asn1_ex_i2d β€” the "i2d" function, responsible for converting an ASN1_VALUE into DER encoding. on entry, *pval will contain the ASN1_VALUE to be encoded.
    • if default tagging is to be used, then tag will be -1 on entry.
    • otherwise, if implicit tagging should be used, then tag and aclass will be the tag and associated class.
    • if out is not NULL, this function should write the DER encoded data to the buffer in *out, and then increment *out to point to immediately after the data just written.
    • if out is NULL, then no data should be written, but the length should still be calculated and returned as if it had been.

the asn1_ex_i2d entry may be NULL if asn1_ex_i2d_ex has been specified instead.

the return value should be negative if a fatal error occurred, or 0 if a non-fatal error occurred. otherwise it should return the length of the encoded data. (three different outcomes, pick wisely 😭)

  • asn1_ex_print β€” the "print" function. out is the BIO to print the output to. *pval is the ASN1_VALUE to be printed. indent is the number of spaces of indenting to be printed before any data is printed. fname is currently unused and is always "". pctx is a pointer to the ASN1_PCTX for the print operation.

returns 0 on error or a positive value on success. and here's the lil easter egg: if the return value is 2, then an additional newline will be printed after the data printed by this function. cute, right? πŸŽ€

  • asn1_ex_new_ex β€” same as asn1_ex_new, except it's additionally passed the OSSL_LIB_CTX to be used in libctx, and any property query string to be used for algorithm fetching in the propq parameter. for further details, see "ALGORITHM FETCHING" in crypto(7). and listen: if asn1_ex_new_ex is non NULL, then it will always be called in preference to asn1_ex_new. it's the favourite child, periodt. πŸ‘‘
  • asn1_ex_d2i_ex β€” same as asn1_ex_d2i, except it's additionally passed the OSSL_LIB_CTX to be used in libctx, and any property query string to be used for algorithm fetching in the propq parameter. for further details, see "ALGORITHM FETCHING" in crypto(7). and same energy as above: if asn1_ex_d2i_ex is non NULL, then it will always be called in preference to asn1_ex_d2i. πŸ’…

🫢 RETURN VALUES 🫢

the return values for the various callbacks are exactly as described above. that's it, that's the section β€” go scroll back up, bestie, it's all up there πŸ’–


πŸ¦‹ SEE ALSO πŸ¦‹


⭐ HISTORY ⭐

the asn1_ex_new_ex and asn1_ex_d2i_ex callbacks were added in OpenSSL 3.0. so if you're on something older... it's not giving. πŸ™ˆ


Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


and that's the whole page, bestie!! πŸŽ€βœ¨ this was ASN1_EXTERN_FUNCS(3SSL) from the OpenSSL manual β€” version 4.0.3, dated 2026-09-29. slay responsibly, and remember: when asn1_ex_new_ex is non NULL it always wins. no cap. πŸ’œπŸŒˆπŸ¦‹

πŸ“¦ where this page comes from