Split get_version/get_capabilities/negotiate_algorithms request.
Fix: #2394
Split get_version/get_capabilities/negotiate_algorithms request.
@Wenxing-hou Is there possibility to have libspdm_process_response which can internally call handle_version_response, handle_caps_response or handle_algo_response ?
@steven-bellock please share your suggestion.
@Wenxing-hou I did test these APIs and here are some of my findings: https://github.com/DMTF/libspdm/issues/2480 Please let me know if you need any logs.
@PrithviAPai We talked about: you suspect that this issue may be related to the following logic, and I am checking it.
In libspdm_send_request we are taking backup of the last message
We are missing to do that when we separate the APIs
/* backup it to last_spdm_request, because the caller wants to compare it with response */
if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
&& ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
&& ((const spdm_message_header_t*) request)->request_response_code != SPDM_CHUNK_SEND) {
libspdm_copy_mem (context->last_spdm_request,
libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
request,
request_size
);
context->last_spdm_request_size = request_size;
}
@Wenxing-hou one more thing is with this split we would need to support encryption and decryption So it would be better to have support for that also in split function. Ofcourse, it will not be supported for VCA but generally we might need to have some mechanism to have support for that. Please share your thoughts
@PrithviAPai , it is hard to debug an issue without real code.
Could you please share your test code, or do some basic debug to see where the problem is?
one more thing is with this split we would need to support encryption and decryption So it would be better to have support for that also in split function. Ofcourse, it will not be supported for VCA but generally we might need to have some mechanism to have support for that. Please share your thoughts
I am not sure what you mean, can you share some code and let us know how you plan to use ?
@jyao1 , here is my sample code which I used to test the PR.
bool getVCA()
{
std::array<uint8_t, 100> request;
std::array<uint8_t, 500> response;
size_t requestSize = request.size();
//Get Version Send Part
if (!validateSpdmRc(libspdm_build_request_get_version(
spdmContext, &request, &requestSize)))
{
freeSpdmContext(spdmContext);
return false;
}
std::vector<uint8_t> data = formSendMessage(requestSize, request);
data.insert(data.begin(), 5); // Transport layer Message Type
//Send the message in async manner and store response in std::vector<uint8_t> responseData;
//Version Receive Part
responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet
std::copy(responseData.begin(), responseData.end(),
response.begin());
if (!validateSpdmRc(libspdm_process_response_version(
spdmContext, &response, responseData.size(),
NULL, NULL)))
{
freeSpdmContext(spdmContext);
return false;
}
// Housekeeping part
std::fill_n(request.begin(), request.size(), 0);
std::fill_n(response.begin(), response.size(), 0);
data.clear();
//Caps Send Part
if (!validateSpdmRc(libspdm_build_request_get_capabilities(
spdmContext, &request, &requestSize)))
{
freeSpdmContext(spdmContext);
return false;
}
data = formSendMessage(requestSize, request);
data.insert(data.begin(), 5); // Transport layer Message Type
//Send the message in async manner and storeresponse in std::vector<uint8_t> responseData;
//Caps Receive Part
responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet
std::copy(responseData.begin(), responseData.end(),
response.begin());
if (!validateSpdmRc(libspdm_process_response_capabilities(
spdmContext, &response, responseData.size())))
{
freeSpdmContext(spdmContext);
return false;
}
// Housekeeping part
std::fill_n(request.begin(), request.size(), 0);
std::fill_n(response.begin(), response.size(), 0);
data.clear();
//Negotiate Algo Send Part
if (!validateSpdmRc(libspdm_build_request_negotiate_algorithms(
spdmContext, &request, &requestSize)))
{
freeSpdmContext(spdmContext);
return false;
}
data = formSendMessage(requestSize, request);
data.insert(data.begin(), 5); // Transport layer Message Type
//Send the message in async manner and store response in std::vector<uint8_t> responseData;
//Algo Receive Part
responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet
std::copy(responseData.begin(), responseData.end(),
response.begin());
if (!validateSpdmRc(libspdm_process_response_algorithms(
spdmContext, &response, responseData.size())))
{
freeSpdmContext(spdmContext);
return false;
}
return true;
}
@jyao1 , here is my sample code which I used to test the PR.
bool getVCA() { std::array<uint8_t, 100> request; std::array<uint8_t, 500> response; size_t requestSize = request.size(); //Get Version Send Part if (!validateSpdmRc(libspdm_build_request_get_version( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } std::vector<uint8_t> data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and store response in std::vector<uint8_t> responseData; //Version Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_version( spdmContext, &response, responseData.size(), NULL, NULL))) { freeSpdmContext(spdmContext); return false; } // Housekeeping part std::fill_n(request.begin(), request.size(), 0); std::fill_n(response.begin(), response.size(), 0); data.clear(); //Caps Send Part if (!validateSpdmRc(libspdm_build_request_get_capabilities( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and storeresponse in std::vector<uint8_t> responseData; //Caps Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_capabilities( spdmContext, &response, responseData.size()))) { freeSpdmContext(spdmContext); return false; } // Housekeeping part std::fill_n(request.begin(), request.size(), 0); std::fill_n(response.begin(), response.size(), 0); data.clear(); //Negotiate Algo Send Part if (!validateSpdmRc(libspdm_build_request_negotiate_algorithms( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and store response in std::vector<uint8_t> responseData; //Algo Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_algorithms( spdmContext, &response, responseData.size()))) { freeSpdmContext(spdmContext); return false; } return true; }
Is my usage wrong here ? The Integrator is looking for Transport encoded payload and payload size. The intention is to send and receive the data asynchronously.
@jyao1 , here is my sample code which I used to test the PR.
bool getVCA() { std::array<uint8_t, 100> request; std::array<uint8_t, 500> response; size_t requestSize = request.size(); //Get Version Send Part if (!validateSpdmRc(libspdm_build_request_get_version( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } std::vector<uint8_t> data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and store response in std::vector<uint8_t> responseData; //Version Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_version( spdmContext, &response, responseData.size(), NULL, NULL))) { freeSpdmContext(spdmContext); return false; } // Housekeeping part std::fill_n(request.begin(), request.size(), 0); std::fill_n(response.begin(), response.size(), 0); data.clear(); //Caps Send Part if (!validateSpdmRc(libspdm_build_request_get_capabilities( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and storeresponse in std::vector<uint8_t> responseData; //Caps Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_capabilities( spdmContext, &response, responseData.size()))) { freeSpdmContext(spdmContext); return false; } // Housekeeping part std::fill_n(request.begin(), request.size(), 0); std::fill_n(response.begin(), response.size(), 0); data.clear(); //Negotiate Algo Send Part if (!validateSpdmRc(libspdm_build_request_negotiate_algorithms( spdmContext, &request, &requestSize))) { freeSpdmContext(spdmContext); return false; } data = formSendMessage(requestSize, request); data.insert(data.begin(), 5); // Transport layer Message Type //Send the message in async manner and store response in std::vector<uint8_t> responseData; //Algo Receive Part responseData.erase(responseData.begin()) // Remove value at index 0 which contains MCTP Message Type; the result contains only SPDM Resp Packet std::copy(responseData.begin(), responseData.end(), response.begin()); if (!validateSpdmRc(libspdm_process_response_algorithms( spdmContext, &response, responseData.size()))) { freeSpdmContext(spdmContext); return false; } return true; }Is my usage wrong here ? The Integrator is looking for Transport encoded payload and payload size. The intention is to send and receive the data asynchronously.
@PrithviAPai
Hi. In libspdm, we first build the request and then call the libspdm_send_request, which will fill the context->last_spdm_request. In your test case, you use your own send function. I think you may need fill the context->last_spdm_request before send. Thanks!
@PrithviAPai Hi. In libspdm, we first build the request and then call the
libspdm_send_request, which will fill thecontext->last_spdm_request. In your test case, you use your own send function. I think you may need fill thecontext->last_spdm_requestbefore send. Thanks!
@Wenxing-hou thank you I will verify and let you know the results. Meanwhile how about the receive part ? How do we need to handle that ? Once we get response from device(SPDM endpoint) ?
@PrithviAPai Hi. In libspdm, we first build the request and then call the
libspdm_send_request, which will fill thecontext->last_spdm_request. In your test case, you use your own send function. I think you may need fill thecontext->last_spdm_requestbefore send. Thanks!@Wenxing-hou thank you I will verify and let you know the results. Meanwhile how about the receive part ? How do we need to handle that ? Once we get response from device(SPDM endpoint) ?
@Wenxing-hou @steven-bellock @jyao1 any suggestions on this ?
calling libspdm_receive_response will trigger the callback which is NOT necessary in this case.
Is there any way to make this work without triggering send and receive callbacks ?
@PrithviAPai Hi. In libspdm, we first build the request and then call the
libspdm_send_request, which will fill thecontext->last_spdm_request. In your test case, you use your own send function. I think you may need fill thecontext->last_spdm_requestbefore send. Thanks!@Wenxing-hou thank you I will verify and let you know the results. Meanwhile how about the receive part ? How do we need to handle that ? Once we get response from device(SPDM endpoint) ?
@Wenxing-hou @steven-bellock @jyao1 any suggestions on this ? calling
libspdm_receive_responsewill trigger the callback which is NOT necessary in this case. Is there any way to make this work without triggering send and receive callbacks ?
The libspdm internal state should be managed correctly. Why you cannot call libspdm_receive_response ?
@PrithviAPai Hi. In libspdm, we first build the request and then call the
libspdm_send_request, which will fill thecontext->last_spdm_request. In your test case, you use your own send function. I think you may need fill thecontext->last_spdm_requestbefore send. Thanks!@Wenxing-hou thank you I will verify and let you know the results. Meanwhile how about the receive part ? How do we need to handle that ? Once we get response from device(SPDM endpoint) ?
@Wenxing-hou @steven-bellock @jyao1 any suggestions on this ? calling
libspdm_receive_responsewill trigger the callback which is NOT necessary in this case. Is there any way to make this work without triggering send and receive callbacks ?The libspdm internal state should be managed correctly. Why you cannot call
libspdm_receive_response?
We are calling libspdm_handle_response with giving response buffer as one of the parameter. So I feel it would be unnecessary to call libspdm_receive_response. Please share your thoughts.
@PrithviAPai , maybe I am a little lost.
Here we are discussing how to support SPDM Requester. Please clarify if you are talking SPDM Requester or SPDM Responder?
Also, there is no libspdm_handle_response API in libspdm. Which API you are talking?
@PrithviAPai , maybe I am a little lost.
Here we are discussing how to support SPDM Requester. Please clarify if you are talking SPDM Requester or SPDM Responder?
Also, there is no
libspdm_handle_responseAPI in libspdm. Which API you are talking?
Yes, this is about SPDM Requester. Sorry for the confusion
When we split encode and decode APIs we have libspdm_process_response_version , libspdm_process_response_capabilities and libspdm_process_response_algorithms. Integrator is supposed to call with response payload. So I did not understand the part when integrator needs to call libspdm_receive_response.
@PrithviAPai
libspdm_send_request() need to maintain the spdm context. For example, to backup the last_spdm_request.
See below:
/* backup it to last_spdm_request, because the caller wants to compare it with response */
if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY
&& ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET
&& ((const spdm_message_header_t*) request)->request_response_code != SPDM_CHUNK_SEND) {
libspdm_copy_mem (context->last_spdm_request,
libspdm_get_scratch_buffer_last_spdm_request_capacity(context),
request,
request_size
);
context->last_spdm_request_size = request_size;
}
Because you do not call the function and your own code does not backup the last_spdm_request, that is the reason on the failure.
@PrithviAPai
libspdm_send_request()need to maintain the spdm context. For example, to backup the last_spdm_request.See below:
/* backup it to last_spdm_request, because the caller wants to compare it with response */ if (((const spdm_message_header_t *)request)->request_response_code != SPDM_RESPOND_IF_READY && ((const spdm_message_header_t *)request)->request_response_code != SPDM_CHUNK_GET && ((const spdm_message_header_t*) request)->request_response_code != SPDM_CHUNK_SEND) { libspdm_copy_mem (context->last_spdm_request, libspdm_get_scratch_buffer_last_spdm_request_capacity(context), request, request_size ); context->last_spdm_request_size = request_size; }Because you do not call the function and your own code does not backup the last_spdm_request, that is the reason on the failure.
Okay I will try with calling libspdm_send_request once I have request to send.
I have question in response phase:
Once I have response from EndPoint I call libspdm_process_response_version which does not support transport decoding/decryption. So what is the suggestion on receive part when we split the Request and Response ?