VirtualBox

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

Last change on this file since 106129 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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