import: refactor how we do gpg validation

Let's split out the actual gpg logic into a helper function, so that we
can add alternative validations later on.
This commit is contained in:
Lennart Poettering
2021-01-19 18:29:59 +01:00
parent 133b34f69a
commit ac71ece3c6
4 changed files with 82 additions and 67 deletions
+79 -64
View File
@@ -363,77 +363,35 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
return 1;
}
int pull_verify(PullJob *main_job,
PullJob *roothash_job,
PullJob *settings_job,
PullJob *checksum_job,
PullJob *signature_job) {
static int verify_gpg(
const void *payload, size_t payload_size,
const void *signature, size_t signature_size) {
_cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
_cleanup_close_ int sig_file = -1;
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
_cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
VerificationStyle style;
int r;
assert(main_job);
assert(main_job->state == PULL_JOB_DONE);
if (!checksum_job)
return 0;
assert(main_job->calc_checksum);
assert(main_job->checksum);
assert(checksum_job->state == PULL_JOB_DONE);
if (!checksum_job->payload || checksum_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
r = verify_one(checksum_job, main_job);
if (r < 0)
return r;
r = verify_one(checksum_job, roothash_job);
if (r < 0)
return r;
r = verify_one(checksum_job, settings_job);
if (r < 0)
return r;
if (!signature_job)
return 0;
r = verification_style_from_url(checksum_job->url, &style);
if (r < 0)
return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", checksum_job->url);
if (style == VERIFICATION_PER_FILE) /* if this is per-file verification, then the signature is in the
* checksum job, let's thus ignore the signature job from now on,
* and use the checksum job as signature job. */
signature_job = checksum_job;
assert(signature_job->state == PULL_JOB_DONE);
if (!signature_job->payload || signature_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
assert(payload || payload_size == 0);
assert(signature || signature_size == 0);
r = pipe2(gpg_pipe, O_CLOEXEC);
if (r < 0)
return log_error_errno(errno, "Failed to create pipe for gpg: %m");
sig_file = mkostemp(sig_file_path, O_RDWR);
if (sig_file < 0)
return log_error_errno(errno, "Failed to create temporary file: %m");
if (signature_size > 0) {
_cleanup_close_ int sig_file = -1;
r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
sig_file = mkostemp(sig_file_path, O_RDWR);
if (sig_file < 0)
return log_error_errno(errno, "Failed to create temporary file: %m");
r = loop_write(sig_file, signature, signature_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
}
}
if (!mkdtemp(gpg_home)) {
@@ -462,7 +420,7 @@ int pull_verify(PullJob *main_job,
NULL, /* dash */
NULL /* trailing NULL */
};
unsigned k = ELEMENTSOF(cmd) - 6;
size_t k = ELEMENTSOF(cmd) - 6;
/* Child */
@@ -478,8 +436,7 @@ int pull_verify(PullJob *main_job,
cmd[k++] = strjoina("--homedir=", gpg_home);
/* We add the user keyring only to the command line
* arguments, if it's around since gpg fails
/* We add the user keyring only to the command line arguments, if it's around since gpg fails
* otherwise. */
if (access(USER_KEYRING_PATH, F_OK) >= 0)
cmd[k++] = "--keyring=" USER_KEYRING_PATH;
@@ -487,7 +444,7 @@ int pull_verify(PullJob *main_job,
cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
cmd[k++] = "--verify";
if (style == VERIFICATION_PER_DIRECTORY) {
if (signature) {
cmd[k++] = sig_file_path;
cmd[k++] = "-";
cmd[k++] = NULL;
@@ -501,7 +458,7 @@ int pull_verify(PullJob *main_job,
gpg_pipe[0] = safe_close(gpg_pipe[0]);
r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
r = loop_write(gpg_pipe[1], payload, payload_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to pipe: %m");
goto finish;
@@ -522,7 +479,8 @@ int pull_verify(PullJob *main_job,
}
finish:
(void) unlink(sig_file_path);
if (signature_size > 0)
(void) unlink(sig_file_path);
if (gpg_home_created)
(void) rm_rf(gpg_home, REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -530,6 +488,63 @@ finish:
return r;
}
int pull_verify(ImportVerify verify,
PullJob *main_job,
PullJob *roothash_job,
PullJob *settings_job,
PullJob *checksum_job,
PullJob *signature_job) {
VerificationStyle style;
int r;
assert(main_job);
assert(main_job->state == PULL_JOB_DONE);
if (verify == IMPORT_VERIFY_NO)
return 0;
assert(main_job->calc_checksum);
assert(main_job->checksum);
assert(checksum_job);
assert(checksum_job->state == PULL_JOB_DONE);
if (!checksum_job->payload || checksum_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
r = verify_one(checksum_job, main_job);
if (r < 0)
return r;
r = verify_one(checksum_job, roothash_job);
if (r < 0)
return r;
r = verify_one(checksum_job, settings_job);
if (r < 0)
return r;
if (verify == IMPORT_VERIFY_CHECKSUM)
return 0;
r = verification_style_from_url(checksum_job->url, &style);
if (r < 0)
return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", checksum_job->url);
if (style == VERIFICATION_PER_DIRECTORY) {
assert(signature_job);
assert(signature_job->state == PULL_JOB_DONE);
if (!signature_job->payload || signature_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
return verify_gpg(checksum_job->payload, checksum_job->payload_size, signature_job->payload, signature_job->payload_size);
} else
return verify_gpg(checksum_job->payload, checksum_job->payload_size, NULL, 0);
}
int verification_style_from_url(const char *url, VerificationStyle *ret) {
_cleanup_free_ char *last = NULL;
int r;
+1 -1
View File
@@ -27,7 +27,7 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
int pull_make_auxiliary_job(PullJob **ret, const char *url, int (*strip_suffixes)(const char *name, char **ret), const char *suffix, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
int pull_verify(ImportVerify verify, PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
typedef enum VerificationStyle {
VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline gpg signature */
+1 -1
View File
@@ -542,7 +542,7 @@ static void raw_pull_job_on_finished(PullJob *j) {
raw_pull_report_progress(i, RAW_VERIFYING);
r = pull_verify(i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job);
r = pull_verify(i->verify, i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job);
if (r < 0)
goto finish;
+1 -1
View File
@@ -336,7 +336,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
tar_pull_report_progress(i, TAR_VERIFYING);
r = pull_verify(i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job);
r = pull_verify(i->verify, i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job);
if (r < 0)
goto finish;