php ssl websocket serversocket phpwebsocket

websocket php mysql



¿Cómo leer los certificados websockets TLS usando PHP? (3)

Parece que a OpenSSL no le gusta tu llave.

Puede intentar llamar a http://php.net/manual/en/function.openssl-error-string.php para ver si hay más información disponible sobre por qué.

O pruebe diferentes combinaciones de archivos clave, según estas preguntas posiblemente relacionadas que presentan el mismo error:

GL

Estoy intentando conectarme a un socket web seguro creado por PHP, pero por alguna razón no funciona. Los archivos de certificado son legibles para PHP.

Este es mi código hasta ahora (lado de PHP; código simplificado para simplificar):

$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: (.*)/r/n#'', $request, $matches); $key = base64_encode(pack( ''H*'', sha1($matches[1] . ''258EAFA5-E914-47DA-95CA-C5AB0DC85B11'') )); $headers = "HTTP/1.1 101 Switching Protocols/r/n"; $headers .= "Upgrade: websocket/r/n"; $headers .= "Connection: Upgrade/r/n"; $headers .= ''Sec-WebSocket-Version: 13'' . "/r/n"; $headers .= ''Sec-WebSocket-Accept: '' . $key . "/r/n/r/n"; socket_write($client, $headers, /mb_strlen($headers)); // do something here... socket_close($client); socket_close($serverSocket);

El lado del cliente:

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); }

No tengo ningún archivo * .pem. Solo los dos archivos, que se utilizan en el servidor web apache. Sería posible convertir esos archivos en un archivo pem, si es necesario. Pero creo que también debería funcionar en php con estos dos archivos, ¿no es así?

Para una mejor prueba, estamos usando un subdominio aislado con un certificado de cifrado. Porque tenemos acceso completo a este servidor. Sin embargo, del generador certifacte solo obtuve los dos archivos mencionados. Para el servidor web funciona perfectamente. Pero, ¿cómo hacer lo mismo para un websocket en PHP?

Ahora, con este código, después de enviar algunos mensajes al cliente, la secuencia de comandos del servidor me dice que no pudo obtener el par de los certificados. No sé qué significa este mensaje y cómo solucionarlo. También traté de intercambiar local_cert y local_pk entre sí, pero no me ha ayudado de ninguna manera.

Edit: Después de investigar un tiempo, resulta que php falla con cada combinación con otro error.

Mis archivos de certificado generados se ven así:

Archivo / opt / psa / var / certificate / 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-----

Archivo / opt / psa / var / certificate / cert-Du9H8N:

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

Todas las líneas de las cadenas de certificado de ambas terminan en la posición de carácter 65.

Como puede leer en la documentación de php, php espera obtener un archivo en formato PEM: http://php.net/manual/en/context.ssl.php#context.ssl.local-cert

Encontré este tutorial para convertir mis dos archivos en un solo archivo PEM, pero mis certificados son diferentes a los mencionados en el sitio y tampoco sé qué incluir exactamente en el archivo PEM, que php necesita: https://www.digicert.com/ssl-support/pem-ssl-creation.htm

Edición 2: Como se menciona a continuación, aquí están los errores exactos que obtengo:

con

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'');

Advertencia: stream_socket_accept (): no se puede establecer el archivo de clave privada `/ opt / psa / var / certificate / cert-0x8zHR ''en ... en línea ...

Advertencia: stream_socket_accept (): Error al habilitar crypto en ... en línea ...

Advertencia: stream_socket_accept (): aceptar error: éxito en ... en línea ...

Advertencia: socket_read () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Aviso: Desplazamiento indefinido: 1 en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_close () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Y con

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'');

Advertencia: stream_socket_accept (): no se puede establecer el archivo de clave privada `/ opt / psa / var / certificate / cert-Du9H8N ''en ... en línea ...

Advertencia: stream_socket_accept (): Error al habilitar crypto en ... en línea ...

Advertencia: stream_socket_accept (): aceptar error: éxito en ... en línea ...

Advertencia: socket_read () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Aviso: Desplazamiento indefinido: 1 en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_close () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Y con (solo una concatenación de cert-0x8zHR con cert-Du9H8N)

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

Advertencia: stream_socket_accept (): no se pudo obtener el certificado de igual en ... ...

Advertencia: stream_socket_accept (): Error al habilitar crypto en ... ...

Advertencia: stream_socket_accept (): aceptar error: éxito en ... ...

Advertencia: socket_read () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Aviso: Desplazamiento indefinido: 1 en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... ...

Advertencia: socket_write () espera que el parámetro 1 sea un recurso, booleano dado en ... ...

Advertencia: socket_close () espera que el parámetro 1 sea un recurso, booleano dado en ... en línea ...

Edit 3: Sí, de hecho, hay un error openssl. Después de la tercera advertencia de socket_stream_accept , ahora obtengo este error simplemente usando el código del ejemplo de php doc:

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

Busqué este error en internet. Dicen que, si aparece este error, he elegido el archivo de certificado incorrecto.

Además, si juego este comando:

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

Tengo dos cadenas diferentes para el módulo. Pero no sé por qué, ni cómo arreglar esto. Estos dos archivos se utilizan en vhost config del servidor web apache y funciona bien:

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

PD: si conoce alguna herramienta para la conversión local a un archivo pem, por favor hágamelo saber. La conversión en línea es imposible.


Prueba esto:

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 eso no funciona, intente comentar la segunda línea ( ca_flie ) y establezca verify_peer en false

¿Qué son los mensajes de error en ambos casos?

Actualización: Por cierto, sus certificados ya están en .pem (ASCII-base64-encoded).


Tu dijiste:

Mis archivos de certificado generados se ven así:

Archivo / opt / psa / var / certificate / cert-0x8zHR:

----- COMENZAR LA SOLICITUD DE CERTIFICADO ----- algunas letras ----- FINALIZAR LA SOLICITUD DE CERTIFICADO -----

----- COMIENCE LA CLAVE PRIVADA ----- algunas letras ----- TERMINE LA CLAVE PRIVADA -----

----- COMENZAR EL CERTIFICADO ----- algunas letras ----- FINALIZAR EL CERTIFICADO -----

----- COMENZAR EL CERTIFICADO ----- algunas letras ----- FINALIZAR EL CERTIFICADO -----

Esto está mal en muchos niveles.

Primero, la parte de "SOLICITUD DE CERTIFICADO" es completamente inútil tan pronto como reciba el certificado. Puedes ignorar esta parte.

Ahora copie la parte "CLAVE PRIVADA", con encabezados en un archivo. Esta es su clave privada, puede usarla donde quiera que tenga opciones "local_pk" o software que solicite una clave.

Entonces tienes dos certificados. Y otro en otro archivo. Tendrá que ordenar todo esto. Si hubiera dado el contenido de los certificados reales (que son contenido público), las personas podrían haberle ayudado mejor. Aquí solo con "algunas letras" solo podemos adivinar.

En el archivo anterior los dos certificados pueden ser el CA y el intermedio. Debe copiarlos en otro archivo, y esto corresponderá a la opción "ca_cert".

Supongo que el segundo archivo es su certificado de prueba (solo una conjetura nuevamente, sin sus datos). Úselo en cualquier lugar donde tenga "local_cert" o solicite un certificado. Este certificado debe coincidir con el archivo de clave privada (no puede verificar que a mano, necesita herramientas).

Una vez que haya creado todos los archivos correctos, el primero ya no se utilizará. Recomendaría usar una semántica mejor para el nombre del archivo porque cert-X y cert-Y serán bastante difíciles. En su lugar, utilice el nombre del sitio web para tener archivos como www.example.com.cert , www.example.com-ca.cert y www.example.com.key , de modo que quede inmediatamente claro qué es qué. O con un directorio llamado www.example.com/ , y luego cert.pem , ca.pem y key.pem dentro del directorio. El software no usa las extensiones por sí mismas y, independientemente del contenido, solo depende de usted definir las cosas que tengan sentido.

Así que primero ordena todo esto, para que tu pregunta sea más clara. En este momento parece que estás probando cosas a ciegas hasta que llegas a algo que funciona, que no es la situación ideal en el ámbito de la seguridad y las cosas de TLS.

De ser posible, también lo alentaría a que intente usar una biblioteca de abstracción de nivel superior para el manejo de TLS, ya que es claramente demasiado bajo, exponiendo tantas opciones que se está perdiendo.