diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 90f16a85..538658b5 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -150,6 +150,7 @@ void HIDDEN xbps_transaction_conflicts(struct xbps_handle *, xbps_array_t); char HIDDEN *xbps_archive_get_file(struct archive *, struct archive_entry *); xbps_dictionary_t HIDDEN xbps_archive_get_dictionary(struct archive *, struct archive_entry *, char **bytes); +xbps_dictionary_t HIDDEN get_safe_idxmeta(xbps_dictionary_t full); const char HIDDEN *vpkg_user_conf(struct xbps_handle *, const char *, bool); xbps_array_t HIDDEN xbps_get_pkg_fulldeptree(struct xbps_handle *, const char *, bool); diff --git a/lib/plist_fetch.c b/lib/plist_fetch.c index 6526c3e0..49baa4ef 100644 --- a/lib/plist_fetch.c +++ b/lib/plist_fetch.c @@ -180,8 +180,13 @@ xbps_repo_fetch_remote(struct xbps_repo *repo, const char *url) { struct archive *a; struct archive_entry *entry; + xbps_dictionary_t idxmeta_tmp = NULL; + size_t meta_signature_len = 0; uint8_t i = 0; + bool verified = false; const char *signature_type = NULL; + unsigned char *meta_digest = NULL; + unsigned char *meta_signature = NULL; assert(url); assert(repo); @@ -199,9 +204,14 @@ xbps_repo_fetch_remote(struct xbps_repo *repo, const char *url) if (strcmp(bfile, XBPS_REPOIDX_META) == 0) { buf = xbps_archive_get_file(a, entry); - repo->idxmeta = xbps_dictionary_internalize(buf); + meta_digest = xbps_buffer_hash_raw(buf, strlen(buf)); + idxmeta_tmp = xbps_dictionary_internalize(buf); free(buf); i++; + } else if (strcmp(bfile, XBPS_REPOIDXMETA_SIG) == 0) { + meta_signature = (unsigned char *) xbps_archive_get_file(a, entry); + meta_signature_len = (size_t) archive_entry_size(entry); + i++; } else if (strcmp(bfile, XBPS_REPOIDX) == 0) { buf = xbps_archive_get_file(a, entry); repo->idx = xbps_dictionary_internalize(buf); @@ -210,17 +220,30 @@ xbps_repo_fetch_remote(struct xbps_repo *repo, const char *url) } else { archive_read_data_skip(a); } - if (i == 2) + if (i == 3) break; } archive_read_finish(a); + verified = xbps_verify_digest_signature(repo, idxmeta_tmp, meta_signature, meta_signature_len, meta_digest); + if (verified) { + xbps_dbg_printf(repo->xhp, "Verification of repo's '%s' signature passed.\n", url); + } else { + xbps_warn_printf("Verification of repo's '%s' signature failed. Taking safe part.\n", url); + idxmeta_tmp = get_safe_idxmeta(idxmeta_tmp); + } + + repo->idxmeta = idxmeta_tmp; + if (xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-type", &signature_type)) repo->is_signed = true; if (xbps_object_type(repo->idx) == XBPS_TYPE_DICTIONARY) return true; + free(meta_digest); + free(meta_signature); + return false; } diff --git a/lib/repo.c b/lib/repo.c index f55c9403..a86b8954 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -126,7 +126,7 @@ repo_get_dict(struct xbps_repo *repo, int *verify_error) } -static xbps_dictionary_t +xbps_dictionary_t HIDDEN get_safe_idxmeta(xbps_dictionary_t full) { static const char *keys[] = { "public-key", @@ -134,13 +134,21 @@ get_safe_idxmeta(xbps_dictionary_t full) { "signature-by", "signature-type", }; - unsigned fields_count = (sizeof keys)/(sizeof *keys); - xbps_dictionary_t safe = xbps_dictionary_create(); + static const unsigned fields_count = (sizeof keys)/(sizeof *keys); + xbps_dictionary_t safe = NULL; + + if (full == NULL) { + return NULL; + } + + safe = xbps_dictionary_create(); for (unsigned i = 0; i < fields_count; ++i) { const char *key = keys[i]; xbps_object_t value = xbps_dictionary_get(full, key); - xbps_dictionary_set(safe, key, value); + if (value != NULL) { + xbps_dictionary_set(safe, key, value); + } } return safe;