Files
cHTTP/src/cert.c
T
2025-07-20 16:46:08 +02:00

140 lines
3.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
static EVP_PKEY *generate_rsa_key_pair(int key_bits)
{
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey;
// Create the context for key generation
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx)
return NULL;
if (EVP_PKEY_keygen_init(ctx) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_bits) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
EVP_PKEY_CTX_free(ctx);
return NULL;
}
EVP_PKEY_CTX_free(ctx);
return pkey;
}
static X509 *create_certificate(EVP_PKEY *pkey, HTTP_String C, HTTP_String O, HTTP_String CN, int days)
{
X509 *x509 = X509_new();
if (!x509)
return NULL;
// Set version (version 3)
X509_set_version(x509, 2);
// Set serial number
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
// Set validity period
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L * days); // days * seconds_per_year
// Set public key
X509_set_pubkey(x509, pkey);
// Set subject name
X509_NAME *name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*) C.ptr, C.len, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*) O.ptr, O.len, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*) CN.ptr, CN.len, -1, 0);
// Set issuer name (same as subject for self-signed)
X509_set_issuer_name(x509, name);
if (!X509_sign(x509, pkey, EVP_sha256())) {
X509_free(x509);
return NULL;
}
return x509;
}
static int save_private_key(EVP_PKEY *pkey, const char *filename)
{
FILE *fp = fopen(filename, "wb");
if (!fp)
return -1;
// Write private key in PEM format
if (!PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL)) {
fclose(fp);
return -1;
}
fclose(fp);
return 0;
}
static int cert_save(X509 *x509, const char *filename)
{
FILE *fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Error opening file for certificate: %s\n", filename);
return -1;
}
// Write certificate in PEM format
if (!PEM_write_X509(fp, x509)) {
fprintf(stderr, "Error writing certificate\n");
fclose(fp);
return -1;
}
fclose(fp);
printf("Certificate saved to: %s\n", filename);
return 0;
}
int http_create_test_certificate(HTTP_String C, HTTP_String O, HTTP_String CN,
HTTP_String cert_file, HTTP_String key_file)
{
EVP_PKEY *pkey = generate_rsa_key_pair(2048);
if (pkey == NULL)
return -1;
X509 *x509 = create_certificate(pkey, C, O, CN, 1)
if (x509 == NULL) {
EVP_PKEY_free(pkey);
return -1;
}
if (save_private_key(pkey, key_file) < 0) {
X509_free(x509);
EVP_PKEY_free(pkey);
return -1;
}
if (save_certificate(x509, cert_file) < 0) {
X509_free(x509);
EVP_PKEY_free(pkey);
return -1;
}
X509_free(x509);
EVP_PKEY_free(pkey);
return 0;
}