xref: /optee_os/ta/pkcs11/src/entry.c (revision 10b907910d58334cc5b1486cb2f91a08f764566e)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2018-2020, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <pkcs11_ta.h>
9 #include <tee_internal_api.h>
10 #include <tee_internal_api_extensions.h>
11 #include <util.h>
12 
13 #include "pkcs11_helpers.h"
14 #include "pkcs11_token.h"
15 
16 TEE_Result TA_CreateEntryPoint(void)
17 {
18 	return pkcs11_init();
19 }
20 
21 void TA_DestroyEntryPoint(void)
22 {
23 	pkcs11_deinit();
24 }
25 
26 TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types,
27 				    TEE_Param __unused params[4],
28 				    void **tee_session)
29 {
30 	struct pkcs11_client *client = register_client();
31 
32 	if (!client)
33 		return TEE_ERROR_OUT_OF_MEMORY;
34 
35 	*tee_session = client;
36 
37 	return TEE_SUCCESS;
38 }
39 
40 void TA_CloseSessionEntryPoint(void *tee_session)
41 {
42 	struct pkcs11_client *client = tee_session2client(tee_session);
43 
44 	unregister_client(client);
45 }
46 
47 /*
48  * Entry point for invocation command PKCS11_CMD_PING
49  *
50  * Return a PKCS11_CKR_* value which is also loaded into the output param#0
51  */
52 static uint32_t entry_ping(uint32_t ptypes, TEE_Param *params)
53 {
54 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
55 						TEE_PARAM_TYPE_NONE,
56 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
57 						TEE_PARAM_TYPE_NONE);
58 	TEE_Param *out = &params[2];
59 	const uint32_t ver[] = {
60 		PKCS11_TA_VERSION_MAJOR,
61 		PKCS11_TA_VERSION_MINOR,
62 		PKCS11_TA_VERSION_PATCH,
63 	};
64 
65 	if (ptypes != exp_pt ||
66 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN ||
67 	    out->memref.size != sizeof(ver))
68 		return PKCS11_CKR_ARGUMENTS_BAD;
69 
70 	TEE_MemMove(out->memref.buffer, ver, sizeof(ver));
71 
72 	return PKCS11_CKR_OK;
73 }
74 
75 static bool __maybe_unused param_is_none(uint32_t ptypes, unsigned int index)
76 {
77 	return TEE_PARAM_TYPE_GET(ptypes, index) ==
78 	       TEE_PARAM_TYPE_NONE;
79 }
80 
81 static bool __maybe_unused param_is_memref(uint32_t ptypes, unsigned int index)
82 {
83 	switch (TEE_PARAM_TYPE_GET(ptypes, index)) {
84 	case TEE_PARAM_TYPE_MEMREF_INPUT:
85 	case TEE_PARAM_TYPE_MEMREF_OUTPUT:
86 	case TEE_PARAM_TYPE_MEMREF_INOUT:
87 		return true;
88 	default:
89 		return false;
90 	}
91 }
92 
93 static bool __maybe_unused param_is_input(uint32_t ptypes, unsigned int index)
94 {
95 	return TEE_PARAM_TYPE_GET(ptypes, index) ==
96 	       TEE_PARAM_TYPE_MEMREF_INPUT;
97 }
98 
99 static bool __maybe_unused param_is_output(uint32_t ptypes, unsigned int index)
100 {
101 	return TEE_PARAM_TYPE_GET(ptypes, index) ==
102 	       TEE_PARAM_TYPE_MEMREF_OUTPUT;
103 }
104 
105 /*
106  * Entry point for PKCS11 TA commands
107  *
108  * Param#0 (ctrl) is an output or an in/out buffer. Input data are serialized
109  * arguments for the invoked command while the output data is used to send
110  * back to the client a PKCS11 finer status ID than the GPD TEE result codes
111  * Client shall check the status ID from the parameter #0 output buffer together
112  * with the GPD TEE result code.
113  */
114 TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd,
115 				      uint32_t ptypes,
116 				      TEE_Param params[TEE_NUM_PARAMS])
117 {
118 	struct pkcs11_client *client = tee_session2client(tee_session);
119 	uint32_t rc = 0;
120 
121 	if (!client)
122 		return TEE_ERROR_SECURITY;
123 
124 	/* All command handlers will check only against 4 parameters */
125 	COMPILE_TIME_ASSERT(TEE_NUM_PARAMS == 4);
126 
127 	/*
128 	 * Param#0 must be either an output or an inout memref as used to
129 	 * store the output return value for the invoked command.
130 	 */
131 	switch (TEE_PARAM_TYPE_GET(ptypes, 0)) {
132 	case TEE_PARAM_TYPE_MEMREF_OUTPUT:
133 	case TEE_PARAM_TYPE_MEMREF_INOUT:
134 		if (params[0].memref.size < sizeof(rc))
135 			return TEE_ERROR_BAD_PARAMETERS;
136 		break;
137 	default:
138 		return TEE_ERROR_BAD_PARAMETERS;
139 	}
140 
141 	DMSG("%s p#0 %"PRIu32"@%p, p#1 %s %"PRIu32"@%p, p#2 %s %"PRIu32"@%p",
142 	     id2str_ta_cmd(cmd),
143 	     params[0].memref.size, params[0].memref.buffer,
144 	     param_is_input(ptypes, 1) ? "in" :
145 	     param_is_output(ptypes, 1) ? "out" : "---",
146 	     param_is_memref(ptypes, 1) ? params[1].memref.size : 0,
147 	     param_is_memref(ptypes, 1) ? params[1].memref.buffer : NULL,
148 	     param_is_input(ptypes, 2) ? "in" :
149 	     param_is_output(ptypes, 2) ? "out" : "---",
150 	     param_is_memref(ptypes, 2) ? params[2].memref.size : 0,
151 	     param_is_memref(ptypes, 2) ? params[2].memref.buffer : NULL);
152 
153 	switch (cmd) {
154 	case PKCS11_CMD_PING:
155 		rc = entry_ping(ptypes, params);
156 		break;
157 
158 	case PKCS11_CMD_SLOT_LIST:
159 		rc = entry_ck_slot_list(ptypes, params);
160 		break;
161 	case PKCS11_CMD_SLOT_INFO:
162 		rc = entry_ck_slot_info(ptypes, params);
163 		break;
164 	case PKCS11_CMD_TOKEN_INFO:
165 		rc = entry_ck_token_info(ptypes, params);
166 		break;
167 	case PKCS11_CMD_MECHANISM_IDS:
168 		rc = entry_ck_token_mecha_ids(ptypes, params);
169 		break;
170 	case PKCS11_CMD_MECHANISM_INFO:
171 		rc = entry_ck_token_mecha_info(ptypes, params);
172 		break;
173 
174 	case PKCS11_CMD_OPEN_SESSION:
175 		rc = entry_ck_open_session(client, ptypes, params);
176 		break;
177 	case PKCS11_CMD_CLOSE_SESSION:
178 		rc = entry_ck_close_session(client, ptypes, params);
179 		break;
180 	case PKCS11_CMD_CLOSE_ALL_SESSIONS:
181 		rc = entry_ck_close_all_sessions(client, ptypes, params);
182 		break;
183 	case PKCS11_CMD_SESSION_INFO:
184 		rc = entry_ck_session_info(client, ptypes, params);
185 		break;
186 
187 	default:
188 		EMSG("Command 0x%"PRIx32" is not supported", cmd);
189 		return TEE_ERROR_NOT_SUPPORTED;
190 	}
191 
192 	DMSG("%s rc 0x%08"PRIx32"/%s", id2str_ta_cmd(cmd), rc, id2str_rc(rc));
193 
194 	TEE_MemMove(params[0].memref.buffer, &rc, sizeof(rc));
195 	params[0].memref.size = sizeof(rc);
196 
197 	if (rc == PKCS11_CKR_BUFFER_TOO_SMALL)
198 		return TEE_ERROR_SHORT_BUFFER;
199 	else
200 		return TEE_SUCCESS;
201 }
202