Comment lire les certificats TLS websockets en utilisant PHP?

j'essaie de me connecter à un websocket sécurisé créé par PHP, mais pour une raison quelconque, cela ne fonctionne pas. Les fichiers de certificats sont lisibles pour PHP.

C'est mon code (PHP côté; dépouillé de code pour des raisons de simplicité):

$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'allow_self_signed', false);
stream_context_set_option($context, 'ssl', 'verify_peer', true);
stream_context_set_option($context,  'ssl', 'peer_name', 'example.com');
stream_context_set_option($context,  'ssl', 'CN_match', 'example.com');
stream_context_set_option($context,  'ssl', 'SNI_enabled', true);
stream_context_set_option($context, 'ssl', 'local_cert',  '/path/to/ssl/cert/example.com');
stream_context_set_option($context, 'ssl', 'local_pk', '/path/to/ssl/private/example.com');

$serverSocket = stream_socket_server(
        'tls://example.com:8090',
        $errNo,
        $errStr,
        STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
        $context
);
$client = stream_socket_accept($serverSocket);

// send initial websocket connection stuff
$request = socket_read($client, 5000);
preg_match('#Sec-WebSocket-Key: (.*)rn#', $request, $matches);
$key = base64_encode(pack(
    'H*',
    sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
));
$headers = "HTTP/1.1 101 Switching Protocolsrn";
$headers .= "Upgrade: websocketrn";
$headers .= "Connection: Upgradern";
$headers .= 'Sec-WebSocket-Version: 13' . "rn";
$headers .= 'Sec-WebSocket-Accept: ' . $key . "rnrn";
socket_write($client, $headers, mb_strlen($headers));

// do something here...

socket_close($client);
socket_close($serverSocket);

Le côté client:

var con = new WebSocket('wss://' + host + ':' + port);
var $chat = $('#chat');

con.onmessage = function(e) {
    $chat.append('<p>' + e.data + '</p>');
};

con.onopen = function(e) {
    con.send('Hello Me!');
};

con.onclose = function (e) {
    console.log('connection closed.', arguments);
}

je n'ai pas tout *.fichier pem. Juste les deux fichiers, qui sont utilisés dans le serveur web apache. Il serait possible de convertir ces fichiers dans un fichier pem, si nécessaire. Mais je pense qu'il devrait aussi travailler en php avec ces deux fichiers, n'est-ce pas?

pour un meilleur test, nous utilisons un sous-domaine isolé avec un certificat let's encrypt. Parce que nous avons un accès complet à ce serveur. Cependant, du générateur de certificat, Je n'ai eu que ces deux fichiers mentionnés. Pour le serveur web, il fonctionne parfaitement. Mais comment faire la même chose pour un websocket en php?

maintenant, avec ce code, après avoir envoyé quelques messages au client, le script du serveur me dit que ce n'était pas capable d'obtenir le pair des certificats. Je ne sais pas ce que ce message signifie et comment arranger ça. J'ai aussi alreay essayé de swap local_cert et local_pk entre eux, mais ça n'a pas aidé de toute façon.

Edit: après quelques recherches, il s'avère que php échoue avec chaque combinaison avec une autre erreur.

les fichiers de certificats générés ressemblent à ceci:

le Fichier /opt/psa/var/certificats/cert-0x8zHR:

-----BEGIN CERTIFICATE REQUEST-----
some letters
-----END CERTIFICATE REQUEST-----

-----BEGIN PRIVATE KEY-----
some letters
-----END PRIVATE KEY-----

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----

le Fichier /opt/psa/var/certificats/cert-Du9H8N:

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----

toutes les lignes des chaînes de certificats des deux se terminent à la position de caractère 65.

Comme vous pouvez le lire dans la documentation de php, php s'attend à obtenir un fichier au format PEM: http://php.net/manual/en/context.ssl.php#context.ssl.local-cert

j'ai trouvé ce tutoriel pour convertir mes deux les fichiers dans un fichier PEM, mais mes certificats semblent différents à mentionné sur le site et aussi je ne sais pas ce qu'il faut exactement inclure dans le fichier PEM, que php a besoin:https://www.digicert.com/ssl-support/pem-ssl-creation.htm

Edit 2: comme mentionné ci-dessous, voici les erreurs exactes que j'obtiens:

stream_context_set_option($cont, 'ssl',  'local_pk', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'local_cert', '/opt/psa/var/certificates/cert-Du9H8N');

avertissement: stream_socket_accept (): impossible de définir le fichier de clés privées `/opt/psa/var/certificats/cert-0x8zHR'... sur ligne ...

Avertissement: stream_socket_accept(): impossible d'activer les crypto ... sur ligne. ..

Avertissement: stream_socket_accept(): accepter a échoué: le Succès dans ... sur la ligne ...

avertissement: socket_read() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Note: Undefined offset: 1 in ... sur ligne ...

attention: socket_write() s'attend à ce que le paramètre 1 soit ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write () s'attend à ce que le paramètre 1 soit resource, boolean donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_close() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Et

stream_context_set_option($cont, 'ssl',  'local_cert', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'local_pk', '/opt/psa/var/certificates/cert-Du9H8N');

avertissement: stream_socket_accept (): impossible de définir le fichier de clés privées `/opt/psa/var/certificats/cert-Du9H8N'... sur ligne ...

Avertissement: stream_socket_accept(): impossible d'activer les crypto ... sur ligne. ..

Avertissement: stream_socket_accept(): accepter a échoué: le Succès dans ... sur la ligne ...

avertissement: socket_read() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Note: Undefined offset: 1 in ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur la ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_close() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Et avec (juste une concaténation de cert-0x8zHR avec cert-Du9H8N)

$file = dirname(__FILE__, 3) . DIRECTORY_SEPARATOR . 'fullchain.pem';
stream_context_set_option($cont, 'ssl', 'local_cert', $file);

Avertissement: stream_socket_accept(): ne Peut pas obtenir de certificat homologue ... ...

avertissement: stream_socket_accept (): échec activer le chiffrement ... ...

Avertissement: stream_socket_accept(): accepter a échoué: le Succès dans ... ...

avertissement: socket_read() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Note: Undefined offset: 1 in ... sur ligne ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

avertissement: socket_write () s'attend à ce que le paramètre 1 soit resource, boolean donné dans ... ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... ...

avertissement: socket_write() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... ...

avertissement: socket_close() s'attend à ce que le paramètre 1 soit une ressource, booléen donné dans ... sur ligne ...

Edit 3: Oui, en effet, il y a une erreur openssl. Après la troisième socket_stream_accept attention maintenant, je reçois cette erreur en utilisant simplement le code de la doc php exemple:

error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch

j'ai cherché cette erreur sur internet. Ils disent, si cette erreur apparaît, j'ai choisi le mauvais fichier de certificat.

aussi, si je joue ceci commande:

openssl x509 -noout -in cert-0x8zHR -modulus

j'ai deux cordes différentes pour le module. Mais je ne sais pas pourquoi, ni comment réparer ça. Ces deux fichiers sont utilisés dans la configuration vhost du serveur web apache et cela fonctionne très bien:

SSLEngine on
SSLVerifyClient none
SSLCertificateFile /opt/psa/var/certificates/cert-0x8zHR
SSLCACertificateFile /opt/psa/var/certificates/cert-Du9H8N

PS: Si vous connaissez un outil de conversion locale vers un fichier pem, merci de me le faire savoir. La conversion en ligne est impossible.

16
demandé sur Grokify 2018-05-11 11:45:00

3 réponses

Vous avez dit:

les fichiers de certificats générés ressemblent à ceci:

le Fichier /opt/psa/var/certificats/cert-0x8zHR:

-----demande de certificat de début - - - - - quelques lettres ----- END CERTIFICATE REQUEST - - - - -

----- - DÉBUT CLÉ PRIVÉE----- certaines lettres -----FIN DE LA CLÉ PRIVÉE-----

-----certificat de début - - - - - quelques lettres ----CERTIFICAT DE FIN D'-----

- - - - - - début Certificat - - - - - quelques lettres ----CERTIFICAT DE FIN D'-----

C'est mal à tant de niveaux.

D'abord la partie" demande de certificat " est complètement inutile dès que vous recevez le certificat. Tu peux juste ignorer cette partie.

maintenant, copiez la partie "clé privée", avec les en-têtes dans un fichier. C'est votre clé privée, vous pouvez utiliser partout où vous avez des options "local_pk" ou logiciel demande une clé.

alors vous avez deux certificats. Et un autre dans un autre fichier. Vous aurez besoin de trier tout cela. Si vous aviez donné le contenu réel des certificats (qui sont du contenu public), les gens auraient pu mieux vous aider. Ici avec juste "quelques lettres" nous ne pouvons que deviner.

dans le fichier ci-dessus, les deux certificats peuvent être L'AC et l'intermédiaire. Vous devez copier les deux fichiers dans un autre fichier, ce qui correspond à l'option "ca_cert".

je suppose que le second fichier est votre certificat d'Essai (seulement une conjecture encore une fois, sans vos coordonnées). Utilisez-le partout où vous avez "local_cert" ou Demander un certificat. Ce certificat devrait correspondre au fichier de clés privées (vous ne pouvez pas vérifier à la main, vous avez besoin d'outils).

une fois que vous avez créé tous les fichiers corrects, le premier ne doit plus être utilisé. Je vous conseille d'utiliser mieux la sémantique pour le nom de fichier car cert-X et cert-Y sera assez difficile. Utilisez plutôt le nom du site web pour que vous ayez des fichiers comme www.example.com.cert, www.example.com-ca.cert et www.example.com.key, de sorte qu'il est immédiatement clair ce qui est quoi. Ou avec un répertoire nommé www.example.com/ et cert.pem,ca.pem et key.pem dans le répertoire. Les extensions en elles-mêmes ne sont pas utilisées par le logiciel et indépendamment du contenu, c'est seulement à vous de définir les choses qui ont du sens.

donc d'abord triez tout cela, pour que votre question soit plus claire. En ce moment, il semble que vous essayez des choses aveuglément jusqu'à ce que venir à quelque chose qui fonctionne, ce qui n'est pas l'idéal situation dans le domaine de la sécurité et des affaires de TLS.

si possible, je vous encourage aussi à essayer d'utiliser une bibliothèque d'abstraction de haut niveau pour la gestion de TLS, car c'est clairement beaucoup trop bas, exposant tellement d'options que vous êtes en train de vous perdre.

4
répondu Patrick Mevzek 2018-05-25 21:33:09

on dirait Qu'OpenSSL n'aime pas votre clé.

Vous pouvez essayer d'appeler http://php.net/manual/en/function.openssl-error-string.php pour voir si il n'y a plus d'informations disponibles sur pourquoi?

ou essayez différentes combinaisons de fichiers clés, selon ces questions éventuellement liées qui comportent la même erreur:

GL

0
répondu Rich 2018-05-25 13:23:17

essaye ceci:

stream_context_set_option($cont, 'ssl', 'local_cert', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'ca_file', '/opt/psa/var/certificates/cert-Du9H8N');

Si cela ne fonctionne pas, essayez de commenter deuxième ligne (ca_flie) et mis verify_peerfalse

Quels sont les messages d'erreur dans les deux cas?

mise à jour: BTW, vos certificats sont déjà en .pem (ASCII codé en base64).

0
répondu SergeAx 2018-05-25 21:06:05