xref: /optee_os/core/drivers/crypto/caam/mp/caam_mp.c (revision e63825bd1845d483e35622ab34932039abb49244)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2018-2021, 2023 NXP
4  */
5 #include <caam_hal_ctrl.h>
6 #include <caam_jr.h>
7 #include <caam_mp.h>
8 #include <caam_status.h>
9 #include <caam_utils_mem.h>
10 #include <caam_utils_status.h>
11 #include <drivers/caam_extension.h>
12 #include <kernel/pm.h>
13 #include <mm/core_memprot.h>
14 #include <string.h>
15 #include <tee/cache.h>
16 #include <tee_api_types.h>
17 #include <utee_defines.h>
18 
19 #define MP_SIGN_MAX_MSG_SIZE (4 * 1024)
20 
21 #ifdef CFG_PHYS_64BIT
22 #define MP_PRIV_DESC_ENTRIES 7
23 #define MP_PUB_DESC_ENTRIES  7
24 #define MP_SIGN_DESC_ENTRIES 13
25 #else
26 #define MP_PRIV_DESC_ENTRIES 6
27 #define MP_PUB_DESC_ENTRIES  6
28 #define MP_SIGN_DESC_ENTRIES 9
29 #endif
30 
31 /*
32  * MP module private data
33  */
34 static struct mp_privdata {
35 	uint8_t curve;		    /* Protocol Data Block curve selection */
36 	uint8_t sec_size;	    /* Security key size in bytes */
37 	vaddr_t ctrl_addr;	    /* Base address of the controller */
38 	enum caam_status mp_status; /* Indicate the MP status */
39 } mp_privdata;
40 
41 /*
42  * Generate manufacturing private key.
43  * The ECDSA private key is securely stored in the MPPKR.
44  * This register is locked to prevent reading or writing.
45  *
46  * @passphrase	Passphrase
47  * @len		Passphrase length
48  */
do_mppriv_gen(const char * passphrase,size_t len)49 static enum caam_status do_mppriv_gen(const char *passphrase, size_t len)
50 {
51 	enum caam_status ret = CAAM_FAILURE;
52 	struct caam_jobctx jobctx = { };
53 	uint32_t *desc = NULL;
54 	uint32_t desclen = 0;
55 
56 	MP_TRACE("MP private key generation");
57 
58 	assert(passphrase && len);
59 
60 	desc = caam_calloc_desc(MP_PRIV_DESC_ENTRIES);
61 	if (!desc)
62 		return CAAM_OUT_MEMORY;
63 
64 	caam_desc_init(desc);
65 	caam_desc_add_word(desc, DESC_HEADER(0));
66 	caam_desc_add_word(desc, PROT_MP_CURVE(mp_privdata.curve));
67 	caam_desc_add_ptr(desc, virt_to_phys((void *)passphrase));
68 	caam_desc_add_word(desc, len);
69 	caam_desc_add_word(desc, MPPRIVK);
70 
71 	desclen = caam_desc_get_len(desc);
72 	caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
73 
74 	MP_DUMPDESC(desc);
75 
76 	cache_operation(TEE_CACHECLEAN, (void *)passphrase, len);
77 
78 	jobctx.desc = desc;
79 	ret = caam_jr_enqueue(&jobctx, NULL);
80 
81 	if (ret != CAAM_NO_ERROR) {
82 		MP_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
83 		ret = CAAM_NOT_SUPPORTED;
84 	}
85 
86 	caam_free_desc(&desc);
87 	return ret;
88 }
89 
caam_mp_export_mpmr(uint8_t * mpmr,size_t * size)90 TEE_Result caam_mp_export_mpmr(uint8_t *mpmr, size_t *size)
91 {
92 	TEE_Result ret = TEE_ERROR_GENERIC;
93 	struct caambuf caam_mpmr = {
94 		.data = mpmr,
95 		.length = *size,
96 	};
97 
98 	MP_TRACE("Get MP message");
99 
100 	ret = caam_hal_ctrl_read_mpmr(mp_privdata.ctrl_addr, &caam_mpmr);
101 	*size = caam_mpmr.length;
102 
103 	return ret;
104 }
105 
caam_mp_export_publickey(uint8_t * pubkey,size_t * size)106 TEE_Result caam_mp_export_publickey(uint8_t *pubkey, size_t *size)
107 {
108 	TEE_Result ret = TEE_ERROR_GENERIC;
109 	enum caam_status retstatus = CAAM_FAILURE;
110 	struct caam_jobctx jobctx = { };
111 	struct caamdmaobj reskey = { };
112 	uint32_t pdb_sgt_flag = 0;
113 	uint32_t desclen = 0;
114 	uint32_t *desc = NULL;
115 
116 	/* Check if MP is operational */
117 	if (mp_privdata.mp_status != CAAM_NO_ERROR)
118 		return caam_status_to_tee_result(mp_privdata.mp_status);
119 
120 	if (!pubkey || !size)
121 		return TEE_ERROR_BAD_PARAMETERS;
122 
123 	/* The public key size is twice the private key size */
124 	if (*size < 2 * mp_privdata.sec_size) {
125 		*size = 2 * mp_privdata.sec_size;
126 		return TEE_ERROR_SHORT_BUFFER;
127 	}
128 
129 	ret = caam_dmaobj_output_sgtbuf(&reskey, pubkey, *size,
130 					2 * mp_privdata.sec_size);
131 	if (ret)
132 		return ret;
133 
134 	if (reskey.sgtbuf.sgt_type)
135 		pdb_sgt_flag = PROT_MP_PUBK_SGT;
136 
137 	desc = caam_calloc_desc(MP_PUB_DESC_ENTRIES);
138 	if (!desc) {
139 		ret = TEE_ERROR_OUT_OF_MEMORY;
140 		goto out;
141 	}
142 
143 	caam_desc_init(desc);
144 	caam_desc_add_word(desc, DESC_HEADER(0));
145 	caam_desc_add_word(desc,
146 			   PROT_MP_CURVE(mp_privdata.curve) | pdb_sgt_flag);
147 	caam_desc_add_ptr(desc, reskey.sgtbuf.paddr);
148 	caam_desc_add_word(desc, reskey.sgtbuf.length);
149 	caam_desc_add_word(desc, MPPUBK);
150 
151 	desclen = caam_desc_get_len(desc);
152 	caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
153 
154 	MP_DUMPDESC(desc);
155 
156 	caam_dmaobj_cache_push(&reskey);
157 
158 	jobctx.desc = desc;
159 	retstatus = caam_jr_enqueue(&jobctx, NULL);
160 
161 	if (retstatus == CAAM_NO_ERROR) {
162 		MP_TRACE("MP Public Key generated");
163 		reskey.orig.length = 2 * mp_privdata.sec_size;
164 		*size = caam_dmaobj_copy_to_orig(&reskey);
165 
166 		MP_DUMPBUF("MP PubKey", pubkey, *size);
167 
168 		ret = caam_status_to_tee_result(retstatus);
169 	} else {
170 		MP_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
171 		ret = job_status_to_tee_result(jobctx.status);
172 	}
173 
174 out:
175 	caam_dmaobj_free(&reskey);
176 	caam_free_desc(&desc);
177 
178 	return ret;
179 }
180 
caam_mp_sign(uint8_t * msg,size_t * msg_size,uint8_t * sig,size_t * sig_size)181 TEE_Result caam_mp_sign(uint8_t *msg, size_t *msg_size, uint8_t *sig,
182 			size_t *sig_size)
183 {
184 	TEE_Result ret = TEE_ERROR_GENERIC;
185 	enum caam_status retstatus = CAAM_FAILURE;
186 	struct caam_jobctx jobctx = { };
187 	struct caamdmaobj msg_input = { };
188 	struct caamdmaobj sign_c = { };
189 	struct caamdmaobj sign_d = { };
190 	struct caambuf hash = { };
191 	uint32_t *desc = NULL;
192 	uint32_t desclen = 0;
193 	uint32_t pdb_sgt_flags = 0;
194 	uint8_t *aligned_msg = NULL;
195 	size_t sign_len = 0;
196 
197 	MP_TRACE("MP sign operation");
198 
199 	/* Check if MP is operational */
200 	if (mp_privdata.mp_status != CAAM_NO_ERROR)
201 		return caam_status_to_tee_result(mp_privdata.mp_status);
202 
203 	if (!msg || !msg_size || !sig || !sig_size)
204 		return TEE_ERROR_BAD_PARAMETERS;
205 
206 	if (*sig_size < 2 * mp_privdata.sec_size) {
207 		*sig_size = 2 * mp_privdata.sec_size;
208 		return TEE_ERROR_SHORT_BUFFER;
209 	}
210 
211 	if (*msg_size > MP_SIGN_MAX_MSG_SIZE)
212 		return TEE_ERROR_EXCESS_DATA;
213 
214 	/* Re-allocate the message to a cache-aligned buffer */
215 	aligned_msg = caam_alloc(*msg_size);
216 	if (!aligned_msg) {
217 		MP_TRACE("Message reallocation error");
218 		ret = TEE_ERROR_OUT_OF_MEMORY;
219 		goto exit_mpsign;
220 	}
221 	memcpy(aligned_msg, msg, *msg_size);
222 
223 	/*
224 	 * Allocate the hash buffer of the Message + MPMR payload
225 	 * Note: Hash is not retrieve, hence no need to do cache
226 	 * maintenance
227 	 */
228 	retstatus = caam_alloc_align_buf(&hash, TEE_MAX_HASH_SIZE);
229 	if (retstatus != CAAM_NO_ERROR) {
230 		MP_TRACE("Hash allocation error");
231 		ret = caam_status_to_tee_result(retstatus);
232 		goto exit_mpsign;
233 	}
234 
235 	/*
236 	 * Re-allocate the signature result buffer with a maximum size
237 	 * of the roundup to 16 bytes of the secure size in bytes if
238 	 * the signature buffer is not aligned or too short.
239 	 *
240 	 *  - 1st Part: size_sec
241 	 *  - 2nd Part: size_sec roundup to 16 bytes
242 	 */
243 	sign_len = ROUNDUP(mp_privdata.sec_size, 16) + mp_privdata.sec_size;
244 
245 	ret = caam_dmaobj_output_sgtbuf(&sign_c, sig, *sig_size, sign_len);
246 	if (ret)
247 		goto exit_mpsign;
248 
249 	if (sign_c.sgtbuf.sgt_type)
250 		pdb_sgt_flags |= PDB_SGT_MP_SIGN_C;
251 
252 	/* Prepare the 2nd Part of the signature. Derived from sign_c */
253 	ret = caam_dmaobj_derive_sgtbuf(&sign_d, &sign_c, mp_privdata.sec_size,
254 					ROUNDUP(mp_privdata.sec_size, 16));
255 	if (ret)
256 		goto exit_mpsign;
257 
258 	if (sign_d.sgtbuf.sgt_type)
259 		pdb_sgt_flags |= PDB_SGT_MP_SIGN_D;
260 
261 	ret = caam_dmaobj_input_sgtbuf(&msg_input, aligned_msg, *msg_size);
262 	if (ret)
263 		goto exit_mpsign;
264 
265 	if (msg_input.sgtbuf.sgt_type)
266 		pdb_sgt_flags |= PDB_SGT_MP_SIGN_MSG;
267 
268 	desc = caam_calloc_desc(MP_SIGN_DESC_ENTRIES);
269 	if (!desc) {
270 		ret = TEE_ERROR_OUT_OF_MEMORY;
271 		goto exit_mpsign;
272 	}
273 
274 	caam_desc_init(desc);
275 	caam_desc_add_word(desc, DESC_HEADER(0));
276 	caam_desc_add_word(desc,
277 			   PROT_MP_CURVE(mp_privdata.curve) | pdb_sgt_flags);
278 	caam_desc_add_ptr(desc, msg_input.sgtbuf.paddr);
279 	caam_desc_add_ptr(desc, hash.paddr);
280 	caam_desc_add_ptr(desc, sign_c.sgtbuf.paddr);
281 	caam_desc_add_ptr(desc, sign_d.sgtbuf.paddr);
282 	caam_desc_add_word(desc, msg_input.sgtbuf.length);
283 	caam_desc_add_word(desc, MPSIGN_OP);
284 
285 	desclen = caam_desc_get_len(desc);
286 	caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
287 
288 	MP_DUMPDESC(desc);
289 
290 	caam_dmaobj_cache_push(&msg_input);
291 	caam_dmaobj_cache_push(&sign_c);
292 
293 	jobctx.desc = desc;
294 	retstatus = caam_jr_enqueue(&jobctx, NULL);
295 
296 	if (retstatus == CAAM_NO_ERROR) {
297 		sign_c.orig.length = 2 * mp_privdata.sec_size;
298 		*sig_size = caam_dmaobj_copy_to_orig(&sign_c);
299 
300 		MP_DUMPBUF("MP Signature", sdata->signature.data,
301 			   sdata->signature.length);
302 
303 		ret = caam_status_to_tee_result(retstatus);
304 	} else {
305 		MP_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
306 		ret = job_status_to_tee_result(jobctx.status);
307 	}
308 
309 exit_mpsign:
310 	caam_free(aligned_msg);
311 	caam_free_buf(&hash);
312 	caam_free_desc(&desc);
313 	caam_dmaobj_free(&msg_input);
314 	caam_dmaobj_free(&sign_c);
315 	caam_dmaobj_free(&sign_d);
316 
317 	return ret;
318 }
319 
caam_mp_init(vaddr_t ctrl_addr)320 enum caam_status caam_mp_init(vaddr_t ctrl_addr)
321 {
322 	/*
323 	 * Manufacturing protection secret values for DSA key pair
324 	 * generation.
325 	 */
326 	static const char passphrase[] = "manufacturing protection";
327 	static const char mpmr_data[] = "value to fill the MPMR content";
328 	enum caam_status retstatus = CAAM_FAILURE;
329 	uint8_t curve = 0;
330 	uint8_t hash_limit = 0;
331 
332 	struct caambuf msg_mpmr = {
333 		.data = (uint8_t *)mpmr_data,
334 		.length = strlen(mpmr_data)
335 	};
336 
337 	mp_privdata.ctrl_addr = ctrl_addr;
338 	mp_privdata.mp_status = CAAM_NOT_INIT;
339 
340 	curve = caam_hal_ctrl_get_mpcurve(ctrl_addr);
341 
342 	if (curve == UINT8_MAX) {
343 		mp_privdata.mp_status = CAAM_NOT_SUPPORTED;
344 		return mp_privdata.mp_status;
345 	}
346 
347 	if (caam_hal_ctrl_is_mp_set(ctrl_addr)) {
348 		mp_privdata.mp_status = CAAM_NO_ERROR;
349 		return CAAM_NO_ERROR;
350 	}
351 
352 	if (!curve) {
353 		/* Get the device HASH Limit to select the MP Curve */
354 		hash_limit = caam_hal_ctrl_hash_limit(ctrl_addr);
355 
356 		switch (hash_limit) {
357 		case TEE_MAIN_ALGO_SHA256:
358 			mp_privdata.curve = PDB_MP_CSEL_P256;
359 			mp_privdata.sec_size = 32;
360 			break;
361 		case TEE_MAIN_ALGO_SHA512:
362 			mp_privdata.curve = PDB_MP_CSEL_P521;
363 			mp_privdata.sec_size = 66;
364 			break;
365 		default:
366 			MP_TRACE("This curve doesn't exist");
367 			return CAAM_FAILURE;
368 		}
369 
370 		MP_TRACE("Generating MP Private key");
371 		retstatus = do_mppriv_gen(passphrase, strlen(passphrase));
372 
373 		if (retstatus != CAAM_NO_ERROR) {
374 			MP_TRACE("do_mppriv_gen failed!");
375 			return retstatus;
376 		}
377 	} else {
378 		/* MP Curve is already programmed. Set the right key size */
379 		mp_privdata.curve = curve;
380 
381 		switch (curve) {
382 		case PDB_MP_CSEL_P256:
383 			mp_privdata.sec_size = 32;
384 			break;
385 		case PDB_MP_CSEL_P521:
386 			mp_privdata.sec_size = 66;
387 			break;
388 		default:
389 			MP_TRACE("This curve is not supported");
390 			return CAAM_FAILURE;
391 		}
392 	}
393 
394 	/* Fill the MPMR content then lock it */
395 	caam_hal_ctrl_fill_mpmr(ctrl_addr, &msg_mpmr);
396 
397 	mp_privdata.mp_status = CAAM_NO_ERROR;
398 
399 	return CAAM_NO_ERROR;
400 }
401 
caam_mp_resume(uint32_t pm_hint)402 enum caam_status caam_mp_resume(uint32_t pm_hint)
403 {
404 	if (pm_hint == PM_HINT_CONTEXT_STATE)
405 		return caam_mp_init(mp_privdata.ctrl_addr);
406 
407 	return CAAM_NO_ERROR;
408 }
409