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