/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * Copyright (c) 2017-2020, Linaro Limited
 */

#ifndef PKCS11_TA_PKCS11_ATTRIBUTES_H
#define PKCS11_TA_PKCS11_ATTRIBUTES_H

#include <inttypes.h>
#include <pkcs11_ta.h>

#include "serializer.h"

/* The key check value (KCV) attribute for objects is 3 bytes */
#define PKCS11_CKA_CHECK_VALUE_SIZE	U(3)

struct obj_attrs;
struct pkcs11_object;
struct pkcs11_session;

/*
 * PKCS#11 directives on object attributes.
 * Those with a '*' are optional, other must be defined, either by caller
 * or by some known default value.
 *
 * [all] objects:	class
 *
 * [stored] objects:	persistent, need_authen, modifiable, copyable,
 *			destroyable, label*.
 *
 * [data] objects:	[all], [stored], application_id*, object_id*, value.
 *
 * [key] objects:	[all], [stored], type, id*, start_date/end_date*,
 *			derive, local, allowed_mechanisms*.
 *
 * [symm-key]:		[key], sensitive, encrypt, decrypt, sign, verify, wrap,
 *			unwrap, extractable, wrap_with_trusted, trusted,
 *			wrap_template, unwrap_template, derive_template.
 */

/*
 * Utils to check compliance of attributes at various processing steps.
 * Any processing operation is exclusively one of the following.
 *
 * Case 1: Create a secret from some local random value (C_CreateKey & friends)
 * - client provides an attributes list template, PKCS11 TA completes with
 *   default attribute values. Object is created if attributes are
 *   consistent and comply token/session state.
 * - PKCS11 sequence:
 *   - check/set token/session state
 *   - create an attribute list from client template and default values.
 *   - check new secret attributes complies requested mechanism.
 *   - check new secret attributes complies token/session state.
 *   - Generate the value for the secret.
 *   - Set some runtime attributes in the new secret.
 *   - Register the new secret and return a handle for it.
 *
 * Case 2: Create a secret from a client clear data (C_CreateObject)
 * - client provides an attributes list template, PKCS11 TA completes with
 *   default attribute values. Object is created if attributes are
 *   consistent and comply token/session state.
 *   - check/set token/session state
 *   - create an attribute list from client template and default values.
 *   - check new secret attributes complies requested mechanism (raw-import).
 *   - check new secret attributes complies token/session state.
 *   - Set some runtime attributes in the new secret.
 *   - Register the new secret and return a handle for it.

 * Case 3: Use a secret for data processing
 * - client provides a mechanism ID and the secret handle.
 * - PKCS11 checks mechanism and secret comply, if mechanism and token/session
 *   state comply and last if secret and token/session state comply.
 *   - check/set token/session state
 *   - check secret's parent attributes complies requested processing.
 *   - check secret's parent attributes complies token/session state.
 *   - check new secret attributes complies secret's parent attributes.
 *   - check new secret attributes complies requested mechanism.
 *   - check new secret attributes complies token/session state.
 *
 * Case 4: Create a secret from a client template and a secret's parent
 * (i.e derive a symmetric key)
 * - client args: new-key template, mechanism ID, parent-key handle.
 * - PKCS11 create a new-key attribute list based on template + default values +
 *   inheritance from the parent key attributes.
 * - PKCS11 checks:
 *   - token/session state
 *   - parent-key vs mechanism
 *   - parent-key vs token/session state
 *   - parent-key vs new-key
 *   - new-key vs mechanism
 *   - new-key vs token/session state
 * - then do processing
 * - then finalize object creation
 */

enum processing_func {
	PKCS11_FUNCTION_DIGEST,
	PKCS11_FUNCTION_GENERATE,
	PKCS11_FUNCTION_GENERATE_PAIR,
	PKCS11_FUNCTION_DERIVE,
	PKCS11_FUNCTION_WRAP,
	PKCS11_FUNCTION_UNWRAP,
	PKCS11_FUNCTION_ENCRYPT,
	PKCS11_FUNCTION_DECRYPT,
	PKCS11_FUNCTION_SIGN,
	PKCS11_FUNCTION_VERIFY,
	PKCS11_FUNCTION_SIGN_RECOVER,
	PKCS11_FUNCTION_VERIFY_RECOVER,
	PKCS11_FUNCTION_IMPORT,
	PKCS11_FUNCTION_COPY,
	PKCS11_FUNCTION_MODIFY,
	PKCS11_FUNCTION_DESTROY,
	PKCS11_FUNCTION_UNKNOWN,
};

enum processing_step {
	PKCS11_FUNC_STEP_INIT,
	PKCS11_FUNC_STEP_ONESHOT,
	PKCS11_FUNC_STEP_UPDATE,
	PKCS11_FUNC_STEP_UPDATE_KEY,
	PKCS11_FUNC_STEP_FINAL,
};

/* Create an attribute list for a new object */
enum pkcs11_rc
create_attributes_from_template(struct obj_attrs **out, void *template,
				size_t template_size, struct obj_attrs *parent,
				enum processing_func func,
				enum pkcs11_mechanism_id proc_mecha,
				enum pkcs11_class_id template_class);

/*
 * The various checks to be performed before a processing:
 * - create a new object in the current token state
 * - use a parent object in the processing
 * - use a mechanism with provided configuration
 */
enum pkcs11_rc check_created_attrs_against_token(struct pkcs11_session *session,
						 struct obj_attrs *head);

enum pkcs11_rc check_created_attrs_against_processing(uint32_t proc_id,
						      struct obj_attrs *head);

enum pkcs11_rc check_created_attrs(struct obj_attrs *key1,
				   struct obj_attrs *key2);

/*
 * Check the attributes of the parent secret (key) used in the processing
 * do match the target processing.
 *
 * @proc_id - PKCS11_CKM_xxx
 * @func - identifier of the processing function operated with @proc_id.
 * @head - head of the attributes of parent object.
 */
enum pkcs11_rc
check_parent_attrs_against_processing(enum pkcs11_mechanism_id proc_id,
				      enum processing_func func,
				      struct obj_attrs *head);

enum pkcs11_rc check_access_attrs_against_token(struct pkcs11_session *session,
						struct obj_attrs *head);

enum pkcs11_rc
check_mechanism_against_processing(struct pkcs11_session *session,
				   enum pkcs11_mechanism_id mechanism_type,
				   enum processing_func function,
				   enum processing_step step);

static inline bool attribute_is_hidden(struct pkcs11_attribute_head *req_attr)
{
	return (req_attr->id & PKCS11_CKA_OPTEE_FLAGS_HIDDEN) ==
		PKCS11_CKA_OPTEE_FLAGS_HIDDEN;
}

bool attribute_is_exportable(struct pkcs11_attribute_head *req_attr,
			     struct pkcs11_object *obj);

bool object_is_private(struct obj_attrs *head);

bool object_is_token(struct obj_attrs *head);

bool object_is_modifiable(struct obj_attrs *head);

bool object_is_copyable(struct obj_attrs *head);

/*
 * Check the attributes passed in template against the attributes which can be
 * modified. These are the attributes marked with * 8,10,11 or 12 in Table 10
 * in PKCS #11 Cryptographic Token InterfaceBase Specification Version 2.40.
 * Few attributes not with this marking but explicitly specified as modifiable
 * in footnote of their tables are also considered to be modifiable
 */
enum pkcs11_rc check_attrs_against_modification(struct pkcs11_session *session,
						struct obj_attrs *head,
						struct pkcs11_object *obj,
						enum processing_func function);

enum pkcs11_rc set_key_data(struct obj_attrs **head, void *data,
			    size_t key_size);

/*
 * Get an allocated copy of key data to be wrapped from @head
 * @head: Object attribute where to find key data to be wrapped
 * @data: Output allocated and filled buffer upon success
 * @sz: Key output data size in bytes upon success
 * Return a pkcs11_rv compliant value
 */
enum pkcs11_rc alloc_key_data_to_wrap(struct obj_attrs *head, void **data,
				      uint32_t *sz);

/*
 * Adds CKA_ID attribute from paired object if missing.
 *
 * @pub_head - Public key object attributes
 * @priv_head - Private key object attributes
 * Return a PKCS11 return code
 */
enum pkcs11_rc add_missing_attribute_id(struct obj_attrs **pub_head,
					struct obj_attrs **priv_head);
/*
 * Check an object's check value (Checksum)
 * @head: Object attribute where to find KCV to be checked
 * Return a pkcs11_rv compliant value
 */
enum pkcs11_rc set_check_value_attr(struct obj_attrs **head);

#endif /*PKCS11_TA_PKCS11_ATTRIBUTES_H*/
