17 out 2026 · segurança, tls, linux · 6 min
O que acontece no handshake TLS
O handshake TLS 1.3 completo leu 778 bytes do servidor. Retomando a sessao com o ticket que o servidor tinha entregado, a mesma conexao leu 241 bytes. Nenhuma dessas linhas trocadas vai para o log do seu servidor, e mesmo assim e o que decide se a conexao esta cifrada ou e lixo puro.
A primeira mensagem e a chave nova
O ClientHello tem 306 bytes e carrega duas coisas que importam: a versao maxima que o cliente aceita e uma chave publica X25519 gerada na hora. Nao e a chave do servidor, nem nada guardado em disco. E uma chave descartavel, criada para aquela conexao e esquecida depois.
O openssl s_client mostra o que foi enviado quando voce pede o estado da conversa:
openssl s_client -connect exemplo.com:443 -servername exemplo.com -state 2>&1 | head -20
E o servidor responde com o ServerHello, que escolhe a versao final e devolve a chave publica dele. As duas metades juntas produzem um segredo que nenhum dos dois conseguira sozinho calcular. Daqui em diante a conversa e cifrada com ele.
O certificado e o que ele prova
Depois do ServerHello vem o certificado. No que medi, a chave do servidor e P-256 e a assinatura e ECDSA com SHA-256, num certificado de 607 bytes:
openssl s_client -connect exemplo.com:443 -servername exemplo.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates
O certificado nao viaja cifrado, e nao viaja nem deveria. Ele e a parte da conversa que o cliente precisa ler em claro para conferir quem esta do outro lado. O que ele garante e o nome e a assinatura, nao o conteudo da pagina. Para o que um certificado resolve e o que nao resolve, o caso dos doze certificados falsos mostra o lado fraco.
Sozinho ele nao resolve nada sem a cadeia. Cada certificado aponta para quem o emitiu, e a corrente precisa terminar numa raiz em que o sistema confia. Acima dela vem o pin que impede um intermediario de emitir certificado para o seu nome.
O finished e o ticket de sessao
O handshake so esta completo quando os dois lados mandam um Finished, assinado com o segredo derivado das chaves. Isso fecha o ataque de intermediario: quem estiver no meio do caminho ve a chave publica, mas nao consegue produzir um Finished valido.
E entao vem a mensagem mais subestimada, que chega depois do handshake pronto: o ticket de sessao, uma chave que resume tudo o que foi negociado.
Medir o handshake inteiro na sua maquina
O script abaixo sobe um servidor TLS local com certificado autoassinado, conecta nele com o s_client e imprime as seis mensagens na ordem. Nada sai para a internet.
#!/usr/bin/env bash
# handshake: sobe um TLS 1.3 local, mede o completo e o retomado.
set -u
if ! command -v openssl > /dev/null 2>&1; then
echo "falta o openssl: instale com apt install openssl e rode de novo"
exit 0
fi
DIR="$(mktemp -d)"
PORTA=14433
# certificado autoassinado, P-256, valido por 2 dias
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-nodes -keyout "$DIR/chave.pem" -out "$DIR/cert.pem" -days 2 \
-subj "/CN=localhost" -addext "subjectAltName=DNS:localhost" 2>/dev/null
echo "== certificado =="
openssl x509 -in "$DIR/cert.pem" -noout -subject -dates
openssl s_server -accept $PORTA -cert "$DIR/cert.pem" -key "$DIR/chave.pem" \
-www -tls1_3 > /dev/null 2>&1 &
SRV=$!
sleep 2
pedir() { printf 'GET / HTTP/1.0\r\n\r\n'; sleep 2; }
echo
echo "== handshake completo, com os estados =="
pedir | openssl s_client -connect 127.0.0.1:$PORTA -servername localhost \
-sess_out "$DIR/sess.pem" -state 2>&1 | grep -E "SSL_connect|Server Temp Key|Cipher is"
echo
echo "== handshake retomado, com o ticket =="
pedir | openssl s_client -connect 127.0.0.1:$PORTA -servername localhost \
-sess_in "$DIR/sess.pem" 2>&1 | grep -E "Reused|New,|handshake has read"
kill $SRV 2>/dev/null
rm -rf "$DIR"
Como verificar
O que interessa sao duas linhas, a do New, e a do Reused,. Na primeira execucao voce ve New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384, na segunda Reused, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384. O Reused diz que o ticket funcionou.
O certificado autoassinado faz a verificacao falhar, e tudo bem: aparecera Verification error: self-signed certificate, o aviso correto para um certificado que ninguem assinou. Com um site publico o mesmo comando mostra Verification: OK.
O tamanho do handshake
Aqui esta o numero que eu mais gosto de olhar. Um handshake completo le 778 bytes do servidor; um retomado le 241. A queda e de 69 por cento, e ela vem de uma coisa so: o certificado tem 607 bytes e nao precisa ser reenviado.
Em um site publico com cadeia de 4 certificados a conta muda: o handshake completo leu 3.727 bytes em TLS 1.3 e 3.878 em TLS 1.2. A cadeia pesa mais que a diferenca de versao, o que explica por que certificados de 6 dias fazem sentido: menos cadeia para carregar.
Se der errado
connect: Connection refused na hora de conectar. O s_server nao subiu. Verifique se a porta 14433 ja estava ocupada com ss -ltnp | grep 14433 e troque por outra no script.
falta o openssl. O script avisa e sai sem tentar rodar o resto. Instale o pacote e rode de novo.
Reused nunca aparece. O servidor pode estar sem -tls1_3, ou a sessao expirou entre as execucoes. Rode as duas linhas em sequencia, sem pausa longa.
As diferencas entre 1.2 e 1.3
| TLS 1.2 | TLS 1.3 | |
|---|---|---|
| mensagens | 2 idas e voltas | 1 ida e volta |
| assinatura do certificado | sobre o handshake inteiro | so sobre o certificado |
| cifra comum | ECDHE-ECDSA-CHACHA20-POLY1305 | TLS_AES_256_GCM_SHA384 |
| bytes lidos no exemplo publico | 3.878 | 3.727 |
O ganho do 1.3 nao esta so no tempo. Tirar a assinatura do handshake inteiro faz a assinatura do servidor valer para varias sessoes, o que deixa o handshake mais barato.
FAQ
O handshake e a mesma coisa que a conexao? Nao. Depois do Finished a conexao esta estabelecida, e a mesma chave continua cifrando os dados. O handshake acontece uma vez, a conexao dura.
Por que a chave publica vai em claro no ClientHello? Porque nao ha segredo nenhum ainda. Quem tentar ler o ClientHello descobre a chave publica de uma sessao que ele mesmo impede de decifrar.
TLS 1.3 tira o certificado? Nao. Ele sai do caminho critico e chega depois da chave estar estabelecida, mas continua sendo a unica prova de quem e o servidor. Para o que ele prova e o que nao prova, veja os certificados falsos e a lista CAA.
Vale a pena forcar TLS 1.3? Vale, e o custo e pequeno: a propria sessao retomada ja e o mecanismo que reduz o trabalho por conexao. O que nao vale e prometer 1.3 e deixar o cliente antigo sem caminho.
Fontes
- RFC 8446, TLS 1.3, secoes 2 e 4, de agosto de 2018.
openssl s_client, OpenSSL 3.0.13, medido em 17 de outubro de 2026.- openssl(1), como usar o s_client, opcoes
-state,-sess_oute-sess_in.