lib/deltas: Add inline signature for static-delta superblock
While the commits contained in the single static-delta file are signed so
we can check them and operate on trusted data, the superblock isn't signed
in any way, so it end up operating on untrusted data to:
1. actually find where the trusted data is, and
2. check whether the update is fit for the current device by looking at
the collection id stored in the metadata
This commit generates signatures of all static data, and concatenate them
to the existing static delta format, i.e. as a GVariant layout `a{sv}ay`
where
- a{sv}: signatures
- ay: existing delta variant
Signed-off-by: Frédéric Danis <frederic.danis@collabora.com>
This commit is contained in:
parent
9c040c1a73
commit
46667567c5
|
|
@ -36,6 +36,8 @@
|
|||
#include "libglnx.h"
|
||||
#include "ostree-varint.h"
|
||||
#include "bsdiff/bsdiff.h"
|
||||
#include "ostree-autocleanups.h"
|
||||
#include "ostree-sign.h"
|
||||
|
||||
#define CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT (30)
|
||||
|
||||
|
|
@ -1335,6 +1337,8 @@ get_fallback_headers (OstreeRepo *self,
|
|||
* - verbose: b: Print diagnostic messages. Default FALSE.
|
||||
* - endianness: b: Deltas use host byte order by default; this option allows choosing (G_BIG_ENDIAN or G_LITTLE_ENDIAN)
|
||||
* - filename: ay: Save delta superblock to this filename, and parts in the same directory. Default saves to repository.
|
||||
* - sign-name: ay: Signature type to use.
|
||||
* - sign-key-ids: as: Array of keys used to sign delta superblock.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_static_delta_generate (OstreeRepo *self,
|
||||
|
|
@ -1368,6 +1372,8 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
|||
g_autoptr(GPtrArray) builder_fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
|
||||
g_auto(GLnxTmpfile) descriptor_tmpf = { 0, };
|
||||
g_autoptr(OtVariantBuilder) descriptor_builder = NULL;
|
||||
const char *opt_sign_name;
|
||||
const char **opt_key_ids;
|
||||
|
||||
if (!g_variant_lookup (params, "min-fallback-size", "u", &min_fallback_size))
|
||||
min_fallback_size = 4;
|
||||
|
|
@ -1407,6 +1413,12 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
|||
if (!g_variant_lookup (params, "filename", "^&ay", &opt_filename))
|
||||
opt_filename = NULL;
|
||||
|
||||
if (!g_variant_lookup (params, "sign-name", "^&ay", &opt_sign_name))
|
||||
opt_sign_name = NULL;
|
||||
|
||||
if (!g_variant_lookup (params, "sign-key-ids", "^a&s", &opt_key_ids))
|
||||
opt_key_ids = NULL;
|
||||
|
||||
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, to,
|
||||
&to_commit, error))
|
||||
return FALSE;
|
||||
|
|
@ -1442,7 +1454,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
|||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC,
|
||||
if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_RDWR | O_CLOEXEC,
|
||||
&descriptor_tmpf, error))
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -1586,12 +1598,85 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
|
|||
g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff);
|
||||
}
|
||||
|
||||
if (fchmod (descriptor_tmpf.fd, 0644) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fchmod");
|
||||
if (opt_sign_name != NULL && opt_key_ids != NULL)
|
||||
{
|
||||
g_autoptr(GBytes) tmpdata = NULL;
|
||||
g_autoptr(OstreeSign) sign = NULL;
|
||||
const gchar *signature_key = NULL;
|
||||
g_autoptr(GVariantBuilder) signature_builder = NULL;
|
||||
g_auto(GLnxTmpfile) descriptor_sign_tmpf = { 0, };
|
||||
g_autoptr(OtVariantBuilder) descriptor_sign_builder = NULL;
|
||||
|
||||
if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
|
||||
descriptor_dfd, descriptor_name, error))
|
||||
return FALSE;
|
||||
lseek (descriptor_tmpf.fd, 0, SEEK_SET);
|
||||
tmpdata = glnx_fd_readall_bytes (descriptor_tmpf.fd, cancellable, error);
|
||||
if (!tmpdata)
|
||||
return FALSE;
|
||||
|
||||
sign = ostree_sign_get_by_name (opt_sign_name, error);
|
||||
if (sign == NULL)
|
||||
return FALSE;
|
||||
|
||||
signature_key = ostree_sign_metadata_key (sign);
|
||||
const gchar *signature_format = ostree_sign_metadata_format (sign);
|
||||
|
||||
signature_builder = g_variant_builder_new (G_VARIANT_TYPE (signature_format));
|
||||
|
||||
for (const char **iter = opt_key_ids; iter && *iter; iter++)
|
||||
{
|
||||
const char *keyid = *iter;
|
||||
g_autoptr(GVariant) secret_key = NULL;
|
||||
g_autoptr(GBytes) signature_bytes = NULL;
|
||||
|
||||
secret_key = g_variant_new_string (keyid);
|
||||
if (!ostree_sign_set_sk (sign, secret_key, error))
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_sign_data (sign, tmpdata, &signature_bytes,
|
||||
NULL, error))
|
||||
return FALSE;
|
||||
|
||||
g_variant_builder_add (signature_builder, "@ay", ot_gvariant_new_ay_bytes (signature_bytes));
|
||||
}
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC,
|
||||
&descriptor_sign_tmpf, error))
|
||||
return FALSE;
|
||||
|
||||
descriptor_sign_builder = ot_variant_builder_new (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SIGNED_FORMAT),
|
||||
descriptor_sign_tmpf.fd);
|
||||
|
||||
if (!ot_variant_builder_add (descriptor_sign_builder, error, "t",
|
||||
GUINT64_TO_BE (OSTREE_STATIC_DELTA_SIGNED_MAGIC)))
|
||||
return FALSE;
|
||||
if (!ot_variant_builder_add (descriptor_sign_builder, error, "@ay", ot_gvariant_new_ay_bytes (tmpdata)))
|
||||
return FALSE;
|
||||
if (!ot_variant_builder_open (descriptor_sign_builder, G_VARIANT_TYPE ("a{sv}"), error))
|
||||
return FALSE;
|
||||
if (!ot_variant_builder_add (descriptor_sign_builder, error, "{sv}",
|
||||
signature_key, g_variant_builder_end(signature_builder)))
|
||||
return FALSE;
|
||||
if (!ot_variant_builder_close (descriptor_sign_builder, error))
|
||||
return FALSE;
|
||||
|
||||
if (!ot_variant_builder_end (descriptor_sign_builder, error))
|
||||
return FALSE;
|
||||
|
||||
if (fchmod (descriptor_sign_tmpf.fd, 0644) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fchmod");
|
||||
|
||||
if (!glnx_link_tmpfile_at (&descriptor_sign_tmpf, GLNX_LINK_TMPFILE_REPLACE,
|
||||
descriptor_dfd, descriptor_name, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fchmod (descriptor_tmpf.fd, 0644) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fchmod");
|
||||
|
||||
if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
|
||||
descriptor_dfd, descriptor_name, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,25 @@ G_BEGIN_DECLS
|
|||
*/
|
||||
#define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")"
|
||||
|
||||
/**
|
||||
* OSTREE_STATIC_DELTA_SIGNED_FORMAT
|
||||
*
|
||||
* magic: t magic number, 8 bytes for alignment
|
||||
* superblock: ay delta supeblock variant
|
||||
* signatures: a{sv}
|
||||
*
|
||||
* The signed static delta starts with the 'OSTSGNDT' magic number followed by
|
||||
* the array of bytes containing the superblock used for the signature.
|
||||
*
|
||||
* Then, the signatures array contains the signatures of the superblock. A
|
||||
* signature has the following form:
|
||||
* type: signature key
|
||||
* signature: variant depending on type used
|
||||
*/
|
||||
#define OSTREE_STATIC_DELTA_SIGNED_FORMAT "(taya{sv})"
|
||||
|
||||
#define OSTREE_STATIC_DELTA_SIGNED_MAGIC 0x4F535453474E4454 /* OSTSGNDT */
|
||||
|
||||
typedef enum {
|
||||
OSTREE_STATIC_DELTA_OPEN_FLAGS_NONE = 0,
|
||||
OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM = (1 << 0),
|
||||
|
|
|
|||
Loading…
Reference in New Issue