web-dev-qa-db-fra.com

openssl s_client -cert: Prouver qu'un certificat client a été envoyé au serveur

Contexte

Je suis coincé dans une correspondance pointée avec un fournisseur de services avec une API protégée par le serveur SSL et le client certificats.

  • J'ai généré une CSR, obtenu un certificat auprès d'une autorité de certification publique (GoDaddy dans ce cas) et fourni le certificat et la chaîne d'autorités de certification au fournisseur de services.
  • Ils ont soi-disant chargé l'AC et mon certificat client dans leur passerelle.
  • Je travaille avec les tests de niveau les plus élémentaires en utilisant openssl s_client -connect ... -cert ... -key ...
  • Le fournisseur me dit que ses journaux suggèrent que mes demandes n'incluent pas du tout de certificat SSL.
  • Étrangement, l'émetteur de CA approprié pour mon certificat apparaît dans la liste des "Noms des AC de certificats de clients acceptables" fournie lors de l'établissement de la liaison SSL.
  • Pour référence, un certificat auto-signé que j'ai créé et que je leur ai fourni pour le test fonctionne effectivement.

Un exemple de requête (échoué)

[Shell ~]$ openssl s_client -connect Host:443 -cert cert_and_key.pem -key cert_and_key.pem -state -quiet
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 **SNIP**
verify return:1
depth=1 **SNIP**
verify return:1
depth=0 **SNIP**
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL3 alert read:fatal:unknown CA
SSL_connect:failed in SSLv3 read finished A
140011313276744:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1197:SSL alert number 48
140011313276744:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

Ma lecture du SSL3 alert read:fatal:unknown CA _ erreur est que le serveur ne reconnaît pas l'émetteur du certificat que je fournis (en fait). Toutefois, le fournisseur "m'assure" que les certificats de l'autorité de certification sont chargés correctement et je n'ai pas pu les convaincre du contraire.

Question

Donc, en mettant d’autres étapes de dépannage (étendues) à part, ce que je voudrais vraiment savoir, c’est:

Existe-t-il une sortie disponible à partir de openssl s_client qui montre de manière concluante qu’un certificat client n’a pas été simplement demandé par le serveur, mais qu’il a en fait été transmis au serveur lors de la négociation SSL?

J'ai expérimenté avec le -state, -msg, -debug et -trace _ options, mais n’ont pas l’arrière-plan nécessaire pour interpréter le résultat.

La réponse de EJP suggère que l'exemple de sortie que j'ai fourni est une preuve suffisante avec le write client certificate A, mais cette sortie apparaît que la -cert options a été utilisée ou non sur la ligne de commande, donc cela n’indique pas qu’un certificat était envoyé.

34
beporter

Pour vérifier qu'un certificat client est envoyé au serveur, vous devez analyser le résultat de la combinaison des indicateurs -state Et -debug.

D'abord comme base, essayez de courir

$ openssl s_client -connect Host:443 -state -debug

Vous obtiendrez une tonne de sortie, mais les lignes qui nous intéressent ressemblent à ceci:

SSL_connect:SSLv3 read server done A
write to 0x211efb0 [0x21ced50] (12 bytes => 12 (0xC))
0000 - 16 03 01 00 07 0b 00 00-03                        .........
000c - <SPACES/NULS>
SSL_connect:SSLv3 write client certificate A

Qu'est-ce qu'il se passe ici:

  • L’indicateur -state Permet d’afficher la fin de la section précédente:

    SSL_connect:SSLv3 read server done A  
    

    Ceci n’est important que pour vous aider à trouver votre place dans la sortie.

  • Ensuite, l'indicateur -debug Affiche les octets bruts envoyés à l'étape suivante:

    write to 0x211efb0 [0x21ced50] (12 bytes => 12 (0xC))
    0000 - 16 03 01 00 07 0b 00 00-03                        .........
    000c - <SPACES/NULS>
    
  • Enfin, le drapeau -state Rapporte à nouveau le résultat de l’étape que -debug Vient d’écho:

    SSL_connect:SSLv3 write client certificate A
    

Donc, en d'autres termes: s_client A fini de lire les données envoyées par le serveur et a envoyé 12 octets au serveur comme (ce que je suppose est) un "pas de certificat client".


Si vous répétez le test, mais cette fois-ci, incluez les drapeaux -cert Et -key Comme ceci:

$ openssl s_client -connect Host:443 \
   -cert cert_and_key.pem \
   -key cert_and_key.pem  \
   -state -debug

votre sortie entre la ligne "read server done" et la ligne "write client certificate" sera beaucoup plus longue et représente la forme binaire de votre certificat client:

SSL_connect:SSLv3 read server done A
write to 0x7bd970 [0x86d890] (1576 bytes => 1576 (0x628))
0000 - 16 03 01 06 23 0b 00 06-1f 00 06 1c 00 06 19 31   ....#..........1
(*SNIP*)
0620 - 95 ca 5e f4 2f 6c 43 11-                          ..^%/lC.
SSL_connect:SSLv3 write client certificate A

Le 1576 bytes Est une excellente indication en soi que le certificat a été transmis, mais en plus, la colonne de droite montrera des parties du certificat lisibles par l'homme: vous devriez pouvoir reconnaître le Le CN et les chaînes de l'émetteur de votre CERT y figurent.

78
beporter

Je sais que c'est une vieille question mais il ne semble pas encore y avoir de réponse. J'ai dupliqué cette situation, mais j'écris l'application serveur. J'ai donc pu établir ce qui se passe côté serveur. Le client envoie le certificat lorsque le serveur le demande et s’il fait référence à un certificat réel dans la ligne de commande s_client. Mon application serveur est configurée pour demander un certificat client et pour échouer si aucun n'est présenté. Voici la ligne de commande que je lance:

Yourhostname here -vvvvvvvvvv s_client -connect <hostname>:443 -cert client.pem -key cckey.pem -CAfile rootcert.pem -cipher ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH -tls1 -state

Lorsque je laisse de côté la partie "-cert client.pem" de la commande, la négociation échoue côté serveur et la commande s_client échoue avec une erreur signalée. Je reçois toujours le rapport "Aucun nom d’autorité de certification du certificat client n’a été envoyé", mais je pense qu’il a été répondu à la question ci-dessus.

La réponse courte est alors que le serveur détermine si un certificat sera envoyé par le client dans des conditions de fonctionnement normales (s_client n’est pas normal) et que l’échec est dû au fait que le serveur ne reconnaît pas l’autorité de certification dans le certificat présenté. Je ne connais pas beaucoup de situations dans lesquelles une authentification bidirectionnelle est effectuée alors qu'elle est requise pour mon projet.

Vous envoyez clairement un certificat. Le serveur le rejette clairement.

Les informations manquantes ici sont la manière exacte dont les certificats ont été créés et la manière dont le fournisseur a chargé le certificat, mais cela est probablement déjà tout résumé.

7
JSAnderson