+The AIA validation flow didn't considered entirely the scenario where a TA child AIA extension didn't matched the actual location from where the TA was fetched (common case: when its downloaded from an HTTPS URI), so despite the TA actually existed it wasn't considered when the validator was working with local files.
+Replace all '-ENOMEM' return codes with the log function 'pr_enomem'.
+Use temporal files whenever an HTTPS file is being downloaded.
+Fix memory leak when working with local TA files.
+The message '{..} discarding any other validation results' is now sent to the operation log.
+Fix GCC 10 warning related to 'strncpy', use 'memcpy' instead.
array->array = calloc(len, sizeof(char *));
if (array->array == NULL)
- return -ENOMEM;
+ return pr_enomem();
for (i = 0; i < len; i++) {
array->array[i] = strdup(values[i]);
if (array->array[i] == NULL) {
string_array_cleanup(array);
- return -ENOMEM;
+ return pr_enomem();
}
}
b64 = BIO_new(BIO_f_base64());
if (b64 == NULL) {
error = ERR_peek_last_error();
- return error ? error_ul2i(error) : -ENOMEM;
+ return error ? error_ul2i(error) : pr_enomem();
}
/*
str_copy = malloc(encoded_len + pad + 1);
if (str_copy == NULL)
- return -ENOMEM;
+ return pr_enomem();
/* Set all with pad char, then replace with the original string */
memset(str_copy, '=', encoded_len + pad);
memcpy(str_copy, str_encoded, encoded_len);
alloc_size = EVP_DECODE_LENGTH(strlen(str_copy));
*result = malloc(alloc_size + 1);
if (*result == NULL) {
- error = -ENOMEM;
+ error = pr_enomem();
goto free_enc;
}
memset(*result, 0, alloc_size);
mem = BIO_new(BIO_s_mem());
if (mem == NULL) {
error = ERR_peek_last_error();
- return error ? error_ul2i(error) : -ENOMEM;
+ return error ? error_ul2i(error) : pr_enomem();
}
b64 = BIO_new(BIO_f_base64());
return 0;
free_mem:
BIO_free_all(b64);
- return error ? error_ul2i(error) : -ENOMEM;
+ return error ? error_ul2i(error) : pr_enomem();
}
#include "http.h"
+#include <errno.h>
+#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include <sys/stat.h>
__http_download_file(struct rpki_uri *uri, http_write_cb cb,
long *response_code, long ims_value, long *cond_met, bool log_operation)
{
+ char const *tmp_suffix = "_tmp";
struct http_handler handler;
struct stat stat;
FILE *out;
unsigned int retries;
+ char const *original_file;
+ char *tmp_file, *tmp;
int error;
retries = 0;
return 0;
}
- error = create_dir_recursive(uri_get_local(uri));
+ original_file = uri_get_local(uri);
+ tmp_file = strdup(original_file);
+ if (tmp_file == NULL)
+ return pr_enomem();
+
+ tmp = realloc(tmp_file, strlen(tmp_file) + strlen(tmp_suffix) + 1);
+ if (tmp == NULL) {
+ error = pr_enomem();
+ goto release_tmp;
+ }
+
+ tmp_file = tmp;
+ strcat(tmp_file, tmp_suffix);
+
+ error = create_dir_recursive(tmp_file);
if (error)
- return ENSURE_NEGATIVE(error);
+ goto release_tmp;
- error = file_write(uri_get_local(uri), &out, &stat);
+ error = file_write(tmp_file, &out, &stat);
if (error)
goto delete_dir;
if (error)
goto delete_dir;
+ /* Overwrite the original file */
+ error = rename(tmp_file, original_file);
+ if (error) {
+ error = errno;
+ pr_val_errno(error, "Renaming temporal file from '%s' to '%s'",
+ tmp_file, original_file);
+ goto delete_dir;
+ }
+
+ free(tmp_file);
return 0;
close_file:
file_close(out);
delete_dir:
- delete_dir_recursive_bottom_up(uri_get_local(uri));
+ delete_dir_recursive_bottom_up(tmp_file);
+release_tmp:
+ free(tmp_file);
return ENSURE_NEGATIVE(error);
}
lfile = malloc(sizeof(struct line_file));
if (lfile == NULL)
- return -ENOMEM;
+ return pr_enomem();
lfile->file = fopen(file_name, "r");
if (lfile->file == NULL) {
* verified to comply with rfc6487#section-4.8.7
*/
static int
-force_aia_validation(struct rpki_uri *caIssuers, void *arg)
+force_aia_validation(struct rpki_uri *caIssuers, X509 *son, bool is_ta_child)
{
- X509 *son = arg;
X509 *parent;
struct rfc5280_name *son_name;
struct rfc5280_name *parent_name;
int error;
- pr_val_debug("AIA's URI didn't matched parent URI, doing AIA RSYNC");
+ pr_val_debug("AIA's URI didn't matched parent URI, trying to SYNC");
/* RSYNC is still the prefered access mechanism */
- error = download_files(caIssuers, false, false);
- if (error)
+ do {
+ error = download_files(caIssuers, false, false);
+ if (!error)
+ break;
+ if (error == EREQFAILED) {
+ pr_val_info("AIA URI couldn't be downloaded, trying to search locally");
+ break;
+ }
return error;
+ } while (0);
+ /*
+ * Consider the scenario where the TA was fetched from a distinct URI
+ * (maybe an HTTPS URI), in that case keep doing the validation since
+ * there's no "right" way to validate the AIA, that's where the flag
+ * 'is_ta_child' comes into play.
+ *
+ * A possible way is to load the certificate from the cert_stack, but
+ * the location itself isn't strictly the location from the AIA (the
+ * solution works, but maybe it isn't right.
+ */
error = certificate_load(caIssuers, &parent);
if (error)
- return error;
+ return !is_ta_child ? error : 0;
error = x509_name_decode(X509_get_subject_name(parent), "subject",
&parent_name);
* the current issuer. This will force an RSYNC of AIA's URI, load
* the certificate and do the comparison.
*/
- return force_aia_validation(caIssuers, cert);
+ return force_aia_validation(caIssuers, cert,
+ certstack_get_x509_num(validation_certstack(state)) == 1);
}
/*
tal = malloc(sizeof(struct tal));
if (tal == NULL) {
- error = -ENOMEM;
+ error = pr_enomem();
goto fail3;
}
if (!thread_arg->sync_files) {
/* Look for local files */
if (!valid_file_or_dir(uri_get_local(uri), true, false,
- pr_val_errno))
+ pr_val_errno)) {
+ validation_destroy(state);
return 0; /* Error already logged */
+ }
break;
}
/* Trying to sync, considering that the sync can be disabled */
if (uri_is_rsync(uri)) {
- if (!config_get_rsync_enabled())
+ if (!config_get_rsync_enabled()) {
+ validation_destroy(state);
return 0; /* Soft error */
+ }
error = download_files(uri, true, false);
break;
}
- if (!config_get_http_enabled())
+ if (!config_get_http_enabled()) {
+ validation_destroy(state);
return 0; /* Soft error */
+ }
error = handle_https_uri(uri);
} while (0);
SLIST_REMOVE_HEAD(&threads, next);
if (thread->exit_status) {
t_error = thread->exit_status;
- pr_val_warn("Validation from TAL '%s' yielded error, discarding any other validation results.",
+ pr_op_warn("Validation from TAL '%s' yielded error, discarding any other validation results.",
thread->tal_file);
}
thread_destroy(thread);
string = malloc(string_len + 1); /* Include NULL chara. */
if (!string)
- return -ENOMEM;
+ return pr_enomem();
memcpy(string, reader->buffer, string_len);
reader->buffer += string_len;
if (tmp_addr == NULL)
return pr_enomem();
- strncpy(tmp_addr, full_address, tmp_addr_len);
+ memcpy(tmp_addr, full_address, tmp_addr_len);
tmp_addr[tmp_addr_len] = '\0';
tmp_serv = strdup(ptr + 1);
if (sarray->count >= sarray->len) {
tmp = realloc(sarray->array, 2 * sarray->len * sarray->size);
if (tmp == NULL)
- return -ENOMEM;
+ return pr_enomem();
sarray->array = tmp;
sarray->len *= 2;
}
result = malloc(sizeof(struct validation));
if (!result)
- return -ENOMEM;
+ return pr_enomem();
error = state_store(result);
if (error)
bio = BIO_new(BIO_s_mem());
if (bio == NULL)
- return -ENOMEM;
+ return pr_enomem();
if (BN_print(bio, bn) == 0) {
BIO_free(bio);