mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
systemd-pull: support .asc and .sha256.* signature
This commit is contained in:
committed by
Lennart Poettering
parent
df8bd4c171
commit
ac9edf9911
@@ -114,16 +114,18 @@
|
||||
URL, with its suffix removed.</para>
|
||||
|
||||
<para>The image is verified before it is made available, unless <option>--verify=no</option> is
|
||||
specified. Verification is done either via an inline signed file with the name of the image and the
|
||||
suffix <filename>.sha256</filename> or via separate <filename>SHA256SUMS</filename> and
|
||||
<filename>SHA256SUMS.gpg</filename> files. The signature files need to be made available on the same
|
||||
web server, under the same URL as the <filename>.tar</filename> file. With
|
||||
specified. Verification is done either via a file with the name of the image and the
|
||||
suffix <filename>.sha256</filename> and a detached <filename>.sha256.asc</filename> or
|
||||
<filename>.sha256.gpg</filename> signature or via separate <filename>SHA256SUMS</filename> and
|
||||
<filename>SHA256SUMS.asc</filename> or <filename>SHA256SUMS.gpg</filename> files. The signature
|
||||
files need to be made available on the same web server, under the same URL as the
|
||||
<filename>.tar</filename> file. With
|
||||
<option>--verify=checksum</option>, only the SHA256 checksum for the file is verified, based on the
|
||||
<filename>.sha256</filename> suffixed file or the <filename>SHA256SUMS</filename> file. With
|
||||
<option>--verify=signature</option>, the sha checksum file is first verified with the inline
|
||||
signature in the <filename>.sha256</filename> file or the detached GPG signature file
|
||||
<filename>SHA256SUMS.gpg</filename>. The public key for this verification step needs to be available
|
||||
in <filename>/usr/lib/systemd/import-pubring.gpg</filename> or
|
||||
<option>--verify=signature</option>, the sha checksum file is first verified with the detached GPG
|
||||
signature of <filename>.sha256</filename> or <filename>SHA256SUMS</filename>. The public key for
|
||||
this verification step needs to be available in
|
||||
<filename>/usr/lib/systemd/import-pubring.gpg</filename> or
|
||||
<filename>/etc/systemd/import-pubring.gpg</filename>.</para>
|
||||
|
||||
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
|
||||
|
||||
@@ -226,14 +226,25 @@ static bool is_checksum_file(const char *fn) {
|
||||
return streq(fn, "SHA256SUMS") || endswith(fn, ".sha256");
|
||||
}
|
||||
|
||||
static bool is_signature_file(const char *fn) {
|
||||
/* Returns true if the specified filename refers to a signature file we grok (reminder:
|
||||
* suse-style .sha256 files are inline signed) */
|
||||
static SignatureStyle signature_style_from_filename(const char *fn) {
|
||||
/* Returns true if the specified filename refers to a signature file we grok */
|
||||
|
||||
if (!fn)
|
||||
return false;
|
||||
return _SIGNATURE_STYLE_INVALID;
|
||||
|
||||
return streq(fn, "SHA256SUMS.gpg") || endswith(fn, ".sha256");
|
||||
if (streq(fn, "SHA256SUMS.gpg"))
|
||||
return SIGNATURE_GPG_PER_DIRECTORY;
|
||||
|
||||
if (streq(fn, "SHA256SUMS.asc"))
|
||||
return SIGNATURE_ASC_PER_DIRECTORY;
|
||||
|
||||
if (endswith(fn, ".sha256.gpg"))
|
||||
return SIGNATURE_GPG_PER_FILE;
|
||||
|
||||
if (endswith(fn, ".sha256.asc"))
|
||||
return SIGNATURE_ASC_PER_FILE;
|
||||
|
||||
return _SIGNATURE_STYLE_INVALID;
|
||||
}
|
||||
|
||||
int pull_make_verification_jobs(
|
||||
@@ -272,7 +283,7 @@ int pull_make_verification_jobs(
|
||||
|
||||
/* Acquire the checksum file if verification or signature verification is requested and the main file
|
||||
* to acquire isn't a checksum or signature file anyway */
|
||||
if (verify != IMPORT_VERIFY_NO && !is_checksum_file(fn) && !is_signature_file(fn)) {
|
||||
if (verify != IMPORT_VERIFY_NO && !is_checksum_file(fn) && signature_style_from_filename(fn) < 0) {
|
||||
_cleanup_free_ char *checksum_url = NULL;
|
||||
const char *suffixed = NULL;
|
||||
|
||||
@@ -296,11 +307,17 @@ int pull_make_verification_jobs(
|
||||
checksum_job->on_not_found = pull_job_restart_with_sha256sum; /* if this fails, look for ubuntu-style checksum */
|
||||
}
|
||||
|
||||
if (verify == IMPORT_VERIFY_SIGNATURE && !is_signature_file(fn)) {
|
||||
if (verify == IMPORT_VERIFY_SIGNATURE && signature_style_from_filename(fn) < 0) {
|
||||
_cleanup_free_ char *signature_url = NULL;
|
||||
const char *suffixed = NULL;
|
||||
|
||||
/* Queue job for the SHA256SUMS.gpg file for the image. */
|
||||
r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
|
||||
if (fn)
|
||||
suffixed = strjoina(fn, ".sha256.asc"); /* Start with the suse-style checksum (if there's a base filename) */
|
||||
else
|
||||
suffixed = "SHA256SUMS.gpg";
|
||||
|
||||
/* Queue job for the signature file for the image. */
|
||||
r = import_url_change_last_component(url, suffixed, &signature_url);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -310,6 +327,7 @@ int pull_make_verification_jobs(
|
||||
|
||||
signature_job->on_finished = on_finished;
|
||||
signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
|
||||
signature_job->on_not_found = pull_job_restart_with_signature;
|
||||
}
|
||||
|
||||
*ret_checksum_job = TAKE_PTR(checksum_job);
|
||||
@@ -348,7 +366,7 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Cannot verify checksum, could not determine server-side file name.");
|
||||
|
||||
if (is_checksum_file(fn) || is_signature_file(fn)) /* We cannot verify checksum files or signature files with a checksum file */
|
||||
if (is_checksum_file(fn) || signature_style_from_filename(fn) >= 0) /* We cannot verify checksum files or signature files with a checksum file */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ELOOP),
|
||||
"Cannot verify checksum/signature files via themselves.");
|
||||
|
||||
@@ -536,7 +554,7 @@ int pull_verify(ImportVerify verify,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract filename from URL '%s': %m", main_job->url);
|
||||
|
||||
if (is_signature_file(fn))
|
||||
if (signature_style_from_filename(fn) >= 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ELOOP),
|
||||
"Main download is a signature file, can't verify it.");
|
||||
|
||||
@@ -572,17 +590,14 @@ int pull_verify(ImportVerify verify,
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", verify_job->url);
|
||||
|
||||
if (style == VERIFICATION_PER_DIRECTORY) {
|
||||
assert(signature_job);
|
||||
assert(signature_job->state == PULL_JOB_DONE);
|
||||
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.");
|
||||
if (!signature_job->payload || signature_job->payload_size <= 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Signature is empty, cannot verify.");
|
||||
|
||||
return verify_gpg(verify_job->payload, verify_job->payload_size, signature_job->payload, signature_job->payload_size);
|
||||
} else
|
||||
return verify_gpg(verify_job->payload, verify_job->payload_size, NULL, 0);
|
||||
return verify_gpg(verify_job->payload, verify_job->payload_size, signature_job->payload, signature_job->payload_size);
|
||||
}
|
||||
|
||||
int verification_style_from_url(const char *url, VerificationStyle *ret) {
|
||||
@@ -623,12 +638,14 @@ int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine verification style of URL '%s': %m", j->url);
|
||||
|
||||
if (style == VERIFICATION_PER_DIRECTORY) /* Nothing to do anymore */
|
||||
if (style == VERIFICATION_PER_DIRECTORY) { /* Nothing to do anymore */
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(style == VERIFICATION_PER_FILE); /* This must have been .sha256 style URL before */
|
||||
|
||||
log_debug("Got 404 for %s, now trying to get SHA256SUMS instead.", j->url);
|
||||
log_debug("Got 404 for '%s', now trying to get SHA256SUMS instead.", j->url);
|
||||
|
||||
r = import_url_change_last_component(j->url, "SHA256SUMS", ret);
|
||||
if (r < 0)
|
||||
@@ -637,6 +654,87 @@ int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int signature_style_from_url(const char *url, SignatureStyle *ret, char **ret_filename) {
|
||||
_cleanup_free_ char *last = NULL;
|
||||
SignatureStyle style;
|
||||
int r;
|
||||
|
||||
assert(url);
|
||||
assert(ret);
|
||||
assert(ret_filename);
|
||||
|
||||
/* Determines which kind of signature style is appropriate for this url */
|
||||
|
||||
r = import_url_last_component(url, &last);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
style = signature_style_from_filename(last);
|
||||
if (style < 0)
|
||||
return style;
|
||||
|
||||
*ret_filename = TAKE_PTR(last);
|
||||
*ret = style;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pull_job_restart_with_signature(PullJob *j, char **ret) {
|
||||
_cleanup_free_ char *last = NULL;
|
||||
SignatureStyle style;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
/* Generic implementation of a PullJobNotFound handler, that restarts the job requesting a different
|
||||
* signature file. After the initial file, additional *.sha256.gpg, SHA256SUMS.gpg and SHA256SUMS.asc
|
||||
* are tried in this order. */
|
||||
|
||||
r = signature_style_from_url(j->url, &style, &last);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine signature style of URL '%s': %m", j->url);
|
||||
|
||||
switch (style) {
|
||||
|
||||
case SIGNATURE_ASC_PER_DIRECTORY: /* Nothing to do anymore */
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
|
||||
case SIGNATURE_ASC_PER_FILE: { /* Try .sha256.gpg next */
|
||||
char *ext;
|
||||
|
||||
log_debug("Got 404 for '%s', now trying to get .sha256.gpg instead.", j->url);
|
||||
|
||||
ext = endswith(last, ".asc");
|
||||
assert(ext);
|
||||
strcpy(ext, ".gpg");
|
||||
|
||||
r = import_url_change_last_component(j->url, last, ret);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to replace .sha256.asc suffix: %m");
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNATURE_GPG_PER_FILE: /* Try SHA256SUMS.gpg next */
|
||||
log_debug("Got 404 for '%s', now trying to get SHA256SUMS.gpg instead.", j->url);
|
||||
r = import_url_change_last_component(j->url, "SHA256SUMS.gpg", ret);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to replace SHA256SUMS suffix: %m");
|
||||
break;
|
||||
|
||||
case SIGNATURE_GPG_PER_DIRECTORY:
|
||||
log_debug("Got 404 for '%s', now trying to get SHA256SUMS.asc instead.", j->url);
|
||||
r = import_url_change_last_component(j->url, "SHA256SUMS.asc", ret);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to replace SHA256SUMS.gpg suffix: %m");
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool pull_validate_local(const char *name, ImportFlags flags) {
|
||||
|
||||
if (FLAGS_SET(flags, IMPORT_DIRECT))
|
||||
@@ -659,5 +757,5 @@ int pull_url_needs_checksum(const char *url) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return !is_checksum_file(fn) && !is_signature_file(fn);
|
||||
return !is_checksum_file(fn) && signature_style_from_filename(fn) < 0;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signat
|
||||
int pull_verify(ImportVerify verify, const char *checksum, PullJob *main_job, PullJob *checksum_job, PullJob *signature_job, PullJob *settings_job, PullJob *roothash_job, PullJob *roothash_signature_job, PullJob *verity_job);
|
||||
|
||||
typedef enum VerificationStyle {
|
||||
VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline gpg signature */
|
||||
VERIFICATION_PER_FILE, /* SUSE-style ".sha256" files with detached gpg signature */
|
||||
VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detached SHA256SUM.gpg signatures */
|
||||
_VERIFICATION_STYLE_MAX,
|
||||
_VERIFICATION_STYLE_INVALID = -EINVAL,
|
||||
@@ -25,7 +25,19 @@ typedef enum VerificationStyle {
|
||||
|
||||
int verification_style_from_url(const char *url, VerificationStyle *style);
|
||||
|
||||
typedef enum SignatureStyle {
|
||||
SIGNATURE_GPG_PER_FILE, /* ".sha256" files with detached .gpg signature */
|
||||
SIGNATURE_ASC_PER_FILE, /* SUSE-style ".sha256" files with detached .asc signature */
|
||||
SIGNATURE_GPG_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detached SHA256SUM.gpg signatures */
|
||||
SIGNATURE_ASC_PER_DIRECTORY, /* SUSE-style SHA256SUM files with detached SHA256SUM.asc signatures */
|
||||
_SIGNATURE_STYLE_MAX,
|
||||
_SIGNATURE_STYLE_INVALID = -EINVAL,
|
||||
} SignatureStyle;
|
||||
|
||||
int signature_style_from_url(const char *url, SignatureStyle *style, char **ret_filename);
|
||||
|
||||
int pull_job_restart_with_sha256sum(PullJob *job, char **ret);
|
||||
int pull_job_restart_with_signature(PullJob *job, char **ret);
|
||||
|
||||
bool pull_validate_local(const char *name, ImportFlags flags);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user