Example #1
0
static CK_RV
attribute_set_check_value (GkmAesKey *self, CK_ATTRIBUTE *attr)
{
	gcry_cipher_hd_t cih;
	gcry_error_t gcry;
	gpointer data;
	CK_RV rv;

	g_assert (GKM_IS_AES_KEY (self));
	g_assert (attr);

	/* Just asking for the length */
	if (!attr->pValue) {
		attr->ulValueLen = 3;
		return CKR_OK;
	}

	cih = gkm_aes_key_get_cipher (self, GCRY_CIPHER_MODE_ECB);
	if (cih == NULL)
		return CKR_FUNCTION_FAILED;

	/* Buffer of zeros */
	data = g_malloc0 (self->n_value);

	/* Encrypt it */
	gcry = gcry_cipher_encrypt (cih, data, self->n_value, NULL, 0);
	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);

	/* Use the first three bytes */
	g_assert (self->n_value > 3);
	rv = gkm_attribute_set_data (attr, data, 3);

	gcry_cipher_close (cih);
	g_free (data);

	return rv;
}
CK_RV
gkm_aes_mechanism_wrap (GkmSession *session, CK_MECHANISM_PTR mech,
                        GkmObject *wrapper, GkmObject *wrapped,
                        CK_BYTE_PTR output, CK_ULONG_PTR n_output)
{
	gcry_cipher_hd_t cih;
	gcry_error_t gcry;
	GkmAesKey *key;
	gpointer value, padded;
	gsize n_value, n_padded;
	gsize block, pos;
	gboolean ret;
	CK_RV rv;

	g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR);
	g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
	g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
	g_return_val_if_fail (GKM_IS_OBJECT (wrapped), CKR_GENERAL_ERROR);
	g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);

	if (!GKM_IS_AES_KEY (wrapper))
		return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
	key = GKM_AES_KEY (wrapper);

	block = gkm_aes_key_get_block_size (key);
	g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);

	/* They just want the length */
	if (!output) {
		rv = retrieve_length (session, wrapped, &n_value);
		if (rv != CKR_OK)
			return rv;
		if (!egg_padding_pkcs7_pad (NULL, block, NULL, n_value, NULL, &n_padded))
			return CKR_KEY_SIZE_RANGE;
		*n_output = n_padded;
		return CKR_OK;
	}

	cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
	if (cih == NULL)
		return CKR_FUNCTION_FAILED;

	if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
		gcry_cipher_close (cih);
		return CKR_MECHANISM_PARAM_INVALID;
	}

	rv = retrieve_value (session, wrapped, &value, &n_value);
	if (rv != CKR_OK) {
		gcry_cipher_close (cih);
		return rv;
	}

	ret = egg_padding_pkcs7_pad (egg_secure_realloc, block, value, n_value, &padded, &n_padded);
	egg_secure_free (value);

	if (ret == FALSE) {
		gcry_cipher_close (cih);
		return CKR_KEY_SIZE_RANGE;
	}

	/* In place encryption */
	for (pos = 0; pos < n_padded; pos += block) {
		gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, block, NULL, 0);
		g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
	}

	gcry_cipher_close (cih);

	rv = gkm_util_return_data (output, n_output, padded, n_padded);
	egg_secure_free (padded);
	return rv;
}
CK_RV
gkm_aes_mechanism_unwrap (GkmSession *session, CK_MECHANISM_PTR mech,
                          GkmObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input,
                          CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
                          GkmObject **unwrapped)
{
	gcry_cipher_hd_t cih;
	gcry_error_t gcry;
	CK_ATTRIBUTE attr;
	GArray *array;
	GkmAesKey *key;
	gpointer padded, value;
	gsize n_padded, n_value;
	GkmTransaction *transaction;
	gsize block, pos;
	gboolean ret;

	g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR);
	g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
	g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
	g_return_val_if_fail (GKM_IS_OBJECT (wrapper), CKR_GENERAL_ERROR);

	if (!GKM_IS_AES_KEY (wrapper))
		return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
	key = GKM_AES_KEY (wrapper);

	block = gkm_aes_key_get_block_size (key);
	g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);

	if (n_input == 0 || n_input % block != 0)
		return CKR_WRAPPED_KEY_LEN_RANGE;

	cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
	if (cih == NULL)
		return CKR_FUNCTION_FAILED;

	if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
		gcry_cipher_close (cih);
		return CKR_MECHANISM_PARAM_INVALID;
	}

	padded = egg_secure_alloc (n_input);
	memcpy (padded, input, n_input);
	n_padded = n_input;

	/* In place decryption */
	for (pos = 0; pos < n_padded; pos += block) {
		gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, block, NULL, 0);
		g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
	}

	gcry_cipher_close (cih);

	/* Unpad the resulting value */
	ret = egg_padding_pkcs7_unpad (egg_secure_realloc, block, padded, n_padded, &value, &n_value);
	egg_secure_free (padded);

	/* TODO: This is dubious, there doesn't seem to be an rv for 'bad decrypt' */
	if (ret == FALSE)
		return CKR_WRAPPED_KEY_INVALID;

	/* Now setup the attributes with our new value */
	array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));

	/* Prepend the value */
	attr.type = CKA_VALUE;
	attr.pValue = value;
	attr.ulValueLen = n_value;
	g_array_append_val (array, attr);

	/* Add the remainder of the attributes */
	g_array_append_vals (array, attrs, n_attrs);

	transaction = gkm_transaction_new ();

	/* Now create an object with these attributes */
	*unwrapped = gkm_session_create_object_for_attributes (session, transaction,
	                                                       (CK_ATTRIBUTE_PTR)array->data, array->len);

	egg_secure_free (value);
	g_array_free (array, TRUE);

	return gkm_transaction_complete_and_unref (transaction);
}