VirtualBox

source: vbox/trunk/src/VBox/Devices/Security/DrvTpmHost.cpp@ 94377

Last change on this file since 94377 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: DrvTpmHost.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * TPM host access driver.
4 */
5
6/*
7 * Copyright (C) 2021-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_TPM_HOST
23#include <VBox/vmm/pdmdrv.h>
24#include <VBox/vmm/pdmtpmifs.h>
25#include <iprt/assert.h>
26#include <iprt/mem.h>
27#include <iprt/string.h>
28#include <iprt/semaphore.h>
29#include <iprt/uuid.h>
30#include <iprt/tpm.h>
31
32#include <iprt/formats/tpm.h>
33
34#include "VBoxDD.h"
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45
46/**
47 * TPM 1.2 buffer size capability response.
48 */
49#pragma pack(1)
50typedef struct TPMRESPGETBUFSZ
51{
52 TPMRESPHDR Hdr;
53 uint32_t u32Length;
54 uint32_t cbBuf;
55} TPMRESPGETBUFSZ;
56#pragma pack()
57typedef TPMRESPGETBUFSZ *PTPMRESPGETBUFSZ;
58typedef const TPMRESPGETBUFSZ *PCTPMRESPGETBUFSZ;
59
60
61/**
62 * TPM 2.0 buffer size capability response.
63 */
64#pragma pack(1)
65typedef struct TPM2RESPGETBUFSZ
66{
67 TPMRESPHDR Hdr;
68 uint8_t fMore;
69 uint32_t u32Cap;
70 uint32_t u32Count;
71 uint32_t u32Prop;
72 uint32_t u32Value;
73} TPM2RESPGETBUFSZ;
74#pragma pack()
75typedef TPM2RESPGETBUFSZ *PTPM2RESPGETBUFSZ;
76typedef const TPM2RESPGETBUFSZ *PCTPM2RESPGETBUFSZ;
77
78
79/**
80 * TPM Host driver instance data.
81 *
82 * @implements PDMITPMCONNECTOR
83 */
84typedef struct DRVTPMHOST
85{
86 /** The stream interface. */
87 PDMITPMCONNECTOR ITpmConnector;
88 /** Pointer to the driver instance. */
89 PPDMDRVINS pDrvIns;
90
91 /** Handle to the host TPM. */
92 RTTPM hTpm;
93 /** Cached TPM version. */
94 TPMVERSION enmTpmVersion;
95 /** Cached buffer size of the host TPM. */
96 uint32_t cbBuffer;
97} DRVTPMHOST;
98/** Pointer to the TPM emulator instance data. */
99typedef DRVTPMHOST *PDRVTPMHOST;
100
101
102/*********************************************************************************************************************************
103* Internal Functions *
104*********************************************************************************************************************************/
105
106/**
107 * Queries the buffer size of the host TPM.
108 *
109 * @returns VBox status code.
110 * @param pThis The host TPM driver instance data.
111 */
112static int drvTpmHostQueryBufferSize(PDRVTPMHOST pThis)
113{
114 uint8_t abResp[_1K];
115 int rc = VINF_SUCCESS;
116
117 switch (pThis->enmTpmVersion)
118 {
119 case TPMVERSION_1_2:
120 {
121 TPMREQGETCAPABILITY Req;
122
123 Req.Hdr.u16Tag = RT_H2BE_U16(TPM_TAG_RQU_COMMAND);
124 Req.Hdr.cbReq = RT_H2BE_U32(sizeof(Req));
125 Req.Hdr.u32Ordinal = RT_H2BE_U32(TPM_ORD_GETCAPABILITY);
126 Req.u32Cap = RT_H2BE_U32(TPM_CAP_PROPERTY);
127 Req.u32Length = RT_H2BE_U32(sizeof(uint32_t));
128 Req.u32SubCap = RT_H2BE_U32(TPM_CAP_PROP_INPUT_BUFFER);
129 rc = RTTpmReqExec(pThis->hTpm, 0 /*bLoc*/, &Req, sizeof(Req), &abResp[0], sizeof(abResp), NULL /*pcbResp*/);
130 break;
131 }
132 case TPMVERSION_2_0:
133 {
134 TPM2REQGETCAPABILITY Req;
135
136 Req.Hdr.u16Tag = RT_H2BE_U16(TPM2_ST_NO_SESSIONS);
137 Req.Hdr.cbReq = RT_H2BE_U32(sizeof(Req));
138 Req.Hdr.u32Ordinal = RT_H2BE_U32(TPM2_CC_GET_CAPABILITY);
139 Req.u32Cap = RT_H2BE_U32(TPM2_CAP_TPM_PROPERTIES);
140 Req.u32Property = RT_H2BE_U32(TPM2_PT_INPUT_BUFFER);
141 Req.u32Count = RT_H2BE_U32(1);
142 rc = RTTpmReqExec(pThis->hTpm, 0 /*bLoc*/, &Req, sizeof(Req), &abResp[0], sizeof(abResp), NULL /*pcbResp*/);
143 break;
144 }
145 default:
146 AssertFailed();
147 }
148
149 if (RT_SUCCESS(rc))
150 {
151 switch (pThis->enmTpmVersion)
152 {
153 case TPMVERSION_1_2:
154 {
155 PCTPMRESPGETBUFSZ pResp = (PCTPMRESPGETBUFSZ)&abResp[0];
156
157 if ( RTTpmRespGetSz(&pResp->Hdr) == sizeof(*pResp)
158 && RT_BE2H_U32(pResp->u32Length) == sizeof(uint32_t))
159 pThis->cbBuffer = RT_BE2H_U32(pResp->cbBuf);
160 else
161 rc = VERR_INVALID_PARAMETER;
162 break;
163 }
164 case TPMVERSION_2_0:
165 {
166 PCTPM2RESPGETBUFSZ pResp = (PCTPM2RESPGETBUFSZ)&abResp[0];
167
168 if ( RTTpmRespGetSz(&pResp->Hdr) == sizeof(*pResp)
169 && RT_BE2H_U32(pResp->u32Count) == 1)
170 pThis->cbBuffer = RT_BE2H_U32(pResp->u32Value);
171 else
172 rc = VERR_INVALID_PARAMETER;
173 break;
174 }
175 default:
176 AssertFailed();
177 }
178 }
179
180 return rc;
181}
182
183
184/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
185static DECLCALLBACK(TPMVERSION) drvTpmHostGetVersion(PPDMITPMCONNECTOR pInterface)
186{
187 PDRVTPMHOST pThis = RT_FROM_MEMBER(pInterface, DRVTPMHOST, ITpmConnector);
188 return pThis->enmTpmVersion;
189}
190
191
192/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetLocalityMax} */
193static DECLCALLBACK(uint32_t) drvTpmHostGetLocalityMax(PPDMITPMCONNECTOR pInterface)
194{
195 PDRVTPMHOST pThis = RT_FROM_MEMBER(pInterface, DRVTPMHOST, ITpmConnector);
196 return RTTpmGetLocalityMax(pThis->hTpm);
197}
198
199
200/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
201static DECLCALLBACK(uint32_t) drvTpmHostGetBufferSize(PPDMITPMCONNECTOR pInterface)
202{
203 PDRVTPMHOST pThis = RT_FROM_MEMBER(pInterface, DRVTPMHOST, ITpmConnector);
204 return pThis->cbBuffer;
205}
206
207
208/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetEstablishedFlag} */
209static DECLCALLBACK(bool) drvTpmHostGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
210{
211 RT_NOREF(pInterface);
212 return false;
213}
214
215
216/** @interface_method_impl{PDMITPMCONNECTOR,pfnResetEstablishedFlag} */
217static DECLCALLBACK(int) drvTpmHostResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
218{
219 RT_NOREF(pInterface, bLoc);
220 return VINF_SUCCESS;
221}
222
223
224/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdExec} */
225static DECLCALLBACK(int) drvTpmHostCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
226{
227 RT_NOREF(bLoc);
228 PDRVTPMHOST pThis = RT_FROM_MEMBER(pInterface, DRVTPMHOST, ITpmConnector);
229
230 return RTTpmReqExec(pThis->hTpm, 0 /*bLoc*/, pvCmd, cbCmd, pvResp, cbResp, NULL /*pcbResp*/);
231}
232
233
234/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdCancel} */
235static DECLCALLBACK(int) drvTpmHostCmdCancel(PPDMITPMCONNECTOR pInterface)
236{
237 PDRVTPMHOST pThis = RT_FROM_MEMBER(pInterface, DRVTPMHOST, ITpmConnector);
238
239 return RTTpmReqCancel(pThis->hTpm);
240}
241
242
243/** @interface_method_impl{PDMIBASE,pfnQueryInterface} */
244static DECLCALLBACK(void *) drvTpmHostQueryInterface(PPDMIBASE pInterface, const char *pszIID)
245{
246 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
247 PDRVTPMHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMHOST);
248 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
249 PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMCONNECTOR, &pThis->ITpmConnector);
250 return NULL;
251}
252
253
254/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
255
256/** @copydoc FNPDMDRVDESTRUCT */
257static DECLCALLBACK(void) drvTpmHostDestruct(PPDMDRVINS pDrvIns)
258{
259 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
260
261 PDRVTPMHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMHOST);
262 LogFlow(("%s\n", __FUNCTION__));
263
264 if (pThis->hTpm != NIL_RTTPM)
265 {
266 int rc = RTTpmClose(pThis->hTpm);
267 AssertRC(rc);
268
269 pThis->hTpm = NIL_RTTPM;
270 }
271}
272
273
274/** @copydoc FNPDMDRVCONSTRUCT */
275static DECLCALLBACK(int) drvTpmHostConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
276{
277 RT_NOREF(fFlags);
278 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
279 PDRVTPMHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMHOST);
280 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
281
282 /*
283 * Init the static parts.
284 */
285 pThis->pDrvIns = pDrvIns;
286 pThis->hTpm = NIL_RTTPM;
287
288 /* IBase */
289 pDrvIns->IBase.pfnQueryInterface = drvTpmHostQueryInterface;
290 /* ITpmConnector */
291 pThis->ITpmConnector.pfnGetVersion = drvTpmHostGetVersion;
292 pThis->ITpmConnector.pfnGetLocalityMax = drvTpmHostGetLocalityMax;
293 pThis->ITpmConnector.pfnGetBufferSize = drvTpmHostGetBufferSize;
294 pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmHostGetEstablishedFlag;
295 pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmHostResetEstablishedFlag;
296 pThis->ITpmConnector.pfnCmdExec = drvTpmHostCmdExec;
297 pThis->ITpmConnector.pfnCmdCancel = drvTpmHostCmdCancel;
298
299 /*
300 * Validate and read the configuration.
301 */
302 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TpmId", "");
303
304 uint32_t idTpm = RTTPM_ID_DEFAULT;
305 int rc = pHlp->pfnCFGMQueryU32Def(pCfg, "TpmId", &idTpm, RTTPM_ID_DEFAULT);
306 if (RT_FAILURE(rc))
307 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
308 N_("Configuration error: querying \"TpmId\" resulted in %Rrc"), rc);
309
310 rc = RTTpmOpen(&pThis->hTpm, idTpm);
311 if (RT_FAILURE(rc))
312 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
313 N_("DrvTpmHost%d: Opening TPM with id %u failed with %Rrc"), pDrvIns->iInstance, idTpm, rc);
314
315 RTTPMVERSION enmVersion = RTTpmGetVersion(pThis->hTpm);
316
317 switch (enmVersion)
318 {
319 case RTTPMVERSION_1_2:
320 pThis->enmTpmVersion = TPMVERSION_1_2;
321 break;
322 case RTTPMVERSION_2_0:
323 pThis->enmTpmVersion = TPMVERSION_2_0;
324 break;
325 case RTTPMVERSION_UNKNOWN:
326 default:
327 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
328 N_("DrvTpmHost%d: TPM version %u of TPM id %u is not supported"),
329 pDrvIns->iInstance, enmVersion, idTpm);
330 }
331
332 rc = drvTpmHostQueryBufferSize(pThis);
333 if (RT_FAILURE(rc))
334 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
335 N_("DrvTpmHost%d: Querying input buffer size of TPM with id %u failed with %Rrc"),
336 pDrvIns->iInstance, idTpm, rc);
337
338 LogRel(("DrvTpmHost#%d: Connected to TPM %u.\n", pDrvIns->iInstance, idTpm));
339 return VINF_SUCCESS;
340}
341
342
343/**
344 * TPM host driver registration record.
345 */
346const PDMDRVREG g_DrvTpmHost =
347{
348 /* u32Version */
349 PDM_DRVREG_VERSION,
350 /* szName */
351 "TpmHost",
352 /* szRCMod */
353 "",
354 /* szR0Mod */
355 "",
356 /* pszDescription */
357 "TPM host driver.",
358 /* fFlags */
359 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
360 /* fClass. */
361 PDM_DRVREG_CLASS_STREAM,
362 /* cMaxInstances */
363 ~0U,
364 /* cbInstance */
365 sizeof(DRVTPMHOST),
366 /* pfnConstruct */
367 drvTpmHostConstruct,
368 /* pfnDestruct */
369 drvTpmHostDestruct,
370 /* pfnRelocate */
371 NULL,
372 /* pfnIOCtl */
373 NULL,
374 /* pfnPowerOn */
375 NULL,
376 /* pfnReset */
377 NULL,
378 /* pfnSuspend */
379 NULL,
380 /* pfnResume */
381 NULL,
382 /* pfnAttach */
383 NULL,
384 /* pfnDetach */
385 NULL,
386 /* pfnPowerOff */
387 NULL,
388 /* pfnSoftReset */
389 NULL,
390 /* u32EndVersion */
391 PDM_DRVREG_VERSION
392};
393
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette