Сервер и клиент как в TLSv1.2, так и в TLSv1.3 считают, что рукопожатие завершено, когда они оба написали сообщение «Finished» и получили его от однорангового узла. Вот как выглядит рукопожатие в TLSv1.2 (взято из RFC5246):
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
Итак, здесь вы можете видеть, что клиент отправляет свои сообщения Certificate и Finished во втором этапе связи с сервером. Затем он ожидает получения сообщений ChangeCipherSpe c и Finished от сервера, прежде чем он сочтет рукопожатие «завершенным» и сможет начать отправку данных приложения.
Это эквивалентный поток для TLSv1.3, взятый из RFC8446:
Client Server
Key ^ ClientHello
Exch | + key_share*
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch
+ pre_shared_key* v
{EncryptedExtensions} ^ Server
{CertificateRequest*} v Params
{Certificate*} ^
{CertificateVerify*} | Auth
{Finished} v
<-------- [Application Data*]
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} -------->
[Application Data] <-------> [Application Data]
Одно из преимуществ TLSv1.3 состоит в том, что он ускоряет время, необходимое для выполнения рукопожатия. В TLSv1.3 клиент получает сообщение «Finished» от сервера перед тем, как он отправляет обратно свои сообщения Certificate и Finished. К тому времени, когда клиент отправляет сообщение «Готово», он уже получил сообщение «Готово», поэтому рукопожатие завершено, и он может немедленно начать отправку данных приложения.
Это, конечно, означает, что клиент не будет знать, принял ли сервер сертификат или нет, пока он в следующий раз не прочитает данные с сервера. Если он был отклонен, следующее, что прочитает клиент, будет предупреждением об ошибке (в противном случае это будут обычные данные приложения).
Я знаю, что протокол рукопожатия полностью переписан однако, как часть TLS 1.3, похоже, что со всеми доступными обратными вызовами я смогу каким-то образом на стороне клиента определить, что аутентификация не удалась, без попытки записи данных на сервер.
Важно не запись данных на сервер, а чтение данных. Только тогда вы узнаете, отправил ли сервер предупреждение или просто данные обычного приложения. Пока эти данные не будут прочитаны, в OpenSSL нет доступных обратных вызовов, которые сообщат вам об этом, потому что сам OpenSSL не знает об этом из-за базового протокола.