SSL_CTX *ctx = sslctx; // Defined elsewhere. X509_STORE *store; char *crlfile = "/path/to/single/file.pem"; char *crlpath = "/path/to/entire/directory"; if (!(store = SSL_CTX_get_cert_store(ctx))) { fprintf(stderr, "No cert store found\n"); return -1; } if (!X509_STORE_load_locations(store, crlfile, crlpath)) { fprintf(stderr, "Unable to load CRL files\n"); return -1; }This will load the CRL files, but will not enable CRL checking; this has to be done by setting a flag value in the X509_STORE *. There at least two possible options: one is to check only the leaf certificate, the other is to check all certificates in the chain. The former option can be accomplished by setting only X509_V_FLAG_CRL_CHECK while the latter can be accomplished by setting two flags X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL. The latter option (the entire chain) is almost certainly what you want.
char* crlmode; // Defined elsewhere. int crlflags; if (!strcmp(crlmode, "chain")) { crlflags = X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; } else if (!strcmp(crlmode, "leaf")) { crlflags = X509_V_FLAG_CRL_CHECK; } else { fprintf(stderr, "Unknown flag mode '%s'\n", crlmode); return -1; } if (X509_STORE_set_flags(store, crlflags) != 1) { fprintf(stderr, "Unable to set flags\n"); return -1; }...and that's it! CRLs should now be enabled for your program. However, do not rest easily just yet, as CRLs offer several pitfalls for the unwary, as detailed below.
The consequence of this is that enabling CRL-checking requires gathering CRL files, a task that is likely non-trivial. The alternative is to override OpenSSL's verify callback by defining your own verify function and then telling OpenSSL to use said function with X509_STORE_set_verify_cb(3). I, however, do not intend to touch that with a 10-foot pole.
While OpenSSL indeed expects each CA to have its own CRL file, it expects the CA file to be named in a very specific manner; it expects the file to be named as the concatenation of the first part of the hash of its issuer name and .rX where X starts as 0 and is incremented for each hash collision that occurs. For example, suppose the hash of CA B is deadbeef, then its CRL filename is expected to be deadbeef.r0. Arguably, the easiest way to support this hash-based filename is to create the actual CRL file with the name of its respective issuer, then create the symbolic link for OpenSSL, which can be done by something like:
for crl in `ls *.pem`; do hash=$(openssl crl -hash -in "${crl}" -noout) # Just assume no collisions for simplicity. ln -s "${crl}" "${hash%$'\n'}.r0" done...which generates a hash for each file suffixed with .pem in the current directory (WARNING: does not take into account hash collisions). With the symbolic links created, you should now be able to use a CRL path.
One more caveat: OpenSSL does not seem to report any error if the CRL path directory does not exist. Figures.