1 /*
2 * Copyright (c) 2010-2012 United States Government, as represented by
3 * the Secretary of Defense. All rights reserved.
4 *
5 * THIS SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED AS IS AND WITHOUT
6 * ANY EXPRESS OR IMPLIED WARRANTIES WHATSOEVER. ALL WARRANTIES
7 * INCLUDING, BUT NOT LIMITED TO, PERFORMANCE, MERCHANTABILITY, FITNESS
8 * FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT ARE HEREBY
9 * DISCLAIMED. USERS ASSUME THE ENTIRE RISK AND LIABILITY OF USING THE
10 * SOFTWARE.
11 */
12
13 #include <types.h>
14 #include <xen/xen.h>
15 #include <mm.h>
16 #include <gnttab.h>
17 #include "tpm/tpm_marshalling.h"
18 #include "vtpm_manager.h"
19 #include "vtpm_cmd.h"
20 #include <tpmback.h>
21
22 #define TRYFAILGOTO(C) \
23 if((C)) { \
24 status = TPM_FAIL; \
25 goto abort_egress; \
26 }
27 #define TRYFAILGOTOMSG(C, msg) \
28 if((C)) { \
29 status = TPM_FAIL; \
30 error(msg); \
31 goto abort_egress; \
32 }
33 #define CHECKSTATUSGOTO(ret, fname) \
34 if((ret) != TPM_SUCCESS) { \
35 error("%s failed with error code (%lu)", fname, (unsigned long) ret); \
36 status = ord; \
37 goto abort_egress; \
38 }
39
40 #define ERR_MALFORMED "Malformed response from backend"
41 #define ERR_TPMFRONT "Error sending command through frontend device"
42
43 struct shpage {
44 void* page;
45 grant_ref_t grantref;
46 };
47
48 typedef struct shpage shpage_t;
49
pack_header(uint8_t ** bptr,UINT32 * len,TPM_TAG tag,UINT32 size,TPM_COMMAND_CODE ord)50 static inline int pack_header(uint8_t** bptr, UINT32* len, TPM_TAG tag, UINT32 size, TPM_COMMAND_CODE ord)
51 {
52 return *bptr == NULL ||
53 tpm_marshal_UINT16(bptr, len, tag) ||
54 tpm_marshal_UINT32(bptr, len, size) ||
55 tpm_marshal_UINT32(bptr, len, ord);
56 }
57
unpack_header(uint8_t ** bptr,UINT32 * len,TPM_TAG * tag,UINT32 * size,TPM_COMMAND_CODE * ord)58 static inline int unpack_header(uint8_t** bptr, UINT32* len, TPM_TAG* tag, UINT32* size, TPM_COMMAND_CODE* ord)
59 {
60 return *bptr == NULL ||
61 tpm_unmarshal_UINT16(bptr, len, tag) ||
62 tpm_unmarshal_UINT32(bptr, len, size) ||
63 tpm_unmarshal_UINT32(bptr, len, ord);
64 }
65
create_error_response(tpmcmd_t * tpmcmd,TPM_RESULT errorcode)66 int create_error_response(tpmcmd_t* tpmcmd, TPM_RESULT errorcode)
67 {
68 TPM_TAG tag;
69 UINT32 len = tpmcmd->req_len;
70 uint8_t* respptr;
71 uint8_t* cmdptr = tpmcmd->req;
72
73 if(!tpm_unmarshal_UINT16(&cmdptr, &len, &tag)) {
74 switch (tag) {
75 case TPM_TAG_RQU_COMMAND:
76 tag = TPM_TAG_RSP_COMMAND;
77 break;
78 case TPM_TAG_RQU_AUTH1_COMMAND:
79 tag = TPM_TAG_RQU_AUTH2_COMMAND;
80 break;
81 case TPM_TAG_RQU_AUTH2_COMMAND:
82 tag = TPM_TAG_RQU_AUTH2_COMMAND;
83 break;
84 }
85 } else {
86 tag = TPM_TAG_RSP_COMMAND;
87 }
88
89 tpmcmd->resp_len = len = 10;
90 tpmcmd->resp = respptr = tpm_malloc(tpmcmd->resp_len);
91
92 return pack_header(&respptr, &len, tag, len, errorcode);
93 }
94
VTPM_GetRandom(struct tpmfront_dev * tpmfront_dev,BYTE * bytes,UINT32 * numbytes)95 TPM_RESULT VTPM_GetRandom(struct tpmfront_dev* tpmfront_dev, BYTE* bytes, UINT32 *numbytes) {
96 TPM_RESULT status = TPM_SUCCESS;
97 uint8_t* cmdbuf, *resp, *bptr;
98 size_t resplen = 0;
99 UINT32 len;
100
101 /*Ask the real tpm for random bytes for the seed */
102 TPM_TAG tag = TPM_TAG_RQU_COMMAND;
103 UINT32 size;
104 TPM_COMMAND_CODE ord = TPM_ORD_GetRandom;
105 len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32);
106
107 /*Create the raw tpm command */
108 bptr = cmdbuf = malloc(size);
109 TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
110 TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, *numbytes));
111
112 /* Send cmd, wait for response */
113 TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen),
114 ERR_TPMFRONT);
115
116 bptr = resp; len = resplen;
117 TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
118
119 //Check return status of command
120 CHECKSTATUSGOTO(ord, "TPM_GetRandom()");
121
122 // Get the number of random bytes in the response
123 TRYFAILGOTOMSG(tpm_unmarshal_UINT32(&bptr, &len, &size), ERR_MALFORMED);
124 *numbytes = size;
125
126 //Get the random bytes out, tpm may give us less bytes than what we wanrt
127 TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, bytes, *numbytes), ERR_MALFORMED);
128
129 goto egress;
130 abort_egress:
131 egress:
132 free(cmdbuf);
133 return status;
134
135 }
136
VTPM_LoadHashKey(struct tpmfront_dev * tpmfront_dev,uint8_t ** data,size_t * data_length)137 TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length)
138 {
139 TPM_RESULT status = TPM_SUCCESS;
140 uint8_t* bptr, *resp;
141 uint8_t* cmdbuf = NULL;
142 size_t resplen = 0;
143 UINT32 len;
144
145 TPM_TAG tag = VTPM_TAG_REQ;
146 UINT32 size;
147 TPM_COMMAND_CODE ord = VTPM_ORD_LOADHASHKEY;
148
149 /*Create the command*/
150 len = size = VTPM_COMMAND_HEADER_SIZE;
151 bptr = cmdbuf = malloc(size);
152 TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
153
154 /* Send the command to vtpm_manager */
155 info("Requesting Encryption key from backend");
156 TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
157
158 /* Unpack response header */
159 bptr = resp;
160 len = resplen;
161 TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
162
163 /* Check return code */
164 CHECKSTATUSGOTO(ord, "VTPM_LoadHashKey()");
165
166 /* Get the size of the key */
167 *data_length = size - VTPM_COMMAND_HEADER_SIZE;
168
169 /* Copy the key bits */
170 *data = malloc(*data_length);
171 memcpy(*data, bptr, *data_length);
172
173 goto egress;
174 abort_egress:
175 error("VTPM_LoadHashKey failed");
176 egress:
177 free(cmdbuf);
178 return status;
179 }
180
VTPM_SaveHashKey(struct tpmfront_dev * tpmfront_dev,uint8_t * data,size_t data_length)181 TPM_RESULT VTPM_SaveHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length)
182 {
183 TPM_RESULT status = TPM_SUCCESS;
184 uint8_t* bptr, *resp;
185 uint8_t* cmdbuf = NULL;
186 size_t resplen = 0;
187 UINT32 len;
188
189 TPM_TAG tag = VTPM_TAG_REQ;
190 UINT32 size;
191 TPM_COMMAND_CODE ord = VTPM_ORD_SAVEHASHKEY;
192
193 /*Create the command*/
194 len = size = VTPM_COMMAND_HEADER_SIZE + data_length;
195 bptr = cmdbuf = malloc(size);
196 TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
197 memcpy(bptr, data, data_length);
198 bptr += data_length;
199
200 /* Send the command to vtpm_manager */
201 info("Sending encryption key to backend");
202 TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
203
204 /* Unpack response header */
205 bptr = resp;
206 len = resplen;
207 TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
208
209 /* Check return code */
210 CHECKSTATUSGOTO(ord, "VTPM_SaveHashKey()");
211
212 goto egress;
213 abort_egress:
214 error("VTPM_SaveHashKey failed");
215 egress:
216 free(cmdbuf);
217 return status;
218 }
219
220 extern struct tpmfront_dev* tpmfront_dev;
VTPM_GetParentQuote(TPM_NONCE * data,TPM_PCR_SELECTION * sel,UINT32 extraInfoFlags,UINT32 * quote_blob_size,BYTE ** quote_blob)221 TPM_RESULT VTPM_GetParentQuote(TPM_NONCE *data, TPM_PCR_SELECTION *sel,
222 UINT32 extraInfoFlags, UINT32 *quote_blob_size, BYTE **quote_blob)
223 {
224 TPM_RESULT status = TPM_SUCCESS;
225 uint8_t* bptr, *resp;
226 uint8_t* cmdbuf = NULL;
227 size_t resplen = 0;
228 UINT32 len;
229
230 TPM_TAG tag = VTPM_TAG_REQ;
231 UINT32 size;
232 TPM_COMMAND_CODE ord = VTPM_ORD_GET_QUOTE;
233
234 /*Create the command*/
235 len = size = VTPM_COMMAND_HEADER_SIZE + 20 + sizeof_TPM_PCR_SELECTION((*sel)) + 4;
236 bptr = cmdbuf = malloc(size);
237 TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
238 TRYFAILGOTO(tpm_marshal_TPM_NONCE(&bptr, &len, data));
239 TRYFAILGOTO(tpm_marshal_TPM_PCR_SELECTION(&bptr, &len, sel));
240 TRYFAILGOTO(tpm_marshal_TPM_DEEP_QUOTE_INFO(&bptr, &len, extraInfoFlags));
241
242 /* Send the command to vtpm_manager */
243 info("Requesting Quote from backend");
244 TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
245
246 /* Unpack response header */
247 bptr = resp;
248 len = resplen;
249 TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
250
251 /* Check return code */
252 CHECKSTATUSGOTO(ord, "VTPM_GetParentQuote()");
253 /* Copy out the value */
254 *quote_blob_size = len;
255 *quote_blob = tpm_malloc(*quote_blob_size);
256 TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, *quote_blob, *quote_blob_size), ERR_MALFORMED);
257
258 goto egress;
259 abort_egress:
260 error("VTPM_GetParentQuote failed");
261 egress:
262 free(cmdbuf);
263 return status;
264 }
265
VTPM_PCRRead(struct tpmfront_dev * tpmfront_dev,UINT32 pcrIndex,BYTE * outDigest)266 TPM_RESULT VTPM_PCRRead(struct tpmfront_dev* tpmfront_dev, UINT32 pcrIndex, BYTE* outDigest)
267 {
268 TPM_RESULT status = TPM_SUCCESS;
269 uint8_t *cmdbuf, *resp, *bptr;
270 size_t resplen = 0;
271 UINT32 len;
272
273 /*Just send a TPM_PCRRead Command to the HW tpm */
274 TPM_TAG tag = TPM_TAG_RQU_COMMAND;
275 UINT32 size;
276 TPM_COMMAND_CODE ord = TPM_ORD_PCRRead;
277 len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32);
278
279 /*Create the raw tpm cmd */
280 bptr = cmdbuf = malloc(size);
281 TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
282 TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, pcrIndex));
283
284 /*Send Cmd wait for response */
285 TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
286
287 bptr = resp; len = resplen;
288 TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
289
290 //Check return status of command
291 CHECKSTATUSGOTO(ord, "TPM_PCRRead");
292
293 //Get the ptr value
294 memcpy(outDigest, bptr, sizeof(TPM_PCRVALUE));
295
296 goto egress;
297 abort_egress:
298 egress:
299 free(cmdbuf);
300 return status;
301
302 }
303