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
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;
+
+ 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;
- return streq(fn, "SHA256SUMS.gpg") || endswith(fn, ".sha256");
+ if (endswith(fn, ".sha256.asc"))
+ return SIGNATURE_ASC_PER_FILE;
+
+ return _SIGNATURE_STYLE_INVALID;
}
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;
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;
+
+ 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 SHA256SUMS.gpg file for the image. */
- r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
+ /* Queue job for the signature file for the image. */
+ r = import_url_change_last_component(url, suffixed, &signature_url);
if (r < 0)
return r;
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);
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.");
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.");
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) {
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)
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))
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;
}
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,
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);