Facing segmentation fault at X509_REVOKED_set_revocationDate

30 Views Asked by At

My objective is to use Openssl APIs to generate and revoke multiple certificates signed by a certificate authority supplied in arguments (with ca.key and ca.crt). This is my code:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>
#include <openssl/err.h>


// Function to generate a self-signed certificate
X509* generate_certificate(EVP_PKEY *ca_key, X509 *ca_cert) {
    X509 *cert = X509_new();
    if (!cert) {
        fprintf(stderr, "Error creating certificate structure.\n");
        return NULL;
    }

    // Set version and serial number
    X509_set_version(cert, 2);  // X509v3
    ASN1_INTEGER_set(X509_get_serialNumber(cert), rand());

    // Set issuer and subject
    X509_set_issuer_name(cert, X509_get_subject_name(ca_cert));
    X509_set_subject_name(cert, X509_get_subject_name(ca_cert));

    // Set validity period (e.g., 1 year)
    X509_gmtime_adj(X509_get_notBefore(cert), 0);
    X509_gmtime_adj(X509_get_notAfter(cert), 31536000L);

    // Set public key
    X509_set_pubkey(cert, ca_key);

    // Sign the certificate
    if (!X509_sign(cert, ca_key, EVP_sha256())) {
        fprintf(stderr, "Error signing the certificate.\n");
        X509_free(cert);
        return NULL;
    }

    return cert;
}

// Function to revoke a certificate
int revoke_certificate(X509_CRL *crl, X509 *cert) {
    time_t revocation_time = time(NULL) + (6 * 30 * 24 * 60 * 60);  // 6 months in seconds
    X509_REVOKED *revoked = X509_REVOKED_new();
    if (!revoked) {
        fprintf(stderr, "Error creating revoked certificate structure.\n");
        return 0;
    }

    ASN1_INTEGER_set(X509_REVOKED_get0_serialNumber(revoked), X509_get_serialNumber(cert));
    X509_REVOKED_set_revocationDate(revoked, (ASN1_TIME *) revocation_time);

    if (X509_CRL_add0_revoked(crl, revoked) != 1) {
        fprintf(stderr, "Error adding revoked certificate to CRL.\n");
        X509_REVOKED_free(revoked);
        return 0;
    }

    X509_REVOKED_free(revoked);
    return 1;
}

// Function to generate a CRL
X509_CRL* generate_crl(EVP_PKEY *ca_key, X509 *ca_cert) {
    X509_CRL *crl = X509_CRL_new();
    if (!crl) {
        fprintf(stderr, "Error creating CRL structure.\n");
        return NULL;
    }

    // Set issuer to CA
    if (X509_CRL_set_issuer_name(crl, X509_get_subject_name(ca_cert)) != 1) {
        fprintf(stderr, "Error setting issuer name.\n");
        X509_CRL_free(crl);
        return NULL;
    }

    // Set last update and next update times
    X509_gmtime_adj(X509_CRL_get_lastUpdate(crl), 0);
    X509_gmtime_adj(X509_CRL_get_nextUpdate(crl), 31536000L);

    return crl;
}

int main(int argc, char *argv[]) {
    // Initialize OpenSSL
    OpenSSL_add_all_algorithms();

    const char *ca_key_path = argv[1];
    const char *ca_cert_path = argv[2];
    const char *crl_path = argv[3];
    const int NUM_REVOKED_CERTS = atoi(argv[4]);

    // Load key and certificate in memory
    X509 *ca_cert = NULL;
    EVP_PKEY *ca_key = NULL;

    FILE *ca_cert_file = fopen(ca_cert_path, "r");
    if (!ca_cert_file) {
        fprintf(stderr, "ERROR opening CA certificate file.\n");
        return 1;
    }

    ca_cert = PEM_read_X509(ca_cert_file, NULL, NULL, NULL);
    fclose(ca_cert_file);

    if (!ca_cert) {
        fprintf(stderr, "ERROR loading CA certificate.\n");
        return 1;
    }

    FILE *ca_key_file = fopen(ca_key_path, "r");
    if (!ca_key_file) {
        fprintf(stderr, "ERROR opening CA private key file.\n");
        X509_free(ca_cert);
        return 1;
    }

    ca_key = PEM_read_PrivateKey(ca_key_file, NULL, NULL, NULL);
    fclose(ca_cert_file);

    if (!ca_key) {
        fprintf(stderr, "ERROR loading CA private key.\n");
        X509_free(ca_cert);
        return 1;
    }

    // Generate CRL
    X509_CRL *crl = generate_crl(ca_key, ca_cert);
    if (!crl) {
        fprintf(stderr, "Error generating CRL.\n");
        X509_free(ca_cert);
        EVP_PKEY_free(ca_key);
        return 1;
    }

    // Generate and revoke multiple certificates
    for (int i = 0; i < NUM_REVOKED_CERTS; i++) {
        X509 *cert = generate_certificate(ca_key, ca_cert);
        if (!cert) {
            fprintf(stderr, "Error generating certificate %d.\n", i + 1);
            return 1; // Exit loop if an error occurs
        }

        // Revoke the certificate
        if (!revoke_certificate(crl, cert)) {
            fprintf(stderr, "Error revoking certificate %d.\n", i + 1);
        }

        X509_free(cert);
    }

    // Save the CRL to a file
    BIO *crl_bio = BIO_new_file(crl_path, "w");
    if (crl_bio && i2d_X509_CRL_bio(crl_bio, crl)) {
        printf("CRL saved to crl.pem\n");
    } else {
        fprintf(stderr, "Error saving CRL to file.\n");
    }

    // Clean up
    X509_CRL_free(crl);
    X509_free(ca_cert);
    EVP_PKEY_free(ca_key);

    // Cleanup OpenSSL
    EVP_cleanup();

    return 0;
}

I keep hitting segmentation faults, I have freed up the memory I used but maybe I have missed somewhere. I need help to point what am I doing wrong in the code above. This is the backtrace of the latest dump:

Core was generated by `./new.out ca.key ca.crt ca.crl 5'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f57bec713c5 in ASN1_STRING_copy () from /usr/local/lib64/libcrypto.so.3
(gdb) bt
#0  0x00007f57bec713c5 in ASN1_STRING_copy () from /usr/local/lib64/libcrypto.so.3
#1  0x00007f57bec7159b in ASN1_STRING_dup () from /usr/local/lib64/libcrypto.so.3
#2  0x00007f57bef254a3 in X509_REVOKED_set_revocationDate () from /usr/local/lib64/libcrypto.so.3
#3  0x000055af8b80e7ea in revoke_certificate (crl=0x55af8d048fa0, cert=0x55af8d0490a0) at new_crl.c:54
#4  0x000055af8b80ebdd in main (argc=5, argv=0x7fff77af9de8) at new_crl.c:149
0

There are 0 best solutions below