[rs-commit] r546 - in /mod_ca/trunk: ChangeLog mod_ca_disk.c
rs-commit at redwax.eu
rs-commit at redwax.eu
Thu Mar 12 16:52:29 CET 2026
Author: minfrin at redwax.eu
Date: Thu Mar 12 16:52:28 2026
New Revision: 546
Log:
mod_ca_disk: When the ca_certstore hook is fired to
save the certificate, but the index has not yet been
updated because the ca_makeserial hook was not used,
update the index while make sure this happens just
once.
Modified:
mod_ca/trunk/ChangeLog
mod_ca/trunk/mod_ca_disk.c
Modified: mod_ca/trunk/ChangeLog
==============================================================================
--- mod_ca/trunk/ChangeLog (original)
+++ mod_ca/trunk/ChangeLog Thu Mar 12 16:52:28 2026
@@ -1,5 +1,11 @@
Changes with v1.0.0
+
+ *) mod_ca_disk: When the ca_certstore hook is fired to
+ save the certificate, but the index has not yet been
+ updated because the ca_makeserial hook was not used,
+ update the index while make sure this happens just
+ once. [Graham Leggett]
*) Add ca_reqauthz hook to mod_ca_disk to verify the case
where the renewal or reissue was signed by a
Modified: mod_ca/trunk/mod_ca_disk.c
==============================================================================
--- mod_ca/trunk/mod_ca_disk.c (original)
+++ mod_ca/trunk/mod_ca_disk.c Thu Mar 12 16:52:28 2026
@@ -70,6 +70,7 @@
typedef struct
{
+ TXT_DB *db;
const char *csr_path;
const char *serial_path;
const char *serial_path_suffix;
@@ -519,6 +520,10 @@
char buf[HUGE_STRING_LEN];
X509 *cert = NULL;
PKCS7 *p7 = NULL;
+ ASN1_INTEGER *si;
+ BIGNUM *bn = NULL;
+ ASN1_TIME *tm = NULL;
+ X509_NAME *subject = NULL;
apr_status_t status;
ca_config_rec *conf = ap_get_module_config(r->per_dir_config,
@@ -559,18 +564,22 @@
return HTTP_BAD_REQUEST;
}
+ /* sanity check the serial number */
+ si = X509_get_serialNumber(cert);
+ if (!si) {
+ log_message(r, APR_SUCCESS,
+ "certificate had no serial number, could not be stored");
+
+ return HTTP_BAD_REQUEST;
+ }
+ bn = ASN1_INTEGER_to_BN(si, NULL);
+
+ apr_pool_cleanup_register(r->pool, bn, ca_BIGNUM_cleanup,
+ apr_pool_cleanup_null);
+
/* extract the serial if requested */
if (conf->serial_path) {
const char *key;
- BIGNUM *bn = NULL;
- ASN1_INTEGER *si = X509_get_serialNumber(cert);
- if (!si) {
- log_message(r, APR_SUCCESS,
- "certificate had no serial number, could not be stored");
-
- return HTTP_BAD_REQUEST;
- }
- bn = ASN1_INTEGER_to_BN(si, NULL);
if (BN_is_zero(bn)) {
key = apr_pstrcat(r->pool, "00.", conf->serial_path_suffix, NULL);
}
@@ -580,7 +589,6 @@
NULL);
OPENSSL_free(tmp);
}
- BN_free(bn);
/* set up the path */
status = apr_filepath_merge(&path, conf->serial_path, key,
@@ -649,7 +657,7 @@
return DECLINED;
}
- /* create a bio for our CSR */
+ /* create a bio for our certificate */
out = BIO_new(BIO_s_mem());
apr_pool_cleanup_register(r->pool, out, ca_BIO_cleanup,
apr_pool_cleanup_null);
@@ -719,6 +727,146 @@
"Could not link the certificate file to the CADiskCertificateByTransactionPath");
apr_file_remove(path, r->pool);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ /* did we already index the serial in the ca_makeserial hook? */
+ if (conf->db) {
+ return OK;
+ }
+
+ /* get the not after time and subject, if set */
+ tm = parse_ASN1_TIME(r->pool,
+ apr_hash_get(params, "notAfter", APR_HASH_KEY_STRING));
+ subject = parse_X509_NAME(r->pool,
+ apr_hash_get(params, "subject", APR_HASH_KEY_STRING));
+
+ /* must we update the openssl database? */
+ if (conf->index_file && tm && subject) {
+
+ char *tname;
+ BIO *in;
+ BIO *out;
+ OPENSSL_STRING *row;
+
+ in = BIO_new(BIO_s_file());
+
+ if (BIO_read_filename(in, conf->index_file) <= 0) {
+ /* on read error, we create a database */
+ BIO_free(in);
+ in = BIO_new(BIO_s_mem());
+ }
+ apr_pool_cleanup_register(r->pool, in, ca_BIO_cleanup,
+ apr_pool_cleanup_null);
+
+ conf->db = TXT_DB_read(in, DB_NUMBER);
+ if (!conf->db) {
+ log_message(r, APR_SUCCESS, "Could not parse the index file");
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ apr_pool_cleanup_register(r->pool, conf->db, ca_TXT_DB_cleanup,
+ apr_pool_cleanup_null);
+
+ if (!TXT_DB_create_index(conf->db, DB_serial, NULL,
+ LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) {
+ log_message(r, APR_SUCCESS,
+ apr_psprintf(r->pool,
+ "Could not hash the index file (%ld,%ld,%ld)",
+ conf->db->error, conf->db->arg1, conf->db->arg2));
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (conf->index_unique
+ && !TXT_DB_create_index(conf->db, DB_name, index_name_qual,
+ LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) {
+ log_message(r, APR_SUCCESS,
+ apr_psprintf(r->pool,
+ "Could not hash the index file (%ld,%ld,%ld)",
+ conf->db->error, conf->db->arg1, conf->db->arg2));
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ row = (char **) OPENSSL_malloc(sizeof(char *)*(DB_NUMBER+1));
+ if (!row) {
+ log_message(r, APR_SUCCESS,
+ "Could not allocate new row into index file");
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ row[DB_type] = (char *) OPENSSL_malloc(2);
+ row[DB_exp_date] = (char *) OPENSSL_malloc(tm->length+1);
+ if (BN_is_zero(bn)) {
+ row[DB_serial] = BUF_strdup("00");
+ }
+ else {
+ row[DB_serial] = BN_bn2hex(bn);
+ }
+ row[DB_rev_date] = NULL;
+ row[DB_file] = (char *) OPENSSL_malloc(8);
+ row[DB_name] = X509_NAME_oneline(subject, NULL, 0);
+ if ((!row[DB_type]) || (!row[DB_exp_date]) || (!row[DB_serial])
+ || (!row[DB_file]) || (!row[DB_name])) {
+ log_message(r, APR_SUCCESS,
+ "Could not allocate new row into index file");
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ row[DB_type][0] = 'V';
+ row[DB_type][1] = '\0';
+ BUF_strlcpy(row[DB_file], "unknown", 8);
+ memcpy(row[DB_exp_date], tm->data, tm->length);
+ row[DB_exp_date][tm->length] = '\0';
+
+ if (!TXT_DB_insert(conf->db, row)) {
+ log_message(r, APR_SUCCESS,
+ conf->db->error == DB_ERROR_INDEX_CLASH ?
+ conf->index_unique ? "Index file clash: serial / subject already used" :
+ "Index file clash: serial already used"
+ : "Could not insert new row into index file");
+
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ out = BIO_new(BIO_s_file());
+
+ tname = apr_pstrcat(r->pool, conf->index_file, ".XXXXXX", NULL);
+ if (BIO_write_filename(out, tname) <= 0) {
+ log_message(r, APR_SUCCESS, "Index file could not be created");
+
+ BIO_free(out);
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (conf->db && !TXT_DB_write(out, conf->db)) {
+ log_message(r, APR_SUCCESS, "Index could not generated");
+
+ BIO_free(out);
+ apr_global_mutex_unlock(ca_disk_mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ BIO_free(out);
+
+ /* rename the file into place */
+ status = apr_file_rename(tname, conf->index_file, r->pool);
+ if (APR_SUCCESS != status) {
+ log_message(r, status,
+ "Could not rename the index temporary file");
+
+ apr_file_remove(tname, r->pool);
+ apr_global_mutex_unlock(ca_disk_mutex);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
@@ -1000,7 +1148,6 @@
apr_file_t *tfile;
ASN1_INTEGER *ai;
BIGNUM *bn = NULL;
- TXT_DB *db = NULL;
ASN1_TIME *tm = NULL;
X509_NAME *subject = NULL;
char *serial_file_new;
@@ -1040,34 +1187,34 @@
apr_pool_cleanup_register(r->pool, in, ca_BIO_cleanup,
apr_pool_cleanup_null);
- db = TXT_DB_read(in, DB_NUMBER);
- if (!db) {
+ conf->db = TXT_DB_read(in, DB_NUMBER);
+ if (!conf->db) {
log_message(r, APR_SUCCESS, "Could not parse the index file");
apr_global_mutex_unlock(ca_disk_mutex);
return HTTP_INTERNAL_SERVER_ERROR;
}
- apr_pool_cleanup_register(r->pool, db, ca_TXT_DB_cleanup,
+ apr_pool_cleanup_register(r->pool, conf->db, ca_TXT_DB_cleanup,
apr_pool_cleanup_null);
- if (!TXT_DB_create_index(db, DB_serial, NULL,
+ if (!TXT_DB_create_index(conf->db, DB_serial, NULL,
LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) {
log_message(r, APR_SUCCESS,
apr_psprintf(r->pool,
"Could not hash the index file (%ld,%ld,%ld)",
- db->error, db->arg1, db->arg2));
+ conf->db->error, conf->db->arg1, conf->db->arg2));
apr_global_mutex_unlock(ca_disk_mutex);
return HTTP_INTERNAL_SERVER_ERROR;
}
if (conf->index_unique
- && !TXT_DB_create_index(db, DB_name, index_name_qual,
+ && !TXT_DB_create_index(conf->db, DB_name, index_name_qual,
LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) {
log_message(r, APR_SUCCESS,
apr_psprintf(r->pool,
"Could not hash the index file (%ld,%ld,%ld)",
- db->error, db->arg1, db->arg2));
+ conf->db->error, conf->db->arg1, conf->db->arg2));
apr_global_mutex_unlock(ca_disk_mutex);
return HTTP_INTERNAL_SERVER_ERROR;
@@ -1157,7 +1304,7 @@
BIO_read(out, buf, size);
BIO_free(out);
- if (db) {
+ if (conf->db) {
OPENSSL_STRING *row =
(char **) OPENSSL_malloc(sizeof(char *)*(DB_NUMBER+1));
if (!row) {
@@ -1198,9 +1345,9 @@
memcpy(row[DB_exp_date], tm->data, tm->length);
row[DB_exp_date][tm->length] = '\0';
- if (!TXT_DB_insert(db, row)) {
+ if (!TXT_DB_insert(conf->db, row)) {
log_message(r, APR_SUCCESS,
- db->error == DB_ERROR_INDEX_CLASH ?
+ conf->db->error == DB_ERROR_INDEX_CLASH ?
conf->index_unique ? "Index file clash: serial / subject already used" :
"Index file clash: serial already used"
: "Could not insert new row into index file");
@@ -1256,7 +1403,7 @@
return HTTP_INTERNAL_SERVER_ERROR;
}
- if (db && !TXT_DB_write(out, db)) {
+ if (conf->db && !TXT_DB_write(out, conf->db)) {
log_message(r, APR_SUCCESS, "Index could not generated");
BIO_free(out);
More information about the rs-commit
mailing list