예제 #1
0
static void
test_asn1_bit_string (Test *test, gconstpointer unused)
{
	GNode *asn;
	GBytes *data;
	gboolean ret;
	GBytes *source, *target;
	gsize target_bits, source_bits;

	asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
	g_assert ("asn test structure is null" && asn != NULL);

	/* Create a string */
	source = g_bytes_new (TEST_STRING, strlen(TEST_STRING));
	g_return_if_fail (source);
	source_bits = g_bytes_get_size(source)*8;

	/* Write the string out */
	ret = gkm_data_asn1_write_bit_string (egg_asn1x_node (asn, "data", NULL),
                                              source, source_bits);
	g_assert ("couldn't write string to asn1" && ret);

	/* Now encode the whole caboodle */
	data = egg_asn1x_encode (asn, NULL);
	g_assert ("encoding asn1 didn't work" && data != NULL);

	egg_asn1x_destroy (asn);

	/* Now decode it all nicely */
	asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestBitString", data);
	g_assert (asn != NULL);

	ret = gkm_data_asn1_read_bit_string (egg_asn1x_node (asn, "data", NULL),
                                             &target, &target_bits);
	egg_asn1x_destroy (asn);
	g_assert ("couldn't read bit string from asn1" && ret);
	g_assert ("bit string returned is null" && target != NULL);
	g_assert ("Source and target length differ" && target_bits == source_bits);
	g_assert ("Bit strings differ" && g_bytes_equal (source, target));

	g_bytes_unref (data);
	g_bytes_unref (source);
	g_bytes_unref (target);
}
예제 #2
0
/**
 * CacheEntryPasswordValidate:
 * @self: Instance with salt/hash to check @password against.
 * @password: Password to check.
 * @error: (out)(allow-none): Error return location or #NULL.
 *
 * Returns: #TRUE if the password matches, or #FALSE if there was an error and
 * @error was set. Not matching is considered an error.
 */
gboolean CacheEntryPasswordValidate(CacheEntry *self, const gchar *password,
                                    GError **error) {
  GBytes *hash = NULL;
  GDateTime *now = NULL;
  gboolean result = FALSE;

  if (!self->salt || !self->hash) {
    g_set_error(error, CACHE_ENTRY_ERROR, CACHE_ENTRY_EMPTY_ERROR,
                "No cached password is available");
    return FALSE;
  }

  g_assert(self->salt);
  g_assert(password);
  g_assert(strlen(password) > 0);
  hash = CacheUtilHashPassword(self->algorithm, self->salt, password);
  if (!hash) {
    g_set_error(error, CACHE_ENTRY_ERROR, CACHE_ENTRY_CORRUPT_ERROR,
                "Unknow hash algorithm selected");
    return FALSE;
  }

  now = g_date_time_new_now_utc();
  CacheEntryUpdateTime(&self->last_tried, now);

  if (g_bytes_equal(hash, self->hash)) {
    CacheEntryUpdateTime(&self->last_used, now);
    self->tries = 0;
    result = TRUE;
  } else {
    self->tries++;
    g_set_error(error, CACHE_ENTRY_ERROR, CACHE_ENTRY_PASSWORD_ERROR,
                "Password doesn't match cached value");
  }

  g_bytes_unref(hash);
  g_date_time_unref(now);
  return result;
}
예제 #3
0
파일: dfu-patch.c 프로젝트: vathpela/fwupd
/**
 * dfu_patch_apply:
 * @self: a #DfuPatch
 * @blob: a #GBytes, typically the old firmware image
 * @flags: a #DfuPatchApplyFlags, e.g. %DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM
 * @error: a #GError, or %NULL
 *
 * Apply the currently loaded patch to a new firmware image.
 *
 * Return value: A #GBytes, typically saved as the new firmware file
 **/
GBytes *
dfu_patch_apply (DfuPatch *self, GBytes *blob, DfuPatchApplyFlags flags, GError **error)
{
	DfuPatchPrivate *priv = GET_PRIVATE (self);
	const guint8 *data_old;
	gsize sz;
	gsize sz_max = 0;
	g_autofree guint8 *data_new = NULL;
	g_autoptr(GBytes) blob_checksum_new = NULL;
	g_autoptr(GBytes) blob_checksum = NULL;
	g_autoptr(GBytes) blob_new = NULL;

	/* not loaded yet */
	if (priv->chunks->len == 0) {
		g_set_error_literal (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "no patches loaded");
		return NULL;
	}

	/* get the hash of the old firmware file */
	blob_checksum = dfu_patch_calculate_checksum (blob);
	if ((flags & DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM) == 0 &&
	    !g_bytes_equal (blob_checksum, priv->checksum_old)) {
		g_autofree gchar *actual = _g_bytes_to_string (blob_checksum);
		g_autofree gchar *expect = _g_bytes_to_string (priv->checksum_old);
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INVALID_FILE,
			     "checksum for source did not match, expected %s, got %s",
			     expect, actual);
		return NULL;
	}

	/* get the size of the new image size */
	for (guint i = 0; i < priv->chunks->len; i++) {
		DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i);
		gsize chunk_sz = g_bytes_get_size (chunk->blob);
		if (chunk->off + chunk_sz > sz_max)
			sz_max = chunk->off + chunk_sz;
	}

	/* first, copy the data buffer */
	data_old = g_bytes_get_data (blob, &sz);
	if (sz_max < sz) {
		g_set_error_literal (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "binary patch cannot truncate binary");
		return NULL;
	}
	if (sz == sz_max) {
		g_debug ("binary staying same size: %" G_GSIZE_FORMAT, sz);
	} else {
		g_debug ("binary growing from: %" G_GSIZE_FORMAT
			 " to %" G_GSIZE_FORMAT, sz, sz_max);
	}

	data_new = g_malloc0 (sz_max);
	memcpy (data_new, data_old, MIN (sz, sz_max));
	for (guint i = 0; i < priv->chunks->len; i++) {
		DfuPatchChunk *chunk = g_ptr_array_index (priv->chunks, i);
		const guint8 *chunk_data;
		gsize chunk_sz;

		/* bigger than the total size */
		chunk_data = g_bytes_get_data (chunk->blob, &chunk_sz);
		if (chunk->off + chunk_sz > sz_max) {
			g_set_error (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "cannot apply chunk as larger than max size");
			return NULL;
		}

		/* apply one chunk */
		g_debug ("applying chunk %u/%u @0x%04x (length %" G_GSIZE_FORMAT ")",
			 i + 1, priv->chunks->len, chunk->off, chunk_sz);
		memcpy (data_new + chunk->off, chunk_data, chunk_sz);
	}

	/* check we got the desired hash */
	blob_new = g_bytes_new (data_new, sz_max);
	blob_checksum_new = dfu_patch_calculate_checksum (blob_new);
	if ((flags & DFU_PATCH_APPLY_FLAG_IGNORE_CHECKSUM) == 0 &&
	    !g_bytes_equal (blob_checksum_new, priv->checksum_new)) {
		g_autofree gchar *actual = _g_bytes_to_string (blob_checksum_new);
		g_autofree gchar *expect = _g_bytes_to_string (priv->checksum_new);
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_INVALID_FILE,
			     "checksum for result did not match, expected %s, got %s",
			     expect, actual);
		return NULL;
	}

	/* success */
	return g_steal_pointer (&blob_new);
}
예제 #4
0
파일: dfu-patch.c 프로젝트: vathpela/fwupd
/**
 * dfu_patch_create:
 * @self: a #DfuPatch
 * @blob1: a #GBytes, typically the old firmware image
 * @blob2: a #GBytes, typically the new firmware image
 * @error: a #GError, or %NULL
 *
 * Creates a patch from two blobs of memory.
 *
 * The blobs should ideally be the same size. If @blob2 is has grown in size
 * the binary diff will still work but the algorithm will probably not perform
 * well unless the majority of data has just been appended.
 *
 * As an additional constrainst, @blob2 cannot be smaller than @blob1, i.e.
 * the firmware cannot be truncated by this format.
 *
 * Return value: %TRUE on success
 **/
gboolean
dfu_patch_create (DfuPatch *self, GBytes *blob1, GBytes *blob2, GError **error)
{
	DfuPatchPrivate *priv = GET_PRIVATE (self);
	DfuPatchCreateHelper helper;
	const guint8 *data1;
	const guint8 *data2;
	gsize sz1 = 0;
	gsize sz2 = 0;
	guint32 same_sz = 0;

	g_return_val_if_fail (DFU_IS_PATCH (self), FALSE);
	g_return_val_if_fail (blob1 != NULL, FALSE);
	g_return_val_if_fail (blob2 != NULL, FALSE);

	/* are the blobs the same */
	if (g_bytes_equal (blob1, blob2)) {
		g_set_error_literal (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "old and new binaries are the same");
		return FALSE;
	}

	/* cannot reuse object */
	if (priv->chunks->len > 0) {
		g_set_error_literal (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "patch has already been loaded");
		return FALSE;
	}

	/* get the hash of the old firmware file */
	priv->checksum_old = dfu_patch_calculate_checksum (blob1);
	priv->checksum_new = dfu_patch_calculate_checksum (blob2);

	/* get the raw data, and ensure they are the same size */
	data1 = g_bytes_get_data (blob1, &sz1);
	data2 = g_bytes_get_data (blob2, &sz2);
	if (sz1 > sz2) {
		g_set_error (error,
			     FWUPD_ERROR,
			     FWUPD_ERROR_NOT_SUPPORTED,
			     "firmware binary cannot go down, got "
			     "%" G_GSIZE_FORMAT " and %" G_GSIZE_FORMAT,
			     sz1, sz2);
		return FALSE;
	}
	if (sz1 == sz2) {
		g_debug ("binary staying same size: %" G_GSIZE_FORMAT, sz1);
	} else {
		g_debug ("binary growing from: %" G_GSIZE_FORMAT
			 " to %" G_GSIZE_FORMAT, sz1, sz2);
	}

	/* start the dumb comparison algorithm */
	helper.diff_start = 0;
	helper.diff_end = 0xffff;
	helper.blob = blob2;
	for (gsize i = 0; i < sz1 || i < sz2; i++) {
		if (i < sz1 && i < sz2 &&
		    data1[i] == data2[i]) {
			/* if we got enough the same, dump what is pending */
			if (++same_sz > sizeof(DfuPatchChunkHeader) * 2)
				dfu_patch_flush (self, &helper);
			continue;
		}
		if (helper.diff_end == 0xffff)
			helper.diff_start = (guint32) i;
		helper.diff_end = (guint32) i;
		same_sz = 0;
	}
	dfu_patch_flush (self, &helper);
	return TRUE;
}