UEFI TLS Socket: TlsDoHandshake error while trying to build response packet

64 views Asked by At

I'm currently trying to communicate with a remote server that only accepts TLS connections, so I have to implement TLS over the TCP protocol in UEFI using the TLS protocol. However when trying build the response packet im getting the following error chain:

TlsDoHandshake SSL_HANDSHAKE_ERROR State=0x4 SSL_ERROR_SSL
TlsDoHandshake ERROR 0x680009F=LD:R9F
TlsDoHandshake ERROR 0x688010A=LD:R8010A
TlsDoHandshake ERROR 0x688010A=LD:R8010A
TlsDoHandshake ERROR 0xA08000D=L14:R8000D

I'm orientating my logic on the HttpsSupport.c file in the HttpDxe as this is the only "documentation" how to use the TLS protocol in UEFI. To send the ClientHello packet I'm calling the BuildResponsePacket function with RequestBuffer and RequestSize on 0 to initiate a Handshake, then I'm looping and reading a TLS record until the Handshake is done. Below is a simplified code without error handling for simplicity and to point out to the logic.

static EFI_STATUS receive_tls_record(void** buffer, unsigned __int16* buffer_size)
{
    TLS_RECORD_HEADER tls_record_header = { 0 };
    bsd_read(&tls_record_header, TLS_RECORD_HEADER_LENGTH);

    if (EFI_ERROR(status))
    {
        return status;
    }

    unsigned __int16 size = 0;

    if (((tls_record_header.ContentType == TlsContentTypeHandshake) ||
        (tls_record_header.ContentType == TlsContentTypeAlert) ||
        (tls_record_header.ContentType == TlsContentTypeChangeCipherSpec) ||
        (tls_record_header.ContentType == TlsContentTypeApplicationData)) &&
        (tls_record_header.Version.Major == 0x03) && (tls_record_header.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR))
    {
        size += TLS_RECORD_HEADER_LENGTH;

    }
    else
    {
        return EFI_PROTOCOL_ERROR;
    }

    unsigned __int16 payload_size = SwapBytes16(tls_record_header.Length);
    void* payload = AllocateZeroPool(payload_size);

    bsd_read(payload, payload_size);

    size += payload_size;

    void* tls_record = AllocatePool(size);

    CopyMem(tls_record, &tls_record_header, sizeof(tls_record_header));
    CopyMem((unsigned __int8*)tls_record + sizeof(tls_record_header), payload, payload_size);

    FreePool(payload);

    *buffer = tls_record;
    *buffer_size = size;

    return EFI_SUCCESS
}

EFI_STATUS tls_handshake()
{
    g_bsd_context.tls_session_state = EfiTlsSessionNotStarted;
    g_bsd_context.tls_protocol->SetSessionData(g_bsd_context.tls_protocol, EfiTlsSessionState, &g_bsd_context.tls_session_state, sizeof(g_bsd_context.tls_session_state));

    unsigned __int64 buffer_size = 0x100;
    void* buffer = AllocateZeroPool(buffer_size);

    EFI_STATUS status = g_bsd_context.tls_protocol->BuildResponsePacket(g_bsd_context.tls_protocol, 0, 0, buffer, &buffer_size);

    if (status == EFI_BUFFER_TOO_SMALL)
    {
        FreePool(buffer);
        buffer = AllocateZeroPool(buffer_size);

        if (!buffer)
        {
            status = EFI_OUT_OF_RESOURCES;
            return status;
        }

        status = g_bsd_context.tls_protocol->BuildResponsePacket(g_bsd_context.tls_protocol, 0, 0, buffer, &buffer_size);
    }

    bsd_write(buffer, buffer_size);

    FreePool(buffer);

    while (g_bsd_context.tls_session_state != EfiTlsSessionDataTransferring)
    {
        void* tls_record = 0;
        unsigned __int16 tls_record_size = 0;

        buffer = 0;
        buffer_size = 0x100;

        status = receive_tls_record((void**)&tls_record, &tls_record_size);

        if (EFI_ERROR(status))
        {
            return status;
        }

        buffer = AllocateZeroPool(buffer_size);

        status = g_bsd_context.tls_protocol->BuildResponsePacket(g_bsd_context.tls_protocol, tls_record, tls_record_size, buffer, &buffer_size);

        if (status == EFI_BUFFER_TOO_SMALL)
        {
            FreePool(buffer);
            buffer = AllocateZeroPool(buffer_size);

            if (!buffer)
            {
                FreePool(tls_record);

                status = EFI_OUT_OF_RESOURCES;
                return status;
            }

            status = g_bsd_context.tls_protocol->BuildResponsePacket(g_bsd_context.tls_protocol, tls_record, tls_record_size, buffer, &buffer_size);
        }

        if (EFI_ERROR(status))
        {
            FreePool(tls_record);
            FreePool(buffer);
            return status;
        }

        if (buffer_size != 0)
        {
            bsd_write(buffer, buffer_size);
        }
        
    FreePool(tls_record);
    FreePool(buffer);

        unsigned __int64 session_data_size = sizeof(EFI_TLS_SESSION_STATE);
        status = g_bsd_context.tls_protocol->GetSessionData(g_bsd_context.tls_protocol, EfiTlsSessionState, &g_bsd_context.tls_session_state, &session_data_size);

        if (g_bsd_context.tls_session_state == EfiTlsSessionError)
        {
            status = EFI_ABORTED;
            return status;
        }
    }

    if (g_bsd_context.tls_session_state != EfiTlsSessionDataTransferring)
    {
        status = EFI_ABORTED;
    }

    return status;
}

Any help would be greatly appreciated!

0

There are 0 answers