summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/cmd_prov_key.c
blob: b09e275d237cf58c58180d868d6251a50b16b423 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * @file - cmd_prov_key.c
 * @brief - NXP command support
 * Command for provisioning encrypted key as black blob,
 *
 * Copyright 2021 NXP
 *
 */

/*
 *Concepts:
 *
 *  - black key: secure encrypted key that can only be used by the CAAM HW
 *               module on the device generating this key.
 *  - black blob: black blob is an encapsulation of black data (key) that can
 *                only be decapsulated by the initiator device. The
 *                decapsulation will result in a new black data readable only
 *                by the CAAM HW.
 *
 *
 *Generation of the key black blob:
 *
 *     1) Compile the bootloader with configuration:
 *        CONFIG_IMX_HAB
 *        CONFIG_FSL_CAAM
 *        CONFIG_IMX_CAAM_MFG_PROT
 *        CONFIG_CMD_PROVISION_KEY
 *     2) Boot the bootloader on the board
 *     3) Bootloader will generate the MPPubK
 *     4) PKEK = hash(MPPUBK)
 *     5) Read the encrypted key from RAM
 *     6) Decrypt using PKEK
 *     7) Encapsulate the decrypted key in black blob
 *     8) Add the 20 bytes TAG to black blob
 *     9) Copy the black blob in a binary file.
 *        The file must have a size of 112 bytes (0x70 bytes).
 */

#include <common.h>
#include <cpu_func.h>
#include <command.h>
#include <malloc.h>
#include <memalign.h>
#include <asm/byteorder.h>
#include <linux/compiler.h>
#include <fsl_sec.h>
#include <hash.h>
#include <u-boot/sha256.h>
#include <asm/arch/clock.h>

/* Key modifier for CAAM blobs, used as a revision number */
static const char caam_key_modifier[16] = {
		'C', 'A', 'A', 'M', '_', 'K', 'E', 'Y',
		'_', 'T', 'Y', 'P', 'E', '_', 'V', '1',
};

/**
 * do_export_key_blob() - Handle the "export_key_blob" command-line command
 * @cmdtp:	Command data struct pointer
 * @flag:	Command flag
 * @argc:	Command-line argument count
 * @argv:	Array of command-line arguments
 *
 * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
 * on error.
 */
static int do_export_key_blob(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
	ulong src_addr, dst_addr;
	uint8_t *src_ptr, *dst_ptr;
	uint8_t *mppubk = NULL, *pkek = NULL, *black_key = NULL;
	size_t key_len = AES256_KEY_SZ, pkek_len = SHA256_SUM_LEN;
	size_t blob_len, blob_max_len;
	int size, ret = 0;

	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, km_ptr, 16);

	if (argc != 3)
		return CMD_RET_USAGE;

	/* generate mppubk */
	mppubk = malloc_cache_aligned(FSL_CAAM_MP_PUBK_BYTES);
	if (!mppubk) {
		printf("Failed to allocate mem for mppubk\n");
		return -ENOMEM;
	}

	ret = gen_mppubk(mppubk);
	if (ret) {
		printf("Failed to generate MPPubK\n");
		goto free_m;
	}

	/* Derive PKEK = SHA256(MPPUBK) */
	pkek = malloc_cache_aligned(pkek_len);
	if (!pkek) {
		printf("Failed to allocate memory for pkek\n");
		ret = -ENOMEM;
		goto free_m;
	}

	ret = hash_block("sha256", mppubk, FSL_CAAM_MP_PUBK_BYTES, pkek, (int *)&pkek_len);
	if (ret)
		goto free_pkek;

	/* use pkek to decrypt src_addr which has enc key*/
	src_addr = simple_strtoul(argv[1], NULL, 16);
	src_ptr = (uint8_t *)(uintptr_t)src_addr;

	black_key = malloc_cache_aligned(key_len);
	if (!black_key) {
		printf("Failed to allocate memory for black_key\n");
		ret = -ENOMEM;
		goto free_pkek;
	}

	ret = aesecb_decrypt(pkek, pkek_len, src_ptr, black_key, key_len);
	if (ret)
		goto free_blk_key;

	/* create key black blob */
	dst_addr = simple_strtoul(argv[2], NULL, 16);
	dst_ptr = (uint8_t *)(uintptr_t)dst_addr;

	/* copy key modifier, must be same as used in kernel */
	memcpy(km_ptr, caam_key_modifier, 16);

	ret = blob_encap((uint8_t *)km_ptr, black_key, dst_ptr, key_len, 1);
	if (ret)
		goto free_blk_key;

	/* Tag the black blob so it can be passed to kernel */
	blob_len = BLOB_SIZE(key_len) + CCM_OVERHEAD;
	blob_max_len = MAX_BLOB_SIZE;
	ret = tag_black_obj(dst_ptr, blob_len, key_len, blob_max_len);
	if (ret)
		printf("Failed to tag black blob: %d\n", ret);

free_blk_key:
	free(black_key);
free_pkek:
	memset(pkek, 0, pkek_len);
	size = ALIGN(pkek_len, ARCH_DMA_MINALIGN);
	flush_dcache_range((unsigned long)pkek, (unsigned long)pkek + size);
	free(pkek);
free_m:
	memset(mppubk, 0, FSL_CAAM_MP_PUBK_BYTES);
	size = ALIGN(FSL_CAAM_MP_PUBK_BYTES, ARCH_DMA_MINALIGN);
	flush_dcache_range((unsigned long)mppubk, (unsigned long)mppubk + size);
	free(mppubk);

	return ret;
}

/***************************************************/

U_BOOT_CMD(
	export_key_blob, 3, 0, do_export_key_blob,
	"Provision encrypted key as black blob.",
	"src_addr dst_addr \n\n"
	" - src_addr: source addr which has encrypted key(32 byte) to provision.\n"
	"             must be 64 byte aligned.\n"
	" - dst_addr: destination addr which will have key black blob(112 byte).\n"
	"             must be 64 byte aligned.\n"
);