[90530] | 1 | /* $Id: DrvTpmEmu.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * TPM emulator using a TCP/socket interface to talk to swtpm (https://github.com/stefanberger/swtpm).
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2021-2023 Oracle and/or its affiliates.
|
---|
[90530] | 8 | *
|
---|
[96407] | 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
|
---|
[90530] | 26 | */
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[91137] | 32 | #define LOG_GROUP LOG_GROUP_DRV_TPM_EMU
|
---|
[90530] | 33 | #include <VBox/vmm/pdmdrv.h>
|
---|
| 34 | #include <VBox/vmm/pdmtpmifs.h>
|
---|
| 35 | #include <iprt/assert.h>
|
---|
| 36 | #include <iprt/file.h>
|
---|
| 37 | #include <iprt/stream.h>
|
---|
| 38 | #include <iprt/alloc.h>
|
---|
| 39 | #include <iprt/pipe.h>
|
---|
| 40 | #include <iprt/poll.h>
|
---|
| 41 | #include <iprt/string.h>
|
---|
| 42 | #include <iprt/semaphore.h>
|
---|
| 43 | #include <iprt/socket.h>
|
---|
| 44 | #include <iprt/tcp.h>
|
---|
| 45 | #include <iprt/uuid.h>
|
---|
| 46 | #include <iprt/json.h>
|
---|
| 47 |
|
---|
[90587] | 48 | #include <iprt/formats/tpm.h>
|
---|
| 49 |
|
---|
[90530] | 50 | #include "VBoxDD.h"
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 | /*********************************************************************************************************************************
|
---|
| 54 | * Defined Constants And Macros *
|
---|
| 55 | *********************************************************************************************************************************/
|
---|
| 56 |
|
---|
| 57 |
|
---|
| 58 | /*********************************************************************************************************************************
|
---|
| 59 | * Structures and Typedefs *
|
---|
| 60 | *********************************************************************************************************************************/
|
---|
| 61 |
|
---|
| 62 | /** @name Protocol definitions to communicate with swtpm, taken from https://github.com/stefanberger/swtpm/blob/master/include/swtpm/tpm_ioctl.h
|
---|
| 63 | * @{ */
|
---|
| 64 | /**
|
---|
| 65 | * Commands going over the control channel (big endian).
|
---|
| 66 | */
|
---|
| 67 | typedef enum SWTPMCMD
|
---|
| 68 | {
|
---|
| 69 | /** Not used. */
|
---|
| 70 | SWTPMCMD_INVALID = 0,
|
---|
| 71 | SWTPMCMD_GET_CAPABILITY,
|
---|
| 72 | SWTPMCMD_INIT,
|
---|
| 73 | SWTPMCMD_SHUTDOWN,
|
---|
| 74 | SWTPMCMD_GET_TPMESTABLISHED,
|
---|
| 75 | SWTPMCMD_SET_LOCALITY,
|
---|
| 76 | SWTPMCMD_HASH_START,
|
---|
| 77 | SWTPMCMD_HASH_DATA,
|
---|
| 78 | SWTPMCMD_HASH_END,
|
---|
| 79 | SWTPMCMD_CANCEL_TPM_CMD,
|
---|
| 80 | SWTPMCMD_STORE_VOLATILE,
|
---|
| 81 | SWTPMCMD_RESET_TPMESTABLISHED,
|
---|
| 82 | SWTPMCMD_GET_STATEBLOB,
|
---|
| 83 | SWTPMCMD_SET_STATEBLOB,
|
---|
| 84 | SWTPMCMD_STOP,
|
---|
| 85 | SWTPMCMD_GET_CONFIG,
|
---|
| 86 | SWTPMCMD_SET_DATAFD,
|
---|
| 87 | SWTPMCMD_SET_BUFFERSIZE,
|
---|
| 88 | SWTPMCMD_GET_INFO,
|
---|
| 89 | /** Blow the enum up to a 32bit size. */
|
---|
| 90 | SWTPMCMD_32BIT_HACK = 0x7fffffff
|
---|
| 91 | } SWTPMCMD;
|
---|
| 92 |
|
---|
| 93 |
|
---|
| 94 | /**
|
---|
| 95 | * Command/Response header.
|
---|
| 96 | */
|
---|
| 97 | typedef union SWTPMHDR
|
---|
| 98 | {
|
---|
| 99 | /** The command opcode. */
|
---|
| 100 | SWTPMCMD enmCmd;
|
---|
| 101 | /** The response result. */
|
---|
| 102 | uint32_t u32Resp;
|
---|
| 103 | } SWTPMHDR;
|
---|
| 104 | AssertCompileSize(SWTPMHDR, sizeof(uint32_t));
|
---|
| 105 | /** Pointer to a command/response header. */
|
---|
| 106 | typedef SWTPMHDR *PSWTPMHDR;
|
---|
| 107 | /** Pointer to a const command/response header. */
|
---|
| 108 | typedef const SWTPMHDR *PCSWTPMHDR;
|
---|
| 109 |
|
---|
| 110 |
|
---|
| 111 | /**
|
---|
| 112 | * Additional command data for SWTPMCMD_INIT.
|
---|
| 113 | */
|
---|
| 114 | typedef struct SWTPMCMDTPMINIT
|
---|
| 115 | {
|
---|
| 116 | /** Additional flags */
|
---|
| 117 | uint32_t u32Flags;
|
---|
| 118 | } SWTPMCMDTPMINIT;
|
---|
| 119 | /** Pointer to a command data struct for SWTPMCMD_INIT. */
|
---|
| 120 | typedef SWTPMCMDTPMINIT *PSWTPMCMDTPMINIT;
|
---|
| 121 | /** Pointer to a const command data struct for SWTPMCMD_INIT. */
|
---|
| 122 | typedef const SWTPMCMDTPMINIT *PCSWTPMCMDTPMINIT;
|
---|
| 123 |
|
---|
| 124 |
|
---|
[90580] | 125 | /** @name Capabilities as returned by SWTPMCMD_INIT.
|
---|
| 126 | * @{ */
|
---|
| 127 | #define SWTPMCMD_INIT_F_DELETE_VOLATILE RT_BIT_32(0);
|
---|
| 128 | /** @} */
|
---|
| 129 |
|
---|
| 130 |
|
---|
[90530] | 131 | /**
|
---|
| 132 | * Response data for a SWTPMCMD_GET_CAPABILITY command.
|
---|
| 133 | */
|
---|
| 134 | typedef struct SWTPMRESPGETCAPABILITY
|
---|
| 135 | {
|
---|
| 136 | /** The capabilities supported. */
|
---|
| 137 | uint32_t u32Caps;
|
---|
| 138 | } SWTPMRESPGETCAPABILITY;
|
---|
| 139 | /** Pointer to a response data struct for SWTPMCMD_GET_CAPABILITY. */
|
---|
| 140 | typedef SWTPMRESPGETCAPABILITY *PSWTPMRESPGETCAPABILITY;
|
---|
| 141 | /** Pointer to a const response data struct for SWTPMCMD_GET_CAPABILITY. */
|
---|
| 142 | typedef const SWTPMRESPGETCAPABILITY *PCSWTPMRESPGETCAPABILITY;
|
---|
| 143 |
|
---|
| 144 |
|
---|
| 145 | /** @name Capabilities as returned by SWTPMCMD_GET_CAPABILITY.
|
---|
| 146 | * @{ */
|
---|
| 147 | #define SWTPM_CAP_INIT RT_BIT_32(0)
|
---|
| 148 | #define SWTPM_CAP_SHUTDOWN RT_BIT_32(1)
|
---|
| 149 | #define SWTPM_CAP_GET_TPMESTABLISHED RT_BIT_32(2)
|
---|
| 150 | #define SWTPM_CAP_SET_LOCALITY RT_BIT_32(3)
|
---|
| 151 | #define SWTPM_CAP_HASHING RT_BIT_32(4)
|
---|
| 152 | #define SWTPM_CAP_CANCEL_TPM_CMD RT_BIT_32(5)
|
---|
| 153 | #define SWTPM_CAP_STORE_VOLATILE RT_BIT_32(6)
|
---|
| 154 | #define SWTPM_CAP_RESET_TPMESTABLISHED RT_BIT_32(7)
|
---|
| 155 | #define SWTPM_CAP_GET_STATEBLOB RT_BIT_32(8)
|
---|
| 156 | #define SWTPM_CAP_SET_STATEBLOB RT_BIT_32(9)
|
---|
| 157 | #define SWTPM_CAP_STOP RT_BIT_32(10)
|
---|
| 158 | #define SWTPM_CAP_GET_CONFIG RT_BIT_32(11)
|
---|
| 159 | #define SWTPM_CAP_SET_DATAFD RT_BIT_32(12)
|
---|
| 160 | #define SWTPM_CAP_SET_BUFFERSIZE RT_BIT_32(13)
|
---|
| 161 | #define SWTPM_CAP_GET_INFO RT_BIT_32(14)
|
---|
| 162 | #define SWTPM_CAP_SEND_COMMAND_HEADER RT_BIT_32(15)
|
---|
| 163 | /** @} */
|
---|
| 164 |
|
---|
| 165 |
|
---|
| 166 | /**
|
---|
[90580] | 167 | * Additional command data for SWTPMCMD_SET_LOCALITY.
|
---|
| 168 | */
|
---|
| 169 | typedef struct SWTPMCMDSETLOCALITY
|
---|
| 170 | {
|
---|
| 171 | /** The locality to set */
|
---|
| 172 | uint8_t bLoc;
|
---|
| 173 | } SWTPMCMDSETLOCALITY;
|
---|
| 174 | /** Pointer to a command data struct for SWTPMCMD_SET_LOCALITY. */
|
---|
| 175 | typedef SWTPMCMDSETLOCALITY *PSWTPMCMDSETLOCALITY;
|
---|
| 176 | /** Pointer to a const command data struct for SWTPMCMD_SET_LOCALITY. */
|
---|
| 177 | typedef const SWTPMCMDSETLOCALITY *PCSWTPMCMDSETLOCALITY;
|
---|
| 178 |
|
---|
| 179 |
|
---|
| 180 | /**
|
---|
[90530] | 181 | * Additional command data for SWTPMCMD_GET_CONFIG.
|
---|
| 182 | */
|
---|
| 183 | typedef struct SWTPMCMDGETCONFIG
|
---|
| 184 | {
|
---|
| 185 | /** Combination of SWTPM_GET_CONFIG_F_XXX. */
|
---|
| 186 | uint64_t u64Flags;
|
---|
| 187 | /** The offset where to start reading from. */
|
---|
| 188 | uint32_t u32Offset;
|
---|
| 189 | /** Some padding to a 8 byte alignment. */
|
---|
| 190 | uint32_t u32Padding;
|
---|
| 191 | } SWTPMCMDGETCONFIG;
|
---|
| 192 | /** Pointer to a response data struct for SWTPMCMD_GET_CONFIG. */
|
---|
| 193 | typedef SWTPMCMDGETCONFIG *PSWTPMCMDGETCONFIG;
|
---|
| 194 | /** Pointer to a const response data struct for SWTPMCMD_GET_CONFIG. */
|
---|
| 195 | typedef const SWTPMCMDGETCONFIG *PCSWTPMCMDGETCONFIG;
|
---|
| 196 |
|
---|
| 197 |
|
---|
| 198 | /** @name Flags for SWTPMCMDGETCONFIG::u64Flags.
|
---|
| 199 | * @{ */
|
---|
| 200 | /** Return the TPM specification JSON object. */
|
---|
| 201 | #define SWTPM_GET_CONFIG_F_TPM_SPECIFICATION RT_BIT_64(0)
|
---|
| 202 | /** Return the TPM attributes JSON object. */
|
---|
| 203 | #define SWTPM_GET_CONFIG_F_TPM_ATTRIBUTES RT_BIT_64(1)
|
---|
| 204 | /** @} */
|
---|
| 205 |
|
---|
| 206 |
|
---|
| 207 | /**
|
---|
| 208 | * Response data for a SWTPMCMD_GET_CONFIG command.
|
---|
| 209 | */
|
---|
| 210 | typedef struct SWTPMRESPGETCONFIG
|
---|
| 211 | {
|
---|
| 212 | /** Total size of the object in bytes. */
|
---|
| 213 | uint32_t cbTotal;
|
---|
| 214 | /** Size of the chunk returned in this response. */
|
---|
| 215 | uint32_t cbThis;
|
---|
| 216 | } SWTPMRESPGETCONFIG;
|
---|
| 217 | /** Pointer to a response data struct for SWTPMCMD_GET_CONFIG. */
|
---|
| 218 | typedef SWTPMRESPGETCONFIG *PSWTPMRESPGETCONFIG;
|
---|
| 219 | /** Pointer to a const response data struct for SWTPMCMD_GET_CONFIG. */
|
---|
| 220 | typedef const SWTPMRESPGETCONFIG *PCSWTPMRESPGETCONFIG;
|
---|
| 221 |
|
---|
| 222 |
|
---|
| 223 | /**
|
---|
[90580] | 224 | * Response data for a SWTPMCMD_GET_TPMESTABLISHED command.
|
---|
| 225 | */
|
---|
| 226 | typedef struct SWTPMRESPGETTPMEST
|
---|
| 227 | {
|
---|
| 228 | /** Flag whether the TPM established bit is set for the TPM. */
|
---|
| 229 | uint8_t fEst;
|
---|
| 230 | } SWTPMRESPGETTPMEST;
|
---|
| 231 | /** Pointer to a response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
|
---|
| 232 | typedef SWTPMRESPGETTPMEST *PSWTPMRESPGETTPMEST;
|
---|
| 233 | /** Pointer to a const response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
|
---|
| 234 | typedef const SWTPMRESPGETTPMEST *PCSWTPMRESPGETTPMEST;
|
---|
| 235 |
|
---|
| 236 |
|
---|
| 237 | /**
|
---|
| 238 | * Additional command data for SWTPMCMD_RESET_TPMESTABLISHED.
|
---|
| 239 | */
|
---|
| 240 | typedef struct SWTPMCMDRSTEST
|
---|
| 241 | {
|
---|
| 242 | /** The locality resetting trying to reset the established bit. */
|
---|
[91005] | 243 | uint8_t bLoc;
|
---|
[90580] | 244 | } SWTPMCMDRSTEST;
|
---|
| 245 | /** Pointer to a response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
|
---|
| 246 | typedef SWTPMCMDRSTEST *PSWTPMCMDRSTEST;
|
---|
| 247 | /** Pointer to a const response data struct for SWTPMCMD_GET_TPMESTABLISHED. */
|
---|
| 248 | typedef const SWTPMCMDRSTEST *PCSWTPMCMDRSTEST;
|
---|
| 249 |
|
---|
| 250 |
|
---|
| 251 | /**
|
---|
[91005] | 252 | * Additional command data for SWTPMCMD_SET_BUFFERSIZE.
|
---|
| 253 | */
|
---|
| 254 | typedef struct SWTPMCMDSETBUFSZ
|
---|
| 255 | {
|
---|
| 256 | /** The buffer size to set, 0 to query for the currently used buffer size. */
|
---|
| 257 | uint32_t cbBuffer;
|
---|
| 258 | } SWTPMCMDSETBUFSZ;
|
---|
| 259 | /** Pointer to a command data struct for SWTPMCMD_SET_BUFFERSIZE. */
|
---|
| 260 | typedef SWTPMCMDSETBUFSZ *PSWTPMCMDSETBUFSZ;
|
---|
| 261 | /** Pointer to a const command data struct for SWTPMCMD_SET_BUFFERSIZE. */
|
---|
| 262 | typedef const SWTPMCMDSETBUFSZ *PCSWTPMCMDSETBUFSZ;
|
---|
| 263 |
|
---|
| 264 |
|
---|
| 265 | /**
|
---|
| 266 | * Response data for a SWTPMCMD_SET_BUFFERSIZE command.
|
---|
| 267 | */
|
---|
| 268 | typedef struct SWTPMRESPSETBUFSZ
|
---|
| 269 | {
|
---|
| 270 | /** Buffer size in use. */
|
---|
| 271 | uint32_t cbBuffer;
|
---|
| 272 | /** Minimum supported buffer size. */
|
---|
| 273 | uint32_t cbBufferMin;
|
---|
| 274 | /** Maximum supported buffer size. */
|
---|
| 275 | uint32_t cbBufferMax;
|
---|
| 276 | } SWTPMRESPSETBUFSZ;
|
---|
| 277 | /** Pointer to a response data struct for SWTPMCMD_SET_BUFFERSIZE. */
|
---|
| 278 | typedef SWTPMRESPSETBUFSZ *PSWTPMRESPSETBUFSZ;
|
---|
| 279 | /** Pointer to a const response data struct for SWTPMCMD_SET_BUFFERSIZE. */
|
---|
| 280 | typedef const SWTPMRESPSETBUFSZ *PCSWTPMRESPSETBUFSZ;
|
---|
| 281 |
|
---|
| 282 |
|
---|
| 283 | /**
|
---|
[90530] | 284 | * TPM emulator driver instance data.
|
---|
| 285 | *
|
---|
| 286 | * @implements PDMITPMCONNECTOR
|
---|
| 287 | */
|
---|
| 288 | typedef struct DRVTPMEMU
|
---|
| 289 | {
|
---|
| 290 | /** The stream interface. */
|
---|
| 291 | PDMITPMCONNECTOR ITpmConnector;
|
---|
| 292 | /** Pointer to the driver instance. */
|
---|
| 293 | PPDMDRVINS pDrvIns;
|
---|
| 294 |
|
---|
| 295 | /** Socket handle for the control connection. */
|
---|
| 296 | RTSOCKET hSockCtrl;
|
---|
| 297 | /** Socket handle for the data connection. */
|
---|
| 298 | RTSOCKET hSockData;
|
---|
| 299 |
|
---|
[90580] | 300 | /** Currently set locality. */
|
---|
| 301 | uint8_t bLoc;
|
---|
[90530] | 302 |
|
---|
| 303 | /** TPM version offered by the emulator. */
|
---|
| 304 | TPMVERSION enmTpmVers;
|
---|
[90580] | 305 | /** Capabilities offered by the TPM emulator. */
|
---|
| 306 | uint32_t fCaps;
|
---|
[91005] | 307 | /** Buffer size for the emulated TPM. */
|
---|
| 308 | uint32_t cbBuffer;
|
---|
[90530] | 309 | } DRVTPMEMU;
|
---|
| 310 | /** Pointer to the TPM emulator instance data. */
|
---|
| 311 | typedef DRVTPMEMU *PDRVTPMEMU;
|
---|
| 312 |
|
---|
[90580] | 313 | /** The special no current locality selected value. */
|
---|
| 314 | #define TPM_NO_LOCALITY_SELECTED 0xff
|
---|
[90530] | 315 |
|
---|
[90580] | 316 |
|
---|
[90530] | 317 | /*********************************************************************************************************************************
|
---|
| 318 | * Internal Functions *
|
---|
| 319 | *********************************************************************************************************************************/
|
---|
| 320 |
|
---|
| 321 | /**
|
---|
| 322 | * Executes the given command over the control connection to the TPM emulator.
|
---|
| 323 | *
|
---|
| 324 | * @returns VBox status code.
|
---|
| 325 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 326 | * @param enmCmd The command to execute.
|
---|
| 327 | * @param pvCmd Additional command data to send.
|
---|
| 328 | * @param cbCmd Size of the additional command data in bytes.
|
---|
| 329 | * @param pu32Resp Where to store the response code from the reply.
|
---|
| 330 | * @param pvResp Where to store additional resposne data.
|
---|
| 331 | * @param cbResp Size of the Response data in bytes (excluding the response status code which is implicit).
|
---|
| 332 | * @param cMillies Number of milliseconds to wait before aborting the command with a timeout error.
|
---|
| 333 | *
|
---|
| 334 | * @note This method can return success even though the request at such failed, check the content of pu32Resp!
|
---|
| 335 | */
|
---|
| 336 | static int drvTpmEmuExecCtrlCmdEx(PDRVTPMEMU pThis, SWTPMCMD enmCmd, const void *pvCmd, size_t cbCmd, uint32_t *pu32Resp,
|
---|
| 337 | void *pvResp, size_t cbResp, RTMSINTERVAL cMillies)
|
---|
| 338 | {
|
---|
| 339 | SWTPMHDR Hdr;
|
---|
| 340 | RTSGBUF SgBuf;
|
---|
| 341 | RTSGSEG aSegs[2];
|
---|
| 342 | uint32_t cSegs = 1;
|
---|
| 343 |
|
---|
| 344 | Hdr.enmCmd = (SWTPMCMD)RT_H2BE_U32(enmCmd);
|
---|
| 345 | aSegs[0].pvSeg = &Hdr;
|
---|
| 346 | aSegs[0].cbSeg = sizeof(Hdr);
|
---|
| 347 | if (cbCmd)
|
---|
| 348 | {
|
---|
| 349 | cSegs++;
|
---|
| 350 | aSegs[1].pvSeg = (void *)pvCmd;
|
---|
| 351 | aSegs[1].cbSeg = cbCmd;
|
---|
| 352 | }
|
---|
| 353 |
|
---|
| 354 | RTSgBufInit(&SgBuf, &aSegs[0], cSegs);
|
---|
| 355 | int rc = RTSocketSgWrite(pThis->hSockCtrl, &SgBuf);
|
---|
| 356 | if (RT_SUCCESS(rc))
|
---|
| 357 | {
|
---|
| 358 | rc = RTSocketSelectOne(pThis->hSockCtrl, cMillies);
|
---|
| 359 | if (RT_SUCCESS(rc))
|
---|
| 360 | {
|
---|
| 361 | uint32_t u32Resp = 0;
|
---|
| 362 | rc = RTSocketRead(pThis->hSockCtrl, &u32Resp, sizeof(u32Resp), NULL /*pcbRead*/);
|
---|
| 363 | if (RT_SUCCESS(rc))
|
---|
| 364 | {
|
---|
| 365 | *pu32Resp = RT_BE2H_U32(u32Resp);
|
---|
| 366 | if (*pu32Resp == 0)
|
---|
[90580] | 367 | {
|
---|
| 368 | if (cbResp)
|
---|
| 369 | rc = RTSocketRead(pThis->hSockCtrl, pvResp, cbResp, NULL /*pcbRead*/);
|
---|
| 370 | }
|
---|
| 371 | else
|
---|
| 372 | rc = VERR_NET_IO_ERROR;
|
---|
[90530] | 373 | }
|
---|
| 374 | }
|
---|
| 375 | }
|
---|
| 376 |
|
---|
| 377 | return rc;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 |
|
---|
| 381 | /**
|
---|
[90580] | 382 | * Continue receiving a response from a previous call of drvTpmEmuExecCtrlCmdEx() or
|
---|
| 383 | * drvTpmEmuExecCtrlCmdNoPayload().
|
---|
| 384 | *
|
---|
| 385 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 386 | * @param enmCmd The command to execute.
|
---|
| 387 | * @param pvResp Where to store additional resposne data.
|
---|
| 388 | * @param cbResp Size of the additional response data in bytes.
|
---|
| 389 | * @param cMillies Number of milliseconds to wait before aborting the receive with a timeout error.
|
---|
| 390 | */
|
---|
| 391 | static int drvTpmEmuExecCtrlCmdRespCont(PDRVTPMEMU pThis, void *pvResp, size_t cbResp, RTMSINTERVAL cMillies)
|
---|
| 392 | {
|
---|
| 393 | int rc = RTSocketSelectOne(pThis->hSockCtrl, cMillies);
|
---|
| 394 | if (RT_SUCCESS(rc))
|
---|
| 395 | rc = RTSocketRead(pThis->hSockCtrl, pvResp, cbResp, NULL /*pcbRead*/);
|
---|
| 396 |
|
---|
| 397 | return rc;
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 |
|
---|
| 401 | /**
|
---|
[90530] | 402 | * Executes the given command over the control connection to the TPM emulator - variant with no command payload.
|
---|
| 403 | *
|
---|
| 404 | * @returns VBox status code.
|
---|
| 405 | * @retval VERR_NET_IO_ERROR if the executed command returned an error in the response status field.
|
---|
| 406 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 407 | * @param enmCmd The command to execute.
|
---|
| 408 | * @param pvResp Where to store additional resposne data.
|
---|
| 409 | * @param cbResp Size of the Response data in bytes (excluding the response status code which is implicit).
|
---|
| 410 | * @param cMillies Number of milliseconds to wait before aborting the command with a timeout error.
|
---|
| 411 | */
|
---|
| 412 | static int drvTpmEmuExecCtrlCmdNoPayload(PDRVTPMEMU pThis, SWTPMCMD enmCmd, void *pvResp, size_t cbResp, RTMSINTERVAL cMillies)
|
---|
| 413 | {
|
---|
| 414 | uint32_t u32Resp = 0;
|
---|
| 415 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, enmCmd, NULL /*pvCmd*/, 0 /*cbCmd*/, &u32Resp,
|
---|
| 416 | pvResp, cbResp, cMillies);
|
---|
| 417 | if (RT_SUCCESS(rc))
|
---|
| 418 | {
|
---|
| 419 | if (u32Resp != 0)
|
---|
| 420 | rc = VERR_NET_IO_ERROR;
|
---|
| 421 | }
|
---|
| 422 |
|
---|
| 423 | return rc;
|
---|
| 424 | }
|
---|
| 425 |
|
---|
| 426 |
|
---|
| 427 | /**
|
---|
[90580] | 428 | * Executes the given command over the control connection to the TPM emulator - variant with no response payload other than the result.
|
---|
| 429 | *
|
---|
| 430 | * @returns VBox status code.
|
---|
| 431 | * @retval VERR_NET_IO_ERROR if the executed command returned an error in the response status field.
|
---|
| 432 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 433 | * @param enmCmd The command to execute.
|
---|
| 434 | * @param pvCmd Additional command data to send.
|
---|
| 435 | * @param cbCmd Size of the additional command data in bytes.
|
---|
| 436 | * @param pu32Resp Where to store the response code from the reply.
|
---|
| 437 | * @param cMillies Number of milliseconds to wait before aborting the command with a timeout error.
|
---|
| 438 | */
|
---|
| 439 | static int drvTpmEmuExecCtrlCmdNoResp(PDRVTPMEMU pThis, SWTPMCMD enmCmd, const void *pvCmd, size_t cbCmd, uint32_t *pu32Resp,
|
---|
| 440 | RTMSINTERVAL cMillies)
|
---|
| 441 | {
|
---|
| 442 | return drvTpmEmuExecCtrlCmdEx(pThis, enmCmd, pvCmd, cbCmd, pu32Resp,
|
---|
| 443 | NULL /*pvResp*/, 0 /*cbResp*/, cMillies);
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 |
|
---|
| 447 | /**
|
---|
[91046] | 448 | * Executes the given command over the control connection to the TPM emulator - variant with no command and response payload.
|
---|
[90587] | 449 | *
|
---|
| 450 | * @returns VBox status code.
|
---|
| 451 | * @retval VERR_NET_IO_ERROR if the executed command returned an error in the response status field.
|
---|
| 452 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 453 | * @param enmCmd The command to execute.
|
---|
| 454 | * @param cMillies Number of milliseconds to wait before aborting the command with a timeout error.
|
---|
| 455 | */
|
---|
| 456 | static int drvTpmEmuExecCtrlCmdNoPayloadAndResp(PDRVTPMEMU pThis, SWTPMCMD enmCmd, RTMSINTERVAL cMillies)
|
---|
| 457 | {
|
---|
| 458 | uint32_t u32Resp = 0;
|
---|
| 459 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, enmCmd, NULL /*pvCmd*/, 0 /*cbCmd*/, &u32Resp,
|
---|
| 460 | NULL /*pvResp*/, 0 /*cbResp*/, cMillies);
|
---|
| 461 | if (RT_SUCCESS(rc))
|
---|
| 462 | {
|
---|
| 463 | if (u32Resp != 0)
|
---|
| 464 | rc = VERR_NET_IO_ERROR;
|
---|
| 465 | }
|
---|
| 466 |
|
---|
| 467 | return rc;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 |
|
---|
| 471 | /**
|
---|
[90530] | 472 | * Queries the version of the TPM offered by the remote emulator.
|
---|
| 473 | *
|
---|
| 474 | * @returns VBox status code.
|
---|
| 475 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 476 | */
|
---|
| 477 | static int drvTpmEmuQueryTpmVersion(PDRVTPMEMU pThis)
|
---|
| 478 | {
|
---|
| 479 | SWTPMCMDGETCONFIG Cmd;
|
---|
| 480 | SWTPMRESPGETCONFIG Resp;
|
---|
[90580] | 481 | uint8_t abData[_4K];
|
---|
[90530] | 482 | uint32_t u32Resp = 0;
|
---|
| 483 |
|
---|
| 484 | RT_ZERO(Cmd); RT_ZERO(Resp);
|
---|
| 485 | Cmd.u64Flags = RT_H2BE_U64(SWTPM_GET_CONFIG_F_TPM_SPECIFICATION);
|
---|
| 486 | Cmd.u32Offset = 0;
|
---|
[90580] | 487 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_GET_INFO, &Cmd, sizeof(Cmd), &u32Resp,
|
---|
[90530] | 488 | &Resp, sizeof(Resp), RT_MS_10SEC);
|
---|
| 489 | if (RT_SUCCESS(rc))
|
---|
| 490 | {
|
---|
[90580] | 491 | /*
|
---|
| 492 | * Currently it is not necessary to get the information in chunks, a single
|
---|
| 493 | * transaction is enough. To fend off future versions of swtpm requiring this
|
---|
| 494 | * we return an error here if the total length is not equal to the length of the chunk.
|
---|
| 495 | */
|
---|
[90530] | 496 | if (RT_BE2H_U32(Resp.cbTotal) == RT_BE2H_U32(Resp.cbThis))
|
---|
| 497 | {
|
---|
[90580] | 498 | /* Fetch the response body. */
|
---|
| 499 | rc = drvTpmEmuExecCtrlCmdRespCont(pThis, &abData[0], RT_BE2H_U32(Resp.cbThis), RT_MS_10SEC);
|
---|
[90530] | 500 | if (RT_SUCCESS(rc))
|
---|
| 501 | {
|
---|
[90580] | 502 | RTJSONVAL hJsonVal = NIL_RTJSONVAL;
|
---|
| 503 | rc = RTJsonParseFromBuf(&hJsonVal, &abData[0], RT_BE2H_U32(Resp.cbThis), NULL /*pErrInfo*/);
|
---|
| 504 | if (RT_SUCCESS(rc))
|
---|
| 505 | {
|
---|
| 506 | RTJSONVAL hJsonTpmSpec = NIL_RTJSONVAL;
|
---|
| 507 | rc = RTJsonValueQueryByName(hJsonVal, "TPMSpecification", &hJsonTpmSpec);
|
---|
| 508 | if (RT_SUCCESS(rc))
|
---|
| 509 | {
|
---|
| 510 | RTJSONVAL hJsonTpmFam = NIL_RTJSONVAL;
|
---|
| 511 | rc = RTJsonValueQueryByName(hJsonTpmSpec, "family", &hJsonTpmFam);
|
---|
| 512 | if (RT_SUCCESS(rc))
|
---|
| 513 | {
|
---|
| 514 | const char *pszFam = NULL;
|
---|
| 515 | rc = RTJsonValueQueryString(hJsonTpmFam, &pszFam);
|
---|
| 516 | if (RT_SUCCESS(rc))
|
---|
| 517 | {
|
---|
| 518 | if (!RTStrCmp(pszFam, "1.2"))
|
---|
| 519 | pThis->enmTpmVers = TPMVERSION_1_2;
|
---|
| 520 | else if (!RTStrCmp(pszFam, "2.0"))
|
---|
| 521 | pThis->enmTpmVers = TPMVERSION_2_0;
|
---|
| 522 | else
|
---|
| 523 | pThis->enmTpmVers = TPMVERSION_UNKNOWN;
|
---|
| 524 | }
|
---|
| 525 |
|
---|
| 526 | RTJsonValueRelease(hJsonTpmFam);
|
---|
| 527 | }
|
---|
| 528 |
|
---|
| 529 | RTJsonValueRelease(hJsonTpmSpec);
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 | RTJsonValueRelease(hJsonVal);
|
---|
| 533 | }
|
---|
[90530] | 534 | }
|
---|
| 535 | }
|
---|
| 536 | else
|
---|
| 537 | rc = VERR_NOT_SUPPORTED;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | return rc;
|
---|
| 541 | }
|
---|
| 542 |
|
---|
| 543 |
|
---|
| 544 | /**
|
---|
| 545 | * Queries the capabilities of the remote TPM emulator and verifies that
|
---|
| 546 | * it offers everything we require for operation.
|
---|
| 547 | *
|
---|
| 548 | * @returns VBox status code.
|
---|
| 549 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 550 | */
|
---|
[90580] | 551 | static int drvTpmEmuQueryCaps(PDRVTPMEMU pThis)
|
---|
[90530] | 552 | {
|
---|
| 553 | SWTPMRESPGETCAPABILITY Resp;
|
---|
| 554 | int rc = drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_GET_CAPABILITY, &Resp, sizeof(Resp), RT_MS_10SEC);
|
---|
| 555 | if (RT_SUCCESS(rc))
|
---|
[90580] | 556 | pThis->fCaps = RT_BE2H_U32(Resp.u32Caps);
|
---|
[90530] | 557 |
|
---|
| 558 | return rc;
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 |
|
---|
[90580] | 562 | /**
|
---|
[91005] | 563 | * Queries the maximum supported buffer size by the emulation.
|
---|
| 564 | *
|
---|
| 565 | * @returns VBox status code.
|
---|
| 566 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 567 | * @param pcbBufferMax Where to store the maximum supported buffer size on success.
|
---|
| 568 | */
|
---|
| 569 | static int drvTpmEmuQueryBufferSzMax(PDRVTPMEMU pThis, uint32_t *pcbBufferMax)
|
---|
| 570 | {
|
---|
| 571 | SWTPMCMDSETBUFSZ Cmd;
|
---|
| 572 | SWTPMRESPSETBUFSZ Resp;
|
---|
| 573 | uint32_t u32Resp = 0;
|
---|
| 574 |
|
---|
| 575 | RT_ZERO(Cmd); RT_ZERO(Resp);
|
---|
| 576 | Cmd.cbBuffer = RT_H2BE_U32(0);
|
---|
| 577 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_SET_BUFFERSIZE, &Cmd, sizeof(Cmd), &u32Resp,
|
---|
| 578 | &Resp, sizeof(Resp), RT_MS_10SEC);
|
---|
| 579 | if (RT_SUCCESS(rc))
|
---|
| 580 | {
|
---|
| 581 | if (u32Resp == 0)
|
---|
| 582 | *pcbBufferMax = RT_BE2H_U32(Resp.cbBufferMax);
|
---|
| 583 | else
|
---|
| 584 | rc = VERR_NET_IO_ERROR;
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | return rc;
|
---|
| 588 | }
|
---|
| 589 |
|
---|
| 590 |
|
---|
| 591 | /**
|
---|
| 592 | * Queries the maximum supported buffer size by the emulation.
|
---|
| 593 | *
|
---|
| 594 | * @returns VBox status code.
|
---|
| 595 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 596 | * @param cbBuffer The buffer size to set.
|
---|
| 597 | */
|
---|
| 598 | static int drvTpmEmuSetBufferSz(PDRVTPMEMU pThis, uint32_t cbBuffer)
|
---|
| 599 | {
|
---|
| 600 | SWTPMCMDSETBUFSZ Cmd;
|
---|
| 601 | SWTPMRESPSETBUFSZ Resp;
|
---|
| 602 | uint32_t u32Resp = 0;
|
---|
| 603 |
|
---|
| 604 | RT_ZERO(Cmd); RT_ZERO(Resp);
|
---|
| 605 | Cmd.cbBuffer = RT_H2BE_U32(cbBuffer);
|
---|
| 606 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_SET_BUFFERSIZE, &Cmd, sizeof(Cmd), &u32Resp,
|
---|
| 607 | &Resp, sizeof(Resp), RT_MS_10SEC);
|
---|
| 608 | if ( RT_SUCCESS(rc)
|
---|
| 609 | && u32Resp != 0)
|
---|
| 610 | rc = VERR_NET_IO_ERROR;
|
---|
| 611 |
|
---|
| 612 | return rc;
|
---|
| 613 | }
|
---|
| 614 |
|
---|
| 615 |
|
---|
| 616 | /**
|
---|
[90580] | 617 | * Sets the given locality for the emulated TPM.
|
---|
| 618 | *
|
---|
| 619 | * @returns VBox status code.
|
---|
| 620 | * @param pThis Pointer to the TPM emulator driver instance data.
|
---|
| 621 | * @param bLoc The locality to set.
|
---|
| 622 | */
|
---|
| 623 | static int drvTpmEmuSetLocality(PDRVTPMEMU pThis, uint8_t bLoc)
|
---|
| 624 | {
|
---|
| 625 | SWTPMCMDSETLOCALITY Cmd;
|
---|
| 626 | uint32_t u32Resp = 0;
|
---|
| 627 |
|
---|
| 628 | Cmd.bLoc = bLoc;
|
---|
| 629 | int rc = drvTpmEmuExecCtrlCmdNoResp(pThis, SWTPMCMD_SET_LOCALITY, &Cmd, sizeof(Cmd), &u32Resp, RT_MS_10SEC);
|
---|
| 630 | if ( RT_SUCCESS(rc)
|
---|
| 631 | && u32Resp != 0)
|
---|
| 632 | rc = VERR_NET_IO_ERROR;
|
---|
| 633 |
|
---|
[90587] | 634 | if (RT_SUCCESS(rc))
|
---|
| 635 | pThis->bLoc = bLoc;
|
---|
| 636 |
|
---|
[90580] | 637 | return rc;
|
---|
| 638 | }
|
---|
| 639 |
|
---|
| 640 |
|
---|
[90530] | 641 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
|
---|
| 642 | static DECLCALLBACK(TPMVERSION) drvTpmEmuGetVersion(PPDMITPMCONNECTOR pInterface)
|
---|
| 643 | {
|
---|
| 644 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 645 | return pThis->enmTpmVers;
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 |
|
---|
[90996] | 649 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetLocalityMax} */
|
---|
| 650 | static DECLCALLBACK(uint32_t) drvTpmEmuGetLocalityMax(PPDMITPMCONNECTOR pInterface)
|
---|
| 651 | {
|
---|
| 652 | RT_NOREF(pInterface);
|
---|
| 653 | return 4;
|
---|
| 654 | }
|
---|
| 655 |
|
---|
| 656 |
|
---|
[91005] | 657 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
|
---|
| 658 | static DECLCALLBACK(uint32_t) drvTpmEmuGetBufferSize(PPDMITPMCONNECTOR pInterface)
|
---|
| 659 | {
|
---|
| 660 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 661 | return pThis->cbBuffer;
|
---|
| 662 | }
|
---|
| 663 |
|
---|
| 664 |
|
---|
[90530] | 665 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnGetEstablishedFlag} */
|
---|
| 666 | static DECLCALLBACK(bool) drvTpmEmuGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
|
---|
| 667 | {
|
---|
[90580] | 668 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 669 |
|
---|
| 670 | SWTPMRESPGETTPMEST Resp;
|
---|
| 671 | int rc = drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_GET_TPMESTABLISHED, &Resp, sizeof(Resp), RT_MS_10SEC);
|
---|
| 672 | if (RT_SUCCESS(rc)
|
---|
| 673 | && Resp.fEst != 0)
|
---|
| 674 | return true;
|
---|
| 675 |
|
---|
[90530] | 676 | return false;
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 |
|
---|
[90904] | 680 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnResetEstablishedFlag} */
|
---|
[90530] | 681 | static DECLCALLBACK(int) drvTpmEmuResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
|
---|
| 682 | {
|
---|
[90580] | 683 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 684 |
|
---|
| 685 | SWTPMCMDRSTEST Cmd;
|
---|
| 686 | uint32_t u32Resp = 0;
|
---|
| 687 |
|
---|
| 688 | Cmd.bLoc = bLoc;
|
---|
| 689 | int rc = drvTpmEmuExecCtrlCmdNoResp(pThis, SWTPMCMD_RESET_TPMESTABLISHED, &Cmd, sizeof(Cmd), &u32Resp, RT_MS_10SEC);
|
---|
| 690 | if ( RT_SUCCESS(rc)
|
---|
| 691 | && u32Resp != 0)
|
---|
| 692 | rc = VERR_NET_IO_ERROR;
|
---|
| 693 |
|
---|
| 694 | return rc;
|
---|
[90530] | 695 | }
|
---|
| 696 |
|
---|
| 697 |
|
---|
| 698 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdExec} */
|
---|
| 699 | static DECLCALLBACK(int) drvTpmEmuCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
|
---|
| 700 | {
|
---|
[90580] | 701 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 702 |
|
---|
| 703 | int rc = VINF_SUCCESS;
|
---|
| 704 | if (pThis->bLoc != bLoc)
|
---|
| 705 | rc = drvTpmEmuSetLocality(pThis, bLoc);
|
---|
| 706 |
|
---|
| 707 | if (RT_SUCCESS(rc))
|
---|
| 708 | {
|
---|
[90587] | 709 | rc = RTSocketWrite(pThis->hSockData, pvCmd, cbCmd);
|
---|
| 710 | if (RT_SUCCESS(rc))
|
---|
| 711 | {
|
---|
| 712 | rc = RTSocketSelectOne(pThis->hSockData, RT_MS_10SEC);
|
---|
| 713 | if (RT_SUCCESS(rc))
|
---|
| 714 | {
|
---|
| 715 | /* Read the response header in first. */
|
---|
| 716 | TPMRESPHDR RespHdr;
|
---|
| 717 | rc = RTSocketRead(pThis->hSockData, &RespHdr, sizeof(RespHdr), NULL /*pcbRead*/);
|
---|
| 718 | if (RT_SUCCESS(rc))
|
---|
| 719 | {
|
---|
| 720 | size_t cbHdrResp = RTTpmRespGetSz(&RespHdr);
|
---|
| 721 | if (cbHdrResp <= cbResp - sizeof(RespHdr))
|
---|
| 722 | {
|
---|
| 723 | memcpy(pvResp, &RespHdr, sizeof(RespHdr));
|
---|
| 724 |
|
---|
| 725 | if (cbHdrResp > sizeof(RespHdr))
|
---|
| 726 | rc = RTSocketRead(pThis->hSockData, (uint8_t *)pvResp + sizeof(RespHdr), cbHdrResp - sizeof(RespHdr),
|
---|
| 727 | NULL /*pcbRead*/);
|
---|
| 728 | }
|
---|
| 729 | else
|
---|
| 730 | rc = VERR_BUFFER_OVERFLOW;
|
---|
| 731 | }
|
---|
| 732 | }
|
---|
| 733 | }
|
---|
[90580] | 734 | }
|
---|
| 735 |
|
---|
| 736 | return rc;
|
---|
[90530] | 737 | }
|
---|
| 738 |
|
---|
| 739 |
|
---|
| 740 | /** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdCancel} */
|
---|
| 741 | static DECLCALLBACK(int) drvTpmEmuCmdCancel(PPDMITPMCONNECTOR pInterface)
|
---|
| 742 | {
|
---|
[90587] | 743 | PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
|
---|
| 744 |
|
---|
| 745 | return drvTpmEmuExecCtrlCmdNoPayloadAndResp(pThis, SWTPMCMD_CANCEL_TPM_CMD, RT_MS_10SEC);
|
---|
[90530] | 746 | }
|
---|
| 747 |
|
---|
| 748 |
|
---|
| 749 | /** @interface_method_impl{PDMIBASE,pfnQueryInterface} */
|
---|
| 750 | static DECLCALLBACK(void *) drvTpmEmuQueryInterface(PPDMIBASE pInterface, const char *pszIID)
|
---|
| 751 | {
|
---|
| 752 | PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
|
---|
| 753 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 754 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
|
---|
| 755 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMCONNECTOR, &pThis->ITpmConnector);
|
---|
| 756 | return NULL;
|
---|
| 757 | }
|
---|
| 758 |
|
---|
| 759 |
|
---|
| 760 | /* -=-=-=-=- PDMDRVREG -=-=-=-=- */
|
---|
| 761 |
|
---|
[91137] | 762 | /**
|
---|
| 763 | * @interface_method_impl{PDMDRVREG,pfnPowerOn}
|
---|
| 764 | */
|
---|
| 765 | static DECLCALLBACK(void) drvTpmEmuPowerOn(PPDMDRVINS pDrvIns)
|
---|
| 766 | {
|
---|
| 767 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 768 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 769 |
|
---|
| 770 | SWTPMCMDTPMINIT Cmd;
|
---|
| 771 | uint32_t u32Resp = 0;
|
---|
| 772 |
|
---|
| 773 | RT_ZERO(Cmd);
|
---|
| 774 | Cmd.u32Flags = 0;
|
---|
| 775 | int rc = drvTpmEmuExecCtrlCmdEx(pThis, SWTPMCMD_INIT, &Cmd, sizeof(Cmd), &u32Resp,
|
---|
| 776 | NULL, 0, RT_MS_10SEC);
|
---|
| 777 | if (RT_FAILURE(rc))
|
---|
| 778 | PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "Failed to startup the TPM with %Rrc", rc);
|
---|
| 779 | }
|
---|
| 780 |
|
---|
| 781 |
|
---|
| 782 | /**
|
---|
| 783 | * @interface_method_impl{PDMDRVREG,pfnPowerOff}
|
---|
| 784 | */
|
---|
| 785 | static DECLCALLBACK(void) drvTpmEmuPowerOff(PPDMDRVINS pDrvIns)
|
---|
| 786 | {
|
---|
| 787 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 788 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 789 |
|
---|
| 790 | int rc = drvTpmEmuExecCtrlCmdNoPayload(pThis, SWTPMCMD_SHUTDOWN, NULL, 0, RT_MS_10SEC);
|
---|
| 791 | if (RT_FAILURE(rc))
|
---|
| 792 | PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "Failed to shutdown the TPM with %Rrc", rc);
|
---|
| 793 | }
|
---|
| 794 |
|
---|
| 795 |
|
---|
[90530] | 796 | /** @copydoc FNPDMDRVDESTRUCT */
|
---|
| 797 | static DECLCALLBACK(void) drvTpmEmuDestruct(PPDMDRVINS pDrvIns)
|
---|
| 798 | {
|
---|
| 799 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 800 | LogFlow(("%s\n", __FUNCTION__));
|
---|
| 801 | PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
|
---|
| 802 |
|
---|
| 803 | if (pThis->hSockCtrl != NIL_RTSOCKET)
|
---|
| 804 | {
|
---|
[90587] | 805 | int rc = RTSocketShutdown(pThis->hSockCtrl, true /* fRead */, true /* fWrite */);
|
---|
[90530] | 806 | AssertRC(rc);
|
---|
| 807 |
|
---|
| 808 | rc = RTSocketClose(pThis->hSockCtrl);
|
---|
| 809 | AssertRC(rc); RT_NOREF(rc);
|
---|
| 810 |
|
---|
| 811 | pThis->hSockCtrl = NIL_RTSOCKET;
|
---|
| 812 | }
|
---|
| 813 |
|
---|
| 814 | if (pThis->hSockData != NIL_RTSOCKET)
|
---|
| 815 | {
|
---|
[90587] | 816 | int rc = RTSocketShutdown(pThis->hSockData, true /* fRead */, true /* fWrite */);
|
---|
[90530] | 817 | AssertRC(rc);
|
---|
| 818 |
|
---|
| 819 | rc = RTSocketClose(pThis->hSockData);
|
---|
| 820 | AssertRC(rc); RT_NOREF(rc);
|
---|
| 821 |
|
---|
| 822 | pThis->hSockCtrl = NIL_RTSOCKET;
|
---|
| 823 | }
|
---|
| 824 | }
|
---|
| 825 |
|
---|
| 826 |
|
---|
| 827 | /** @copydoc FNPDMDRVCONSTRUCT */
|
---|
| 828 | static DECLCALLBACK(int) drvTpmEmuConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
|
---|
| 829 | {
|
---|
| 830 | RT_NOREF(fFlags);
|
---|
| 831 | PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
|
---|
[91867] | 832 | PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
|
---|
| 833 | PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
|
---|
[90530] | 834 |
|
---|
| 835 | /*
|
---|
| 836 | * Init the static parts.
|
---|
| 837 | */
|
---|
| 838 | pThis->pDrvIns = pDrvIns;
|
---|
| 839 | pThis->hSockCtrl = NIL_RTSOCKET;
|
---|
| 840 | pThis->hSockData = NIL_RTSOCKET;
|
---|
| 841 | pThis->enmTpmVers = TPMVERSION_UNKNOWN;
|
---|
[90580] | 842 | pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
|
---|
[90530] | 843 |
|
---|
| 844 | /* IBase */
|
---|
| 845 | pDrvIns->IBase.pfnQueryInterface = drvTpmEmuQueryInterface;
|
---|
| 846 | /* ITpmConnector */
|
---|
| 847 | pThis->ITpmConnector.pfnGetVersion = drvTpmEmuGetVersion;
|
---|
[90996] | 848 | pThis->ITpmConnector.pfnGetLocalityMax = drvTpmEmuGetLocalityMax;
|
---|
[91005] | 849 | pThis->ITpmConnector.pfnGetBufferSize = drvTpmEmuGetBufferSize;
|
---|
[90530] | 850 | pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmEmuGetEstablishedFlag;
|
---|
| 851 | pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmEmuResetEstablishedFlag;
|
---|
| 852 | pThis->ITpmConnector.pfnCmdExec = drvTpmEmuCmdExec;
|
---|
| 853 | pThis->ITpmConnector.pfnCmdCancel = drvTpmEmuCmdCancel;
|
---|
| 854 |
|
---|
| 855 | /*
|
---|
| 856 | * Validate and read the configuration.
|
---|
| 857 | */
|
---|
[91005] | 858 | PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|BufferSize", "");
|
---|
[90530] | 859 |
|
---|
| 860 | char szLocation[_1K];
|
---|
[91867] | 861 | int rc = pHlp->pfnCFGMQueryString(pCfg, "Location", &szLocation[0], sizeof(szLocation));
|
---|
[90530] | 862 | if (RT_FAILURE(rc))
|
---|
| 863 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 864 | N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
|
---|
| 865 |
|
---|
| 866 | /*
|
---|
| 867 | * Create/Open the socket.
|
---|
| 868 | */
|
---|
| 869 | char *pszPort = strchr(szLocation, ':');
|
---|
| 870 | if (!pszPort)
|
---|
| 871 | return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_FOUND, RT_SRC_POS,
|
---|
| 872 | N_("DrvTpmEmu#%d: The location misses the port to connect to"),
|
---|
| 873 | pDrvIns->iInstance);
|
---|
| 874 |
|
---|
| 875 | *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */
|
---|
| 876 | uint32_t uPort = 0;
|
---|
| 877 | rc = RTStrToUInt32Ex(pszPort + 1, NULL, 10, &uPort);
|
---|
| 878 | if (RT_FAILURE(rc))
|
---|
| 879 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 880 | N_("DrvTpmEmu#%d: The port part of the location is not a numerical value"),
|
---|
| 881 | pDrvIns->iInstance);
|
---|
| 882 |
|
---|
| 883 | rc = RTTcpClientConnect(szLocation, uPort, &pThis->hSockCtrl);
|
---|
| 884 | *pszPort = ':'; /* Restore delimiter before checking the status. */
|
---|
| 885 | if (RT_FAILURE(rc))
|
---|
| 886 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
[90587] | 887 | N_("DrvTpmEmu#%d failed to connect to control socket %s"),
|
---|
[90530] | 888 | pDrvIns->iInstance, szLocation);
|
---|
| 889 |
|
---|
[90580] | 890 | rc = drvTpmEmuQueryCaps(pThis);
|
---|
[90530] | 891 | if (RT_FAILURE(rc))
|
---|
| 892 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
[90580] | 893 | N_("DrvTpmEmu#%d failed to query capabilities offered by %s"),
|
---|
[90530] | 894 | pDrvIns->iInstance, szLocation);
|
---|
| 895 |
|
---|
[90580] | 896 | if (!(pThis->fCaps & SWTPM_CAP_GET_CONFIG))
|
---|
| 897 | return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
|
---|
[91048] | 898 | N_("DrvTpmEmu#%d Emulated TPM at '%s' misses the GET_CONFIG capability"),
|
---|
[90580] | 899 | pDrvIns->iInstance, szLocation);
|
---|
| 900 |
|
---|
| 901 | rc = drvTpmEmuQueryTpmVersion(pThis);
|
---|
[90530] | 902 | if (RT_FAILURE(rc))
|
---|
| 903 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
[90580] | 904 | N_("DrvTpmEmu#%d failed to query TPM version from %s"),
|
---|
[90530] | 905 | pDrvIns->iInstance, szLocation);
|
---|
| 906 |
|
---|
[90580] | 907 | if (pThis->enmTpmVers == TPMVERSION_UNKNOWN)
|
---|
| 908 | return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
|
---|
| 909 | N_("DrvTpmEmu#%d Emulated TPM version of %s is not supported"),
|
---|
| 910 | pDrvIns->iInstance, szLocation);
|
---|
| 911 |
|
---|
| 912 | const char *pszTpmVers = NULL;
|
---|
| 913 | uint32_t fCapsReq = SWTPM_CAP_INIT | SWTPM_CAP_SHUTDOWN | SWTPM_CAP_GET_TPMESTABLISHED
|
---|
| 914 | | SWTPM_CAP_SET_LOCALITY | SWTPM_CAP_CANCEL_TPM_CMD | SWTPM_CAP_GET_STATEBLOB
|
---|
| 915 | | SWTPM_CAP_SET_STATEBLOB | SWTPM_CAP_STOP | SWTPM_CAP_SET_BUFFERSIZE;
|
---|
| 916 | switch (pThis->enmTpmVers)
|
---|
| 917 | {
|
---|
| 918 | case TPMVERSION_1_2:
|
---|
| 919 | /* No additional capabilities needed. */
|
---|
| 920 | pszTpmVers = "1.2";
|
---|
| 921 | break;
|
---|
| 922 | case TPMVERSION_2_0:
|
---|
| 923 | fCapsReq |= SWTPM_CAP_RESET_TPMESTABLISHED;
|
---|
| 924 | pszTpmVers = "2.0";
|
---|
| 925 | break;
|
---|
| 926 | default:
|
---|
[91032] | 927 | AssertMsgFailedReturn(("DrvTpmEmu#%d Emulated TPM version %d is not correctly handled", pDrvIns->iInstance, pThis->enmTpmVers),
|
---|
| 928 | VERR_INVALID_STATE);
|
---|
[90580] | 929 | }
|
---|
| 930 |
|
---|
| 931 | if ((pThis->fCaps & fCapsReq) != fCapsReq)
|
---|
| 932 | return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
|
---|
| 933 | N_("DrvTpmEmu#%d Emulated TPM version of %s does not offer required set of capabilities (%#x requested vs. %#x offered)"),
|
---|
| 934 | pDrvIns->iInstance, szLocation, fCapsReq, pThis->fCaps);
|
---|
| 935 |
|
---|
[91005] | 936 | uint32_t cbBufferMax = 0;
|
---|
| 937 | rc = drvTpmEmuQueryBufferSzMax(pThis, &cbBufferMax);
|
---|
| 938 | if (RT_FAILURE(rc))
|
---|
| 939 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 940 | N_("DrvTpmEmu#%d failed to query maximum buffer size from %s"),
|
---|
| 941 | pDrvIns->iInstance, szLocation);
|
---|
| 942 |
|
---|
| 943 | /* Configure the buffer size. */
|
---|
[91867] | 944 | rc = pHlp->pfnCFGMQueryU32Def(pCfg, "BufferSize", &pThis->cbBuffer, cbBufferMax);
|
---|
[91005] | 945 | if (RT_FAILURE(rc))
|
---|
| 946 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 947 | N_("Configuration error: querying \"BufferSize\" resulted in %Rrc"), rc);
|
---|
| 948 |
|
---|
| 949 | /* Set the buffer size. */
|
---|
| 950 | rc = drvTpmEmuSetBufferSz(pThis, pThis->cbBuffer);
|
---|
| 951 | if (RT_FAILURE(rc))
|
---|
| 952 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 953 | N_("DrvTpmEmu#%d failed to set buffer size to %u for %s"),
|
---|
| 954 | pDrvIns->iInstance, pThis->cbBuffer, szLocation);
|
---|
| 955 |
|
---|
[90587] | 956 | /* Connect the data channel now. */
|
---|
| 957 | /** @todo Allow configuring a different port. */
|
---|
| 958 | *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */
|
---|
| 959 | rc = RTTcpClientConnect(szLocation, uPort + 1, &pThis->hSockData);
|
---|
| 960 | *pszPort = ':'; /* Restore delimiter before checking the status. */
|
---|
| 961 | if (RT_FAILURE(rc))
|
---|
| 962 | return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
|
---|
| 963 | N_("DrvTpmEmu#%d failed to connect to data socket %s"),
|
---|
| 964 | pDrvIns->iInstance, szLocation);
|
---|
| 965 |
|
---|
[90580] | 966 | LogRel(("DrvTpmEmu#%d: Connected to %s, emulating TPM version %s\n", pDrvIns->iInstance, szLocation, pszTpmVers));
|
---|
[90530] | 967 | return VINF_SUCCESS;
|
---|
| 968 | }
|
---|
| 969 |
|
---|
| 970 |
|
---|
| 971 | /**
|
---|
[91093] | 972 | * TPM emulator driver registration record.
|
---|
[90530] | 973 | */
|
---|
| 974 | const PDMDRVREG g_DrvTpmEmu =
|
---|
| 975 | {
|
---|
| 976 | /* u32Version */
|
---|
| 977 | PDM_DRVREG_VERSION,
|
---|
| 978 | /* szName */
|
---|
| 979 | "TpmEmu",
|
---|
| 980 | /* szRCMod */
|
---|
| 981 | "",
|
---|
| 982 | /* szR0Mod */
|
---|
| 983 | "",
|
---|
| 984 | /* pszDescription */
|
---|
| 985 | "TPM emulator driver.",
|
---|
| 986 | /* fFlags */
|
---|
| 987 | PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
|
---|
| 988 | /* fClass. */
|
---|
| 989 | PDM_DRVREG_CLASS_STREAM,
|
---|
| 990 | /* cMaxInstances */
|
---|
| 991 | ~0U,
|
---|
| 992 | /* cbInstance */
|
---|
| 993 | sizeof(DRVTPMEMU),
|
---|
| 994 | /* pfnConstruct */
|
---|
| 995 | drvTpmEmuConstruct,
|
---|
| 996 | /* pfnDestruct */
|
---|
| 997 | drvTpmEmuDestruct,
|
---|
| 998 | /* pfnRelocate */
|
---|
| 999 | NULL,
|
---|
| 1000 | /* pfnIOCtl */
|
---|
| 1001 | NULL,
|
---|
| 1002 | /* pfnPowerOn */
|
---|
[91137] | 1003 | drvTpmEmuPowerOn,
|
---|
[90530] | 1004 | /* pfnReset */
|
---|
| 1005 | NULL,
|
---|
| 1006 | /* pfnSuspend */
|
---|
| 1007 | NULL,
|
---|
| 1008 | /* pfnResume */
|
---|
| 1009 | NULL,
|
---|
| 1010 | /* pfnAttach */
|
---|
| 1011 | NULL,
|
---|
| 1012 | /* pfnDetach */
|
---|
| 1013 | NULL,
|
---|
| 1014 | /* pfnPowerOff */
|
---|
[91137] | 1015 | drvTpmEmuPowerOff,
|
---|
[90530] | 1016 | /* pfnSoftReset */
|
---|
| 1017 | NULL,
|
---|
| 1018 | /* u32EndVersion */
|
---|
| 1019 | PDM_DRVREG_VERSION
|
---|
| 1020 | };
|
---|
| 1021 |
|
---|