Resumo

  • CertificateVerify assina o transcript com a chave privada do certificado; Finished autentica uma fronteira posterior com chave derivada do segredo de tráfego de handshake do emissor.
  • Um Finished válido do servidor não comprova o Finished do cliente, aceitação de 0-RTT, a perna upstream de um proxy, autorização da aplicação ou resultado persistido.

O êxito chegou uma mensagem cedo

A cadeia e o nome do serviço eram aceitáveis, e CertificateVerify estava correto. Depois, o verify_data não coincidiu com o transcript e a chave calculados pelo cliente. A RFC 9846 exige falha fatal. Não houve sessão quase válida; o handshake fracassou.

CertificateVerify demonstra controle da chave privada ligada à credencial e assina uma construção separada por papel até Certificate. Política de cadeia e identidade continuam sendo decisões próprias.

Finished não repete a assinatura. O TLS 1.3 deriva finished_key do segredo de tráfego de handshake de quem envia e calcula HMAC sobre o transcript até CertificateVerify, quando presente. Ele confirma as chaves computadas e aquela história exata.

No modo PSK, Certificate e CertificateVerify podem não existir, mas Finished continua obrigatório. Uma prova não substitui a outra.

O transcript segue a mensagem, não o pacote

O hash inclui mensagens de handshake em ordem, com tipo e comprimento. Cabeçalhos de record, alertas e dados da aplicação ficam fora. Fragmentação não altera a sequência lógica.

HelloRetryRequest representa o primeiro ClientHello por um message_hash sintético. Além disso, o restante do handshake TLS 1.3 é cifrado. Uma captura precisa de segredos diagnósticos do endpoint ou evidência equivalente; concatenar bytes visíveis não basta.

O hash da suíte também governa HKDF. Em TLS 1.3, verify_data tem o tamanho da saída desse hash, não os doze octetos fixos do TLS 1.2.

Cada direção termina em seu momento

Cliente e servidor têm segredos distintos, geram Finished diferentes e verificam o par em instantes diferentes. Depois de enviar o próprio Finished, o servidor pode usar chaves de aplicação e transmitir dados antes do Finished cliente. Ainda não possui garantia de identidade ou presença do cliente, pois o ClientHello pode ter sido repetido.

O cliente verifica o servidor, envia sua autenticação se solicitada e então seu Finished. Um único tls_complete apaga essas diferenças. O registro deve manter finished_sent, peer_finished_verified e o estado real por endpoint.

0-RTT é exceção explícita: pode sair cedo, deriva de PSK anterior e é repetível. Oferta, aceitação ou recusa de early data devem ficar separadas da conclusão ordinária.

Um proxy possui duas histórias

Cliente–proxy e proxy–origem não compartilham transcript, segredo ou Finished. Copiar a marca downstream para upstream inventa continuidade. Correlação de aplicação liga pedidos, mas cada perna prova seu próprio handshake.

OpenSSL distingue SSL_is_init_finished() de SSL_get_verify_result(), limitado ao certificado. Key log ajuda no laboratório, mas expõe segredos. BoringSSL informa que seus acessores Finished retornam zero em TLS 1.3; GnuTLS oferece hooks e erro específico. Cada biblioteca exige teste próprio.

O teste decisivo mantém certificado e CertificateVerify válidos, muda um byte de Finished e exige encerramento. Depois retém o Finished cliente, usa PSK sem certificado, força HelloRetryRequest e repete em duas pernas de proxy. Isso prova código em execução; um símbolo de API não prova execução.