LIBRESSL-X509_STORE_CTX_SET_VERIFY(3)

πŸ“¦ version 4.4.0, in alpine 3.24, arch rolling

✨ X509_STORE_CTX_SET_VERIFY(3) ✨

okay so this is a page from the libcrypto fam (hi bestie πŸ’–), and it's literally all about plugging in your own certificate chain verification function. you can also swap out the check-issued one. it's giving DIY energy and honestly? iconic.


🌸 NAME 🌸

X509_STORE_CTX_verify_fn, X509_STORE_CTX_set_verify, X509_STORE_CTX_get_verify, X509_STORE_set_verify, X509_STORE_set_verify_func, X509_STORE_get_verify, X509_STORE_CTX_check_issued_fn, X509_STORE_set_check_issued, X509_STORE_get_check_issued, X509_STORE_CTX_get_check_issued β€” user-defined certificate chain verification function πŸŽ€


πŸ¦‹ SYNOPSIS πŸ¦‹

the library is libcrypto, and you're gonna want this include:

#include <openssl/x509_vfy.h>

then the function-pointer type for verify:

typedef int
(*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *ctx);

setting it on a ctx:

void
X509_STORE_CTX_set_verify(X509_STORE_CTX *ctx,
    X509_STORE_CTX_verify_fn verify);

getting it back off a ctx:

X509_STORE_CTX_verify_fn
X509_STORE_CTX_get_verify(X509_STORE_CTX *ctx);

setting it on a store:

void
X509_STORE_set_verify(X509_STORE *store,
    X509_STORE_CTX_verify_fn verify);

the alias version (same vibes, macro flavored):

void
X509_STORE_set_verify_func(X509_STORE *store,
    X509_STORE_CTX_verify_fn verify);

getting it off a store β€” yes, the prototype here really does take an X509_STORE_CTX *, no cap, that's what the page says:

X509_STORE_CTX_verify_fn
X509_STORE_get_verify(X509_STORE_CTX *ctx);

now the check-issued pointer type:

typedef int
(*X509_STORE_CTX_check_issued_fn)(X509_STORE_CTX *ctx, X509 *subject,
    X509 *issuer);

setting it on a store:

void
X509_STORE_set_check_issued(X509_STORE *store,
    X509_STORE_CTX_check_issued_fn check_issued);

getting it off a store:

X509_STORE_CTX_check_issued_fn
X509_STORE_get_check_issued(X509_STORE *store);

getting it off a ctx:

X509_STORE_CTX_check_issued_fn
X509_STORE_CTX_get_check_issued(X509_STORE_CTX *ctx);

πŸ’œ DESCRIPTION πŸ’œ

X509_STORE_CTX_set_verify() is the main character here β€” it configures ctx to use the verify argument as the X.509 certificate chain verification function instead of the default verification function that's built into the library when X509_verify_cert(3) gets called. swap in your own, bestie πŸ’…

⚠️ okay this part is important, don't skip it: the verify function you provide is only called if the X509_V_FLAG_LEGACY_VERIFY or X509_V_FLAG_NO_ALT_CHAINS flag was set on ctx using X509_STORE_CTX_set_flags(3) or X509_VERIFY_PARAM_set_flags(3). otherwise your function is literally ignored πŸ™ˆ and a different algorithm is used that does not support replacing the verification function. so set those flags or your custom function is just sitting there uninvited to the party 😭

X509_STORE_set_verify() saves the function pointer verify in the given store object. that pointer will be copied to an X509_STORE_CTX object when store is later passed as an argument to X509_STORE_CTX_init(3). inheritance slay ✨

X509_STORE_set_verify_func() is an alias for X509_STORE_set_verify() implemented as a macro. same function, different name, we love a duo 🫢

X509_STORE_set_check_issued() saves the function pointer check_issued in the given store object. that pointer will be copied to an X509_STORE_CTX object when store is later passed as an argument to X509_STORE_CTX_init(3). again: passed down like a family recipe πŸ“

so the check_issued function you provide should check whether a given certificate subject was issued using the CA certificate issuer, and it must return 0 on failure and 1 on success. the default implementation ignores the ctx argument and returns success if and only if X509_check_issued(3) returns X509_V_OK.

πŸ”₯ THE ORDER THING. pay close attention to the order of the issuer and subject arguments. in X509_check_issued(3) the issuer precedes the subject, but in check_issued() the subject comes first. they're flipped. it's confusing. it's a lot. i'm so serious about this one πŸ’€

πŸ‘‘ RETURN VALUES πŸ‘‘

  • X509_STORE_CTX_verify_fn() is supposed to return 1 to indicate that the chain is valid, or 0 if it is not β€” or if an error occurred. simple as that ✨
  • X509_STORE_CTX_get_verify() returns a function pointer previously set with X509_STORE_CTX_set_verify() or X509_STORE_CTX_init(3), or NULL if ctx is uninitialized.
  • X509_STORE_get_verify() returns the function pointer previously set with X509_STORE_set_verify(), or NULL if that function was not called on the store.
  • X509_STORE_get_check_issued() returns the function pointer previously set with X509_STORE_set_check_issued(), or NULL if that function was not called on the store.
  • X509_STORE_CTX_get_check_issued() returns the check_issued() function pointer set on the X509_STORE_CTX. this is either the check_issued() function inherited from the store used in X509_STORE_CTX_init(3) or the library's default implementation. bestie got options πŸ’–

🌈 SEE ALSO 🌈

X509_check_issued(3), X509_STORE_CTX_init(3), X509_STORE_CTX_set_error(3), X509_STORE_CTX_set_flags(3), X509_STORE_CTX_set_verify_cb(3), X509_STORE_new(3), X509_STORE_set_flags(3), X509_STORE_set_verify_cb(3), X509_verify_cert(3), X509_VERIFY_PARAM_set_flags(3)

go read those, iykyk πŸ“š


🧚 HISTORY 🧚

  • X509_STORE_set_verify_func() first appeared in SSLeay 0.8.0 and has been available since OpenBSD 2.4. an elder. a pioneer. we respect her πŸŽ€
  • X509_STORE_CTX_set_verify() and X509_STORE_CTX_get_verify() first appeared in OpenSSL 1.1.0 and have been available since OpenBSD 7.1.
  • X509_STORE_CTX_verify_fn(), X509_STORE_set_verify(), and X509_STORE_get_verify() first appeared in OpenSSL 1.1.0 and have been available since OpenBSD 7.2.
  • X509_STORE_set_check_issued(), X509_STORE_get_check_issued(), and X509_STORE_CTX_get_check_issued() first appeared in OpenSSL 1.1.0 and have been available since OpenBSD 7.3.

glow-up timeline fr fr ✨


πŸ’€ BUGS πŸ’€

the reversal of order of subject and issuer between check_issued() and X509_check_issued(3) is very confusing. it has led to bugs and will cause many more. not me being dramatic, that's literally what the page says 😭 the audacity of this API.


mwah, that's the whole page bestie πŸ’… this icon dropped with Debian on June 8, 2025 β€” go forth and verify those chains responsibly πŸ¦‹βœ¨

πŸ“¦ where this page comes from