Files
cHTTP/src/sec.c
T
2025-07-21 23:19:11 +02:00

220 lines
4.9 KiB
C

#ifndef HTTP_AMALGAMATION
#include "sec.h"
#endif
#ifndef HTTPS_ENABLED
void secure_context_global_init(void)
{
}
void secure_context_global_free(void)
{
}
int secure_context_init_as_client(SecureContext *sec)
{
(void) sec;
return 0;
}
int secure_context_init_as_server(SecureContext *sec,
HTTP_String cert_file, HTTP_String key_file)
{
(void) sec;
(void) cert_file;
(void) key_file;
return 0;
}
int secure_context_add_cert(SecureContext *sec,
HTTP_String domain, HTTP_String cert_file,
HTTP_String key_file)
{
(void) sec;
(void) domain;
(void) cert_file;
(void) key_file;
return -1;
}
void secure_context_free(SecureContext *sec)
{
(void) sec;
}
#else
void secure_context_global_init(void)
{
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
void secure_context_global_free(void)
{
EVP_cleanup();
}
int secure_context_init_as_client(SecureContext *sec)
{
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
if (!ctx)
return -1;
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
if (SSL_CTX_set_default_verify_paths(ctx) != 1) {
SSL_CTX_free(ctx);
return -1;
}
sec->is_server = false;
sec->ctx = ctx;
sec->num_certs = 0;
return 0;
}
static int servername_callback(SSL *ssl, int *ad, void *arg)
{
SecureContext *sec = arg;
(void) ad; // TODO: use this?
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (servername == NULL)
return SSL_TLSEXT_ERR_NOACK;
for (int i = 0; i < sec->num_certs; i++) {
CertData *cert = &sec->certs[i];
if (!strcmp(cert->domain, servername)) {
SSL_set_SSL_CTX(ssl, cert->ctx);
return SSL_TLSEXT_ERR_OK;
}
}
return SSL_TLSEXT_ERR_NOACK;
}
int secure_context_init_as_server(SecureContext *sec,
HTTP_String cert_file, HTTP_String key_file)
{
SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
if (!ctx)
return -1;
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
char cert_buffer[1024];
if (cert_file.len >= (int) sizeof(cert_buffer)) {
SSL_CTX_free(ctx);
return -1;
}
memcpy(cert_buffer, cert_file.ptr, cert_file.len);
cert_buffer[cert_file.len] = '\0';
// Copy private key file path to static buffer
char key_buffer[1024];
if (key_file.len >= (int) sizeof(key_buffer)) {
SSL_CTX_free(ctx);
return -1;
}
memcpy(key_buffer, key_file.ptr, key_file.len);
key_buffer[key_file.len] = '\0';
// Load certificate and private key
if (SSL_CTX_use_certificate_file(ctx, cert_buffer, SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(ctx);
return -1;
}
if (SSL_CTX_use_PrivateKey_file(ctx, key_buffer, SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(ctx);
return -1;
}
// Verify that the private key matches the certificate
if (SSL_CTX_check_private_key(ctx) != 1) {
SSL_CTX_free(ctx);
return -1;
}
SSL_CTX_set_tlsext_servername_callback(ctx, servername_callback);
SSL_CTX_set_tlsext_servername_arg(ctx, sec);
sec->is_server = true;
sec->ctx = ctx;
sec->num_certs = 0;
return 0;
}
void secure_context_free(SecureContext *sec)
{
SSL_CTX_free(sec->ctx);
for (int i = 0; i < sec->num_certs; i++)
SSL_CTX_free(sec->certs[i].ctx);
}
int secure_context_add_cert(SecureContext *sec,
HTTP_String domain, HTTP_String cert_file,
HTTP_String key_file)
{
if (!sec->is_server)
return -1;
if (sec->num_certs == MAX_CERTS)
return -1;
SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
if (!ctx)
return -1;
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
char cert_buffer[1024];
if (cert_file.len >= (int) sizeof(cert_buffer)) {
SSL_CTX_free(ctx);
return -1;
}
memcpy(cert_buffer, cert_file.ptr, cert_file.len);
cert_buffer[cert_file.len] = '\0';
char key_buffer[1024];
if (key_file.len >= (int) sizeof(key_buffer)) {
SSL_CTX_free(ctx);
return -1;
}
memcpy(key_buffer, key_file.ptr, key_file.len);
key_buffer[key_file.len] = '\0';
if (SSL_CTX_use_certificate_file(ctx, cert_buffer, SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(ctx);
return -1;
}
if (SSL_CTX_use_PrivateKey_file(ctx, key_buffer, SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(ctx);
return -1;
}
if (SSL_CTX_check_private_key(ctx) != 1) {
SSL_CTX_free(ctx);
return -1;
}
CertData *cert = &sec->certs[sec->num_certs];
if (domain.len >= (int) sizeof(cert->domain)) {
SSL_CTX_free(ctx);
return -1;
}
memcpy(cert->domain, domain.ptr, domain.len);
cert->domain[domain.len] = '\0';
cert->ctx = ctx;
sec->num_certs++;
return 0;
}
#endif