-/* $OpenBSD: ssl_both.c,v 1.42 2022/02/05 14:54:10 jsing Exp $ */
+/* $OpenBSD: ssl_both.c,v 1.43 2022/10/01 16:23:15 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
return (0);
}
-int
-ssl3_send_finished(SSL *s, int state_a, int state_b)
-{
- CBB cbb, finished;
-
- memset(&cbb, 0, sizeof(cbb));
-
- if (s->s3->hs.state == state_a) {
- if (!tls12_derive_finished(s))
- goto err;
-
- /* Copy finished so we can use it for renegotiation checks. */
- if (!s->server) {
- memcpy(s->s3->previous_client_finished,
- s->s3->hs.finished, s->s3->hs.finished_len);
- s->s3->previous_client_finished_len =
- s->s3->hs.finished_len;
- } else {
- memcpy(s->s3->previous_server_finished,
- s->s3->hs.finished, s->s3->hs.finished_len);
- s->s3->previous_server_finished_len =
- s->s3->hs.finished_len;
- }
-
- if (!ssl3_handshake_msg_start(s, &cbb, &finished,
- SSL3_MT_FINISHED))
- goto err;
- if (!CBB_add_bytes(&finished, s->s3->hs.finished,
- s->s3->hs.finished_len))
- goto err;
- if (!ssl3_handshake_msg_finish(s, &cbb))
- goto err;
-
- s->s3->hs.state = state_b;
- }
-
- return (ssl3_handshake_write(s));
-
- err:
- CBB_cleanup(&cbb);
-
- return (-1);
-}
-
-int
-ssl3_get_finished(SSL *s, int a, int b)
-{
- int al, md_len, ret;
- CBS cbs;
-
- /* should actually be 36+4 :-) */
- if ((ret = ssl3_get_message(s, a, b, SSL3_MT_FINISHED, 64)) <= 0)
- return ret;
-
- /* If this occurs, we have missed a message */
- if (!s->s3->change_cipher_spec) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerror(s, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
- goto fatal_err;
- }
- s->s3->change_cipher_spec = 0;
-
- md_len = TLS1_FINISH_MAC_LENGTH;
-
- if (s->internal->init_num < 0) {
- al = SSL_AD_DECODE_ERROR;
- SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
- goto fatal_err;
- }
-
- CBS_init(&cbs, s->internal->init_msg, s->internal->init_num);
-
- if (s->s3->hs.peer_finished_len != md_len ||
- CBS_len(&cbs) != md_len) {
- al = SSL_AD_DECODE_ERROR;
- SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
- goto fatal_err;
- }
-
- if (!CBS_mem_equal(&cbs, s->s3->hs.peer_finished, CBS_len(&cbs))) {
- al = SSL_AD_DECRYPT_ERROR;
- SSLerror(s, SSL_R_DIGEST_CHECK_FAILED);
- goto fatal_err;
- }
-
- /* Copy finished so we can use it for renegotiation checks. */
- OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE);
- if (s->server) {
- memcpy(s->s3->previous_client_finished,
- s->s3->hs.peer_finished, md_len);
- s->s3->previous_client_finished_len = md_len;
- } else {
- memcpy(s->s3->previous_server_finished,
- s->s3->hs.peer_finished, md_len);
- s->s3->previous_server_finished_len = md_len;
- }
-
- return (1);
- fatal_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return (0);
-}
-
-int
-ssl3_send_change_cipher_spec(SSL *s, int a, int b)
-{
- size_t outlen;
- CBB cbb;
-
- memset(&cbb, 0, sizeof(cbb));
-
- if (s->s3->hs.state == a) {
- if (!CBB_init_fixed(&cbb, s->internal->init_buf->data,
- s->internal->init_buf->length))
- goto err;
- if (!CBB_add_u8(&cbb, SSL3_MT_CCS))
- goto err;
- if (!CBB_finish(&cbb, NULL, &outlen))
- goto err;
-
- if (outlen > INT_MAX)
- goto err;
-
- s->internal->init_num = (int)outlen;
- s->internal->init_off = 0;
-
- if (SSL_is_dtls(s)) {
- s->d1->handshake_write_seq =
- s->d1->next_handshake_write_seq;
- dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
- s->d1->handshake_write_seq, 0, 0);
- dtls1_buffer_message(s, 1);
- }
-
- s->s3->hs.state = b;
- }
-
- /* SSL3_ST_CW_CHANGE_B */
- return ssl3_record_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
-
- err:
- CBB_cleanup(&cbb);
-
- return -1;
-}
-
static int
ssl3_add_cert(CBB *cbb, X509 *x)
{
-/* $OpenBSD: ssl_clnt.c,v 1.153 2022/08/17 07:39:19 jsing Exp $ */
+/* $OpenBSD: ssl_clnt.c,v 1.154 2022/10/01 16:23:15 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b);
+static int ssl3_send_client_hello(SSL *s);
+static int ssl3_get_dtls_hello_verify(SSL *s);
+static int ssl3_get_server_hello(SSL *s);
+static int ssl3_get_certificate_request(SSL *s);
+static int ssl3_get_new_session_ticket(SSL *s);
+static int ssl3_get_cert_status(SSL *s);
+static int ssl3_get_server_done(SSL *s);
+static int ssl3_send_client_verify(SSL *s);
+static int ssl3_send_client_certificate(SSL *s);
+static int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
+static int ssl3_send_client_key_exchange(SSL *s);
+static int ssl3_get_server_key_exchange(SSL *s);
+static int ssl3_get_server_certificate(SSL *s);
+static int ssl3_check_cert_and_algorithm(SSL *s);
+static int ssl3_check_finished(SSL *s);
+static int ssl3_send_client_change_cipher_spec(SSL *s);
+static int ssl3_send_client_finished(SSL *s);
+static int ssl3_get_server_finished(SSL *s);
+
int
ssl3_connect(SSL *s)
{
case SSL3_ST_CW_CHANGE_B:
if (SSL_is_dtls(s) && !s->internal->hit)
dtls1_start_timer(s);
- ret = ssl3_send_change_cipher_spec(s,
- SSL3_ST_CW_CHANGE_A, SSL3_ST_CW_CHANGE_B);
+ ret = ssl3_send_client_change_cipher_spec(s);
if (ret <= 0)
goto end;
case SSL3_ST_CW_FINISHED_B:
if (SSL_is_dtls(s) && !s->internal->hit)
dtls1_start_timer(s);
- ret = ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A,
- SSL3_ST_CW_FINISHED_B);
+ ret = ssl3_send_client_finished(s);
if (ret <= 0)
goto end;
if (!SSL_is_dtls(s))
s->d1->change_cipher_spec_ok = 1;
else
s->s3->flags |= SSL3_FLAGS_CCS_OK;
- ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
- SSL3_ST_CR_FINISHED_B);
+ ret = ssl3_get_server_finished(s);
if (ret <= 0)
goto end;
if (SSL_is_dtls(s))
return (ret);
}
-int
+static int
ssl3_send_client_hello(SSL *s)
{
CBB cbb, client_hello, session_id, cookie, cipher_suites;
return (-1);
}
-int
+static int
ssl3_get_dtls_hello_verify(SSL *s)
{
CBS hello_verify_request, cookie;
return -1;
}
-int
+static int
ssl3_get_server_hello(SSL *s)
{
CBS cbs, server_random, session_id;
return (-1);
}
-int
+static int
ssl3_get_server_certificate(SSL *s)
{
CBS cbs, cert_list, cert_data;
return 0;
}
-int
+static int
ssl3_get_server_key_exchange(SSL *s)
{
CBS cbs, signature;
return (-1);
}
-int
+static int
ssl3_get_certificate_request(SSL *s)
{
CBS cert_request, cert_types, rdn_list;
return (X509_NAME_cmp(*a, *b));
}
-int
+static int
ssl3_get_new_session_ticket(SSL *s)
{
uint32_t lifetime_hint;
return (-1);
}
-int
+static int
ssl3_get_cert_status(SSL *s)
{
CBS cert_status, response;
return (-1);
}
-int
+static int
ssl3_get_server_done(SSL *s)
{
int ret;
return ret;
}
-int
+static int
ssl3_send_client_key_exchange(SSL *s)
{
unsigned long alg_k;
}
#endif
-int
+static int
ssl3_send_client_verify(SSL *s)
{
const struct ssl_sigalg *sigalg;
return (-1);
}
-int
+static int
ssl3_send_client_certificate(SSL *s)
{
EVP_PKEY *pkey = NULL;
#define has_bits(i,m) (((i)&(m)) == (m))
-int
+static int
ssl3_check_cert_and_algorithm(SSL *s)
{
long alg_k, alg_a;
* session tickets we have to check the next message to be sure.
*/
-int
+static int
ssl3_check_finished(SSL *s)
{
int ret;
return (1);
}
-int
+static int
ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
{
int i = 0;
i = s->ctx->internal->client_cert_cb(s, px509, ppkey);
return (i);
}
+
+static int
+ssl3_send_client_change_cipher_spec(SSL *s)
+{
+ size_t outlen;
+ CBB cbb;
+
+ memset(&cbb, 0, sizeof(cbb));
+
+ if (s->s3->hs.state == SSL3_ST_CW_CHANGE_A) {
+ if (!CBB_init_fixed(&cbb, s->internal->init_buf->data,
+ s->internal->init_buf->length))
+ goto err;
+ if (!CBB_add_u8(&cbb, SSL3_MT_CCS))
+ goto err;
+ if (!CBB_finish(&cbb, NULL, &outlen))
+ goto err;
+
+ if (outlen > INT_MAX)
+ goto err;
+
+ s->internal->init_num = (int)outlen;
+ s->internal->init_off = 0;
+
+ if (SSL_is_dtls(s)) {
+ s->d1->handshake_write_seq =
+ s->d1->next_handshake_write_seq;
+ dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+ s->d1->handshake_write_seq, 0, 0);
+ dtls1_buffer_message(s, 1);
+ }
+
+ s->s3->hs.state = SSL3_ST_CW_CHANGE_B;
+ }
+
+ /* SSL3_ST_CW_CHANGE_B */
+ return ssl3_record_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+
+ err:
+ CBB_cleanup(&cbb);
+
+ return -1;
+}
+
+static int
+ssl3_send_client_finished(SSL *s)
+{
+ CBB cbb, finished;
+
+ memset(&cbb, 0, sizeof(cbb));
+
+ if (s->s3->hs.state == SSL3_ST_CW_FINISHED_A) {
+ if (!tls12_derive_finished(s))
+ goto err;
+
+ /* Copy finished so we can use it for renegotiation checks. */
+ memcpy(s->s3->previous_client_finished,
+ s->s3->hs.finished, s->s3->hs.finished_len);
+ s->s3->previous_client_finished_len =
+ s->s3->hs.finished_len;
+
+ if (!ssl3_handshake_msg_start(s, &cbb, &finished,
+ SSL3_MT_FINISHED))
+ goto err;
+ if (!CBB_add_bytes(&finished, s->s3->hs.finished,
+ s->s3->hs.finished_len))
+ goto err;
+ if (!ssl3_handshake_msg_finish(s, &cbb))
+ goto err;
+
+ s->s3->hs.state = SSL3_ST_CW_FINISHED_B;
+ }
+
+ return (ssl3_handshake_write(s));
+
+ err:
+ CBB_cleanup(&cbb);
+
+ return (-1);
+}
+
+static int
+ssl3_get_server_finished(SSL *s)
+{
+ int al, md_len, ret;
+ CBS cbs;
+
+ /* should actually be 36+4 :-) */
+ if ((ret = ssl3_get_message(s, SSL3_ST_CR_FINISHED_A,
+ SSL3_ST_CR_FINISHED_B, SSL3_MT_FINISHED, 64)) <= 0)
+ return ret;
+
+ /* If this occurs, we have missed a message */
+ if (!s->s3->change_cipher_spec) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerror(s, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+ goto fatal_err;
+ }
+ s->s3->change_cipher_spec = 0;
+
+ md_len = TLS1_FINISH_MAC_LENGTH;
+
+ if (s->internal->init_num < 0) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
+ goto fatal_err;
+ }
+
+ CBS_init(&cbs, s->internal->init_msg, s->internal->init_num);
+
+ if (s->s3->hs.peer_finished_len != md_len ||
+ CBS_len(&cbs) != md_len) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
+ goto fatal_err;
+ }
+
+ if (!CBS_mem_equal(&cbs, s->s3->hs.peer_finished, CBS_len(&cbs))) {
+ al = SSL_AD_DECRYPT_ERROR;
+ SSLerror(s, SSL_R_DIGEST_CHECK_FAILED);
+ goto fatal_err;
+ }
+
+ /* Copy finished so we can use it for renegotiation checks. */
+ OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_server_finished,
+ s->s3->hs.peer_finished, md_len);
+ s->s3->previous_server_finished_len = md_len;
+
+ return (1);
+ fatal_err:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return (0);
+}
-/* $OpenBSD: ssl_locl.h,v 1.425 2022/09/10 15:29:33 jsing Exp $ */
+/* $OpenBSD: ssl_locl.h,v 1.426 2022/10/01 16:23:15 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
int SSL_SESSION_ticket(SSL_SESSION *ss, unsigned char **out, size_t *out_len);
const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
-int ssl3_send_server_certificate(SSL *s);
-int ssl3_send_newsession_ticket(SSL *s);
-int ssl3_send_cert_status(SSL *s);
-int ssl3_get_finished(SSL *s, int state_a, int state_b);
-int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b);
int ssl3_do_write(SSL *s, int type);
int ssl3_send_alert(SSL *s, int level, int desc);
int ssl3_get_req_cert_types(SSL *s, CBB *cbb);
int ssl3_get_message(SSL *s, int st1, int stn, int mt, long max);
-int ssl3_send_finished(SSL *s, int state_a, int state_b);
int ssl3_num_ciphers(void);
const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
const SSL_CIPHER *ssl3_get_cipher_by_id(unsigned int id);
int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
unsigned int len);
-/* some client-only functions */
-int ssl3_send_client_hello(SSL *s);
-int ssl3_get_dtls_hello_verify(SSL *s);
-int ssl3_get_server_hello(SSL *s);
-int ssl3_get_certificate_request(SSL *s);
-int ssl3_get_new_session_ticket(SSL *s);
-int ssl3_get_cert_status(SSL *s);
-int ssl3_get_server_done(SSL *s);
-int ssl3_send_client_verify(SSL *s);
-int ssl3_send_client_certificate(SSL *s);
-int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
-int ssl3_send_client_key_exchange(SSL *s);
-int ssl3_get_server_key_exchange(SSL *s);
-int ssl3_get_server_certificate(SSL *s);
-int ssl3_check_cert_and_algorithm(SSL *s);
-int ssl3_check_finished(SSL *s);
-
-/* some server-only functions */
-int ssl3_get_client_hello(SSL *s);
-int ssl3_send_dtls_hello_verify_request(SSL *s);
-int ssl3_send_server_hello(SSL *s);
-int ssl3_send_hello_request(SSL *s);
-int ssl3_send_server_key_exchange(SSL *s);
-int ssl3_send_certificate_request(SSL *s);
-int ssl3_send_server_done(SSL *s);
-int ssl3_get_client_certificate(SSL *s);
-int ssl3_get_client_key_exchange(SSL *s);
-int ssl3_get_cert_verify(SSL *s);
-
int ssl_kex_generate_dhe(DH *dh, DH *dh_params);
int ssl_kex_generate_dhe_params_auto(DH *dh, size_t key_len);
int ssl_kex_params_dhe(DH *dh, CBB *cbb);
-/* $OpenBSD: ssl_srvr.c,v 1.149 2022/08/17 07:39:19 jsing Exp $ */
+/* $OpenBSD: ssl_srvr.c,v 1.150 2022/10/01 16:23:15 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* OTHERWISE.
*/
+#include <limits.h>
#include <stdio.h>
#include <openssl/bn.h>
#include "ssl_sigalgs.h"
#include "ssl_tlsext.h"
+static int ssl3_get_client_hello(SSL *s);
+static int ssl3_send_dtls_hello_verify_request(SSL *s);
+static int ssl3_send_server_hello(SSL *s);
+static int ssl3_send_hello_request(SSL *s);
+static int ssl3_send_server_certificate(SSL *s);
+static int ssl3_send_server_key_exchange(SSL *s);
+static int ssl3_send_certificate_request(SSL *s);
+static int ssl3_send_server_done(SSL *s);
+static int ssl3_get_client_certificate(SSL *s);
+static int ssl3_get_client_key_exchange(SSL *s);
+static int ssl3_get_cert_verify(SSL *s);
+static int ssl3_send_newsession_ticket(SSL *s);
+static int ssl3_send_cert_status(SSL *s);
+static int ssl3_send_server_change_cipher_spec(SSL *s);
+static int ssl3_send_server_finished(SSL *s);
+static int ssl3_get_client_finished(SSL *s);
+
int
ssl3_accept(SSL *s)
{
s->d1->change_cipher_spec_ok = 1;
else
s->s3->flags |= SSL3_FLAGS_CCS_OK;
- ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
- SSL3_ST_SR_FINISHED_B);
+ ret = ssl3_get_client_finished(s);
if (ret <= 0)
goto end;
if (SSL_is_dtls(s))
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
- ret = ssl3_send_change_cipher_spec(s,
- SSL3_ST_SW_CHANGE_A, SSL3_ST_SW_CHANGE_B);
+ ret = ssl3_send_server_change_cipher_spec(s);
if (ret <= 0)
goto end;
s->s3->hs.state = SSL3_ST_SW_FINISHED_A;
case SSL3_ST_SW_FINISHED_A:
case SSL3_ST_SW_FINISHED_B:
- ret = ssl3_send_finished(s, SSL3_ST_SW_FINISHED_A,
- SSL3_ST_SW_FINISHED_B);
+ ret = ssl3_send_server_finished(s);
if (ret <= 0)
goto end;
s->s3->hs.state = SSL3_ST_SW_FLUSH;
return (ret);
}
-int
+static int
ssl3_send_hello_request(SSL *s)
{
CBB cbb, hello;
return (-1);
}
-int
+static int
ssl3_get_client_hello(SSL *s)
{
CBS cbs, client_random, session_id, cookie, cipher_suites;
return (ret);
}
-int
+static int
ssl3_send_dtls_hello_verify_request(SSL *s)
{
CBB cbb, verify, cookie;
return (-1);
}
-int
+static int
ssl3_send_server_hello(SSL *s)
{
CBB cbb, server_hello, session_id;
return (-1);
}
-int
+static int
ssl3_send_server_done(SSL *s)
{
CBB cbb, done;
return 0;
}
-int
+static int
ssl3_send_server_key_exchange(SSL *s)
{
CBB cbb, cbb_params, cbb_signature, server_kex;
return (-1);
}
-int
+static int
ssl3_send_certificate_request(SSL *s)
{
CBB cbb, cert_request, cert_types, sigalgs, cert_auth, dn;
return 0;
}
-int
+static int
ssl3_get_client_key_exchange(SSL *s)
{
unsigned long alg_k;
return (-1);
}
-int
+static int
ssl3_get_cert_verify(SSL *s)
{
CBS cbs, signature;
return (ret);
}
-int
+static int
ssl3_get_client_certificate(SSL *s)
{
CBS cbs, cert_list, cert_data;
return (ret);
}
-int
+static int
ssl3_send_server_certificate(SSL *s)
{
CBB cbb, server_cert;
}
/* send a new session ticket (not necessarily for a new session) */
-int
+static int
ssl3_send_newsession_ticket(SSL *s)
{
CBB cbb, session_ticket, ticket;
return (-1);
}
-int
+static int
ssl3_send_cert_status(SSL *s)
{
CBB cbb, certstatus, ocspresp;
return (-1);
}
+
+static int
+ssl3_send_server_change_cipher_spec(SSL *s)
+{
+ size_t outlen;
+ CBB cbb;
+
+ memset(&cbb, 0, sizeof(cbb));
+
+ if (s->s3->hs.state == SSL3_ST_SW_CHANGE_A) {
+ if (!CBB_init_fixed(&cbb, s->internal->init_buf->data,
+ s->internal->init_buf->length))
+ goto err;
+ if (!CBB_add_u8(&cbb, SSL3_MT_CCS))
+ goto err;
+ if (!CBB_finish(&cbb, NULL, &outlen))
+ goto err;
+
+ if (outlen > INT_MAX)
+ goto err;
+
+ s->internal->init_num = (int)outlen;
+ s->internal->init_off = 0;
+
+ if (SSL_is_dtls(s)) {
+ s->d1->handshake_write_seq =
+ s->d1->next_handshake_write_seq;
+ dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+ s->d1->handshake_write_seq, 0, 0);
+ dtls1_buffer_message(s, 1);
+ }
+
+ s->s3->hs.state = SSL3_ST_SW_CHANGE_B;
+ }
+
+ /* SSL3_ST_SW_CHANGE_B */
+ return ssl3_record_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+
+ err:
+ CBB_cleanup(&cbb);
+
+ return -1;
+}
+
+static int
+ssl3_get_client_finished(SSL *s)
+{
+ int al, md_len, ret;
+ CBS cbs;
+
+ /* should actually be 36+4 :-) */
+ if ((ret = ssl3_get_message(s, SSL3_ST_SR_FINISHED_A,
+ SSL3_ST_SR_FINISHED_B, SSL3_MT_FINISHED, 64)) <= 0)
+ return ret;
+
+ /* If this occurs, we have missed a message */
+ if (!s->s3->change_cipher_spec) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerror(s, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+ goto fatal_err;
+ }
+ s->s3->change_cipher_spec = 0;
+
+ md_len = TLS1_FINISH_MAC_LENGTH;
+
+ if (s->internal->init_num < 0) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
+ goto fatal_err;
+ }
+
+ CBS_init(&cbs, s->internal->init_msg, s->internal->init_num);
+
+ if (s->s3->hs.peer_finished_len != md_len ||
+ CBS_len(&cbs) != md_len) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerror(s, SSL_R_BAD_DIGEST_LENGTH);
+ goto fatal_err;
+ }
+
+ if (!CBS_mem_equal(&cbs, s->s3->hs.peer_finished, CBS_len(&cbs))) {
+ al = SSL_AD_DECRYPT_ERROR;
+ SSLerror(s, SSL_R_DIGEST_CHECK_FAILED);
+ goto fatal_err;
+ }
+
+ /* Copy finished so we can use it for renegotiation checks. */
+ OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_client_finished,
+ s->s3->hs.peer_finished, md_len);
+ s->s3->previous_client_finished_len = md_len;
+
+ return (1);
+ fatal_err:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return (0);
+}
+
+static int
+ssl3_send_server_finished(SSL *s)
+{
+ CBB cbb, finished;
+
+ memset(&cbb, 0, sizeof(cbb));
+
+ if (s->s3->hs.state == SSL3_ST_SW_FINISHED_A) {
+ if (!tls12_derive_finished(s))
+ goto err;
+
+ /* Copy finished so we can use it for renegotiation checks. */
+ memcpy(s->s3->previous_server_finished,
+ s->s3->hs.finished, s->s3->hs.finished_len);
+ s->s3->previous_server_finished_len = s->s3->hs.finished_len;
+
+ if (!ssl3_handshake_msg_start(s, &cbb, &finished,
+ SSL3_MT_FINISHED))
+ goto err;
+ if (!CBB_add_bytes(&finished, s->s3->hs.finished,
+ s->s3->hs.finished_len))
+ goto err;
+ if (!ssl3_handshake_msg_finish(s, &cbb))
+ goto err;
+
+ s->s3->hs.state = SSL3_ST_SW_FINISHED_B;
+ }
+
+ return (ssl3_handshake_write(s));
+
+ err:
+ CBB_cleanup(&cbb);
+
+ return (-1);
+}