【问题标题】:Indy TCP client-server don't work with OpenSSLIndy TCP 客户端-服务器不适用于 OpenSSL
【发布时间】:2019-04-29 07:05:31
【问题描述】:

在 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 一切正常,但在添加 IdSSLIOHandlerSocketOpenSSL1IdServerIOHandlerSSLOpenSSL1 组件并将它们分配给 TCP 客户端-服务器组件(IOHandler 属性)后,我收到错误“无法加载 SSL 库强>”。在那种情况下,我使用了来自https://indy.fulgan.com/SSL/ 的 OpenSSL 1.0.2 二进制文件(ssleay32.dll 和 libeay32.dll)。

但是,我设法找到了已成功加载的旧 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

【问题讨论】:

    标签: delphi openssl c++builder indy rad-studio


    【解决方案1】:

    在添加 IdSSLIOHandlerSocketOpenSSL1IdServerIOHandlerSSLOpenSSL1 组件并将它们分配给 TCP 客户端-服务器组件(IOHandler 属性)后,我收到错误“无法加载 SSL 库”。

    确保您的应用文件夹或您使用 @987654326 中的 IdOpenSSLSetLibPath() 函数指定的文件夹中具有最新的 OpenSSL 1.0.2 DLL(Indy 尚不支持 OpenSSL 1.1.x) @在程序启动时。

    如果您仍然遇到错误,您可以使用 Indy 的 WhichFailedToLoad() 函数在 IdSSLOpenSSLHeaders.hpp 中找出未加载 DLL 的原因 - 要么是因为 DLL 本身无法找到或加载到内存中,要么是因为它们缺少 Indy 使用的必需导出函数。

    在这种情况下,我使用来自https://indy.fulgan.com/SSL/ 的 OpenSSL 1.0.2 二进制文件(ssleay32.dll 和 libeay32.dll)。

    众所周知,这些 DLL 可以在 Indy 上正常工作。

    然后我收到以下错误:

    使用 SSL 连接时出错。观察到 EOF 违反了协议。

    该错误意味着服务器在客户端仍在执行 SSL/TLS 握手时关闭了 TCP 连接。例如,如果在服务器端引发异常,就会发生这种情况。默认情况下,TIdTCPServer 通过关闭套接字来处理未捕获的异常。

    在服务器端不将TIdSSLIOHandlerSocketOpenSSL::PassThrough 属性设置为false 是一个常见错误。它需要手动设置,因为TIdTCPServer 不会自动设置它,以允许用户决定哪些端口应该使用 SSL/TLS。 PassThrough需要在connecton的两端设置为true

    在客户端,您可以在调用 Connect() 之前(即,对于隐式 SSL)或之后(即,对于类似 STARTTLS 的命令)设置 PassThrough

    在服务器端,您可以在OnConnect 事件(即,用于隐式 SSL)或OnExecute 事件(即,用于类似 STARTTLS 的命令)中设置PassThrough

    在你的例子中,试试这个:

    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();
    }
    

    而且,不用说,确保双方的 IOHandler 配置相似,以使用兼容的 SSL/TLS 协议版本、证书等。

    【讨论】:

    • 只有当我在两边都将PassThrough 设置为true 时,您的修改才对我有效。如果它设置为false(就像您在示例中指定的那样)我收到握手失败错误?
    • @Tracer 这应该是一个问题还是一个陈述?我向您保证,这些东西在正确使用 时可以正常工作,所以您一定遗漏了一些您还没有描述的东西。请编辑您的问题以显示实际错误以及两端的实际组件设置。
    • 我已经把所有东西都放在了一个最小的项目中来演示:link。请检查一下。运行此项目并尝试发送数据时,我收到握手失败错误。但是,如果我将 PassThrough 更改为 true 它工作正常。所以,我有点困惑应该将它设置为true(就像你在帖子中说的那样)还是应该是false(就像你在上面的例子中指定的那样。
    • @Tracer 当PassThrough 为真时,数据在没有 SSL/TLS 加密的情况下按原样“通过”套接字。当PassThrough 为假时,数据被加密。我所说的一切都是准确的。如果您遇到握手错误,那是因为您在设置中的某个地方有错误。但是我看不到你的设置,我不会去从另一个站点下载代码来寻找它。 StackOverflow 是一个问答网站,问题旨在自包含。同样,请编辑您的问题,直接在其中发布相关详细信息,它们所属的位置
    • 好的。我现在了解PassThrough。抱歉,我不知道您需要我提供什么信息。我只在所有组件中使用默认设置。由于您不想检查我发送的样品,我只能感谢您迄今为止的时间和帮助,并将尝试在其他地方搜索。问候!
    【解决方案2】:

    如果您的程序是 32 位,请确保使用 32 位 OpenSSL DLL (i386-win32)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-28
      • 2017-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多