static CK_RV gkm_secret_object_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr) { GkmSecretObject *self = GKM_SECRET_OBJECT (base); switch (attr->type) { case CKA_MODIFIABLE: return gkm_attribute_set_bool (attr, TRUE); case CKA_ID: return gkm_attribute_set_string (attr, gkm_secret_object_get_identifier (self)); case CKA_LABEL: return gkm_attribute_set_string (attr, gkm_secret_object_get_label (self)); case CKA_G_LOCKED: return gkm_attribute_set_bool (attr, gkm_secret_object_is_locked (self, session)); case CKA_G_CREATED: return gkm_attribute_set_time (attr, gkm_secret_object_get_created (self)); case CKA_G_MODIFIED: return gkm_attribute_set_time (attr, gkm_secret_object_get_modified (self)); } return GKM_OBJECT_CLASS (gkm_secret_object_parent_class)->get_attribute (base, session, attr); }
static gboolean generate_encrypted_data (EggBuffer *buffer, GkmSecretCollection *collection, GkmSecretData *data) { GkmSecretObject *obj; GkmSecretItem *item; GList *items, *l; GHashTable *attributes; const gchar *label; GkmSecret *secret; GList *acl; int i; g_assert (buffer); g_assert (GKM_IS_SECRET_COLLECTION (collection)); g_assert (GKM_IS_SECRET_DATA (data)); /* Make sure we're using non-pageable memory */ egg_buffer_set_allocator (buffer, egg_secure_realloc); items = gkm_secret_collection_get_items (collection); for (l = items; l && !egg_buffer_has_error(buffer); l = g_list_next (l)) { item = GKM_SECRET_ITEM (l->data); obj = GKM_SECRET_OBJECT (l->data); label = gkm_secret_object_get_label (obj); buffer_add_utf8_string (buffer, label); secret = gkm_secret_data_get_secret (data, gkm_secret_object_get_identifier (obj)); buffer_add_secret (buffer, secret); if (!buffer_add_time (buffer, gkm_secret_object_get_created (obj)) || !buffer_add_time (buffer, gkm_secret_object_get_modified (obj))) break; /* reserved: */ if (!buffer_add_utf8_string (buffer, NULL)) break; for (i = 0; i < 4; i++) egg_buffer_add_uint32 (buffer, 0); attributes = gkm_secret_item_get_fields (item); if (!buffer_add_attributes (buffer, attributes, FALSE)) break; acl = g_object_get_data (G_OBJECT (item), "compat-acl"); if (!generate_acl_data (buffer, acl)) break; } g_list_free (items); /* Iteration completed prematurely == fail */ return (l == NULL); }
static void gkm_secret_object_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { GkmSecretObject *self = GKM_SECRET_OBJECT (obj); switch (prop_id) { case PROP_LABEL: g_value_set_string (value, gkm_secret_object_get_label (self)); break; case PROP_IDENTIFIER: g_value_set_string (value, gkm_secret_object_get_identifier (self)); break; case PROP_CREATED: g_value_set_long (value, gkm_secret_object_get_created (self)); break; case PROP_MODIFIED: g_value_set_long (value, gkm_secret_object_get_modified (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; } }
GkmDataResult gkm_secret_binary_write (GkmSecretCollection *collection, GkmSecretData *sdata, gpointer *data, gsize *n_data) { GkmSecretObject *obj; EggBuffer to_encrypt; GkmSecret *master; guchar digest[16]; EggBuffer buffer; gint hash_iterations; gint lock_timeout; guchar salt[8]; guint flags = 0; int i; g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (collection), GKM_DATA_FAILURE); g_return_val_if_fail (GKM_IS_SECRET_DATA (sdata), GKM_DATA_LOCKED); g_return_val_if_fail (data && n_data, GKM_DATA_FAILURE); g_return_val_if_fail (gcry_md_get_algo_dlen (GCRY_MD_MD5) == sizeof (digest), GKM_DATA_FAILURE); obj = GKM_SECRET_OBJECT (collection); egg_buffer_init_full (&buffer, 256, g_realloc); /* Prepare the keyring for encryption */ hash_iterations = g_random_int_range (1000, 4096); gcry_create_nonce (salt, sizeof (salt)); egg_buffer_append (&buffer, (guchar*)KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN); egg_buffer_add_byte (&buffer, 0); /* Major version */ egg_buffer_add_byte (&buffer, 0); /* Minor version */ egg_buffer_add_byte (&buffer, 0); /* crypto (0 == AES) */ egg_buffer_add_byte (&buffer, 0); /* hash (0 == MD5) */ buffer_add_utf8_string (&buffer, gkm_secret_object_get_label (obj)); buffer_add_time (&buffer, gkm_secret_object_get_modified (obj)); buffer_add_time (&buffer, gkm_secret_object_get_created (obj)); lock_timeout = gkm_secret_collection_get_lock_idle (collection); if (lock_timeout) { flags |= LOCK_ON_IDLE_FLAG; } else { lock_timeout = gkm_secret_collection_get_lock_after (collection); if (lock_timeout) flags |= LOCK_AFTER_FLAG; } egg_buffer_add_uint32 (&buffer, flags); egg_buffer_add_uint32 (&buffer, lock_timeout); egg_buffer_add_uint32 (&buffer, hash_iterations); egg_buffer_append (&buffer, salt, 8); /* Reserved: */ for (i = 0; i < 4; i++) egg_buffer_add_uint32 (&buffer, 0); /* Hashed items: */ generate_hashed_items (collection, &buffer); /* Encrypted data. Use non-pageable memory */ egg_buffer_init_full (&to_encrypt, 4096, egg_secure_realloc); egg_buffer_append (&to_encrypt, (guchar*)digest, 16); /* Space for hash */ if (!generate_encrypted_data (&to_encrypt, collection, sdata)) { egg_buffer_uninit (&to_encrypt); egg_buffer_uninit (&buffer); return GKM_DATA_FAILURE; } /* Pad with zeros to multiple of 16 bytes */ while (to_encrypt.len % 16 != 0) egg_buffer_add_byte (&to_encrypt, 0); gcry_md_hash_buffer (GCRY_MD_MD5, (void*)digest, (guchar*)to_encrypt.buf + 16, to_encrypt.len - 16); memcpy (to_encrypt.buf, digest, 16); /* If no master password is set, we shouldn't be writing binary... */ master = gkm_secret_data_get_master (sdata); g_return_val_if_fail (master, GKM_DATA_FAILURE); if (!encrypt_buffer (&to_encrypt, master, salt, hash_iterations)) { egg_buffer_uninit (&buffer); egg_buffer_uninit (&to_encrypt); return GKM_DATA_FAILURE; } if (egg_buffer_has_error (&to_encrypt) || egg_buffer_has_error (&buffer)) { egg_buffer_uninit (&buffer); egg_buffer_uninit (&to_encrypt); return GKM_DATA_FAILURE; } egg_buffer_add_uint32 (&buffer, to_encrypt.len); egg_buffer_append (&buffer, to_encrypt.buf, to_encrypt.len); egg_buffer_uninit (&to_encrypt); *data = egg_buffer_uninit_steal (&buffer, n_data); return GKM_DATA_SUCCESS; }