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