libspdm icon indicating copy to clipboard operation
libspdm copied to clipboard

Split get_version/get_capabilities/negotiate_algorithms request.

Open Wenxing-hou opened this issue 2 years ago • 17 comments

Fix: #2394

Split get_version/get_capabilities/negotiate_algorithms request.

Wenxing-hou avatar Oct 13 '23 03:10 Wenxing-hou

@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.

PrithviAPai avatar Dec 16 '23 03:12 PrithviAPai

@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 avatar Dec 18 '23 13:12 PrithviAPai

@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 avatar Dec 20 '23 02:12 Wenxing-hou

@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 avatar Dec 20 '23 03:12 PrithviAPai

@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 avatar Dec 20 '23 06:12 jyao1

@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;
}

PrithviAPai avatar Dec 20 '23 06:12 PrithviAPai

@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 avatar Dec 21 '23 06:12 PrithviAPai

@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.

Wenxing-hou avatar Dec 25 '23 03:12 Wenxing-hou

@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!

Wenxing-hou avatar Dec 25 '23 03:12 Wenxing-hou

@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!

@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 avatar Dec 25 '23 14:12 PrithviAPai

@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!

@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 avatar Jan 04 '24 04:01 PrithviAPai

@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!

@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 ?

The libspdm internal state should be managed correctly. Why you cannot call libspdm_receive_response ?

jyao1 avatar Jan 10 '24 00:01 jyao1

@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!

@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 ?

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 avatar Jan 10 '24 04:01 PrithviAPai

@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?

jyao1 avatar Jan 10 '24 06:01 jyao1

@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?

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 avatar Jan 10 '24 08:01 PrithviAPai

@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.

jyao1 avatar Jan 10 '24 10:01 jyao1

@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 ?

PrithviAPai avatar Jan 10 '24 10:01 PrithviAPai