rejectunauthorized false err_tls_cert_altname_invalid doesn altnames node.js ssl openssl ssl-certificate csr

node.js - false - Hostname/IP no coincide con el altname del certificado



hostname/ip doesn''t match certificate''s altnames nodemailer (5)

Estoy tratando de crear una configuración de servidor / cliente TLS usando Node.js 0.8.8 con un certificado autofirmado.

El código del servidor esencial parece

var tlsServer = tls.createServer({ key: fs.readFileSync(''server-key.pem''), cert: fs.readFileSync(''server-cert.pem'') }, function (connection) { // [...] }); tlsServer.listen(3000);

Ahora cuando intento conectarme a este servidor, uso el siguiente código:

var connection = tls.connect({ host: ''192.168.178.31'', port: 3000, rejectUnauthorized: true, ca: [ fs.readFileSync(''server-cert.pem'') ] }, function () { console.log(connection.authorized); console.log(connection.authorizationError); console.log(connection.getPeerCertificate()); });

Si quito la linea

ca: [ fs.readFileSync(''server-cert.pem'') ]

Desde el código del lado del cliente, Node.js DEPTH_ZERO_SELF_SIGNED_CERT un error que me dice DEPTH_ZERO_SELF_SIGNED_CERT . Según tengo entendido, esto se debe al hecho de que se trata de un certificado autofirmado y no hay otra parte que confíe en este certificado.

Si me quito

rejectUnauthorized: true,

también, el error desapareció, pero la connection.authorized Autorizado es igual a false que efectivamente significa que mi conexión no está cifrada. De todos modos, utilizando getPeerCertificate() puedo acceder al certificado enviado por el servidor. Como deseo hacer cumplir una conexión encriptada, entiendo que no puedo eliminar esta línea.

Ahora leo que puedo usar la propiedad ca para especificar cualquier CA en la que quiero que Node.js confíe. La documentación del módulo TLS implica que es suficiente para agregar el certificado del servidor a la matriz ca , y entonces todo debería estar bien.

Si hago eso, este error desaparece, pero recibo uno nuevo:

Hostname/IP doesn''t match certificate''s altnames

Para mí, esto significa que la CA ahora es básicamente confiable, por lo tanto, está bien ahora, pero el certificado se realizó para otro host que no sea el que uso.

He creado el certificado utilizando

$ openssl genrsa -out server-key.pem 2048 $ openssl req -new -key server-key.pem -out server-csr.pem $ openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem

como lo indica la documentación. Al crear la CSR, me hacen las preguntas habituales, como país, estado, ... y nombre común (CN). Como se le indica "en la web" para un certificado SSL, no proporciona su nombre como CN, sino el nombre de host que desea utilizar.

Y aquí es probablemente donde yo fracaso.

Lo intenté

  • localhost
  • 192.168.178.31
  • eisbaer
  • eisbaer.fritz.box

donde los dos últimos son el nombre local y el nombre local completo de mi máquina.

¿Alguna idea de lo que estoy haciendo mal aquí?


En tls.js, líneas 112-141 , puede ver que si el nombre de host utilizado al llamar a connect es una dirección IP, el CN ​​del certificado se ignora y solo se usan las SAN.

Como mi certificado no usa SAN, la verificación falla.


Lo que estás haciendo mal es usar una dirección IP en lugar de un nombre de dominio. Cree un nombre de dominio y péguelo en un servidor DNS (o simplemente en un archivo de hosts), cree un certificado autofirmado con el nombre de dominio como Nombre común y conéctese al nombre de dominio en lugar de a la dirección IP.


Mitar tenía la suposición errónea de que checkServerIdentity debería devolver ''true'' al éxito, pero en realidad debería devolver ''indefinido'' al éxito. Cualquier otro valor se trata como descripciones de error.

Así que tal código es correcto:

var options = { host: ''192.168.178.31'', port: 3000, ca: [ fs.readFileSync(''server-cert.pem'') ], checkServerIdentity: function (host, cert) { // It can be useful to resolve both parts to IP or to Hostname (with some synchronous resolver (I wander why they did not add done() callback as the third parameter)). // Be carefull with SNI (when many names are bound to the same IP). if (host != cert.subject.CN) return ''Incorrect server identity'';// Return error in case of failed checking. // Return undefined value in case of successful checking. // I.e. you could use empty function body to accept all CN''s. } }; options.agent = new https.Agent(options); var req = https.request(options, function (res) { //... });

Intenté simplemente editar la respuesta de Mitar, pero la edición fue rechazada, así que creé una respuesta separada.


Recientemente, hubo una adición a node.js que permite anular la verificación del nombre de host con una función personalizada. Se agregó a v0.11.14 y estará disponible en la próxima versión estable (0.12). Ahora puedes hacer algo como:

var options = { host: ''192.168.178.31'', port: 3000, ca: [ fs.readFileSync(''server-cert.pem'') ], checkServerIdentity: function (host, cert) { return undefined; } }; options.agent = new https.Agent(options); var req = https.request(options, function (res) { //... });

Esto ahora aceptará cualquier identidad de servidor, pero seguirá cifrando la conexión y las claves de verificación.

Tenga en cuenta que en versiones anteriores (por ejemplo, v0.11.14 ), checkServerIdentity era devolver un valor boolean indicaba la validez del servidor. Eso se ha cambiado (antes de v4.3.1 ) a la función que return (no throw ) un error si hay un problema y undefined está undefined si es válida.


Si está utilizando un nombre de host para conectarse, el nombre del host se comparará con los Nombres alternativos del sujeto del tipo de DNS, si corresponde, y volverá a aparecer en el CN ​​en el Nombre distinguido del sujeto de lo contrario.

Si está utilizando una dirección IP para conectarse, la dirección IP se comparará con las SAN de tipo de dirección IP , sin recurrir a la CN.

Esto es al menos lo que hacen las implementaciones compatibles con la especificación HTTP sobre TLS (es decir, HTTPS). Algunos navegadores son un poco más tolerantes.

Este es exactamente el mismo problema que en esta respuesta en Java , que también proporciona un método para colocar SAN personalizadas a través de OpenSSL (consulte también este documento ).

En general, a menos que sea para una CA de prueba, es bastante difícil administrar certificados que se basan en direcciones IP. Conectarse con un nombre de host es mejor.