MINOR: ssl/crtlist: split the ckch_conf loading from the crtlist line parsing

ckch_conf loading is not that simple as it requires to check
- if the cert already exists in the ckchs_tree
- if the ckch_conf is compatible with an existing cert in ckchs_tree
- if the cert is a bundle which need to load multiple ckch_store

This logic could be reuse elsewhere, so this commit introduce the new
crtlist_load_crt() function which does that.
This commit is contained in:
William Lallemand 2025-02-11 15:01:33 +01:00
parent ab2fa95bdd
commit 6e91a7872e
2 changed files with 136 additions and 116 deletions

View File

@ -41,6 +41,7 @@ struct crtlist *crtlist_new(const char *filename, int unique);
int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, struct ckch_conf *conf, const char *file, int linenum, int from_cli, char **err);
int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, struct crtlist **crtlist, char **err);
int crtlist_load_cert_dir(char *path, struct bind_conf *bind_conf, struct crtlist **crtlist, char **err);
int crtlist_load_crt(char *crt_path, struct ckch_conf *cc, struct crtlist *newlist, struct crtlist_entry *entry, char *file, int linenum, char **err);
void crtlist_deinit();

View File

@ -501,6 +501,138 @@ error:
return cfgerr;
}
/*
* Look for a ckch_store <crt_path> which is a compatible with <cc>
* Or create a new ckch_store if none exists with this name.
*
* If the file is a bundle, then duplicate the entries
* Then insert the entries in the list
*/
int crtlist_load_crt(char *crt_path, struct ckch_conf *cc, struct crtlist *newlist, struct crtlist_entry *entry, char *file, int linenum, char **err)
{
struct ckch_store *ckchs;
int found = 0;
struct stat st;
int cfgerr = 0;
/* Look for a ckch_store or create one */
ckchs = ckchs_lookup(crt_path);
if (ckchs == NULL) {
if (stat(crt_path, &st) == 0) {
found++;
free(cc->crt);
cc->crt = strdup(crt_path);
if (cc->crt == NULL) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
ckchs = ckch_store_new_load_files_conf(crt_path, cc, err);
if (ckchs == NULL) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
ckchs->conf = *cc;
entry->node.key = ckchs;
entry->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry->node);
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
} else if (global_ssl.extra_files & SSL_GF_BUNDLE) {
/* If we didn't find the file, this could be a
bundle, since 2.3 we don't support multiple
certificate in the same OpenSSL store, so we
emulate it by loading each file separately. To
do so we need to duplicate the entry in the
crt-list because it becomes independent */
char fp[MAXPATHLEN+1] = {0};
int n = 0;
struct crtlist_entry *entry_dup = entry; /* use the previous created entry */
for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
int ret;
ret = snprintf(fp, sizeof(fp), "%s.%s", crt_path, SSL_SOCK_KEYTYPE_NAMES[n]);
if (ret > sizeof(fp))
continue;
ckchs = ckchs_lookup(fp);
if (!ckchs) {
if (stat(fp, &st) == 0) {
if (cc->used) {
memprintf(err, "%sCan't load '%s'. Using crt-store keyword is not compatible with multi certificates bundle.\n",
err && *err ? *err : "", crt_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
}
ckchs = ckch_store_new_load_files_path(fp, err);
if (!ckchs) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
} else {
continue; /* didn't find this extension, skip */
}
}
found++;
linenum++; /* we duplicate the line for this entry in the bundle */
if (!entry_dup) { /* if the entry was used, duplicate one */
linenum++;
entry_dup = crtlist_entry_dup(entry);
if (!entry_dup) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
entry_dup->linenum = linenum;
}
entry_dup->node.key = ckchs;
entry_dup->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry_dup->node);
LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry_dup->by_ckch_store);
entry_dup = NULL; /* the entry was used, we need a new one next round */
}
#if HA_OPENSSL_VERSION_NUMBER < 0x10101000L
if (found) {
memprintf(err, "%sCan't load '%s'. Loading a multi certificates bundle requires OpenSSL >= 1.1.1\n",
err && *err ? *err : "", crt_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
}
#endif
}
if (!found) {
memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
err && *err ? *err : "", crt_path, strerror(errno));
cfgerr |= ERR_ALERT | ERR_FATAL;
}
} else {
if (ckch_conf_cmp(&ckchs->conf, cc, err) != 0) {
memprintf(err, "'%s' in crt-list '%s' line %d, is already defined with incompatible parameters:\n %s", crt_path, file, linenum, err ? *err : "");
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
entry->node.key = ckchs;
entry->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry->node);
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
found++;
}
entry = NULL;
error:
return cfgerr;
}
/* This function parse a crt-list file and store it in a struct crtlist, each line is a crtlist_entry structure
@ -514,7 +646,6 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
struct crtlist_entry *entry = NULL;
char thisline[CRT_LINESIZE];
FILE *f;
struct stat buf;
int linenum = 0;
int cfgerr = 0;
int missing_lf = -1;
@ -536,9 +667,7 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
char *line = thisline;
char *crt_path;
char path[MAXPATHLEN+1];
struct ckch_store *ckchs;
struct ckch_conf cc = {};
int found = 0;
if (missing_lf != -1) {
memprintf(err, "parsing [%s:%d]: Stray NUL character at position %d.\n",
@ -601,120 +730,10 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
crt_path = path;
}
/* Look for a ckch_store or create one */
ckchs = ckchs_lookup(crt_path);
if (ckchs == NULL) {
if (stat(crt_path, &buf) == 0) {
found++;
free(cc.crt);
cc.crt = strdup(crt_path);
if (cc.crt == NULL) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
cfgerr |= crtlist_load_crt(crt_path, &cc, newlist, entry, file, linenum, err);
if (cfgerr & ERR_CODE)
goto error;
ckchs = ckch_store_new_load_files_conf(crt_path, &cc, err);
if (ckchs == NULL) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
ckchs->conf = cc;
entry->node.key = ckchs;
entry->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry->node);
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
} else if (global_ssl.extra_files & SSL_GF_BUNDLE) {
/* If we didn't find the file, this could be a
bundle, since 2.3 we don't support multiple
certificate in the same OpenSSL store, so we
emulate it by loading each file separately. To
do so we need to duplicate the entry in the
crt-list because it becomes independent */
char fp[MAXPATHLEN+1] = {0};
int n = 0;
struct crtlist_entry *entry_dup = entry; /* use the previous created entry */
for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
struct stat buf;
int ret;
ret = snprintf(fp, sizeof(fp), "%s.%s", crt_path, SSL_SOCK_KEYTYPE_NAMES[n]);
if (ret > sizeof(fp))
continue;
ckchs = ckchs_lookup(fp);
if (!ckchs) {
if (stat(fp, &buf) == 0) {
if (cc.used) {
memprintf(err, "%sCan't load '%s'. Using crt-store keyword is not compatible with multi certificates bundle.\n",
err && *err ? *err : "", crt_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
}
ckchs = ckch_store_new_load_files_path(fp, err);
if (!ckchs) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
} else {
continue; /* didn't find this extension, skip */
}
}
found++;
linenum++; /* we duplicate the line for this entry in the bundle */
if (!entry_dup) { /* if the entry was used, duplicate one */
linenum++;
entry_dup = crtlist_entry_dup(entry);
if (!entry_dup) {
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
entry_dup->linenum = linenum;
}
entry_dup->node.key = ckchs;
entry_dup->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry_dup->node);
LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry_dup->by_ckch_store);
entry_dup = NULL; /* the entry was used, we need a new one next round */
}
#if HA_OPENSSL_VERSION_NUMBER < 0x10101000L
if (found) {
memprintf(err, "%sCan't load '%s'. Loading a multi certificates bundle requires OpenSSL >= 1.1.1\n",
err && *err ? *err : "", crt_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
}
#endif
}
if (!found) {
memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
err && *err ? *err : "", crt_path, strerror(errno));
cfgerr |= ERR_ALERT | ERR_FATAL;
}
} else {
if (ckch_conf_cmp(&ckchs->conf, &cc, err) != 0) {
memprintf(err, "'%s' in crt-list '%s' line %d, is already defined with incompatible parameters:\n %s", crt_path, file, linenum, err ? *err : "");
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
entry->node.key = ckchs;
entry->crtlist = newlist;
ebpt_insert(&newlist->entries, &entry->node);
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
found++;
}
entry = NULL;
}
if (missing_lf != -1) {