Repository: valkey-io/valkey
File: src/tls.c (C)

Code before:
    if (client_ctx) SSL_CTX_free(client_ctx);
    *out_ctx = NULL;
    *out_client_ctx = NULL;
    return C_ERR;
}

/* Last known TLS materials metadata to detect changes */
static unsigned char last_cert_fingerprint[EVP_MAX_MD_SIZE] = {0};
static unsigned int last_cert_fingerprint_len = 0;
static unsigned char last_client_cert_fingerprint[EVP_MAX_MD_SIZE] = {0};
static unsigned int last_client_cert_fingerprint_len = 0;
static unsigned char last_ca_cert_fingerprint[EVP_MAX_MD_SIZE] = {0};
static unsigned int last_ca_cert_fingerprint_len = 0;
static ino_t last_ca_cert_dir_inode = 0;
static time_t last_ca_cert_dir_mtime = 0;
static ino_t last_key_file_inode = 0;
static time_t last_key_file_mtime = 0;
static ino_t last_client_key_file_inode = 0;
static time_t last_client_key_file_mtime = 0;

/* Compute certificate fingerprint from file. */
static int getCertFingerprint(const char *cert_file, unsigned char *fingerprint, unsigned int *fingerprint_len) {
    if (!cert_file) return C_ERR;

    FILE *fp = fopen(cert_file, "r");
    if (!fp) return C_ERR;

    X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL);
    fclose(fp);
    if (!cert) return C_ERR;

    const EVP_MD *digest = EVP_sha256();
    if (X509_digest(cert, digest, fingerprint, fingerprint_len) != 1) {
        X509_free(cert);
        return C_ERR;
    }

    X509_free(cert);
    return C_OK;
}

/* Check if a single TLS cert file fingerprint changed and update cached value. */
static int checkAndUpdateFingerprint(const char *file,
                                     unsigned char *last_fingerprint,
                                     unsigned int *last_len) {
    unsigned char current[EVP_MAX_MD_SIZE];
    unsigned int current_len;

    if (!file) return 0;
    if (getCertFingerprint(file, current, &current_len) != C_OK) return 0;


Review comment (performance):
fopen (or even an open with NON-block) might hang here if the storage device is network attached (I'm thinking about EBS as the volume backend might be slow). It would be nice to have the entire process of fetching the data be on the background thread. This is technically true today, but we will be checking it a lot more, so I'm a little bit more worried about it.

I wouldn't call this strictly a blocker, or could be done iteratively. I like the expensive work is already offloaded.

Code after:
    if (client_ctx) SSL_CTX_free(client_ctx);
    *out_ctx = NULL;
    *out_client_ctx = NULL;
    return C_ERR;
}

/* TLS materials metadata for change detection */
typedef struct {
    unsigned char cert_fingerprint[EVP_MAX_MD_SIZE];
    unsigned int cert_fingerprint_len;
    unsigned char client_cert_fingerprint[EVP_MAX_MD_SIZE];
    unsigned int client_cert_fingerprint_len;
    unsigned char ca_cert_fingerprint[EVP_MAX_MD_SIZE];
    unsigned int ca_cert_fingerprint_len;
    ino_t ca_cert_dir_inode;
    time_t ca_cert_dir_mtime;
    ino_t key_file_inode;
    time_t key_file_mtime;
    ino_t client_key_file_inode;
    time_t client_key_file_mtime;
} tlsMaterialsMetadata;

/* Pending TLS reload that holds both SSL contexts and their metadata.
 * Updated serially by BIO thread, applied atomically by main thread. */
typedef struct {
    SSL_CTX *ctx;
    SSL_CTX *client_ctx;
    tlsMaterialsMetadata metadata;
} tlsPendingReload;

/* Last known (active) TLS materials metadata */
static tlsMaterialsMetadata active_metadata = {0};

/* Compute certificate fingerprint from file. */
static int getCertFingerprint(const char *cert_file, unsigned char *fingerprint, unsigned int *fingerprint_len) {
    if (!cert_file) return C_ERR;

    FILE *fp = fopen(cert_file, "r");
    if (!fp) {
        serverLog(LL_WARNING, "Failed to open certificate file '%s': %s", cert_file, strerror(errno));
        return C_ERR;
    }

    X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL);
    fclose(fp);
    if (!cert) {
        serverLog(LL_WARNING, "Failed to parse X509 certificate from '%s'", cert_file);
        return C_ERR;
    }

    const EVP_MD *digest = EVP_sha256();