Indy TCP клиент-сервер не работает с OpenSSL - PullRequest
0 голосов
/ 29 апреля 2019

В C ++ Builder 10.3.1 я использую клиент-серверные компоненты Indy TCP (TIdTCPClient & TIdTCPServer) для создания примера зашифрованной связи с OpenSSL. Я использую этот пример кода:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    C1->Connect();
    C1->Socket->Write(4);
    int res = C1->Socket->ReadInt32();
    C1->Disconnect();
    ShowMessage(res);
}

void __fastcall TForm1::S1Execute(TIdContext *AContext)
{
    int x = AContext->Connection->Socket->ReadInt32();
    AContext->Connection->Socket->Write(x * x);
    AContext->Connection->Disconnect();
}

Без OpenSSL все работает нормально, но после добавления компонентов IdSSLIOHandlerSocketOpenSSL1 и IdServerIOHandlerSSLOpenSSL1 и назначения их для клиент-серверных компонентов TCP (свойство IOHandler) я получаю сообщение об ошибке " Не удалось загрузить библиотеку SSL ». В этом случае я использовал двоичные файлы OpenSSL 1.0.2 (ssleay32.dll и libeay32.dll) из https://indy.fulgan.com/SSL/.

Но мне удалось найти старые библиотеки OpenSSL, которые были успешно загружены. Тем не менее, тогда я получаю следующую ошибку:

Ошибка подключения по SSL. EOF был замечен, что нарушает протокол.

Как заставить это работать?

РЕДАКТИРОВАТЬ: После установки PassThrough на false как на стороне клиента, так и на сервере я получаю:

ошибка: 14094410: процедуры SSL: SSL3_READ_BYTES: сбой квитирования оповещения sslv3

РЕДАКТИРОВАТЬ: Вот полный код моей формы и DFM:

unit1.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    IdSSLIOHandlerSocketOpenSSL1->PassThrough = false;
    C1->Connect();
    C1->Socket->Write(5);
    int res = C1->Socket->ReadInt32();
    C1->Disconnect();
    ShowMessage(res);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::S1Execute(TIdContext *AContext)
{
    int x = AContext->Connection->Socket->ReadInt32();
    AContext->Connection->Socket->Write(x * x);
    AContext->Connection->Disconnect();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::S1Connect(TIdContext *AContext)
{
    static_cast<TIdSSLIOHandlerSocketOpenSSL*>(AContext->Connection->Socket)->PassThrough = false;
}
//---------------------------------------------------------------------------

Unit1.h

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdCustomTCPServer.hpp>
#include <IdIOHandler.hpp>
#include <IdIOHandlerSocket.hpp>
#include <IdIOHandlerStack.hpp>
#include <IdServerIOHandler.hpp>
#include <IdSSL.hpp>
#include <IdSSLOpenSSL.hpp>
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>
#include <IdTCPServer.hpp>
#include <IdContext.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TIdTCPClient *C1;
    TIdTCPServer *S1;
    TIdServerIOHandlerSSLOpenSSL *IdServerIOHandlerSSLOpenSSL1;
    TIdSSLIOHandlerSocketOpenSSL *IdSSLIOHandlerSocketOpenSSL1;
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall S1Execute(TIdContext *AContext);
    void __fastcall S1Connect(TIdContext *AContext);
private:    // User declarations
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.dfm

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 299
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 24
    Top = 208
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object C1: TIdTCPClient
    IOHandler = IdSSLIOHandlerSocketOpenSSL1
    ConnectTimeout = 0
    Host = '127.0.0.1'
    IPVersion = Id_IPv4
    Port = 5577
    ReadTimeout = -1
    Left = 168
    Top = 96
  end
  object S1: TIdTCPServer
    Active = True
    Bindings = <
      item
        IP = '0.0.0.0'
        Port = 5577
      end>
    DefaultPort = 0
    IOHandler = IdServerIOHandlerSSLOpenSSL1
    OnConnect = S1Connect
    OnExecute = S1Execute
    Left = 240
    Top = 96
  end
  object IdServerIOHandlerSSLOpenSSL1: TIdServerIOHandlerSSLOpenSSL
    SSLOptions.Mode = sslmUnassigned
    SSLOptions.VerifyMode = []
    SSLOptions.VerifyDepth = 0
    Left = 464
    Top = 40
  end
  object IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL
    Destination = '127.0.0.1:5577'
    Host = '127.0.0.1'
    MaxLineAction = maException
    Port = 5577
    DefaultPort = 0
    SSLOptions.Mode = sslmUnassigned
    SSLOptions.VerifyMode = []
    SSLOptions.VerifyDepth = 0
    Left = 320
    Top = 184
  end
end

Ответы [ 2 ]

3 голосов
/ 29 апреля 2019

после добавления компонентов IdSSLIOHandlerSocketOpenSSL1 и IdServerIOHandlerSSLOpenSSL1 и назначения их клиент-серверным компонентам TCP (свойство IOHandler) появляется сообщение об ошибке «Не удалось загрузить библиотеку SSL».

Убедитесь, что у вас есть актуальные библиотеки OpenSSL 1.0.2 (Indy еще не поддерживает OpenSSL 1.1.x) в папке вашего приложения или в папке, которую вы указываете с помощью функции IdOpenSSLSetLibPath() в IdSSLOpenSSLHeaders.hpp в программепри запуске.

Если у вас по-прежнему возникает ошибка, вы можете использовать функцию Indy WhichFailedToLoad() в IdSSLOpenSSLHeaders.hpp, чтобы выяснить, почему библиотеки DLL не загружаются - либо потому, что сами библиотеки DLL не могут быть найдены или загружены в памятьили из-за отсутствия необходимых экспортируемых функций, которые использует Indy.

В этом случае я использовал двоичные файлы OpenSSL 1.0.2 (ssleay32.dll и libeay32.dll) из https://indy.fulgan.com/SSL/.

Известно, что эти DLL прекрасно работают с Indy.

тогда я получаю следующую ошибку:

Ошибка подключения по SSL.Обнаружено, что EOF нарушает протокол.

Эта ошибка означает, что сервер закрыл соединение TCP на своем конце, пока клиент все еще выполнял рукопожатие SSL / TLS.Это может произойти, например, если возникнет исключение на стороне сервера.По умолчанию TIdTCPServer обрабатывает необработанное исключение, закрывая сокет.

Распространенной ошибкой не является установка для свойства TIdSSLIOHandlerSocketOpenSSL::PassThrough значения false на стороне сервера.Его необходимо установить вручную, поскольку TIdTCPServer не устанавливает его автоматически, чтобы позволить пользователям решать, какой порт (ы) должен использовать SSL / TLS.PassThrough необходимо установить на true на обоих концах соединения.

На стороне клиента вы можете установить PassThrough перед вызовом Connect() (т. Е. Для неявного SSL) или после (т.е. для STARTTLS-подобных команд).

На стороне сервера вы можете установить PassThrough в событии OnConnect (т. е. для неявного SSL) или в событии OnExecute (т. е. дляSTARTTLS-подобные команды).

В вашем примере попробуйте это:

void __fastcall TForm1::Button1Click(TObject *Sender) 
{
    IdSSLIOHandlerSocketOpenSSL1->PassThrough = false;
    C1->Connect();
    C1->Socket->Write(4);
    int res = C1->Socket->ReadInt32();
    C1->Disconnect();
    ShowMessage(res);
}

void __fastcall TForm1::S1Connect(TIdContext *AContext)
{
    static_cast<TIdSSLIOHandlerSocketOpenSSL*>(AContext->Connection->Socket)->PassThrough = false;
}

void __fastcall TForm1::S1Execute(TIdContext *AContext)
{
    int x = AContext->Connection->Socket->ReadInt32();
    AContext->Connection->Socket->Write(x * x);
    AContext->Connection->Disconnect();
}

И, разумеется, убедитесь, что IOHandlers с обеих сторон настроены одинаково для использования совместимых SSL / TLSверсии протокола, сертификаты и т. д.

0 голосов
/ 29 апреля 2019

Убедитесь, что вы используете 32-битные библиотеки OpenSSL (i386-win32), если ваша программа 32-битная.

...