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 // Store SPDM object pointer to libspdm context 437 CHECK_SPDM_STATUS(libspdm_set_data(pSpdm->pLibspdmContext, LIBSPDM_DATA_APP_CONTEXT_DATA, 438 NULL, (void *)&pSpdm, sizeof(void *))); 439 440 // 441 // Perform any device-specific initialization. spdmDeviceInit is also 442 // responsible for registering transport layer functions with libspdm. 443 // 444 status = spdmDeviceInit_HAL(pGpu, pSpdm); 445 if (status != NV_OK) 446 { 447 goto ErrorExit; 448 } 449 450 libspdm_register_device_buffer_func(pSpdm->pLibspdmContext, 451 NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES, NV_SPDM_SYSMEM_SURFACE_SIZE_IN_BYTES, 452 _spdmAcquireTransportBuffer, _spdmReleaseTransportBuffer, 453 _spdmAcquireTransportBuffer, _spdmReleaseTransportBuffer); 454 455 // 456 // Allocate scratch space required for libspdm processing. 457 // We need to wait for transport layer initialization (i.e. after device init) 458 // in order to properly calculate the required scratch size. 459 // 460 pSpdm->libspdmScratchSize = libspdm_get_sizeof_required_scratch_buffer(pSpdm->pLibspdmContext); 461 pSpdm->pLibspdmScratch = portMemAllocNonPaged(pSpdm->libspdmScratchSize); 462 if (pSpdm->libspdmScratchSize == 0 || pSpdm->pLibspdmScratch == NULL) 463 { 464 status = NV_ERR_NO_MEMORY; 465 goto ErrorExit; 466 } 467 468 portMemSet(pSpdm->pLibspdmScratch, 0, pSpdm->libspdmScratchSize); 469 libspdm_set_scratch_buffer(pSpdm->pLibspdmContext, pSpdm->pLibspdmScratch, 470 pSpdm->libspdmScratchSize); 471 472 // 473 // Verifier is responsible for verifying the certificate chain. To avoid concerns 474 // with libspdm compatibility, override certificate validation function with stub. 475 // 476 libspdm_register_verify_spdm_cert_chain_func(pSpdm->pLibspdmContext, _spdmVerifyCertChain); 477 478 // Initialize session message count to zero. 479 pSpdm->sessionMsgCount = 0; 480 481 ErrorExit: 482 483 // Clear all SPDM state on failure. 484 if (status != NV_OK) 485 { 486 _spdmClearContext(pSpdm); 487 } 488 489 return status; 490 } 491 492 NV_STATUS 493 spdmContextDeinit_IMPL 494 ( 495 OBJGPU *pGpu, 496 Spdm *pSpdm, 497 NvBool bForceClear 498 ) 499 { 500 NV_STATUS status = NV_OK; 501 502 if (pGpu == NULL || pSpdm == NULL) 503 { 504 return NV_ERR_INVALID_ARGUMENT; 505 } 506 507 // If no session to end, just wipe state and return. 508 if (pSpdm->pLibspdmContext == NULL) 509 { 510 _spdmClearContext(pSpdm); 511 return NV_OK; 512 } 513 514 // 515 // Make sure to unregister heartbeats in case we didn't 516 // hit normal teardown path. Best effort attempt. 517 // 518 status = spdmUnregisterFromHeartbeats(pGpu, pSpdm); 519 NV_ASSERT_OK(status); 520 521 // 522 // End the session by deinitializing the Responder. 523 // We don't send END_SESSION as Responder will handle teardown. 524 // 525 NV_PRINTF(LEVEL_INFO, "SPDM: Tearing down session.\n"); 526 status = spdmDeviceDeinit_HAL(pGpu, pSpdm, NV_TRUE); 527 528 // Regardless of success or failure, clear any context. 529 _spdmClearContext(pSpdm); 530 531 // We really shouldn't fail on deinitialization - ASSERT if we do. 532 NV_ASSERT_OK(status); 533 return status; 534 } 535 536 NV_STATUS 537 spdmStart_IMPL 538 ( 539 OBJGPU *pGpu, 540 Spdm *pSpdm 541 ) 542 { 543 NV_STATUS status = NV_OK; 544 545 if (pGpu == NULL || pSpdm == NULL) 546 { 547 return NV_ERR_INVALID_ARGUMENT; 548 } 549 550 if (pSpdm->pLibspdmContext == NULL) 551 { 552 return NV_ERR_NOT_READY; 553 } 554 555 // Send GET_VERSION, GET_CAPABILITIES, and NEGOTIATE_ALGORITHMS to Responder. 556 NV_PRINTF(LEVEL_INFO, "SPDM: Starting new SPDM connection.\n"); 557 CHECK_SPDM_STATUS(libspdm_init_connection(pSpdm->pLibspdmContext, NV_FALSE)); 558 559 if (!nvspdm_check_and_clear_libspdm_assert()) 560 { 561 NV_PRINTF(LEVEL_ERROR, "SPDM: libspdm_init_connection() assert hit !!!.\n"); 562 status = NV_ERR_GENERIC; 563 goto ErrorExit; 564 } 565 566 // Ensure the connection attributes match expected. 567 status = spdmCheckConnection_HAL(pGpu, pSpdm); 568 if (status != NV_OK) 569 { 570 NV_PRINTF(LEVEL_ERROR, "SPDM: Connection attributes did not match expected!\n"); 571 goto ErrorExit; 572 } 573 574 // Fetch the certificates from the responder and validate them 575 status = spdmGetCertificates_HAL(pGpu, pSpdm); 576 if (status != NV_OK) 577 { 578 NV_PRINTF(LEVEL_ERROR, "SPDM: Certificate retrieval failed!\n"); 579 goto ErrorExit; 580 } 581 582 if (!nvspdm_check_and_clear_libspdm_assert()) 583 { 584 NV_PRINTF(LEVEL_ERROR, "SPDM: spdmGetCertificates_HAL() assert hit !!!.\n"); 585 status = NV_ERR_GENERIC; 586 goto ErrorExit; 587 } 588 589 // 590 // Complete the SPDM handshake and start the secured session. 591 // Ensure we match type of sessionId parameter with what libspdm expects. 592 // 593 if (spdmDeviceSecuredSessionSupported_HAL(pGpu, pSpdm) == NV_OK) 594 { 595 NvU8 heartbeatPeriodInSec = 0; 596 597 NV_PRINTF(LEVEL_INFO, "SPDM: Attempting to establish SPDM session.\n"); 598 CHECK_SPDM_STATUS(libspdm_start_session(pSpdm->pLibspdmContext, NV_FALSE, NULL, 0, 599 SPDM_KEY_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, 600 SPDM_CERT_DEFAULT_SLOT_ID, 0, &pSpdm->sessionId, 601 &heartbeatPeriodInSec, NULL)); 602 if (!nvspdm_check_and_clear_libspdm_assert()) 603 { 604 NV_PRINTF(LEVEL_ERROR, "SPDM: libspdm_start_session() assert hit !!!.\n"); 605 status = NV_ERR_GENERIC; 606 goto ErrorExit; 607 } 608 else if (heartbeatPeriodInSec != SPDM_DEFAULT_HEARTBEAT_PERIOD_IN_SEC) 609 { 610 // 611 // Do a basic check to make sure the SPDM heartbeat period agreed between 612 // Requester and Responder is expected, even if it is overridden via regkey. 613 // 614 NV_PRINTF(LEVEL_ERROR, "SPDM: Responder returned unexpected heartbeat 0x%x\n", 615 heartbeatPeriodInSec); 616 status = NV_ERR_NOT_SUPPORTED; 617 goto ErrorExit; 618 } 619 620 NV_PRINTF(LEVEL_INFO, "SPDM: Session establishment successful: sessionId 0x%x.\n", 621 pSpdm->sessionId); 622 pSpdm->bSessionEstablished = NV_TRUE; 623 pSpdm->bUsePolling = NV_FALSE; 624 } 625 626 ErrorExit: 627 628 // 629 // On error, set session as invalid. Don't need to reset context, since 630 // restarting SPDM exchange is valid scenario. Responder may not support. 631 // 632 if (status != NV_OK) 633 { 634 pSpdm->sessionId = INVALID_SESSION_ID; 635 pSpdm->bSessionEstablished = NV_FALSE; 636 NV_PRINTF(LEVEL_ERROR, "SPDM: Session establishment failed!\n"); 637 DBG_BREAKPOINT(); 638 } 639 640 return status; 641 } 642 643 NV_STATUS 644 spdmRetrieveExportSecret_IMPL 645 ( 646 OBJGPU *pGpu, 647 Spdm *pSpdm, 648 NvU32 keySize, 649 NvU8 *pKeyOut 650 ) 651 { 652 size_t keySizeSizeT = 0; 653 libspdm_secured_message_context_t *pSessionContext = NULL; 654 655 // Basic parameter validation. 656 if (pGpu == NULL || pSpdm == NULL || keySize == 0 || pKeyOut == NULL) 657 { 658 return NV_ERR_INVALID_ARGUMENT; 659 } 660 661 // Ensure we are in valid state. Note that export master secret can only be retrieved once. 662 if (pSpdm->pLibspdmContext == NULL || !pSpdm->bSessionEstablished || pSpdm->bExportSecretCleared) 663 { 664 return NV_ERR_NOT_READY; 665 } 666 667 pSessionContext = 668 libspdm_get_secured_message_context_via_session_id(pSpdm->pLibspdmContext, pSpdm->sessionId); 669 if (pSessionContext == NULL) 670 { 671 return NV_ERR_INVALID_STATE; 672 } 673 674 // 675 // Fetch the export master secret. 676 // Use temporary size variable to handle type differences and avoid overflow. 677 // 678 keySizeSizeT = keySize; 679 if (!libspdm_secured_message_export_master_secret(pSessionContext, pKeyOut, &keySizeSizeT)) 680 { 681 return NV_ERR_INVALID_STATE; 682 } 683 684 // Clear the export master secret from SPDM memory. 685 libspdm_secured_message_clear_export_master_secret(pSessionContext); 686 pSpdm->bExportSecretCleared = NV_TRUE; 687 688 return NV_OK; 689 } 690