macos - EIdOSSLUnderlyingCryptoError 和 "Error connecting with SSL. error:14094410..."

标签 macos delphi openssl indy

我在 OS X 上的 Delphi 10.1 Berlin 中遇到 Indy 组件问题。我使用 TIdHTTP 通过 HTTPS 连接到 Web 服务。问题是从 OS X 客户端连接到服务器。在 OS X 上运行时,我总是遇到同样的错误:

Project raised exception class EIdOSSLUnderlyingCryptoError with message 'Error connecting 
with SSL. error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure'.

我设置了 TIdHTTP.IOHandler 属性以使用 OpenSSL:

IdHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

在 OS X 上,当我在终端中运行此命令时:

openssl version

它返回 OpenSSL 0.9,这是 OS X 附带的默认版本。

即使我使用 Homebrew 或 MacPort 安装最新版本的 OpenSSL,也没有帮助。它每次都会给我同样的错误。

我在 VMWare 中安装了 OS X,如果这有帮助的话。我还尝试了两个版本的 OS X:Yosemite 和 El Capitan。同样的问题。

这是我使用的代码:

unit uApiClient1;

interface

uses
  IdHTTP, System.JSON, IdSSLOpenSSLHeaders, System.Classes, IdCTypes,
  System.SysUtils, IdSSLOpenSSL;

const
  API_URL = 'https://www.myserver.com/ws.php';
  WS_METHOD = 'validate_status';

type
  TAPIClient = class(TObject)
    function ValidateStatus(userId, deviceId: string): TJSONObject;
  private
    procedure PrepareHTTPObject(var IdHTTP: TIdHTTP);
  end;


implementation

{ APIClient }

procedure TAPIClient.PrepareHTTPObject(var IdHTTP: TIdHTTP);
begin
  IdHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  TIdSSLIOHandlerSocketOpenSSL(IdHTTP.IOHandler).SSLOptions.Method := sslvTLSv1_2;
  //
  IdHTTP.Request.Accept := 'text/javascript';
  IdHTTP.Request.ContentType := 'application/json';
  IdHTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
end;

function TAPIClient.ValidateStatus(userId, deviceId: string): TJSONObject;
var
  IdHTTP: TIdHTTP;
  LJSONObject: TJSONObject;
  dataResult: string;
begin
  LJSONObject := nil;
  IdHTTP := TIdHTTP.Create(nil);
  try
    try
      PrepareHTTPObject(IdHTTP);
      dataResult := IdHTTP.Get(API_URL + format('?action=%s&user_id=%s&device_id=%s', [WS_METHOD, userId, deviceid]));
      LJSONObject := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(dataResult), 0) as TJSONObject;
    except
    end;
  finally
   IdHTTP.Free;
  end;
  Result := LJSONObject;
end;

end.

我尝试比较由我的应用程序和 Safari 生成的 WireShark 数据包,这就是我得到的结果:

我的应用程序:

Handshake Protocol: Client Hello
    Handshake Type: Client Hello (1)
    Length: 114
    Version: TLS 1.0 (0x0301)
    Random
        GMT Unix Time: Aug 24, 2016 20:26:07.000000000 EEST
        Random Bytes: 49c48ba758048a2429dd01ee2e390ed06eb320e5248d016d...
    Session ID Length: 0
    Cipher Suites Length: 46
    Cipher Suites (23 suites)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
        Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA (0x0038)
        Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
        Cipher Suite: TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (0x0016)
        Cipher Suite: TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA (0x0013)
        Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
        Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA (0x0032)
        Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
        Cipher Suite: TLS_DHE_RSA_WITH_SEED_CBC_SHA (0x009a)
        Cipher Suite: TLS_DHE_DSS_WITH_SEED_CBC_SHA (0x0099)
        Cipher Suite: TLS_RSA_WITH_SEED_CBC_SHA (0x0096)
        Cipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005)
        Cipher Suite: TLS_RSA_WITH_RC4_128_MD5 (0x0004)
        Cipher Suite: TLS_DHE_RSA_WITH_DES_CBC_SHA (0x0015)
        Cipher Suite: TLS_DHE_DSS_WITH_DES_CBC_SHA (0x0012)
        Cipher Suite: TLS_RSA_WITH_DES_CBC_SHA (0x0009)
        Cipher Suite: TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA (0x0014)
        Cipher Suite: TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA (0x0011)
        Cipher Suite: TLS_RSA_EXPORT_WITH_DES40_CBC_SHA (0x0008)
        Cipher Suite: TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (0x0006)
        Cipher Suite: TLS_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)
        Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
    Compression Methods Length: 1
    Compression Methods (1 method)
    Extensions Length: 27
    Extension: server_name
    Extension: SessionTicket TLS
        Type: SessionTicket TLS (0x0023)
        Length: 0
        Data (0 bytes)

Safari 浏览器:

Handshake Protocol: Client Hello
    Handshake Type: Client Hello (1)
    Length: 229
    Version: TLS 1.2 (0x0303)
    Random
        GMT Unix Time: Aug 24, 2016 20:35:07.000000000 EEST
        Random Bytes: d0f0bc116fd51dff15c739bb76f7e6032a931d07e2e56a56...
    Session ID Length: 0
    Cipher Suites Length: 44
    Cipher Suites (22 suites)
        Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA (0xc008)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
        Cipher Suite: TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (0xc012)
        Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
        Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
        Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
        Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
        Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
        Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
        Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
    Compression Methods Length: 1
    Compression Methods (1 method)
    Extensions Length: 144
    Extension: server_name
    Extension: elliptic_curves
    Extension: ec_point_formats
    Extension: signature_algorithms
        Type: signature_algorithms (0x000d)
        Length: 14
        Signature Hash Algorithms Length: 12
        Signature Hash Algorithms (6 algorithms)
    Extension: next_protocol_negotiation
        Type: next_protocol_negotiation (0x3374)
        Length: 0
    Extension: Application Layer Protocol Negotiation
        Type: Application Layer Protocol Negotiation (0x0010)
        Length: 48
        ALPN Extension Length: 46
        ALPN Protocol
    Extension: status_request
        Type: status_request (0x0005)
        Length: 5
        Certificate Status Type: OCSP (1)
        Responder ID list Length: 0
        Request Extensions Length: 0
    Extension: signed_certificate_timestamp
        Type: signed_certificate_timestamp (0x0012)
        Length: 0
        Data (0 bytes)

在WireShark的协议(protocol)栏中,对于Savari来说是TLSv1.2,对于我的应用程序来说是TLSv1,即使我将方法设置为sslvTLSv1_2 > 在代码中。

两个 SNI 均已正确设置。


这是来自 WireShark 的 TLS 警报:

Secure Sockets Layer
    TLSv1 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
        Content Type: Alert (21)
        Version: TLS 1.0 (0x0301)
        Length: 2
        Alert Message
            Level: Fatal (2)
            Description: Handshake Failure (40)

最佳答案

经过多天的研究,我终于找到了解决我的问题的方法。

为了确保应用程序使用最新版本的 OpenSSL 库(不依赖于 OS X 中安装的库),我发现我可以在应用程序包中包含已编译的 OpenSSL 库。

就我而言,我需要 openSSL 库的 x86 编译版本。 Homebrew 和 Macport 在安装最后一个 openssl 时,编译 x64 版本的库,这就是使用此链接的原因:

Compilation and Installation of OpenSSL libraries

我编译了 x86 版本的 openSSL 库。

接下来感谢Marco Cantu tech Blog ,我发现我可以使用 IdOpenSSLSetLibPath 方法来设置 openssl 库路径。

最后,将编译后的库与应用程序包含在同一包中并使用以下代码:

IdOpenSSLSetLibPath(ExtractFilePath(ParamStr(0)));

我获得了支持 TLSv1.2 的正确版本的 openssl 库

关于macos - EIdOSSLUnderlyingCryptoError 和 "Error connecting with SSL. error:14094410...",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39093781/

相关文章:

c# - 有什么方法可以在 OS X 上开发 Silverlight 应用程序吗?

macos - NSTask的实时输出

macos - 核心显卡和 cocoa 闪烁

delphi - 需要表格仅保留在父级之上

delphi - delphi中如何创建xml文件

c++ - 即使使用 lib 文件也无法修复未解析的外部符号 _AES_encrypt

c++ - 如何使用C或C++在Mac上模拟鼠标移动和鼠标点击

delphi - URL停止使用Delphi服务

c++ - 通过 C++ 从 PKCS7 (CMS) 获取详细信息

openssl - 使用 socat 和 openssl 作为 DTLS/PSK 隧道