diff --git a/lib/repo.c b/lib/repo.c index eb823863..f55c9403 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -61,7 +61,7 @@ xbps_repo_path_with_name(struct xbps_handle *xhp, const char *url, const char *n url, xhp->target_arch ? xhp->target_arch : xhp->native_arch, name); } -static bool +static int repo_verify_index(struct xbps_repo *repo, xbps_dictionary_t idxmeta, unsigned char *digest) { bool verified = false; unsigned char *sig_buf = NULL; @@ -72,28 +72,28 @@ repo_verify_index(struct xbps_repo *repo, xbps_dictionary_t idxmeta, unsigned ch xbps_dbg_printf(repo->xhp, "%s: read_next_header %s\n", repo->uri, archive_error_string(repo->ar)); - return false; + return ENOENT; } if (strcmp(archive_entry_pathname(entry), XBPS_REPOIDXMETA_SIG) != 0) { xbps_dbg_printf(repo->xhp, "%s: no signature of %s\n", repo->uri, XBPS_REPOIDX_META); - return false; + return ENOENT; } sigfilelen = (size_t)archive_entry_size(entry); sig_buf = (unsigned char *) xbps_archive_get_file(repo->ar, entry); if (sig_buf == NULL) { - return false; + return EIO; } verified = xbps_verify_digest_signature(repo, idxmeta, sig_buf, sigfilelen, digest); free(sig_buf); - return verified; + return verified ? 0 : EINVAL; } static xbps_dictionary_t -repo_get_dict(struct xbps_repo *repo, bool *verified) +repo_get_dict(struct xbps_repo *repo, int *verify_error) { struct archive_entry *entry; int rv; @@ -101,8 +101,8 @@ repo_get_dict(struct xbps_repo *repo, bool *verified) char *bytes = NULL; unsigned char *digest = NULL; - if (verified != NULL) - *verified = false; + if (verify_error != NULL) + *verify_error = -1; if (repo->ar == NULL) return NULL; @@ -116,15 +116,36 @@ repo_get_dict(struct xbps_repo *repo, bool *verified) } dict = xbps_archive_get_dictionary(repo->ar, entry, &bytes); idxmeta = (repo->idxmeta != NULL) ? repo->idxmeta : dict; - if (verified != NULL && bytes != NULL) { + if (verify_error != NULL && bytes != NULL) { digest = xbps_buffer_hash_raw(bytes, strlen(bytes)); - *verified = repo_verify_index(repo, idxmeta, digest); + *verify_error = repo_verify_index(repo, idxmeta, digest); } free(digest); free(bytes); return dict; } + +static xbps_dictionary_t +get_safe_idxmeta(xbps_dictionary_t full) { + static const char *keys[] = { + "public-key", + "public-key-size", + "signature-by", + "signature-type", + }; + unsigned fields_count = (sizeof keys)/(sizeof *keys); + xbps_dictionary_t 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); + } + + return safe; +} + bool xbps_repo_lock(struct xbps_handle *xhp, const char *repodir, int *lockfd, char **lockfname) @@ -180,8 +201,9 @@ repo_open_local(struct xbps_repo *repo, const char *repofile) { struct stat st; int rv = 0; - bool verified = false; + int verify_error = -1; const char *signature_type = NULL; + xbps_dictionary_t idxmeta = NULL; if (fstat(repo->fd, &st) == -1) { rv = errno; @@ -213,14 +235,26 @@ repo_open_local(struct xbps_repo *repo, const char *repofile) return false; } xbps_dictionary_make_immutable(repo->idx); - repo->idxmeta = repo_get_dict(repo, &verified); - if (repo->idxmeta != NULL) { - if (xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-type", &signature_type)) + idxmeta = repo_get_dict(repo, &verify_error); + if (idxmeta != NULL) { + if (verify_error == ENOENT) { + xbps_dbg_printf(repo->xhp, "Metadata of repo '%s' not signed. Taking safe part.\n", repofile); + idxmeta = get_safe_idxmeta(idxmeta); + verify_error = 0; + } else if (verify_error) { + xbps_warn_printf("Verification of repo's '%s' signature failed. Taking safe part.\n", repofile); + idxmeta = get_safe_idxmeta(idxmeta); + } else { + xbps_dbg_printf(repo->xhp, "Verification of repo's '%s' signature passed.\n", repofile); + } + if (xbps_dictionary_get_cstring_nocopy(idxmeta, "signature-type", &signature_type)) { repo->is_signed = true; - xbps_dictionary_make_immutable(repo->idxmeta); + } + xbps_dictionary_make_immutable(idxmeta); } + repo->idxmeta = idxmeta; - return verified || (!repo->is_remote && !repo->is_signed); + return !verify_error || (!repo->is_remote && !repo->is_signed); } static bool