Ошибки установления SSL-соединения — плохой сертификат клиента

Вы просматриваете документацию Apigee Edge .
Перейдите в документацию Apigee
X.info

Симптом

Клиентское приложение получает HTTP-статус 503 с сообщением "Сервис недоступен" в ответ на запрос к API. В трассировке пользовательского интерфейса вы увидите, что в потоке целевого запроса для неудачного запроса к API указано "Получено фатальное Received fatal alert: bad_certificate .

Если у вас есть доступ к журналам обработчика сообщений, вы увидите сообщение об ошибке « 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

Возможные причины

Возможные причины этой проблемы следующие:

Причина Описание Инструкции по устранению неполадок, применимые для
Сертификат клиента отсутствует В хранилище ключей, используемом в целевой конечной точке целевого сервера, отсутствует клиентский сертификат. Пользователи частных и публичных облачных решений на периферии сети
Несоответствие центра сертификации Центр сертификации конечного сертификата (первого сертификата в цепочке сертификатов) в хранилище ключей обработчика сообщений не совпадает ни с одним из центров сертификации, принимаемых бэкэнд-сервером. Пользователи частных и публичных облачных решений на периферии сети

Общие этапы диагностики

  1. Включите трассировку в пользовательском интерфейсе Edge, выполните вызов API и воспроизведите проблему.
  2. В результатах трассировки пользовательского интерфейса пройдите по каждому этапу и определите, где произошла ошибка. Ошибка, скорее всего, произошла в потоке целевого запроса.
  3. Изучите поток выполнения, в котором отображается ошибка; вы должны увидеть ошибку, как показано в приведенном ниже примере трассировки:

    alt_text

  4. Как видно на скриншоте выше, ошибка error.cause имеет вид "Получено критическое предупреждение: bad_certificate" .
  5. Если вы используете частное облако , следуйте приведенным ниже инструкциям:
    1. Идентификатор сообщения для неудачного запроса API можно получить, определив значение заголовка ошибки " X-Apigee.Message-ID " в фазе, указанной AX в трассировке.
    2. Найдите этот идентификатор сообщения в журнале обработчика сообщений /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. Для дальнейшего изучения этой проблемы вам потребуется перехватить TCP/IP-пакеты с помощью инструмента tcpdump .
    1. Если вы используете частное облако , то можете перехватывать TCP/IP-пакеты на бэкэнд-сервере или в обработчике сообщений. Предпочтительно перехватывать их на бэкэнд-сервере, поскольку расшифровка пакетов происходит именно там.
    2. Если вы используете публичное облако , то перехватывайте TCP/IP-пакеты на бэкэнд-сервере.
    3. После того, как вы определились с местом, где хотите перехватывать TCP/IP-пакеты, используйте приведенную ниже команду tcpdump для захвата TCP/IP-пакетов.
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      Если вы обрабатываете TCP/IP-пакеты на процессоре сообщений, используйте публичный IP-адрес бэкэнд-сервера в команде tcpdump .

      Если для бэкэнд-сервера/обработчика сообщений используется несколько IP-адресов, то вам потребуется использовать другую команду tcpdump. Для получения дополнительной информации об этом инструменте и других вариантах этой команды обратитесь к документации tcpdump .

  7. Проанализируйте TCP/IP-пакеты с помощью инструмента Wireshark или аналогичного инструмента, с которым вы знакомы.

Вот анализ данных тестовых TCP/IP-пакетов, выполненный с помощью инструмента Wireshark:

alt_text

  1. Сообщение №4 в приведенном выше дампе tcpdump показывает, что обработчик сообщений (источник) отправил сообщение "Client Hello" на серверную часть (получатель).
  2. Сообщение № 5 показывает, что серверная часть подтверждает получение сообщения Client Hello от обработчика сообщений.
  3. Бэкенд-сервер отправляет сообщение "Server Hello" вместе со своим сертификатом, а затем запрашивает у клиента отправку своего сертификата в сообщении №7.
  4. Обработчик сообщений завершает проверку сертификата и подтверждает получение сообщения ServerHello от бэкэнд-сервера в сообщении № 8.
  5. Обработчик сообщений отправляет свой сертификат на серверную часть в сообщении № 9.
  6. Серверная часть подтверждает получение сертификата обработчика сообщений в сообщении № 11.
  7. Однако система немедленно отправляет обработчику сообщений сообщение Fatal Alert: Bad Certificate (сообщение № 12). Это указывает на то, что сертификат, отправленный обработчиком сообщений, был недействительным, и, следовательно, проверка сертификата на бэкэнд-сервере завершилась неудачей. В результате рукопожатие SSL завершилось неудачей, и соединение будет разорвано.


    alt_text

  8. Теперь давайте посмотрим на сообщение № 9, чтобы проверить содержимое сертификата, отправленного обработчиком сообщений:


    alt_text

  9. Как вы можете заметить, серверная часть не получила сертификат от клиента ( длина сертификата: 0) . Следовательно, серверная часть отправляет критическое предупреждение: Неверный сертификат.
  10. Обычно это происходит, когда клиент, то есть обработчик сообщений (процесс на основе Java):
    1. В хранилище ключей отсутствует клиентский сертификат, или;
    2. Не удается отправить клиентский сертификат. Это может произойти, если не удается найти сертификат, выданный одним из допустимых центров сертификации бэкэнд-сервера. Это означает, что если центр сертификации конечного сертификата клиента (т.е. первого сертификата в цепочке) не совпадает ни с одним из допустимых центров сертификации бэкэнд-сервера, то обработчик сообщений не отправит сертификат.

Рассмотрим каждую из этих причин по отдельности следующим образом.

Причина: Отсутствует клиентский сертификат

Диагноз

Если в хранилище ключей, указанном в разделе SSL Info целевой конечной точки или целевого сервера, используемого в целевой конечной точке, отсутствует сертификат, то это и является причиной данной ошибки.

Выполните следующие шаги, чтобы определить, является ли это причиной:

  1. Определите хранилище ключей, используемое в целевой конечной точке или целевом сервере для конкретного API-прокси, выполнив следующие шаги:
    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-прокси -> Конфигурации среды.

      Выберите вкладку «Ссылки» и найдите имя ссылки на хранилище ключей. Запишите имя в столбце «Ссылка» для конкретной ссылки на хранилище ключей. Это будет имя вашего хранилища ключей.


      alt_text

    4. В приведенном выше примере вы можете заметить, что myKeystoreRef содержит ссылку на "myKeystore". Следовательно, имя хранилища ключей — myKeystore.
  2. Проверьте, содержит ли это хранилище ключей сертификат, используя пользовательский интерфейс Edge или API «Список сертификатов для хранилища ключей» .
  3. Если хранилище ключей содержит сертификаты, перейдите к разделу «Причина: несоответствие центра сертификации» .
  4. Если хранилище ключей не содержит сертификата, то именно по этой причине обработчик сообщений не отправляет клиентский сертификат.

Разрешение

  1. Убедитесь, что правильная и полная цепочка клиентских сертификатов загружена в соответствующее хранилище ключей в обработчике сообщений.

Причина: Несоответствие центра сертификации

Как правило, когда сервер запрашивает у клиента отправку сертификата, он указывает набор принятых издателей или центров сертификации. Если издатель/центр сертификации конечного сертификата (т.е. первого сертификата в цепочке сертификатов) в хранилище ключей обработчика сообщений не совпадает ни с одним из центров сертификации, принятых бэкэнд-сервером, то обработчик сообщений (который представляет собой процесс на основе Java ) не отправит сертификат на бэкэнд-сервер.

Выполните следующие шаги, чтобы убедиться в этом:

  1. Вывести список сертификатов для API хранилища ключей .
  2. Получите подробную информацию о каждом сертификате, полученном на шаге №1 выше, используя 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>
    

    Обратитесь к разделу «Допустимые имена центров сертификации клиентских сертификатов» в выводе этой команды, как показано ниже:

    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, со списком принятых издателей или центров сертификации бэкэнд-сервера, полученным на шаге №4. В случае несоответствия обработчик сообщений не отправит клиентский сертификат на бэкэнд-сервер.

    В приведенном выше примере вы можете заметить, что эмитент конечного сертификата клиента в хранилище ключей обработчика сообщений не совпадает ни с одним из принятых центров сертификации бэкэнд-сервера. Следовательно, обработчик сообщений не отправляет сертификат клиента на бэкэнд-сервер. Это приводит к сбою SSL-рукопожатия, и бэкэнд-сервер отправляет сообщение " Fatal alert: bad_certificate ".

Разрешение

  1. Убедитесь, что сертификат с издателем/центром сертификации, соответствующим издателю/центру сертификации конечного сертификата клиента (первого сертификата в цепочке), хранится в хранилище доверенных сертификатов бэкэнд-сервера.
  2. В примере, описанном в этом руководстве, для решения проблемы в хранилище доверенных сертификатов на бэкэнд-сервере был добавлен сертификат с издателем "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" .

Если проблема сохраняется, перейдите к разделу «Необходимо собрать диагностическую информацию» .

Необходимо собрать диагностическую информацию.

Если проблема сохраняется даже после выполнения вышеуказанных инструкций, пожалуйста, соберите следующую диагностическую информацию. Свяжитесь со службой поддержки Apigee Edge и предоставьте её:

  1. Если вы являетесь пользователем публичного облака, предоставьте следующую информацию:
    1. Название организации
    2. Название среды
    3. Имя API-прокси
    4. Выполните команду curl для воспроизведения ошибки.
    5. Файл трассировки, отображающий ошибку.
    6. TCP/IP-пакеты, перехваченные на бэкэнд-сервере.
  2. Если вы являетесь пользователем частного облака, предоставьте следующую информацию:
    1. Полное сообщение об ошибке.
    2. Пакет API-прокси
    3. Файл трассировки, отображающий ошибку.
    4. Журналы обработчика сообщений /opt/apigee/var/log/edge-message-processor/logs/system.log
    5. TCP/IP-пакеты, перехваченные на бэкэнд-сервере или в обработчике сообщений.
    6. Результат выполнения команды Get cert for keystore API .
  3. Пожалуйста, укажите, какие разделы этого руководства вы уже пробовали, а также любые другие замечания, которые помогут нам ускорить решение этой проблемы.