Add CRL number extension to CRL using OpenSSL

543 Views Asked by At

For some client testing I need to generate certificates and revocation lists "on the fly". I am able to setup a revocation list with the CRL number extension using OpenSSL console commands and configuration files. However I can't make this work in code.

Here are my relevant functions:

X509* g_certificate[MAX_CERTIFICATE_COUNT];
EVP_PKEY* g_certificateKeyPair[MAX_CERTIFICATE_COUNT];
X509_CRL* g_crl;

UINT16 GenerateCrl(UINT16 issuerCertificateIndex, UINT16 crlNumber, INT32 lastUpdate, INT32 nextUpdate)
{
    ASN1_TIME* lastUpdateTime = ASN1_TIME_new();
    ASN1_TIME* nextUpdateTime = ASN1_TIME_new();
    char crlNumberString[32];
    int result = 1;

    if (g_crl != NULL) X509_CRL_free(g_crl);
    g_crl = X509_CRL_new();

    result &= X509_CRL_set_version(g_crl, 1);
    result &= X509_CRL_set_issuer_name(g_crl, X509_get_subject_name(g_certificate[issuerCertificateIndex]));
    // there are multiple X509 certificate objects stored in memory, which I use to setup certificate chains

    ASN1_TIME_set(lastUpdateTime, time(NULL) + lastUpdate);
    ASN1_TIME_set(nextUpdateTime, time(NULL) + nextUpdate);
    result &= X509_CRL_set1_lastUpdate(g_crl, lastUpdateTime);
    result &= X509_CRL_set1_nextUpdate(g_crl, nextUpdateTime);
    ASN1_TIME_free(lastUpdateTime);
    ASN1_TIME_free(nextUpdateTime);

    _itoa_s((int)crlNumber, crlNumberString, 10);
    // my CRLs need to have the authority key identifier and CRL number extensions
    result &= SetCrlExtension(issuerCertificateIndex, NID_authority_key_identifier, "keyid:always");  // this does add the auth key id extension
    result &= SetCrlExtension(issuerCertificateIndex, NID_crl_number, crlNumberString);  // this does not add CRL number the extension

    result &= X509_CRL_sign(g_crl, g_certificateKeyPair[issuerCertificateIndex], EVP_sha256());

    return result;
}

INT16 SetCrlExtension(UINT16 issuerCertificateIndex, INT16 extensionNid, const char* extensionData)
{
    X509V3_CTX ctx;
    X509_EXTENSION* extension;
    lhash_st_CONF_VALUE conf;  // actually I have no idea what this is for, probably it is not required here
    int result = 1;

    X509V3_set_ctx(&ctx, g_certificate[issuerCertificateIndex], NULL, NULL, g_crl, 0);
    extension = X509V3_EXT_conf_nid(&conf, &ctx, extensionNid, (char*)extensionData);
    result &= X509_CRL_add_ext(g_crl, extension, -1);

    return result;
}

void SaveCrlAsPem(const char* fileName)
{
    FILE* f;

    fopen_s(&f, fileName, "wb");
    PEM_write_X509_CRL(f, g_crl);
    if (f != NULL) fclose(f);
}

So e.g.

GenerateCrl(1, 1234, -3600, 36000);
SaveCrlAsPem("crl.pem"); 

should result in a CRL having said extension. But it does only contain the authority key identifier extension. Everything else is fine. Im also adding the certificate extensions in basically the same way and dont't have any issues there.

So how can I get the CRL number attached to my CRL?

1

There are 1 best solutions below

1
dhanushka On BEST ANSWER

You mention that you are able to setup the CRL number extension from OpenSSL command line. You should probably take a look at the source code of the particular command then.

I haven't used CRLs, but I believe you are using the ca command. Looking for NID_crl_number in its source at apps/ca.c (from OpenSSL 1.1.1g) shows the following code:

/* Add any extensions asked for */

if (crl_ext != NULL || crlnumberfile != NULL) {
    X509V3_CTX crlctx;
    X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
    X509V3_set_nconf(&crlctx, conf);

    if (crl_ext != NULL)
        if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, crl_ext, crl))
            goto end;
    if (crlnumberfile != NULL) {
        tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL);
        if (!tmpser)
            goto end;
        X509_CRL_add1_ext_i2d(crl, NID_crl_number, tmpser, 0, 0);
        ASN1_INTEGER_free(tmpser);
        crl_v2 = 1;
        if (!BN_add_word(crlnumber, 1))
            goto end;
    }
}

So, it seems you can use X509V3_EXT_CRL_add_nconf or X509_CRL_add1_ext_i2d for the purpose. Please refer the apps/ca.c of the OpenSSL version that you are using.

Another solution: Maybe not the best approach, but you can probably launch the same OpenSSL commands as processes from code and process their output if it's acceptable.