Saltar al contenido
sudoquest@root
Modelo OSI

Capa 6 · Presentación

Los datos como bytes, UTF-8 y el mojibake, formatos y compresión, y el cifrado con TLS, los certificados y la cadena de confianza.

20 min de lectura

Las capas de abajo llevan bytes de un sitio a otro, y la sesión los ordena en una conversación. Pero un byte no significa nada por sí solo: F1 puede ser una “ñ”, un “±” o la mitad de otra letra, según con qué regla se lea. La capa 6, la de presentación, se ocupa de que lo que llega se entienda igual que se envió. También de que nadie pueda leerlo ni cambiarlo por el camino.

Aquí las averías son las del “se ve, pero…”. La conexión se abre y la sesión también, y aun así la intranet enseña “Núñez” como “N��ez”, el informe de la sucursal sale en Excel lleno de “ñ”, o el navegador avisa de que la conexión no es privada y no deja pasar. La red, los servicios y las sesiones están bien: lo que falla es cómo se presentan los datos.

Las siete capas del modelo OSI, con la capa 6 resaltada7Aplicacióndatos6Presentacióndatos5Sesióndatos4Transportesegmentos3Redpaquetes2Enlace de datostramas1Físicabits
La capa de presentación, encima de la de sesión: la sesión ordena la conversación; la presentación decide cómo se escriben los datos, y si van cifrados.

Qué es la presentación (y dónde está en TCP/IP)

La capa de presentación pone los datos en una forma que el otro entienda, y los protege para el viaje:

  • Codificar: cómo se escribe cada letra, cada número o cada imagen como bytes.
  • Comprimir: ocupar menos, sin perder nada.
  • Cifrar: que solo el destinatario pueda leerlo, y que sepa que nadie lo cambió.

Como la de sesión, en TCP/IP no existe aparte: cada aplicación decide en qué codificación escribe y en cuál lee. El cifrado sí tiene un protocolo propio que usan casi todas, TLS (la “s” de HTTPS), que se mete entre la capa 4 y la aplicación. Por eso aquí tampoco se aprende “un protocolo de presentación”, sino lo que falla cuando los dos extremos no leen con las mismas reglas.

Los caracteres son números

Un ordenador solo guarda números. Para guardar texto, hace falta una tabla que diga qué número es cada letra: una codificación.

  • ASCII, la primera que se extendió: 128 caracteres (las letras inglesas, los números, los signos). La “N” es el 78, en hexadecimal 4E. No tiene “ñ” ni tildes.
  • Las páginas de códigos: ASCII más 128 caracteres extra, distintos en cada una. En los Windows de Europa occidental, Windows-1252 (la “ñ” es F1). La consola de Windows en español usa otra más antigua, la 850, donde F1 es “±”.
  • Unicode: una sola lista con todos los caracteres de todos los idiomas (y los emojis). Se guarda casi siempre en UTF-8, que usa de 1 a 4 bytes por carácter: lo que es ASCII ocupa uno y sigue siendo igual, y lo demás ocupa más. La “ñ” son dos: C3 B1.
La palabra Núñez guardada de dos formas. En UTF-8 ocupa 7 bytes: 4E para la N, C3 BA para la ú, C3 B1 para la ñ, 65 para la e y 7A para la z. En Windows-1252 ocupa 5: 4E, FA, F1, 65 y 7A. La N, la e y la z son ASCII y se guardan igual con las dos reglas; la ú y la ñ, no. el textoNúñezUTF-8 · 7 bytes4EC3 BAC3 B1657AWindows-1252 · 5 bytes4EFAF1657AN, e y z (ASCII): iguales con las dos reglas
La misma palabra con dos reglas. En UTF-8, la ú y la ñ ocupan dos bytes cada una; en Windows-1252, uno. Lo que es ASCII no cambia.

UTF-8 es hoy la regla de casi todo: las webs, Linux, los programas nuevos. Pero en una oficina con Windows todavía quedan programas y archivos en Windows-1252, y ahí empiezan los líos.

El mojibake: la regla equivocada

Cuando un texto se lee con una regla distinta de la que se usó para escribirlo, no falta ni un byte, pero sale basura. Tiene nombre japonés: mojibake. Y como hay dos reglas en juego, hay dos direcciones, y cada una deja su huella:

Primera dirección: el texto se guardó en UTF-8, así que la ñ son dos bytes, C3 B1. Quien lo lee cree que es Windows-1252, un byte por letra: C3 es la à y B1 es el signo ±. La ñ sale como ñ, y Núñez como Núñez: dos letras raras por cada letra con tilde.UTF-8, leído con un byteguardado en UTF-8C3 B1leído como Windows-1252C3 → à B1 → ±Ã±Núñez → Núñezdos letras por cada unaSegunda dirección: el texto se guardó en Windows-1252, así que la ñ es un solo byte, F1. Quien lo lee cree que es UTF-8, y en UTF-8 ese byte anuncia una letra de varios bytes que no llegan: no es válido. Sale el carácter de sustitución, un rombo con una interrogación, y Núñez se lee N��ez.Un byte, leído como UTF-8guardado en Windows-1252F1leído como UTF-8F1 no es UTF-8 válido�Núñez → N��ezun rombo por cada byte roto
UTF-8 leído con un byte por letra da ñ; un byte por letra leído como UTF-8 da �. Por la huella se sabe qué pasó.
  • ñ, é, ú (una “Ô delante de algo raro): es UTF-8 leído como Windows-1252. El texto está bien guardado; el que lo abre se equivoca de regla.
  • � (el rombo con la interrogación): es un texto de un byte por letra leído como UTF-8. Esos bytes no son UTF-8 válido, y el que lee pone un rombo donde no entiende.

Para saber qué hay de verdad, se miran los bytes. En PowerShell, Format-Hex enseña un archivo tal cual, byte a byte (a la izquierda, dónde empieza cada fila; en medio, los bytes; a la derecha, un intento de leerlos):

La ñ son dos bytes, C3 B1: el archivo está en UTF-8
PS C:\Users\conta1> Format-Hex .\informe-ventas.csv

         Ruta: C:\Users\conta1\informe-ventas.csv

         00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   43 6C 69 65 6E 74 65 3B 50 61 C3 AD 73 0D 0A 4E  Cliente;País..N
00000010   C3 BA C3 B1 65 7A 3B 45 73 70 61 C3 B1 61 0D 0A  úñez;España..
Un F1 suelto: este archivo está en Windows-1252
PS C:\Users\conta1> Format-Hex .\nombre.txt

         Ruta: C:\Users\conta1\nombre.txt

         00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   4E FA F1 65 7A                                   Núñez

Los 0D 0A del final de cada línea son el salto de línea de Windows (más abajo, en los formatos).

Quién dice la codificación

Un archivo de texto no dice en qué codificación está: son solo bytes. Lo dice otro:

  • En una web, la cabecera que manda el servidor (Content-Type: text/html; charset=utf-8), o una etiqueta en la propia página (<meta charset="utf-8">). Si las dos dicen algo, manda la cabecera. Y si dicen una regla y la página se guardó con otra, sale mojibake.
  • En un archivo, el programa que lo abre, a veces con una pista: la marca de orden de bytes (BOM), tres bytes al principio de un archivo UTF-8 (EF BB BF) que dicen “esto es UTF-8”.
  • En la consola, su página de códigos (chcp).

curl.exe, que viene con Windows, enseña las cabeceras de una página con -I:

El servidor dice que la página es UTF-8
C:\Users\ventas2> curl.exe -I https://10.20.1.200/personal.html
HTTP/1.1 200 OK
Content-Length: 2211
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 24 Sep 2026 16:02:51 GMT
Accept-Ranges: bytes
Server: Microsoft-IIS/10.0
Date: Fri, 25 Sep 2026 07:14:03 GMT

Si esa página se guardó en Windows-1252, el navegador cree a la cabecera y la lee como UTF-8: cada ñ, un rombo. Se arregla haciendo que digan lo mismo. Lo bueno es guardar la página en UTF-8, que es lo que dice la cabecera y lo que se espera hoy.

La consola también tiene su regla. En español, la 850: un archivo UTF-8 se ve mal con type aunque esté perfecto. chcp la dice y la cambia (65001 es UTF-8):

El archivo está bien; la consola lo lee con la 850
C:\Users\conta1> type informe-ventas.csv
Cliente;País
N├║├▒ez;Espa├▒a

C:\Users\conta1> chcp
Página de códigos activa: 850

C:\Users\conta1> chcp 65001
Página de códigos activa: 65001

C:\Users\conta1> type informe-ventas.csv
Cliente;País
Núñez;España

Formatos, Base64 y compresión

La codificación de los caracteres es solo una parte. La capa 6 también es el formato de lo que viaja, y cada extremo tiene que saber cuál es:

Tipo (MIME) Qué es
text/html una página web
text/csv una tabla en texto, separada por comas o ;
application/pdf un documento PDF
image/png una imagen
  • El tipo MIME va en la misma cabecera Content-Type: el navegador decide por él si enseña la página, abre el PDF o descarga el archivo. Un tipo equivocado hace que un PDF se descargue en vez de abrirse, o que una página se vea como texto.
  • Base64 convierte cualquier cosa en letras seguras (64 caracteres: A–Z, a–z, 0–9, + y /), para meterla por un canal que solo acepta texto. Así viajan los adjuntos del correo. Cada 3 bytes se vuelven 4 caracteres: ocupa un tercio más. “Núñez” en UTF-8 es TsO6w7Fleg== en Base64. No es cifrar: cualquiera lo deshace.
  • Comprimir: un servidor web puede mandar la página con gzip y avisar en la cabecera (Content-Encoding: gzip). El navegador la descomprime antes de leerla.
  • Los saltos de línea: Windows termina cada línea con dos bytes, 0D 0A (CRLF); Linux y macOS, con uno, 0A (LF). Un script escrito en Windows puede fallar en un servidor Linux por ese 0D de más.

Cifrar: una clave o dos

Cifrar es transformar los datos para que solo pueda leerlos quien tiene la clave. Hay dos formas, y en la práctica se usan juntas:

  • Cifrado simétrico: la misma clave cifra y descifra (AES, por ejemplo). Es rápido, bueno para mucho tráfico. El problema: los dos extremos tienen que tener la misma clave, y no se la pueden mandar por la red en claro.
  • Cifrado asimétrico: cada uno tiene dos claves, una pública (que enseña a todos) y una privada (que no sale de su equipo). Lo que se cifra con una solo se abre con la otra. Sirve para acordar una clave sin mandarla y para firmar: lo que firma la privada, cualquiera lo comprueba con la pública. Es lento para mucho tráfico.

TLS usa los dos: al empezar, la parte asimétrica acuerda una clave nueva para esa conexión y prueba quién es el servidor. Después, todo va con cifrado simétrico con esa clave.

El saludo de TLS

Antes de que pase un solo byte de la página, navegador y servidor se ponen de acuerdo:

El saludo de TLS 1.3 entre un navegador y un servidor. En claro: el navegador manda el ClientHello, con las versiones que sabe (1.3 o 1.2) y los cifrados; el servidor contesta con el ServerHello, eligiendo TLS 1.3 y con su parte de la clave. Desde ahí, todo va cifrado: el servidor manda su certificado y su firma, y el navegador comprueba tres cosas: si lo firmó alguien de quien se fía, si está en fecha y si es para el nombre al que entró. Si todo cuadra, manda Finished, y la página llega cifrada como Application Data. Si algo falla, el navegador corta con una alerta y enseña el aviso. navegadorservidoren clarocifradoClientHello: TLS 1.3 o 1.2, cifradosServerHello: TLS 1.3, su parte de la claveel certificado, y su firma¿de fiar? ¿en fecha? ¿este nombre?Finished: todo cuadraApplication Data: la página
TLS 1.3: el ClientHello y el ServerHello van en claro. Desde ahí, todo va cifrado, el certificado también, y el navegador lo comprueba antes de seguir.
  • ClientHello: el navegador dice qué versiones de TLS sabe, qué cifrados, y su parte de la clave. Si se entra por un nombre, lo manda aquí (se llama SNI), para que un servidor con varias webs sepa cuál enseñar. Si se entra por IP, no va.
  • ServerHello: el servidor elige la versión y el cifrado, y manda su parte de la clave. Con las dos partes, cada extremo calcula la misma clave simétrica sin que haya viajado.
  • El certificado: quién es el servidor, firmado por alguien. El navegador lo comprueba (la sección siguiente); si no se fía, corta con una alerta y enseña el aviso.
  • Si todo cuadra, la página viaja como Application Data: bytes cifrados.

Para el capturador, eso cambia las cosas: en TLS 1.3 solo ve en claro los dos primeros mensajes. Desde el ServerHello, ni la página ni el certificado: para ver el certificado, el navegador. (En TLS 1.2 el certificado iba sin cifrar, y el capturador sí lo veía.)

Los certificados y la cadena de confianza

Un certificado es una promesa firmada: “esta clave pública es de este nombre, desde tal fecha hasta tal otra”. Lo firma una entidad de certificación (CA). Y el navegador se fía de él si se fía de quien lo firmó.

¿Y de quién se fía? De las raíces de confianza que el equipo tiene instaladas. Windows trae las de las entidades públicas (por eso las webs de internet abren sin avisos). Una empresa puede tener su propia entidad, para sus servidores internos: su raíz la reparte el dominio a sus puestos.

La cadena de confianza. Arriba, la raíz de la empresa, EMPRESA-CA, instalada en las raíces de confianza del puesto. Ella firma el certificado de la intranet, que es para srv-sede.empresa.lan y para 10.20.1.200, lo emitió EMPRESA-CA y vale del 1 de octubre de 2025 al 1 de octubre de 2026. El navegador comprueba tres cosas, y cada una tiene su aviso si falla: si lo firmó una raíz de confianza (ERR_CERT_AUTHORITY_INVALID), si está en fecha (ERR_CERT_DATE_INVALID) y si es para el nombre al que se entró (ERR_CERT_COMMON_NAME_INVALID). EMPRESA-CA (raíz)en las raíces de confianza del puestofirmael certificado de la intranetpara: srv-sede.empresa.lan, 10.20.1.200emisor: EMPRESA-CAválido: 1/10/2025 – 1/10/2026el navegador comprueba¿lo firmó una raíz de confianza?si no: ERR_CERT_AUTHORITY_INVALID¿está en fecha?si no: ERR_CERT_DATE_INVALID¿es para el nombre al que entré?si no: ERR_CERT_COMMON_NAME_INVALID
La raíz, instalada en el puesto, firma el certificado de la intranet. El navegador comprueba tres cosas, y cada una tiene su aviso.

Si falla una de las tres, sale “La conexión no es privada”, con el motivo debajo:

  • NET::ERR_CERT_AUTHORITY_INVALID: lo firmó alguien que este puesto no conoce. Si solo le pasa a un puesto, a ese le falta la raíz.
  • NET::ERR_CERT_DATE_INVALID: caducado (o aún no válido). Pasa también si el reloj del puesto se ha ido años: las capas se apoyan.
  • NET::ERR_CERT_COMMON_NAME_INVALID: es para otro nombre. Los nombres válidos van en la lista de nombres alternativos del sujeto (SAN), y si se entra por la IP, la IP tiene que estar en esa lista.

curl.exe no enseña avisos: se niega, con el error de Windows, que dice cuál de las tres es:

Este puesto no conoce a quien firmó el certificado
C:\Users\ventas1> curl.exe -I https://10.20.1.200
curl: (60) schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - La cadena de certificación fue emitida por una entidad en la que no se confía.
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the webpage mentioned above.

(Para un certificado caducado, SEC_E_CERT_EXPIRED; para otro nombre, SEC_E_WRONG_PRINCIPAL.) certutil -store root lista las raíces del equipo, y certutil -addstore root añade una (como administrador):

La raíz de la empresa, en las raíces de confianza de este puesto
C:\Windows\system32> certutil -addstore root empresa-ca.cer
root "Entidades de certificación raíz de confianza"
La firma coincide con la clave pública
Se agregó el certificado "EMPRESA-CA" al almacén.
CertUtil: -addstore comando completado correctamente.

En un dominio no hace falta ir puesto a puesto (ni una consola de administrador en cada uno): la raíz la reparte una directiva, y gpupdate /force hace que el puesto la traiga ya, sin esperar a la próxima vez que la mire. La directiva (y el archivo de la raíz, si se importa a mano) se trae de las carpetas compartidas del servidor, por el 445: si el puesto no llega a ellas, gpupdate no puede traer nada. Lo mismo le pasa al programa de la sucursal, que deja ahí su informe.

Y cuando se emite un certificado nuevo, hay que enlazarlo: decirle al servidor web que presente ese. Emitirlo sin más lo deja guardado en el servidor, y el sitio sigue presentando el viejo.

Las versiones de TLS

Versión Año Hoy
SSL 3.0 1996 prohibida
TLS 1.0 1999 retirada
TLS 1.1 2006 retirada
TLS 1.2 2008 en uso
TLS 1.3 2018 la recomendada

Las versiones viejas tienen fallos conocidos, y los navegadores ya no las aceptan: solo hablan TLS 1.2 y 1.3. Un servidor con una configuración antigua que solo acepta TLS 1.0 no comparte ninguna versión con ellos, y la conexión no llega a abrirse: el aviso es ERR_SSL_VERSION_OR_CIPHER_MISMATCH, y en el capturador se ve el ClientHello, con sus versiones, y la alerta del servidor como toda respuesta. Se arregla en el servidor: habilitar TLS 1.2 (y 1.3) y apagar las viejas.

Cómo se diagnostica la capa 6

Con las capas de abajo descartadas (conecta, la sesión se abre), se pregunta por cómo se presentan los datos. Si no conecta (la intranet se queda cargando, las carpetas no abren), no es de esta capa: se baja a la 4, con Test-NetConnection y netstat -ano: ¿escucha el servicio del servidor, deja pasar su Firewall el puerto (el 443 de HTTPS, el 445 de las carpetas)? Si conecta:

  1. ¿Qué ve exactamente? Leer el aviso entero o la basura con cuidado: dicen mucho.
  2. Si es basura con Ã: UTF-8 leído con otra regla. Si son rombos �: otra regla leída como UTF-8. Mirar los bytes (Format-Hex) y quién dice la regla (la cabecera con curl.exe -I; el BOM, para Excel; chcp, en la consola).
  3. Si es un aviso de certificado: ¿cuál de los tres? El código (AUTHORITY, DATE, COMMON_NAME) y el visor del certificado del navegador: quién lo firmó, hasta cuándo vale, para qué nombres.
  4. ¿A todos o a uno? Si solo le pasa a un puesto, lo raro está en ese puesto (su raíz, su reloj, su consola). Si a todos, en el servidor.
  5. Si no hay ni aviso de certificado: ¿comparten versión de TLS? El capturador: ClientHello y, como respuesta, una alerta.
  6. Y el arreglo, en su sitio: el certificado se renueva y se enlaza; la raíz, se instala; la regla se pone de acuerdo en los dos extremos. Nada de “continuar de todos modos”.