1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /***************************************************************************\ 25 * * 26 * SPDM Object Module * 27 * * 28 \**************************************************************************/ 29 30 /* ------------------------ Includes --------------------------------------- */ 31 #include "gpu/spdm/spdm.h" 32 #include "spdm/rmspdmtransport.h" 33 #include "spdm/rmspdmvendordef.h" 34 #include "gpu/gpu.h" 35 #include "gpu/gpu_resource.h" 36 #include "nvspdm_rmconfig.h" 37 #include "gpu/mem_mgr/mem_mgr.h" 38 #include "platform/sli/sli.h" 39 #include "rmapi/client_resource.h" 40 #include "gpu/bus/kern_bus.h" 41 #include "os/os.h" 42 43 // 44 // Libspdm only supported on certain builds, 45 // take note if you are copying header elsewhere. 46 // 47 #include "gpu/spdm/libspdm_includes.h" 48 49 /* ------------------------ Static Function Prototypes --------------------- */ 50 static void _spdmClearContext(Spdm *pSpdm); 51 libspdm_return_t _spdmAcquireTransportBuffer(void *context, void **msg_buf_ptr); 52 void _spdmReleaseTransportBuffer(void *context, const void *msg_buf_ptr); 53 bool _spdmVerifyCertChain(void *spdm_context, uint8_t slot_id, size_t cert_chain_size, 54 const void *cert_chain, const void **trust_anchor, size_t *trust_anchor_size); 55 56 /* ------------------------ Static Functions ------------------------------- */ 57 /* 58 * Helper to clear and free any SPDM object context. 59 */ 60 void 61 _spdmClearContext 62 ( 63 Spdm *pSpdm 64 ) 65 { 66 if (pSpdm == NULL) 67 { 68 return; 69 } 70 71 // 72 // If we haven't deinitialized session, not much we can do now. 73 // Make best effort to free any allocated Requester context, 74 // ensuring we scrub the libspdm context. 75 // 76 if (pSpdm->pLibspdmContext != NULL) 77 { 78 libspdm_deinit_context(pSpdm->pLibspdmContext); 79 libspdm_reset_context(pSpdm->pLibspdmContext); 80 portMemSet((NvU8 *)pSpdm->pLibspdmContext, 0, pSpdm->libspdmContextSize); 81 } 82 83 if (pSpdm->pLibspdmScratch != NULL) 84 { 85 portMemSet((NvU8 *)pSpdm->pLibspdmScratch, 0, pSpdm->libspdmScratchSize); 86 } 87 88 // memdescFree and memdescDestroy handle NULL gracefully. 89 memdescFree(pSpdm->pPayloadBufferMemDesc); 90 memdescDestroy(pSpdm->pPayloadBufferMemDesc); 91 92 pSpdm->pPayloadBufferMemDesc = NULL; 93 pSpdm->payloadBufferSize = 0; 94 95 // portMemFree handles NULL pointers gracefully. 96 portMemFree(pSpdm->pLibspdmContext); 97 portMemFree(pSpdm->pLibspdmScratch); 98 portMemFree(pSpdm->pAttestationCertChain); 99 portMemFree(pSpdm->pDeviceIOContext); 100 portMemFree(pSpdm->pMsgLog); 101 102 pSpdm->pLibspdmContext = NULL; 103 pSpdm->pLibspdmScratch = NULL; 104 pSpdm->pAttestationCertChain = NULL; 105 pSpdm->pDeviceIOContext = NULL; 106 pSpdm->pMsgLog = NULL; 107 108 pSpdm->libspdmContextSize = 0; 109 pSpdm->libspdmScratchSize = 0; 110 pSpdm->attestationCertChainSize = 0; 111 pSpdm->msgLogMaxSize = 0; 112 113 pSpdm->sessionId = INVALID_SESSION_ID; 114 pSpdm->bSessionEstablished = NV_FALSE; 115 pSpdm->bUsePolling = NV_FALSE; 116 } 117 118 /* 119 * Transport layer helpers for send/receive message buffers. 120 */ 121 libspdm_return_t 122 _spdmAcquireTransportBuffer 123 ( 124 void *context, 125 void **msg_buf_ptr 126 ) 127 { 128 if (context == NULL || msg_buf_ptr == NULL) 129 { 130 return LIBSPDM_STATUS_INVALID_PARAMETER; 131 } 132 133 *msg_buf_ptr = portMemAllocNonPaged(NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES); 134 if (*msg_buf_ptr == NULL) 135 { 136 return LIBSPDM_STATUS_BUFFER_FULL; 137 } 138 139 return LIBSPDM_STATUS_SUCCESS; 140 } 141 142 void 143 _spdmReleaseTransportBuffer 144 ( 145 void *context, 146 const void *msg_buf_ptr 147 ) 148 { 149 portMemFree((void *)msg_buf_ptr); 150 } 151 152 bool 153 _spdmVerifyCertChain 154 ( 155 void *spdm_context, 156 uint8_t slot_id, 157 size_t cert_chain_size, 158 const void *cert_chain, 159 const void **trust_anchor, 160 size_t *trust_anchor_size 161 ) 162 { 163 return NV_TRUE; 164 } 165 166 /* ------------------------ Public Functions ------------------------------- */ 167 /*! 168 * Constructor 169 */ 170 NV_STATUS 171 spdmConstruct_IMPL 172 ( 173 Spdm *pSpdm 174 ) 175 { 176 177 if (pSpdm == NULL) 178 { 179 return NV_ERR_INVALID_ARGUMENT; 180 } 181 182 pSpdm->pLibspdmContext = NULL; 183 pSpdm->pLibspdmScratch = NULL; 184 pSpdm->pAttestationCertChain = NULL; 185 pSpdm->pDeviceIOContext = NULL; 186 pSpdm->pMsgLog = NULL; 187 188 pSpdm->libspdmContextSize = 0; 189 pSpdm->libspdmScratchSize = 0; 190 pSpdm->attestationCertChainSize = 0; 191 pSpdm->msgLogMaxSize = 0; 192 193 pSpdm->sessionId = INVALID_SESSION_ID; 194 pSpdm->bSessionEstablished = NV_FALSE; 195 pSpdm->bUsePolling = NV_FALSE; 196 pSpdm->bExportSecretCleared = NV_FALSE; 197 198 pSpdm->pPayloadBufferMemDesc = NULL; 199 pSpdm->payloadBufferSize = 0; 200 201 pSpdm->pHeartbeatEvent = NULL; 202 pSpdm->heartbeatPeriodSec = 0; 203 204 return NV_OK; 205 } 206 207 /*! 208 * Destructor 209 */ 210 void 211 spdmDestruct_IMPL 212 ( 213 Spdm * pSpdm 214 ) 215 { 216 _spdmClearContext(pSpdm); 217 } 218 219 NV_STATUS 220 spdmSetupCommunicationBuffers_IMPL 221 ( 222 OBJGPU *pGpu, 223 Spdm *pSpdm 224 ) 225 { 226 MemoryManager *pMemoryManager = NULL; 227 TRANSFER_SURFACE surf = {0}; 228 NV_STATUS status = NV_OK; 229 230 // Create memory descriptor for payload buffer 231 status = memdescCreate(&pSpdm->pPayloadBufferMemDesc, pGpu, NV_SPDM_SYSMEM_SURFACE_SIZE_PAGE_ALIGNED, 232 NV_SPDM_SYSMEM_SURFACE_ALIGNMENT_IN_BYTES, NV_TRUE, ADDR_SYSMEM, 233 NV_MEMORY_CACHED, MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY); 234 if (status != NV_OK || pSpdm->pPayloadBufferMemDesc == NULL) 235 { 236 status = NV_ERR_INSUFFICIENT_RESOURCES; 237 goto ErrorExit; 238 } 239 240 memdescTagAlloc(status, NV_FB_ALLOC_RM_INTERNAL_OWNER_UNNAMED_TAG_82, pSpdm->pPayloadBufferMemDesc); 241 if (status != NV_OK) 242 { 243 goto ErrorExit; 244 } 245 246 // We over-allocate since we must allocate page-aligned. Set size only to what we will use. 247 pSpdm->payloadBufferSize = NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES; 248 249 // Scrub surface 250 SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY) 251 pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu); 252 surf.offset = 0; 253 254 surf.pMemDesc = pSpdm->pPayloadBufferMemDesc; 255 status = memmgrMemSet(pMemoryManager, &surf, 0, pSpdm->payloadBufferSize, TRANSFER_FLAGS_NONE); 256 if (status != NV_OK) 257 { 258 SLI_LOOP_GOTO(ErrorExit); 259 } 260 261 SLI_LOOP_END 262 263 ErrorExit: 264 265 if (status != NV_OK) 266 { 267 _spdmClearContext(pSpdm); 268 } 269 270 return status; 271 } 272 273 NV_STATUS 274 spdmContextInit_IMPL 275 ( 276 OBJGPU *pGpu, 277 Spdm *pSpdm 278 ) 279 { 280 NV_STATUS status = NV_OK; 281 libspdm_data_parameter_t parameter; 282 uint8_t ctExponent; 283 uint32_t capFlags; 284 uint8_t measSpec; 285 uint32_t baseAsymAlgo; 286 uint32_t baseHashAlgo; 287 uint16_t dheGroup; 288 uint16_t aeadSuite; 289 uint16_t keySched; 290 uint32_t maxSessionCount; 291 uint8_t maxRetries; 292 293 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP 294 uint16_t reqAsymAlgo; 295 NvU8 *pEncapCertChain; 296 NvU32 encapCertChainSize; 297 #endif 298 299 if (pGpu == NULL || pSpdm == NULL) 300 { 301 return NV_ERR_INVALID_ARGUMENT; 302 } 303 304 // Allocate and initialize all required memory for context and certificates. 305 pSpdm->libspdmContextSize = libspdm_get_context_size(); 306 pSpdm->pLibspdmContext = portMemAllocNonPaged(pSpdm->libspdmContextSize); 307 308 if (pSpdm->libspdmContextSize == 0 || pSpdm->pLibspdmContext == NULL) 309 { 310 status = NV_ERR_NO_MEMORY; 311 goto ErrorExit; 312 } 313 314 portMemSet(pSpdm->pLibspdmContext, 0, pSpdm->libspdmContextSize); 315 libspdm_init_context(pSpdm->pLibspdmContext); 316 317 318 // Allocate message transcript recording buffer. 319 pSpdm->pMsgLog = portMemAllocNonPaged(NV_SPDM_MAX_TRANSCRIPT_BUFFER_SIZE); 320 pSpdm->msgLogMaxSize = NV_SPDM_MAX_TRANSCRIPT_BUFFER_SIZE; 321 322 if (pSpdm->pMsgLog == NULL) 323 { 324 pSpdm->msgLogMaxSize = 0; 325 status = NV_ERR_NO_MEMORY; 326 goto ErrorExit; 327 } 328 329 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP 330 // Get requester cert chain for mutual authentication process. 331 pEncapCertChain = NULL; 332 encapCertChainSize = 0; 333 status = spdmGetReqEncapCertificates_HAL(pGpu, pSpdm, &pEncapCertChain, &encapCertChainSize); 334 335 if (status != NV_OK || pEncapCertChain == NULL || encapCertChainSize == 0) 336 { 337 status = NV_ERR_NOT_SUPPORTED; 338 goto ErrorExit; 339 } 340 #endif 341 342 // 343 // Eventually, owner of Spdm object may want to set their own 344 // specific configuration. For now, hardcode the only supported configuration. 345 // 346 portMemSet(¶meter, 0, sizeof(parameter)); 347 parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; 348 349 // Requester will not check Responder's timing, set to maximum value. 350 ctExponent = LIBSPDM_MAX_CT_EXPONENT; 351 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, 352 ¶meter, &ctExponent, sizeof(ctExponent))); 353 354 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP 355 capFlags = SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP | 356 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP | 357 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP | 358 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP | 359 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP | 360 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCAP_CAP | 361 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP | 362 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP; 363 #else 364 capFlags = SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP | 365 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP | 366 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP | 367 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP | 368 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP | 369 SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP; 370 #endif 371 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, 372 LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, 373 &capFlags, sizeof(capFlags))); 374 375 measSpec = SPDM_MEASUREMENT_SPECIFICATION_DMTF; 376 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, 377 LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, 378 &measSpec, sizeof(measSpec))); 379 380 baseAsymAlgo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384; 381 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_BASE_ASYM_ALGO, 382 ¶meter, &baseAsymAlgo, 383 sizeof(baseAsymAlgo))); 384 385 baseHashAlgo = SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384; 386 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_BASE_HASH_ALGO, 387 ¶meter, &baseHashAlgo, 388 sizeof(baseHashAlgo))); 389 390 dheGroup = SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1; 391 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_DHE_NAME_GROUP, 392 ¶meter, &dheGroup, sizeof(dheGroup))); 393 394 aeadSuite = SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM; 395 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_AEAD_CIPHER_SUITE, 396 ¶meter, &aeadSuite, sizeof(aeadSuite))); 397 398 keySched = SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH; 399 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_KEY_SCHEDULE, 400 ¶meter, &keySched, sizeof(keySched))); 401 402 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP 403 reqAsymAlgo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072; 404 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, 405 ¶meter, &reqAsymAlgo, 406 sizeof(reqAsymAlgo))); 407 408 // 409 // Set certification for encapsulated command process. 410 // Specify certificate location, passing slot number as well. 411 // 412 parameter.additional_data[0] = SPDM_CERT_DEFAULT_SLOT_ID; 413 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN, 414 ¶meter, pEncapCertChain, 415 encapCertChainSize)); 416 #endif 417 418 // Ensure that we set only DHE sessions as allowed, not PSK sessions. 419 maxSessionCount = 1; 420 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_MAX_DHE_SESSION_COUNT, 421 ¶meter, &maxSessionCount, sizeof(maxSessionCount))); 422 423 maxSessionCount = 0; 424 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_MAX_PSK_SESSION_COUNT, 425 ¶meter, &maxSessionCount, sizeof(maxSessionCount))); 426 427 428 // We don't allow SPDM message retries. 429 maxRetries = 0; 430 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_REQUEST_RETRY_TIMES, 431 ¶meter, &maxRetries, sizeof(maxRetries))); 432 433 libspdm_init_msg_log(pSpdm->pLibspdmContext, pSpdm->pMsgLog, pSpdm->msgLogMaxSize); 434 435 // 436 // Perform any device-specific initialization. spdmDeviceInit is also 437 // responsible for registering transport layer functions with libspdm. 438 // 439 status = spdmDeviceInit_HAL(pGpu, pSpdm); 440 if (status != NV_OK) 441 { 442 goto ErrorExit; 443 } 444 445 libspdm_register_device_buffer_func(pSpdm->pLibspdmContext, 446 NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES, NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES, 447 _spdmAcquireTransportBuffer, _spdmReleaseTransportBuffer, 448 _spdmAcquireTransportBuffer, _spdmReleaseTransportBuffer); 449 450 // 451 // Allocate scratch space required for libspdm processing. 452 // We need to wait for transport layer initialization (i.e. after device init) 453 // in order to properly calculate the required scratch size. 454 // 455 pSpdm->libspdmScratchSize = libspdm_get_sizeof_required_scratch_buffer(pSpdm->pLibspdmContext); 456 pSpdm->pLibspdmScratch = portMemAllocNonPaged(pSpdm->libspdmScratchSize); 457 if (pSpdm->libspdmScratchSize == 0 || pSpdm->pLibspdmScratch == NULL) 458 { 459 status = NV_ERR_NO_MEMORY; 460 goto ErrorExit; 461 } 462 463 portMemSet(pSpdm->pLibspdmScratch, 0, pSpdm->libspdmScratchSize); 464 libspdm_set_scratch_buffer(pSpdm->pLibspdmContext, pSpdm->pLibspdmScratch, 465 pSpdm->libspdmScratchSize); 466 467 // 468 // Verifier is responsible for verifying the certificate chain. To avoid concerns 469 // with libspdm compatibility, override certificate validation function with stub. 470 // 471 libspdm_register_verify_spdm_cert_chain_func(pSpdm->pLibspdmContext, _spdmVerifyCertChain); 472 473 // Initialize session message count to zero. 474 pSpdm->sessionMsgCount = 0; 475 476 ErrorExit: 477 478 // Clear all SPDM state on failure. 479 if (status != NV_OK) 480 { 481 _spdmClearContext(pSpdm); 482 } 483 484 return status; 485 } 486 487 NV_STATUS 488 spdmContextDeinit_IMPL 489 ( 490 OBJGPU *pGpu, 491 Spdm *pSpdm, 492 NvBool bForceClear 493 ) 494 { 495 NV_STATUS status = NV_OK; 496 497 if (pGpu == NULL || pSpdm == NULL) 498 { 499 return NV_ERR_INVALID_ARGUMENT; 500 } 501 502 // If no session to end, just wipe state and return. 503 if (pSpdm->pLibspdmContext == NULL) 504 { 505 _spdmClearContext(pSpdm); 506 return NV_OK; 507 } 508 509 // 510 // Make sure to unregister heartbeats in case we didn't 511 // hit normal teardown path. Best effort attempt. 512 // 513 status = spdmUnregisterFromHeartbeats(pGpu, pSpdm); 514 NV_ASSERT_OK(status); 515 516 // 517 // End the session by deinitializing the Responder. 518 // We don't send END_SESSION as Responder will handle teardown. 519 // 520 NV_PRINTF(LEVEL_INFO, "SPDM: Tearing down session.\n"); 521 status = spdmDeviceDeinit_HAL(pGpu, pSpdm, NV_TRUE); 522 523 // Regardless of success or failure, clear any context. 524 _spdmClearContext(pSpdm); 525 526 // We really shouldn't fail on deinitialization - ASSERT if we do. 527 NV_ASSERT_OK(status); 528 return status; 529 } 530 531 NV_STATUS 532 spdmStart_IMPL 533 ( 534 OBJGPU *pGpu, 535 Spdm *pSpdm 536 ) 537 { 538 NV_STATUS status = NV_OK; 539 540 if (pGpu == NULL || pSpdm == NULL) 541 { 542 return NV_ERR_INVALID_ARGUMENT; 543 } 544 545 if (pSpdm->pLibspdmContext == NULL) 546 { 547 return NV_ERR_NOT_READY; 548 } 549 550 // Send GET_VERSION, GET_CAPABILITIES, and NEGOTIATE_ALGORITHMS to Responder. 551 NV_PRINTF(LEVEL_INFO, "SPDM: Starting new SPDM connection.\n"); 552 CHECK_SPDM_STATUS(libspdm_init_connection(pSpdm->pLibspdmContext, NV_FALSE)); 553 554 if (!nvspdm_check_and_clear_libspdm_assert()) 555 { 556 NV_PRINTF(LEVEL_ERROR, "SPDM: libspdm_init_connection() assert hit !!!.\n"); 557 status = NV_ERR_GENERIC; 558 goto ErrorExit; 559 } 560 561 // Ensure the connection attributes match expected. 562 status = spdmCheckConnection_HAL(pGpu, pSpdm); 563 if (status != NV_OK) 564 { 565 NV_PRINTF(LEVEL_ERROR, "SPDM: Connection attributes did not match expected!\n"); 566 goto ErrorExit; 567 } 568 569 // Fetch the certificates from the responder and validate them 570 status = spdmGetCertificates_HAL(pGpu, pSpdm); 571 if (status != NV_OK) 572 { 573 NV_PRINTF(LEVEL_ERROR, "SPDM: Certificate retrieval failed!\n"); 574 goto ErrorExit; 575 } 576 577 if (!nvspdm_check_and_clear_libspdm_assert()) 578 { 579 NV_PRINTF(LEVEL_ERROR, "SPDM: spdmGetCertificates_HAL() assert hit !!!.\n"); 580 status = NV_ERR_GENERIC; 581 goto ErrorExit; 582 } 583 584 // 585 // Complete the SPDM handshake and start the secured session. 586 // Ensure we match type of sessionId parameter with what libspdm expects. 587 // 588 if (spdmDeviceSecuredSessionSupported_HAL(pGpu, pSpdm) == NV_OK) 589 { 590 NvU8 heartbeatPeriodInSec = 0; 591 592 NV_PRINTF(LEVEL_INFO, "SPDM: Attempting to establish SPDM session.\n"); 593 CHECK_SPDM_STATUS(libspdm_start_session(pSpdm->pLibspdmContext, NV_FALSE, NULL, 0, 594 SPDM_KEY_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, 595 SPDM_CERT_DEFAULT_SLOT_ID, 0, &pSpdm->sessionId, 596 &heartbeatPeriodInSec, NULL)); 597 if (!nvspdm_check_and_clear_libspdm_assert()) 598 { 599 NV_PRINTF(LEVEL_ERROR, "SPDM: libspdm_start_session() assert hit !!!.\n"); 600 status = NV_ERR_GENERIC; 601 goto ErrorExit; 602 } 603 else if (heartbeatPeriodInSec != SPDM_DEFAULT_HEARTBEAT_PERIOD_IN_SEC) 604 { 605 // 606 // Do a basic check to make sure the SPDM heartbeat period agreed between 607 // Requester and Responder is expected, even if it is overridden via regkey. 608 // 609 NV_PRINTF(LEVEL_ERROR, "SPDM: Responder returned unexpected heartbeat 0x%x\n", 610 heartbeatPeriodInSec); 611 status = NV_ERR_NOT_SUPPORTED; 612 goto ErrorExit; 613 } 614 615 NV_PRINTF(LEVEL_INFO, "SPDM: Session establishment successful: sessionId 0x%x.\n", 616 pSpdm->sessionId); 617 pSpdm->bSessionEstablished = NV_TRUE; 618 pSpdm->bUsePolling = NV_FALSE; 619 } 620 621 ErrorExit: 622 623 // 624 // On error, set session as invalid. Don't need to reset context, since 625 // restarting SPDM exchange is valid scenario. Responder may not support. 626 // 627 if (status != NV_OK) 628 { 629 pSpdm->sessionId = INVALID_SESSION_ID; 630 pSpdm->bSessionEstablished = NV_FALSE; 631 NV_PRINTF(LEVEL_ERROR, "SPDM: Session establishment failed!\n"); 632 DBG_BREAKPOINT(); 633 } 634 635 return status; 636 } 637 638 NV_STATUS 639 spdmRetrieveExportSecret_IMPL 640 ( 641 OBJGPU *pGpu, 642 Spdm *pSpdm, 643 NvU32 keySize, 644 NvU8 *pKeyOut 645 ) 646 { 647 size_t keySizeSizeT = 0; 648 libspdm_secured_message_context_t *pSessionContext = NULL; 649 650 // Basic parameter validation. 651 if (pGpu == NULL || pSpdm == NULL || keySize == 0 || pKeyOut == NULL) 652 { 653 return NV_ERR_INVALID_ARGUMENT; 654 } 655 656 // Ensure we are in valid state. Note that export master secret can only be retrieved once. 657 if (pSpdm->pLibspdmContext == NULL || !pSpdm->bSessionEstablished || pSpdm->bExportSecretCleared) 658 { 659 return NV_ERR_NOT_READY; 660 } 661 662 pSessionContext = 663 libspdm_get_secured_message_context_via_session_id(pSpdm->pLibspdmContext, pSpdm->sessionId); 664 if (pSessionContext == NULL) 665 { 666 return NV_ERR_INVALID_STATE; 667 } 668 669 // 670 // Fetch the export master secret. 671 // Use temporary size variable to handle type differences and avoid overflow. 672 // 673 keySizeSizeT = keySize; 674 if (!libspdm_secured_message_export_master_secret(pSessionContext, pKeyOut, &keySizeSizeT)) 675 { 676 return NV_ERR_INVALID_STATE; 677 } 678 679 // Clear the export master secret from SPDM memory. 680 libspdm_secured_message_clear_export_master_secret(pSessionContext); 681 pSpdm->bExportSecretCleared = NV_TRUE; 682 683 return NV_OK; 684 } 685