xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_vab.c (revision cab83c34871aa3d20bab81d3fca34c3d746c3db4)
147549250SJit Loon Lim /*
247549250SJit Loon Lim  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
347549250SJit Loon Lim  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
4*cab83c34SJit Loon Lim  * Copyright (c) 2024, Altera Corporation. All rights reserved.
547549250SJit Loon Lim  *
647549250SJit Loon Lim  * SPDX-License-Identifier: BSD-3-Clause
747549250SJit Loon Lim  */
847549250SJit Loon Lim 
947549250SJit Loon Lim #include <assert.h>
1047549250SJit Loon Lim #include <errno.h>
1147549250SJit Loon Lim 
1247549250SJit Loon Lim #include <arch_helpers.h>
1347549250SJit Loon Lim #include <common/debug.h>
1447549250SJit Loon Lim #include <common/tbbr/tbbr_img_def.h>
1547549250SJit Loon Lim #include <drivers/delay_timer.h>
1647549250SJit Loon Lim #include <lib/mmio.h>
1747549250SJit Loon Lim #include <lib/utils.h>
1847549250SJit Loon Lim #include <tools_share/firmware_image_package.h>
1947549250SJit Loon Lim 
2047549250SJit Loon Lim #include "socfpga_mailbox.h"
2147549250SJit Loon Lim #include "socfpga_vab.h"
2247549250SJit Loon Lim 
2347549250SJit Loon Lim static size_t get_img_size(uint8_t *img_buf, size_t img_buf_sz)
2447549250SJit Loon Lim {
2547549250SJit Loon Lim 	uint8_t *img_buf_end = img_buf + img_buf_sz;
2647549250SJit Loon Lim 	uint32_t cert_sz = get_unaligned_le32(img_buf_end - sizeof(uint32_t));
2747549250SJit Loon Lim 	uint8_t *p = img_buf_end - cert_sz - sizeof(uint32_t);
2847549250SJit Loon Lim 
2947549250SJit Loon Lim 	/* Ensure p is pointing within the img_buf */
3047549250SJit Loon Lim 	if (p < img_buf || p > (img_buf_end - VAB_CERT_HEADER_SIZE))
3147549250SJit Loon Lim 		return 0;
3247549250SJit Loon Lim 
3347549250SJit Loon Lim 	if (get_unaligned_le32(p) == SDM_CERT_MAGIC_NUM)
3447549250SJit Loon Lim 		return (size_t)(p - img_buf);
3547549250SJit Loon Lim 
3647549250SJit Loon Lim 	return 0;
3747549250SJit Loon Lim }
3847549250SJit Loon Lim 
3947549250SJit Loon Lim 
4047549250SJit Loon Lim 
4147549250SJit Loon Lim int socfpga_vendor_authentication(void **p_image, size_t *p_size)
4247549250SJit Loon Lim {
4347549250SJit Loon Lim 	int retry_count = 20;
4447549250SJit Loon Lim 	uint8_t hash384[FCS_SHA384_WORD_SIZE];
4547549250SJit Loon Lim 	uint64_t img_addr, mbox_data_addr;
4647549250SJit Loon Lim 	uint32_t img_sz, mbox_data_sz;
4747549250SJit Loon Lim 	uint8_t *cert_hash_ptr, *mbox_relocate_data_addr;
4847549250SJit Loon Lim 	uint32_t resp = 0, resp_len = 1;
4947549250SJit Loon Lim 	int ret = 0;
5047549250SJit Loon Lim 
5147549250SJit Loon Lim 	img_addr = (uintptr_t)*p_image;
5247549250SJit Loon Lim 	img_sz = get_img_size((uint8_t *)img_addr, *p_size);
5347549250SJit Loon Lim 
5447549250SJit Loon Lim 	if (!img_sz) {
5547549250SJit Loon Lim 		NOTICE("VAB certificate not found in image!\n");
56*cab83c34SJit Loon Lim 		return -ENOVABCERT;
5747549250SJit Loon Lim 	}
5847549250SJit Loon Lim 
5947549250SJit Loon Lim 	if (!IS_BYTE_ALIGNED(img_sz, sizeof(uint32_t))) {
6047549250SJit Loon Lim 		NOTICE("Image size (%d bytes) not aliged to 4 bytes!\n", img_sz);
6147549250SJit Loon Lim 		return -EIMGERR;
6247549250SJit Loon Lim 	}
6347549250SJit Loon Lim 
6447549250SJit Loon Lim 	/* Generate HASH384 from the image */
6547549250SJit Loon Lim 	/* TODO: This part need to cross check !!!!!! */
6647549250SJit Loon Lim 	sha384_csum_wd((uint8_t *)img_addr, img_sz, hash384, CHUNKSZ_PER_WD_RESET);
6747549250SJit Loon Lim 	cert_hash_ptr = (uint8_t *)(img_addr + img_sz +
6847549250SJit Loon Lim 	VAB_CERT_MAGIC_OFFSET + VAB_CERT_FIT_SHA384_OFFSET);
6947549250SJit Loon Lim 
7047549250SJit Loon Lim 	/*
7147549250SJit Loon Lim 	 * Compare the SHA384 found in certificate against the SHA384
7247549250SJit Loon Lim 	 * calculated from image
7347549250SJit Loon Lim 	 */
7447549250SJit Loon Lim 	if (memcmp(hash384, cert_hash_ptr, FCS_SHA384_WORD_SIZE)) {
7547549250SJit Loon Lim 		NOTICE("SHA384 does not match!\n");
7647549250SJit Loon Lim 		return -EKEYREJECTED;
7747549250SJit Loon Lim 	}
7847549250SJit Loon Lim 
7947549250SJit Loon Lim 
8047549250SJit Loon Lim 	mbox_data_addr = img_addr + img_sz - sizeof(uint32_t);
8147549250SJit Loon Lim 	/* Size in word (32bits) */
8247549250SJit Loon Lim 	mbox_data_sz = (BYTE_ALIGN(*p_size - img_sz, sizeof(uint32_t))) >> 2;
8347549250SJit Loon Lim 
8447549250SJit Loon Lim 	NOTICE("mbox_data_addr = %lx    mbox_data_sz = %d\n", mbox_data_addr, mbox_data_sz);
8547549250SJit Loon Lim 
8647549250SJit Loon Lim 	/* TODO: This part need to cross check !!!!!! */
8747549250SJit Loon Lim 	// mbox_relocate_data_addr = (uint8_t *)malloc(mbox_data_sz * sizeof(uint32_t));
8847549250SJit Loon Lim 	// if (!mbox_relocate_data_addr) {
8947549250SJit Loon Lim 		// NOTICE("Cannot allocate memory for VAB certificate relocation!\n");
9047549250SJit Loon Lim 		// return -ENOMEM;
9147549250SJit Loon Lim 	// }
9247549250SJit Loon Lim 
9347549250SJit Loon Lim 	memcpy(mbox_relocate_data_addr, (uint8_t *)mbox_data_addr, mbox_data_sz * sizeof(uint32_t));
9447549250SJit Loon Lim 	*(uint32_t *)mbox_relocate_data_addr = 0;
9547549250SJit Loon Lim 
9647549250SJit Loon Lim 	do {
9747549250SJit Loon Lim 		/* Invoke SMC call to ATF to send the VAB certificate to SDM */
9847549250SJit Loon Lim 		ret  = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_VAB_SRC_CERT,
9947549250SJit Loon Lim (uint32_t *)mbox_relocate_data_addr, mbox_data_sz, 0, &resp, &resp_len);
10047549250SJit Loon Lim 
10147549250SJit Loon Lim 		/* If SDM is not available, just delay 50ms and retry again */
10247549250SJit Loon Lim 		/* 0x1FF = The device is busy */
10347549250SJit Loon Lim 		if (ret == MBOX_RESP_ERR(0x1FF)) {
10447549250SJit Loon Lim 			mdelay(50);
10547549250SJit Loon Lim 		} else {
10647549250SJit Loon Lim 			break;
10747549250SJit Loon Lim 		}
10847549250SJit Loon Lim 	} while (--retry_count);
10947549250SJit Loon Lim 
11047549250SJit Loon Lim 	/* Free the relocate certificate memory space */
11147549250SJit Loon Lim 	zeromem((void *)&mbox_relocate_data_addr, sizeof(uint32_t));
11247549250SJit Loon Lim 
11347549250SJit Loon Lim 
11447549250SJit Loon Lim 	/* Exclude the size of the VAB certificate from image size */
11547549250SJit Loon Lim 	*p_size = img_sz;
11647549250SJit Loon Lim 
11747549250SJit Loon Lim 	if (ret) {
11847549250SJit Loon Lim 		/*
11947549250SJit Loon Lim 		 * Unsupported mailbox command or device not in the
12047549250SJit Loon Lim 		 * owned/secure state
12147549250SJit Loon Lim 		 */
12247549250SJit Loon Lim 		 /* 0x85 = Not allowed under current security setting */
12347549250SJit Loon Lim 		if (ret == MBOX_RESP_ERR(0x85)) {
12447549250SJit Loon Lim 			/* SDM bypass authentication */
12547549250SJit Loon Lim 			NOTICE("Image Authentication bypassed at address\n");
12647549250SJit Loon Lim 			return 0;
12747549250SJit Loon Lim 		}
12847549250SJit Loon Lim 		NOTICE("VAB certificate authentication failed in SDM\n");
12947549250SJit Loon Lim 		/* 0x1FF = The device is busy */
13047549250SJit Loon Lim 		if (ret == MBOX_RESP_ERR(0x1FF)) {
13147549250SJit Loon Lim 			NOTICE("Operation timed out\n");
13247549250SJit Loon Lim 			return -ETIMEOUT;
13347549250SJit Loon Lim 		} else if (ret == MBOX_WRONG_ID) {
13447549250SJit Loon Lim 			NOTICE("No such process\n");
13547549250SJit Loon Lim 			return -EPROCESS;
13647549250SJit Loon Lim 		}
13747549250SJit Loon Lim 	} else {
13847549250SJit Loon Lim 		/* If Certificate Process Status has error */
13947549250SJit Loon Lim 		if (resp) {
14047549250SJit Loon Lim 			NOTICE("VAB certificate execution format error\n");
14147549250SJit Loon Lim 			return -EIMGERR;
14247549250SJit Loon Lim 		}
14347549250SJit Loon Lim 	}
14447549250SJit Loon Lim 
14547549250SJit Loon Lim 	NOTICE("Image Authentication bypassed at address\n");
14647549250SJit Loon Lim 	return ret;
14747549250SJit Loon Lim 
14847549250SJit Loon Lim }
14947549250SJit Loon Lim 
15047549250SJit Loon Lim static uint32_t get_unaligned_le32(const void *p)
15147549250SJit Loon Lim {
15247549250SJit Loon Lim 	/* TODO: Temp for testing */
15347549250SJit Loon Lim 	//return le32_to_cpup((__le32 *)p);
15447549250SJit Loon Lim 	return 0;
15547549250SJit Loon Lim }
15647549250SJit Loon Lim 
157*cab83c34SJit Loon Lim static void sha512_transform(uint64_t *state, const uint8_t *input)
158*cab83c34SJit Loon Lim {
159*cab83c34SJit Loon Lim 	uint64_t a, b, c, d, e, f, g, h, t1, t2;
160*cab83c34SJit Loon Lim 
161*cab83c34SJit Loon Lim 	int i;
162*cab83c34SJit Loon Lim 	uint64_t W[16];
163*cab83c34SJit Loon Lim 
164*cab83c34SJit Loon Lim 	/* load the state into our registers */
165*cab83c34SJit Loon Lim 	a = state[0];   b = state[1];   c = state[2];   d = state[3];
166*cab83c34SJit Loon Lim 	e = state[4];   f = state[5];   g = state[6];   h = state[7];
167*cab83c34SJit Loon Lim 
168*cab83c34SJit Loon Lim 	/* now iterate */
169*cab83c34SJit Loon Lim 	for (i = 0 ; i < 80; i += 8) {
170*cab83c34SJit Loon Lim 		if (!(i & 8)) {
171*cab83c34SJit Loon Lim 			int j;
172*cab83c34SJit Loon Lim 
173*cab83c34SJit Loon Lim 			if (i < 16) {
174*cab83c34SJit Loon Lim 				/* load the input */
175*cab83c34SJit Loon Lim 				for (j = 0; j < 16; j++)
176*cab83c34SJit Loon Lim 					LOAD_OP(i + j, W, input);
177*cab83c34SJit Loon Lim 			} else {
178*cab83c34SJit Loon Lim 				for (j = 0; j < 16; j++) {
179*cab83c34SJit Loon Lim 					BLEND_OP(i + j, W);
180*cab83c34SJit Loon Lim 				}
181*cab83c34SJit Loon Lim 			}
182*cab83c34SJit Loon Lim 		}
183*cab83c34SJit Loon Lim 
184*cab83c34SJit Loon Lim 		t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i & 15)];
185*cab83c34SJit Loon Lim 		t2 = e0(a) + Maj(a, b, c);    d += t1;    h = t1 + t2;
186*cab83c34SJit Loon Lim 		t1 = g + e1(d) + Ch(d, e, f) + sha512_K[i+1] + W[(i & 15) + 1];
187*cab83c34SJit Loon Lim 		t2 = e0(h) + Maj(h, a, b);    c += t1;    g = t1 + t2;
188*cab83c34SJit Loon Lim 		t1 = f + e1(c) + Ch(c, d, e) + sha512_K[i+2] + W[(i & 15) + 2];
189*cab83c34SJit Loon Lim 		t2 = e0(g) + Maj(g, h, a);    b += t1;    f = t1 + t2;
190*cab83c34SJit Loon Lim 		t1 = e + e1(b) + Ch(b, c, d) + sha512_K[i+3] + W[(i & 15) + 3];
191*cab83c34SJit Loon Lim 		t2 = e0(f) + Maj(f, g, h);    a += t1;    e = t1 + t2;
192*cab83c34SJit Loon Lim 		t1 = d + e1(a) + Ch(a, b, c) + sha512_K[i+4] + W[(i & 15) + 4];
193*cab83c34SJit Loon Lim 		t2 = e0(e) + Maj(e, f, g);    h += t1;    d = t1 + t2;
194*cab83c34SJit Loon Lim 		t1 = c + e1(h) + Ch(h, a, b) + sha512_K[i+5] + W[(i & 15) + 5];
195*cab83c34SJit Loon Lim 		t2 = e0(d) + Maj(d, e, f);    g += t1;    c = t1 + t2;
196*cab83c34SJit Loon Lim 		t1 = b + e1(g) + Ch(g, h, a) + sha512_K[i+6] + W[(i & 15) + 6];
197*cab83c34SJit Loon Lim 		t2 = e0(c) + Maj(c, d, e);    f += t1;    b = t1 + t2;
198*cab83c34SJit Loon Lim 		t1 = a + e1(f) + Ch(f, g, h) + sha512_K[i+7] + W[(i & 15) + 7];
199*cab83c34SJit Loon Lim 		t2 = e0(b) + Maj(b, c, d);    e += t1;    a = t1 + t2;
200*cab83c34SJit Loon Lim 	}
201*cab83c34SJit Loon Lim 
202*cab83c34SJit Loon Lim 	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
203*cab83c34SJit Loon Lim 	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
204*cab83c34SJit Loon Lim 
205*cab83c34SJit Loon Lim 	/* erase our data */
206*cab83c34SJit Loon Lim 	a = b = c = d = e = f = g = h = t1 = t2 = 0;
207*cab83c34SJit Loon Lim }
208*cab83c34SJit Loon Lim 
209*cab83c34SJit Loon Lim static void sha512_block_fn(sha512_context *sst, const uint8_t *src,
210*cab83c34SJit Loon Lim 				    int blocks)
211*cab83c34SJit Loon Lim {
212*cab83c34SJit Loon Lim 	while (blocks--) {
213*cab83c34SJit Loon Lim 		sha512_transform(sst->state, src);
214*cab83c34SJit Loon Lim 		src += SHA512_BLOCK_SIZE;
215*cab83c34SJit Loon Lim 	}
216*cab83c34SJit Loon Lim }
217*cab83c34SJit Loon Lim 
218*cab83c34SJit Loon Lim 
219*cab83c34SJit Loon Lim static void sha512_base_do_finalize(sha512_context *sctx)
220*cab83c34SJit Loon Lim {
221*cab83c34SJit Loon Lim 	const int bit_offset = SHA512_BLOCK_SIZE - sizeof(uint64_t[2]);
222*cab83c34SJit Loon Lim 	uint64_t *bits = (uint64_t *)(sctx->buf + bit_offset);
223*cab83c34SJit Loon Lim 	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
224*cab83c34SJit Loon Lim 
225*cab83c34SJit Loon Lim 	sctx->buf[partial++] = 0x80;
226*cab83c34SJit Loon Lim 	if (partial > bit_offset) {
227*cab83c34SJit Loon Lim 		memset(sctx->buf + partial, 0x0, SHA512_BLOCK_SIZE - partial);
228*cab83c34SJit Loon Lim 		partial = 0;
229*cab83c34SJit Loon Lim 
230*cab83c34SJit Loon Lim 		sha512_block_fn(sctx, sctx->buf, 1);
231*cab83c34SJit Loon Lim 	}
232*cab83c34SJit Loon Lim 
233*cab83c34SJit Loon Lim 	memset(sctx->buf + partial, 0x0, bit_offset - partial);
234*cab83c34SJit Loon Lim 	//fixme bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
235*cab83c34SJit Loon Lim 	//fixme bits[1] = cpu_to_be64(sctx->count[0] << 3);
236*cab83c34SJit Loon Lim 	bits[0] = (sctx->count[1] << 3 | sctx->count[0] >> 61);
237*cab83c34SJit Loon Lim 	bits[1] = (sctx->count[0] << 3);
238*cab83c34SJit Loon Lim 	sha512_block_fn(sctx, sctx->buf, 1);
239*cab83c34SJit Loon Lim }
240*cab83c34SJit Loon Lim 
241*cab83c34SJit Loon Lim static void sha512_base_do_update(sha512_context *sctx,
242*cab83c34SJit Loon Lim 					const uint8_t *data,
243*cab83c34SJit Loon Lim 					unsigned int len)
244*cab83c34SJit Loon Lim {
245*cab83c34SJit Loon Lim 	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
246*cab83c34SJit Loon Lim 
247*cab83c34SJit Loon Lim 	sctx->count[0] += len;
248*cab83c34SJit Loon Lim 	if (sctx->count[0] < len)
249*cab83c34SJit Loon Lim 		sctx->count[1]++;
250*cab83c34SJit Loon Lim 
251*cab83c34SJit Loon Lim 	if (((partial + len) >= SHA512_BLOCK_SIZE)) {
252*cab83c34SJit Loon Lim 		int blocks;
253*cab83c34SJit Loon Lim 
254*cab83c34SJit Loon Lim 		if (partial) {
255*cab83c34SJit Loon Lim 			int p = SHA512_BLOCK_SIZE - partial;
256*cab83c34SJit Loon Lim 
257*cab83c34SJit Loon Lim 			memcpy(sctx->buf + partial, data, p);
258*cab83c34SJit Loon Lim 			data += p;
259*cab83c34SJit Loon Lim 			len -= p;
260*cab83c34SJit Loon Lim 
261*cab83c34SJit Loon Lim 			sha512_block_fn(sctx, sctx->buf, 1);
262*cab83c34SJit Loon Lim 		}
263*cab83c34SJit Loon Lim 
264*cab83c34SJit Loon Lim 		blocks = len / SHA512_BLOCK_SIZE;
265*cab83c34SJit Loon Lim 		len %= SHA512_BLOCK_SIZE;
266*cab83c34SJit Loon Lim 
267*cab83c34SJit Loon Lim 		if (blocks) {
268*cab83c34SJit Loon Lim 			sha512_block_fn(sctx, data, blocks);
269*cab83c34SJit Loon Lim 			data += blocks * SHA512_BLOCK_SIZE;
270*cab83c34SJit Loon Lim 		}
271*cab83c34SJit Loon Lim 		partial = 0;
272*cab83c34SJit Loon Lim 	}
273*cab83c34SJit Loon Lim 	if (len)
274*cab83c34SJit Loon Lim 		memcpy(sctx->buf + partial, data, len);
275*cab83c34SJit Loon Lim }
276*cab83c34SJit Loon Lim 
277*cab83c34SJit Loon Lim void sha384_starts(sha512_context *ctx)
278*cab83c34SJit Loon Lim {
279*cab83c34SJit Loon Lim 	ctx->state[0] = SHA384_H0;
280*cab83c34SJit Loon Lim 	ctx->state[1] = SHA384_H1;
281*cab83c34SJit Loon Lim 	ctx->state[2] = SHA384_H2;
282*cab83c34SJit Loon Lim 	ctx->state[3] = SHA384_H3;
283*cab83c34SJit Loon Lim 	ctx->state[4] = SHA384_H4;
284*cab83c34SJit Loon Lim 	ctx->state[5] = SHA384_H5;
285*cab83c34SJit Loon Lim 	ctx->state[6] = SHA384_H6;
286*cab83c34SJit Loon Lim 	ctx->state[7] = SHA384_H7;
287*cab83c34SJit Loon Lim 	ctx->count[0] = ctx->count[1] = 0;
288*cab83c34SJit Loon Lim }
289*cab83c34SJit Loon Lim 
290*cab83c34SJit Loon Lim void sha384_update(sha512_context *ctx, const uint8_t *input, uint32_t length)
291*cab83c34SJit Loon Lim {
292*cab83c34SJit Loon Lim 	sha512_base_do_update(ctx, input, length);
293*cab83c34SJit Loon Lim }
294*cab83c34SJit Loon Lim 
295*cab83c34SJit Loon Lim void sha384_finish(sha512_context *ctx, uint8_t digest[SHA384_SUM_LEN])
296*cab83c34SJit Loon Lim {
297*cab83c34SJit Loon Lim 	int i;
298*cab83c34SJit Loon Lim 
299*cab83c34SJit Loon Lim 	sha512_base_do_finalize(ctx);
300*cab83c34SJit Loon Lim 	for (i = 0; i < SHA384_SUM_LEN / sizeof(uint64_t); i++)
301*cab83c34SJit Loon Lim 		PUT_UINT64_BE(ctx->state[i], digest, i * 8);
302*cab83c34SJit Loon Lim }
303*cab83c34SJit Loon Lim 
30447549250SJit Loon Lim void sha384_csum_wd(const unsigned char *input, unsigned int ilen,
30547549250SJit Loon Lim 		unsigned char *output, unsigned int chunk_sz)
30647549250SJit Loon Lim {
307*cab83c34SJit Loon Lim 	sha512_context ctx;
308*cab83c34SJit Loon Lim // #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
309*cab83c34SJit Loon Lim 	// const unsigned char *end;
310*cab83c34SJit Loon Lim 	// unsigned char *curr;
311*cab83c34SJit Loon Lim 	// int chunk;
312*cab83c34SJit Loon Lim // #endif
313*cab83c34SJit Loon Lim 
314*cab83c34SJit Loon Lim 	sha384_starts(&ctx);
315*cab83c34SJit Loon Lim 
316*cab83c34SJit Loon Lim // #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
317*cab83c34SJit Loon Lim 	// curr = (unsigned char *)input;
318*cab83c34SJit Loon Lim 	// end = input + ilen;
319*cab83c34SJit Loon Lim 	// while (curr < end) {
320*cab83c34SJit Loon Lim 		// chunk = end - curr;
321*cab83c34SJit Loon Lim 		// if (chunk > chunk_sz)
322*cab83c34SJit Loon Lim 			// chunk = chunk_sz;
323*cab83c34SJit Loon Lim 		// sha384_update(&ctx, curr, chunk);
324*cab83c34SJit Loon Lim 		// curr += chunk;
325*cab83c34SJit Loon Lim 		// schedule();
326*cab83c34SJit Loon Lim 	// }
327*cab83c34SJit Loon Lim // #else
328*cab83c34SJit Loon Lim 	sha384_update(&ctx, input, ilen);
329*cab83c34SJit Loon Lim // #endif
330*cab83c34SJit Loon Lim 
331*cab83c34SJit Loon Lim 	sha384_finish(&ctx, output);
33247549250SJit Loon Lim }
333