]> git.sur5r.net Git - u-boot/blob - drivers/mmc/rpmb.c
0b6b6222bdce9ae7c44a4510d01dfa18de40c22c
[u-boot] / drivers / mmc / rpmb.c
1 /*
2  * Copyright 2014, Staubli Faverges
3  * Pierre Aubert
4  *
5  * eMMC- Replay Protected Memory Block
6  * According to JEDEC Standard No. 84-A441
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <config.h>
12 #include <common.h>
13 #include <memalign.h>
14 #include <mmc.h>
15 #include <u-boot/sha256.h>
16 #include "mmc_private.h"
17
18 /* Request codes */
19 #define RPMB_REQ_KEY            1
20 #define RPMB_REQ_WCOUNTER       2
21 #define RPMB_REQ_WRITE_DATA     3
22 #define RPMB_REQ_READ_DATA      4
23 #define RPMB_REQ_STATUS         5
24
25 /* Response code */
26 #define RPMB_RESP_KEY           0x0100
27 #define RPMB_RESP_WCOUNTER      0x0200
28 #define RPMB_RESP_WRITE_DATA    0x0300
29 #define RPMB_RESP_READ_DATA     0x0400
30
31 /* Error codes */
32 #define RPMB_OK                 0
33 #define RPMB_ERR_GENERAL        1
34 #define RPMB_ERR_AUTH   2
35 #define RPMB_ERR_COUNTER        3
36 #define RPMB_ERR_ADDRESS        4
37 #define RPMB_ERR_WRITE          5
38 #define RPMB_ERR_READ           6
39 #define RPMB_ERR_KEY            7
40 #define RPMB_ERR_CNT_EXPIRED    0x80
41 #define RPMB_ERR_MSK            0x7
42
43 /* Sizes of RPMB data frame */
44 #define RPMB_SZ_STUFF           196
45 #define RPMB_SZ_MAC             32
46 #define RPMB_SZ_DATA            256
47 #define RPMB_SZ_NONCE           16
48
49 #define SHA256_BLOCK_SIZE       64
50
51 /* Error messages */
52 static const char * const rpmb_err_msg[] = {
53         "",
54         "General failure",
55         "Authentication failure",
56         "Counter failure",
57         "Address failure",
58         "Write failure",
59         "Read failure",
60         "Authentication key not yet programmed",
61 };
62
63
64 /* Structure of RPMB data frame. */
65 struct s_rpmb {
66         unsigned char stuff[RPMB_SZ_STUFF];
67         unsigned char mac[RPMB_SZ_MAC];
68         unsigned char data[RPMB_SZ_DATA];
69         unsigned char nonce[RPMB_SZ_NONCE];
70         unsigned int write_counter;
71         unsigned short address;
72         unsigned short block_count;
73         unsigned short result;
74         unsigned short request;
75 };
76
77 static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
78                               bool is_rel_write)
79 {
80         struct mmc_cmd cmd = {0};
81
82         cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
83         cmd.cmdarg = blockcount & 0x0000FFFF;
84         if (is_rel_write)
85                 cmd.cmdarg |= 1 << 31;
86         cmd.resp_type = MMC_RSP_R1;
87
88         return mmc_send_cmd(mmc, &cmd, NULL);
89 }
90 static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
91                             unsigned int count, bool is_rel_write)
92 {
93         struct mmc_cmd cmd = {0};
94         struct mmc_data data;
95         int ret;
96
97         ret = mmc_set_blockcount(mmc, count, is_rel_write);
98         if (ret) {
99 #ifdef CONFIG_MMC_RPMB_TRACE
100                 printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
101 #endif
102                 return 1;
103         }
104
105         cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
106         cmd.cmdarg = 0;
107         cmd.resp_type = MMC_RSP_R1b;
108
109         data.src = (const char *)s;
110         data.blocks = 1;
111         data.blocksize = MMC_MAX_BLOCK_LEN;
112         data.flags = MMC_DATA_WRITE;
113
114         ret = mmc_send_cmd(mmc, &cmd, &data);
115         if (ret) {
116 #ifdef CONFIG_MMC_RPMB_TRACE
117                 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
118 #endif
119                 return 1;
120         }
121         return 0;
122 }
123 static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
124                              unsigned short expected)
125 {
126         struct mmc_cmd cmd = {0};
127         struct mmc_data data;
128         int ret;
129
130         ret = mmc_set_blockcount(mmc, 1, false);
131         if (ret) {
132 #ifdef CONFIG_MMC_RPMB_TRACE
133                 printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
134 #endif
135                 return -1;
136         }
137         cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
138         cmd.cmdarg = 0;
139         cmd.resp_type = MMC_RSP_R1;
140
141         data.dest = (char *)s;
142         data.blocks = 1;
143         data.blocksize = MMC_MAX_BLOCK_LEN;
144         data.flags = MMC_DATA_READ;
145
146         ret = mmc_send_cmd(mmc, &cmd, &data);
147         if (ret) {
148 #ifdef CONFIG_MMC_RPMB_TRACE
149                 printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
150 #endif
151                 return -1;
152         }
153         /* Check the response and the status */
154         if (be16_to_cpu(s->request) != expected) {
155 #ifdef CONFIG_MMC_RPMB_TRACE
156                 printf("%s:response= %x\n", __func__,
157                        be16_to_cpu(s->request));
158 #endif
159                 return -1;
160         }
161         ret = be16_to_cpu(s->result);
162         if (ret) {
163                 printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
164                        (ret & RPMB_ERR_CNT_EXPIRED) ?
165                        "Write counter has expired" : "");
166         }
167
168         /* Return the status of the command */
169         return ret;
170 }
171 static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
172 {
173         ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
174
175         memset(rpmb_frame, 0, sizeof(struct s_rpmb));
176         rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
177         if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
178                 return -1;
179
180         /* Read the result */
181         return mmc_rpmb_response(mmc, rpmb_frame, expected);
182 }
183 static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
184                       unsigned char *output)
185 {
186         sha256_context ctx;
187         int i;
188         unsigned char k_ipad[SHA256_BLOCK_SIZE];
189         unsigned char k_opad[SHA256_BLOCK_SIZE];
190
191         sha256_starts(&ctx);
192
193         /* According to RFC 4634, the HMAC transform looks like:
194            SHA(K XOR opad, SHA(K XOR ipad, text))
195
196            where K is an n byte key.
197            ipad is the byte 0x36 repeated blocksize times
198            opad is the byte 0x5c repeated blocksize times
199            and text is the data being protected.
200         */
201
202         for (i = 0; i < RPMB_SZ_MAC; i++) {
203                 k_ipad[i] = key[i] ^ 0x36;
204                 k_opad[i] = key[i] ^ 0x5c;
205         }
206         /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
207         for ( ; i < SHA256_BLOCK_SIZE; i++) {
208                 k_ipad[i] = 0x36;
209                 k_opad[i] = 0x5c;
210         }
211         sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
212         sha256_update(&ctx, buff, len);
213         sha256_finish(&ctx, output);
214
215         /* Init context for second pass */
216         sha256_starts(&ctx);
217
218         /* start with outer pad */
219         sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
220
221         /* then results of 1st hash */
222         sha256_update(&ctx, output, RPMB_SZ_MAC);
223
224         /* finish up 2nd pass */
225         sha256_finish(&ctx, output);
226 }
227 int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
228 {
229         int ret;
230         ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
231
232         /* Fill the request */
233         memset(rpmb_frame, 0, sizeof(struct s_rpmb));
234         rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
235         if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
236                 return -1;
237
238         /* Read the result */
239         ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
240         if (ret)
241                 return ret;
242
243         *pcounter = be32_to_cpu(rpmb_frame->write_counter);
244         return 0;
245 }
246 int mmc_rpmb_set_key(struct mmc *mmc, void *key)
247 {
248         ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
249         /* Fill the request */
250         memset(rpmb_frame, 0, sizeof(struct s_rpmb));
251         rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
252         memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
253
254         if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
255                 return -1;
256
257         /* read the operation status */
258         return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
259 }
260 int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
261                   unsigned short cnt, unsigned char *key)
262 {
263         ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
264         int i;
265
266         for (i = 0; i < cnt; i++) {
267                 /* Fill the request */
268                 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
269                 rpmb_frame->address = cpu_to_be16(blk + i);
270                 rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
271                 if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
272                         break;
273
274                 /* Read the result */
275                 if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
276                         break;
277
278                 /* Check the HMAC if key is provided */
279                 if (key) {
280                         unsigned char ret_hmac[RPMB_SZ_MAC];
281
282                         rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
283                         if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
284                                 printf("MAC error on block #%d\n", i);
285                                 break;
286                         }
287                 }
288                 /* Copy data */
289                 memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
290         }
291         return i;
292 }
293 int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
294                   unsigned short cnt, unsigned char *key)
295 {
296         ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
297         unsigned long wcount;
298         int i;
299
300         for (i = 0; i < cnt; i++) {
301                 if (mmc_rpmb_get_counter(mmc, &wcount)) {
302                         printf("Cannot read RPMB write counter\n");
303                         break;
304                 }
305
306                 /* Fill the request */
307                 memset(rpmb_frame, 0, sizeof(struct s_rpmb));
308                 memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
309                 rpmb_frame->address = cpu_to_be16(blk + i);
310                 rpmb_frame->block_count = cpu_to_be16(1);
311                 rpmb_frame->write_counter = cpu_to_be32(wcount);
312                 rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
313                 /* Computes HMAC */
314                 rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
315
316                 if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
317                         break;
318
319                 /* Get status */
320                 if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
321                         break;
322         }
323         return i;
324 }