Échecs de handshake SSL – Certificat client incorrect

Vous consultez la documentation d'Apigee Edge.
Consultez la documentation Apigee X.
en savoir plus

Problème constaté

L'application cliente reçoit un code d'état HTTP 503 ainsi que le message Service non disponible en réponse à une requête API. Dans la trace de l'interface utilisateur, vous constaterez que error.cause est défini sur Received fatal alert: bad_certificate dans le flux de requête cible de la requête API qui a échoué.

Si vous avez accès aux journaux du processeur de messages, vous remarquerez le message d'erreur Received fatal alert: bad_certificate pour la requête API ayant échoué. Cette erreur est observée lors du processus de handshake SSL entre le processeur de messages et le serveur backend dans le cadre d'une configuration TLS bidirectionnelle.

Message d'erreur

L'application cliente obtient le code de réponse suivant:

HTTP/1.1 503 Service Unavailable

De plus, le message d'erreur suivant peut s'afficher:

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

Les utilisateurs du cloud privé verront l'erreur suivante pour la requête API spécifique dans les journaux du processeur de messages /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

Causes possibles :

Voici les causes possibles de ce problème:

Cause Description Instructions de dépannage applicables à
Aucun certificat client Le keystore utilisé dans le point de terminaison cible du serveur cible ne possède aucun certificat client. Utilisateurs périphériques de cloud privé et public
Non-concordance de l'autorité de certification L'autorité de certification du certificat d'entité finale (le premier certificat de la chaîne de certificats) dans le keystore du processeur de messages ne correspond à aucune autorité de certification acceptée par le serveur backend. Utilisateurs périphériques de cloud privé et public

Étapes de diagnostic courantes

  1. Activez la trace dans l'interface utilisateur Edge, effectuez l'appel d'API et reproduisez le problème.
  2. Dans les résultats de la trace de l'UI, parcourez chaque phase et déterminez où l'erreur s'est produite. L'erreur se serait produite dans le flux de requête cible.
  3. Examinez le flux qui affiche l'erreur. Vous devriez observer l'erreur, comme illustré dans l'exemple de trace ci-dessous :

    alt_text

  4. Comme vous pouvez le voir dans la capture d'écran ci-dessus, le champ error.cause est défini sur error.cause (Alerte fatale reçue : bad_certificate).
  5. Si vous êtes un utilisateur du Private Cloud, suivez les instructions ci-dessous :
    1. Vous pouvez obtenir l'ID du message de la requête API ayant échoué en déterminant la valeur de l'en-tête d'erreur "X-Apigee.Message-ID" dans la phase indiquée par AX dans la trace.
    2. Recherchez cet ID de message dans le journal du processeur de messages /opt/apigee/var/log/edge-message-processor/system.log et déterminez si vous pouvez trouver d'autres informations sur l'erreur :
      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]
      

      Le journal du processeur de messages contenait une trace de la pile pour l'erreur Received fatal alert: bad_certificate, mais ne contient aucune autre information indiquant la cause de ce problème.

  6. Pour approfondir l'analyse du problème, vous devez capturer des paquets TCP/IP à l'aide de l'outil tcpdump.
    1. Si vous êtes un utilisateur de cloud privé, vous pouvez capturer les paquets TCP/IP sur le serveur backend ou le processeur de messages. De préférence, les capturer sur le serveur backend au fur et à mesure que les paquets sont déchiffrés sur le serveur backend.
    2. Si vous êtes un utilisateur de cloud public, capturez les paquets TCP/IP sur le serveur backend.
    3. Une fois que vous avez choisi l'emplacement de capture des paquets TCP/IP, exécutez la commande tcpdump ci-dessous.
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      Si vous prenez les paquets TCP/IP sur le processeur de messages, utilisez l'adresse IP publique du serveur backend dans la commande tcpdump.

      S'il existe plusieurs adresses IP pour le serveur backend/le processeur de messages, vous devez utiliser une autre commande tcpdump. Pour plus d'informations sur cet outil et pour découvrir d'autres variantes de cette commande, reportez-vous à la section tcpdump.

  7. Analysez les paquets TCP/IP à l'aide de l'outil Wireshark ou d'un outil similaire que vous connaissez.

Voici l'analyse d'exemples de données de paquets TCP/IP à l'aide de l'outil Wireshark:

alt_text

  1. Le message n° 4 de tcpdump ci-dessus indique que le processeur de messages (source) a envoyé un message "Client Hello" au serveur backend (destination).
  2. Le message n° 5 indique que le serveur backend accuse réception du message client Hello du processeur de messages.
  3. Le serveur backend envoie le message "Server Hello" avec son certificat, puis demande au client d'envoyer son certificat dans le message 7.
  4. Le processeur de messages termine la vérification du certificat et accuse réception du message ServerHello du serveur backend dans le message n° 8.
  5. Le processeur de messages envoie son certificat au serveur backend dans le message n° 9.
  6. Le serveur backend accuse réception du certificat du processeur de messages dans le message 11.
  7. Cependant, il envoie immédiatement une alerte fatale: certificat incorrect au processeur de messages (message n° 12). Cela indique que le certificat envoyé par le processeur de messages était incorrect et que la vérification du certificat a donc échoué sur le serveur backend. Par conséquent, le handshake SSL a échoué et la connexion est fermée.


    alt_text

  8. Examinons maintenant le message n° 9 pour vérifier le contenu du certificat envoyé par le processeur de messages:


    alt_text

  9. Comme vous pouvez le constater, le serveur backend n'a reçu aucun certificat du client (Longueur du certificat: 0). Le serveur backend envoie donc l'alerte fatale: certificat incorrect.
  10. Cela se produit généralement lorsque le client, c'est-à-dire un processeur de messages (un processus basé sur Java) :
    1. n'a pas de certificat client dans son keystore ; ou
    2. Impossible d'envoyer un certificat client. Ce problème peut survenir si le certificat émis par l'une des autorités de certification autorisées du serveur de backend ne s'y trouve pas. Cela signifie que si l'autorité de certification du certificat feuille du client (c'est-à-dire le premier certificat de la chaîne) ne correspond à aucune des autorités de certification acceptables pour le serveur backend, le processeur de messages n'enverra pas le certificat.

Examinons chacune de ces causes séparément, comme suit.

Cause: aucun certificat client

Diagnostic

Si aucun certificat n'existe dans le keystore spécifié dans la section "Informations SSL" du point de terminaison cible ou sur le serveur cible utilisé dans ce point de terminaison, c'est la cause de cette erreur.

Pour déterminer si le problème est à l'origine du problème, procédez comme suit:

  1. Déterminez le keystore utilisé dans le point de terminaison cible ou le serveur cible pour le proxy d'API spécifique en procédant comme suit :
    1. Obtenez le nom de référence du keystore à partir de l'élément Keystore dans la section SSLInfo du point de terminaison cible ou du serveur cible.

      Examinons un exemple de section SSLInfo dans une configuration de point de terminaison cible:

      <SSLInfo>
        <Enabled>true</Enabled>
        <ClientAuthEnabled>true</ClientAuthEnabled>
        <KeyStore>ref://myKeystoreRef</KeyStore>
        <KeyAlias>myKey</KeyAlias>
        <TrustStore>ref://myTrustStoreRef</TrustStore>
      </SSLInfo>
    2. Dans l'exemple ci-dessus, le nom de la référence du keystore est myKeystoreRef.
    3. Accédez à l'interface utilisateur Edge et sélectionnez API Proxies -> Environment Configurations (Proxys d'API -> Configurations d'environnement).

      Sélectionnez l'onglet References (Références) et recherchez le nom de référence du keystore. Notez le nom dans la colonne Reference (Référence) pour la référence Keystore spécifique. Il s'agit du nom de votre keystore.


      alt_text

    4. Dans l'exemple ci-dessus, vous pouvez remarquer que myKeystoreRef contient la référence à "myKeystore". Le nom du keystore est donc myKeystore.
  2. Vérifiez si ce keystore contient le certificat à l'aide de l'interface utilisateur Edge ou de la page Lister les certificats pour l'API keystore.
  3. Si le keystore contient un ou plusieurs certificats, passez à l'étape Cause: différence d'autorité de certification.
  4. Si le keystore ne contient aucun certificat, c'est la raison pour laquelle le certificat client n'est pas envoyé par le processeur de messages.

Résolution

  1. Assurez-vous que la chaîne de certificats client correcte et complète est importée dans le keystore spécifique du processeur de messages.

Cause: incohérence de l'autorité de certification

En règle générale, lorsque le serveur demande au client d'envoyer son certificat, il indique l'ensemble des émetteurs ou autorités de certification acceptés. Si l'émetteur/l'autorité de certification du certificat d'entité finale (c'est-à-dire le premier certificat de la chaîne de certificats) dans le keystore du processeur de messages ne correspond à aucune des autorités de certification acceptées par le serveur backend, le processeur de messages (qui est un processus basé sur Java) n'enverra pas le certificat au serveur backend.

Pour vérifier si c'est le cas, procédez comme suit:

  1. Répertorier les certificats pour l'API keystore
  2. Obtenez les détails de chaque certificat obtenu à l'étape 1 ci-dessus à l'aide de la section Obtenir un certificat pour l'API keystore.
  3. Notez l'émetteur du certificat d'entité finale (c'est-à-dire le premier certificat de la chaîne de certificats) stocké dans le keystore.

    Exemple de certificat feuille

    {
      "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"
    }
    

    Dans l'exemple ci-dessus, l'émetteur/l'autorité de certification est "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com".

  4. Déterminez la liste d'émetteurs ou d'autorités de certification acceptées par le serveur backend en utilisant l'une des techniques suivantes:

    Technique n° 1: utilisez la commande openssl ci-dessous:

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

    Reportez-vous à la section intitulée Noms des autorités de certification des certificats client acceptés dans le résultat de cette commande, comme indiqué ci-dessous:

    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
    

    Technique n° 2: vérifiez le paquet Certificate Request dans les paquets TCP/IP, où le serveur backend demande au client d'envoyer son certificat:

    Dans l'exemple de paquets TCP/IP ci-dessus, le paquet Certificate Request correspond au message n° 7. Consultez la section "Noms distincts", qui contient les autorités de certification acceptables du serveur backend.

    alt_text

  5. Vérifiez si l'autorité de certification obtenue à l'étape 3 correspond à la liste des émetteurs ou des autorités de certification acceptés du serveur backend à l'étape 4. En cas de non-concordance, le processeur de messages n'enverra pas le certificat client au serveur backend.

    Dans l'exemple ci-dessus, vous pouvez remarquer que l'émetteur du certificat de feuille du client dans le keystore du processeur de messages ne correspond à aucune des autorités de certification acceptées du serveur backend. Par conséquent, le processeur de messages n'envoie pas le certificat client au serveur backend. Cela entraîne l'échec du handshake SSL et le serveur backend envoie le message "Fatal alert: bad_certificate".

Résolution

  1. Assurez-vous que le certificat auprès de l'émetteur ou de l'autorité de certification correspondant à l'émetteur ou à l'autorité de certification du certificat feuille du client (premier certificat de la chaîne) est stocké dans le Truststore du serveur backend.
  2. Dans l'exemple décrit dans ce playbook, le certificat avec l'émetteur "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" a été ajouté au Truststore du serveur backend pour résoudre le problème.

Si le problème persiste, consultez Obtention des informations de diagnostic requis.

Doit recueillir des informations de diagnostic

Si le problème persiste même après avoir suivi les instructions ci-dessus, veuillez rassembler les informations de diagnostic suivantes. Contactez-les et partagez-les avec l'assistance Apigee Edge:

  1. Si vous êtes un utilisateur de cloud public, fournissez les informations suivantes :
    1. Nom de l'organisation
    2. Nom de l'environnement
    3. Nom du proxy d'API
    4. Exécuter la commande curl pour reproduire l'erreur
    5. Fichier de suivi affichant l'erreur
    6. Paquets TCP/IP capturés sur le serveur backend
  2. Si vous êtes un utilisateur de cloud privé, fournissez les informations suivantes :
    1. Message d'erreur complet observé
    2. Groupe de proxys d'API
    3. Fichier de suivi affichant l'erreur
    4. Journaux du processeur de messages /opt/apigee/var/log/edge-message-processor/logs/system.log
    5. Paquets TCP/IP capturés sur le serveur backend ou sur le processeur de messages
    6. Résultat de l'invite Obtenir un certificat pour l'API keystore.
  3. Informations sur les sections de ce playbook que vous avez essayées et sur les autres informations qui nous aideront à accélérer la résolution de ce problème.