SSL 握手失败 - 客户端证书无效

<ph type="x-smartling-placeholder"></ph> 您正在查看 Apigee Edge 文档。
转到 Apigee X 文档
信息

问题

客户端应用收到 HTTP 状态代码 503, 消息 "Service Unavailable" 作为对 API 请求的响应。 在界面跟踪记录中,您会发现 error.cause 在目标请求流中处于“Received fatal alert: bad_certificate”状态 为失败的 API 请求提供此属性

如果您可以访问消息处理器日志 那么您会看到如下错误消息:Received fatal alert: bad_certificate 为失败的 API 请求提供此属性在 SSL 握手期间观察到此错误 采用双向 TLS 设置在邮件处理器和后端服务器之间传输数据。

错误消息

客户端应用将获得以下响应代码:

HTTP/1.1 503 Service Unavailable

此外,您可能还会看到以下错误消息:

{
 "fault": {
    "faultstring":"The Service is temporarily unavailable",
    "detail":{
        "errorcode":"messaging.adaptors.http.flow.ServiceUnavailable"
    }
 }
}

私有云用户会看到特定 API 请求的以下错误 在消息处理器日志 /opt/apigee/var/log/edge-message-processor/system.log 中:

2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate

可能的原因

此问题可能的原因如下:

原因 说明 适用的问题排查说明
无客户端证书 目标服务器的目标端点中使用的密钥库没有任何客户端证书。 Edge Private 和 Public Cloud 用户
证书授权机构不匹配 叶证书(证书链中的第一个证书)的证书授权机构 与后端服务器接受的任何证书授权机构都不匹配。 Edge Private 和 Public Cloud 用户

常见诊断步骤

  1. 在 Edge 界面中启用跟踪记录,进行 API 调用,并重现问题。
  2. 在界面轨迹结果中,浏览每个阶段并确定 发生错误。错误会发生在目标请求流中。
  3. 检查显示错误的 Flow,您应该会看到如下所示的错误 在下面的示例跟踪中:

    alt_text

  4. 如上面的屏幕截图所示,error.cause “收到了严重警报:bad_certificate”
  5. 如果您是 Private Cloud 用户,请按照以下说明操作: <ph type="x-smartling-placeholder">
      </ph>
    1. 您可以确定失败的 API 请求的消息 ID, 错误标头“X-Apigee.Message-ID”的值 与跟踪记录中的 AX 指示的阶段相一致
    2. 在消息处理器日志中搜索此邮件 ID /opt/apigee/var/log/edge-message-processor/system.log并确定 如果您能找到有关该错误的任何其他信息,请执行以下操作:
      2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() :
      SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1
      bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate
      2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLInfo:
      KeyStore:java.security.KeyStore@52de60d9 KeyAlias:KeyAlias TrustStore:java.security.KeyStore@6ec45759
      2017-10-23 05:28:57,814 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR ADAPTORS.HTTP.FLOW - RequestWriteListener.onException() :
      RequestWriteListener.onException(HTTPRequest@6071a73d)
      javax.net.ssl.SSLException: Received fatal alert: bad_certificate
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[na:1.8.0_101]
      at com.apigee.nio.NIOSelector$SelectedIterator.findNext(NIOSelector.java:496) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na]
      at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:312) [nio-1.0.0.jar:na]
      at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:302) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na]
      at com.apigee.nio.handlers.NIOThread.run(NIOThread.java:59) [nio-1.0.0.jar:na]
      

      消息处理器日志有该错误的堆栈轨迹 Received fatal alert: bad_certificate,但不 了解导致此问题的原因的任何其他信息。

  6. 要进一步调查此问题,您需要使用 tcpdump 工具中的命令。
    1. 如果您是 Private Cloud 用户, 后端服务器或消息处理器上的 TCP/IP 数据包。 最好在解密数据包时在后端服务器上捕获它们 后端服务器
    2. 如果您是公有云用户,请捕获 发送大量的数据包
    3. 确定了捕获 TCP/IP 数据包的位置后,请使用 低于 tcpdump 命令来捕获 TCP/IP 数据包。
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      如果您要接收消息处理器上的 TCP/IP 数据包,请使用 tcpdump 命令中后端服务器的公共 IP 地址。

      如果后端服务器/消息处理器有多个 IP 地址,那么 您需要使用其他 tcpdump 命令。请参阅 tcpdump 详细了解此工具以及此命令的其他变体。

  7. 使用 Wireshark 工具或您熟悉的类似工具来分析 TCP/IP 数据包。

下面展示了使用 Wireshark 工具分析 TCP/IP 数据包数据的示例:

alt_text

  1. 上述 tcpdump 中的消息 #4 显示消息处理器(源) 向后端服务器(目标)发送了一条 "Client Hello" 消息。
  2. 消息 #5 显示后端服务器确认 Client Hello 消息 从消息处理器中进行处理
  3. 后端服务器将“Server Hello”消息及其证书, 然后在消息 #7 中请求客户端发送其证书。
  4. 消息处理器完成证书的验证并确认 消息 #8 中后端服务器的 ServerHello 消息。
  5. 消息处理器将其证书发送到消息 #9 中的后端服务器。
  6. 后端服务器确认收到消息处理器的 消息 #11 中的证书。
  7. 但是,它会立即向 消息处理器(消息 #12)。这表示 消息处理器损坏,因此导致证书验证在 后端服务器因此,SSL 握手失败, 将会关闭。


    alt_text

  8. 现在,我们来看一下第 9 条消息,以检查消息处理器所发送证书的内容:


    alt_text

  9. 如您所见,后端服务器没有从客户端获取任何证书 (证书长度:0)。因此,后端服务器会发送严重警报:证书无效。
  10. 当客户端,即消息处理器(基于 Java 的进程)执行以下操作时,通常会发生这种情况: <ph type="x-smartling-placeholder">
      </ph>
    1. 密钥库中没有任何客户端证书,或者;
    2. 它无法发送客户端证书。如果找不到 由后端服务器可接受的证书授权机构颁发的证书。 也就是说,如果客户端的叶证书的证书授权机构 (即链中的第一个证书)与任何后端服务器 可接受的证书授权中心,那么消息处理器就不会发送证书。

下面我们分别介绍一下每种原因。

原因:无客户端证书

诊断

如果“SSL 信息”部分中指定的密钥库中没有证书 目标端点或目标端点中使用的目标服务器名称, 那么这就是导致此错误的原因。

请按照以下步骤确定是否是造成这种情况的原因:

  1. 确定目标端点或目标服务器中使用的密钥库 特定 API 代理的 API 密钥: <ph type="x-smartling-placeholder">
      </ph>
    1. Keystore 元素获取密钥库引用名称 在目标端点或目标服务器的 SSLInfo 部分。

      我们来看一下目标端点配置中的示例 SSLInfo 部分:

      <SSLInfo>
        <Enabled>true</Enabled>
        <ClientAuthEnabled>true</ClientAuthEnabled>
        <KeyStore>ref://myKeystoreRef</KeyStore>
        <KeyAlias>myKey</KeyAlias>
        <TrustStore>ref://myTrustStoreRef</TrustStore>
      </SSLInfo>
    2. 在上面的示例中,密钥库引用名称为“myKeystoreRef”。
    3. 前往 Edge 界面,然后选择 API 代理 ->环境配置。

      选择引用标签页,然后搜索密钥库引用名称。 记下 Reference 列中特定密钥库引用的名称。 这将是您的密钥库名称。


      alt_text

    4. 在上面的示例中,您可以看到 myKeystoreRef 包含引用 更改为“myKeystore”。因此,密钥库名称为 myKeystore。
  2. 请使用 Edge 界面或 列出 Keystore API 的证书
  3. 如果密钥库包含证书,则移至 原因:证书授权机构不匹配
  4. 如果密钥库不包含任何证书 消息处理器不会发送客户端证书。

分辨率

  1. 确保将正确且完整的客户端证书链上传到消息处理器中的特定密钥库。

原因:证书授权机构不匹配

通常,当服务器请求客户端发送其证书时, 表示一组可接受的颁发者或证书授权中心。 如果叶证书的颁发者/证书授权机构(即第一个 证书链中的证书) 与后端服务器接受的任何证书授权机构都不匹配, 则消息处理器(基于 Java 的进程)会 不会将证书发送到后端服务器。

请按照以下步骤确认是否属于这种情况:

  1. 列出 Keystore API 的证书
  2. 使用 获取 Keystore API 的证书
  3. 记下密钥库中存储的叶证书(即证书链中的第一个证书)的颁发者

    叶证书示例

    {
      "certInfo" : [ {
        "basicConstraints" : "CA:FALSE",
        "expiryDate" : 1578889324000,
        "isValid" : "Yes",
        "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com",
        "publicKey" : "RSA Public Key, 2048 bits",
        "serialNumber" : "65:00:00:00:d2:3e:12:d8:56:fa:e2:a9:69:00:06:00:00:00:d2",
        "sigAlgName" : "SHA256withRSA",
        "subject" : "CN=nonprod-api.mycompany.com, OU=ITS, O=MyCompany, L=MELBOURNE, ST=VIC, C=AU",
        "subjectAlternativeNames" : [ ],
        "validFrom" : 1484281324000,
        "version" : 3
      } ],
      "certName" : "nonprod-api.mycompany.com.key.pem-cert"
    }
    

    在上面的示例中,颁发者/证书授权机构为 "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com"

  4. 使用以下任一方法确定后端服务器接受的颁发者或证书授权机构列表:

    方法 1:使用以下 openssl 命令

    openssl s_client -host <backend server host name> -port <Backend port#> -cert <Client Certificate> -key <Client Private Key>
    

    请参阅标题为“可接受的客户端证书 CA 名称”的部分 如下所示:

    Acceptable client certificate CA names
    /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
    /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
    

    技巧 2:检查Certificate Request TCP/IP 数据包,后端服务器请求客户端发送其证书

    在上面显示的示例 TCP/IP 数据包中,Certificate Request 数据包是消息 7。请参阅“可分辨名称”部分, ,其中包含后端服务器可接受的证书授权机构。

    alt_text

  5. 验证第 3 步中获得的证书授权机构是否与列表匹配 。 如果不匹配,消息处理器将不会发送客户端证书 发送到后端服务器。

    在上面的示例中,您可以看到客户端的叶证书的颁发者 与后端服务器的任何密钥都不匹配 接受的证书授权机构。因此,消息处理器不会 将客户端证书发送到后端服务器。 这会导致 SSL 握手失败,并且后端服务器会发送“Fatal alert: bad_certificate”消息。

分辨率

  1. 请确保颁发机构/证书授权机构提供的证书与 客户端叶证书(第一个证书)的颁发者/证书授权机构 存储在后端服务器的 Truststore 中。
  2. 在本手册描述的示例中,证书颁发者为 "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" 已添加到后端服务器的信任库以解决此问题。

如果问题仍然存在,请参阅必须收集诊断信息

必须收集的诊断信息

如果按照上述说明操作后,问题仍然存在,请 请收集以下诊断信息。与好友联系并分享到 Apigee Edge 支持

  1. 如果您是公有云用户,请提供以下信息: <ph type="x-smartling-placeholder">
      </ph>
    1. 组织名称
    2. 环境名称
    3. API 代理名称
    4. 完整 curl 命令以重现该错误
    5. 显示错误的跟踪文件
    6. 在后端服务器上捕获的 TCP/IP 数据包
  2. 如果您是 Private Cloud 用户,请提供以下信息: <ph type="x-smartling-placeholder">
      </ph>
    1. 观察到完整的错误消息
    2. API 代理软件包
    3. 显示错误的跟踪文件
    4. 消息处理器日志“/opt/apigee/var/log/edge-message-processor/logs/system.log
    5. 后端服务器或消息处理器上捕获的 TCP/IP 数据包。
    6. 获取 Keystore API 的证书的输出。
  3. 详细说明您在本手册中的哪些部分尝试过,以及 ,帮助我们快速解决此问题。