diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2017-10-12 15:52:51 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2017-10-12 15:52:51 +0000 |
commit | a237183be8f3b436eac1f0e037c1d10b31909a28 (patch) | |
tree | debfa25f36f1d852190d28dad27c583794f23bca | |
parent | 0d1c36f475a7a40a1422e1915e5b0f457a03a725 (diff) |
Fold dtls1_accept() into ssl_accept(), removing a lot of duplicated code.
With review/feedback from inoguchi@
-rw-r--r-- | lib/libssl/d1_meth.c | 4 | ||||
-rw-r--r-- | lib/libssl/d1_srvr.c | 538 | ||||
-rw-r--r-- | lib/libssl/ssl_locl.h | 4 | ||||
-rw-r--r-- | lib/libssl/ssl_srvr.c | 153 |
4 files changed, 143 insertions, 556 deletions
diff --git a/lib/libssl/d1_meth.c b/lib/libssl/d1_meth.c index e513c4a9be9..9ecca0027cb 100644 --- a/lib/libssl/d1_meth.c +++ b/lib/libssl/d1_meth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: d1_meth.c,v 1.14 2017/10/10 15:13:26 jsing Exp $ */ +/* $OpenBSD: d1_meth.c,v 1.15 2017/10/12 15:52:50 jsing Exp $ */ /* * DTLS implementation written by Nagendra Modadugu * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. @@ -72,7 +72,7 @@ static const SSL_METHOD_INTERNAL DTLSv1_method_internal_data = { .ssl_new = dtls1_new, .ssl_clear = dtls1_clear, .ssl_free = dtls1_free, - .ssl_accept = dtls1_accept, + .ssl_accept = ssl3_accept, .ssl_connect = ssl3_connect, .ssl_read = ssl3_read, .ssl_peek = ssl3_peek, diff --git a/lib/libssl/d1_srvr.c b/lib/libssl/d1_srvr.c index 05c92be46cd..57b8ea0e24a 100644 --- a/lib/libssl/d1_srvr.c +++ b/lib/libssl/d1_srvr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: d1_srvr.c,v 1.90 2017/10/08 16:56:51 jsing Exp $ */ +/* $OpenBSD: d1_srvr.c,v 1.91 2017/10/12 15:52:50 jsing Exp $ */ /* * DTLS implementation written by Nagendra Modadugu * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. @@ -125,8 +125,6 @@ #include <openssl/objects.h> #include <openssl/x509.h> -static int dtls1_send_hello_verify_request(SSL *s); - static const SSL_METHOD_INTERNAL DTLSv1_server_method_internal_data = { .version = DTLS1_VERSION, .min_version = DTLS1_VERSION, @@ -134,7 +132,7 @@ static const SSL_METHOD_INTERNAL DTLSv1_server_method_internal_data = { .ssl_new = dtls1_new, .ssl_clear = dtls1_clear, .ssl_free = dtls1_free, - .ssl_accept = dtls1_accept, + .ssl_accept = ssl3_accept, .ssl_connect = ssl_undefined_function, .ssl_read = ssl3_read, .ssl_peek = ssl3_peek, @@ -176,538 +174,6 @@ dtls1_get_server_method(int ver) } int -dtls1_accept(SSL *s) -{ - void (*cb)(const SSL *ssl, int type, int val) = NULL; - unsigned long alg_k; - int ret = -1; - int new_state, state, skip = 0; - int listen; - - ERR_clear_error(); - errno = 0; - - if (s->internal->info_callback != NULL) - cb = s->internal->info_callback; - else if (s->ctx->internal->info_callback != NULL) - cb = s->ctx->internal->info_callback; - - listen = D1I(s)->listen; - - /* init things to blank */ - s->internal->in_handshake++; - if (!SSL_in_init(s) || SSL_in_before(s)) - SSL_clear(s); - - D1I(s)->listen = listen; - - if (s->cert == NULL) { - SSLerror(s, SSL_R_NO_CERTIFICATE_SET); - ret = -1; - goto end; - } - - for (;;) { - state = S3I(s)->hs.state; - - switch (S3I(s)->hs.state) { - case SSL_ST_RENEGOTIATE: - s->internal->renegotiate = 1; - /* S3I(s)->hs.state=SSL_ST_ACCEPT; */ - - case SSL_ST_BEFORE: - case SSL_ST_ACCEPT: - case SSL_ST_BEFORE|SSL_ST_ACCEPT: - case SSL_ST_OK|SSL_ST_ACCEPT: - s->server = 1; - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_START, 1); - - if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) { - SSLerror(s, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - s->internal->type = SSL_ST_ACCEPT; - - if (!ssl3_setup_init_buffer(s)) { - ret = -1; - goto end; - } - if (!ssl3_setup_buffers(s)) { - ret = -1; - goto end; - } - - s->internal->init_num = 0; - - if (S3I(s)->hs.state != SSL_ST_RENEGOTIATE) { - /* - * Ok, we now need to push on a buffering BIO - * so that the output is sent in a way that - * TCP likes :-) - * ...but not with SCTP :-) - */ - if (!ssl_init_wbio_buffer(s, 1)) { - ret = -1; - goto end; - } - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - - S3I(s)->hs.state = SSL3_ST_SR_CLNT_HELLO_A; - s->ctx->internal->stats.sess_accept++; - } else { - /* - * S3I(s)->hs.state == SSL_ST_RENEGOTIATE, - * we will just send a HelloRequest. - */ - s->ctx->internal->stats.sess_accept_renegotiate++; - S3I(s)->hs.state = SSL3_ST_SW_HELLO_REQ_A; - } - break; - - case SSL3_ST_SW_HELLO_REQ_A: - case SSL3_ST_SW_HELLO_REQ_B: - s->internal->shutdown = 0; - dtls1_clear_record_buffer(s); - dtls1_start_timer(s); - ret = ssl3_send_hello_request(s); - if (ret <= 0) - goto end; - S3I(s)->hs.next_state = SSL3_ST_SR_CLNT_HELLO_A; - S3I(s)->hs.state = SSL3_ST_SW_FLUSH; - s->internal->init_num = 0; - - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_HELLO_REQ_C: - S3I(s)->hs.state = SSL_ST_OK; - break; - - case SSL3_ST_SR_CLNT_HELLO_A: - case SSL3_ST_SR_CLNT_HELLO_B: - case SSL3_ST_SR_CLNT_HELLO_C: - s->internal->shutdown = 0; - ret = ssl3_get_client_hello(s); - if (ret <= 0) - goto end; - dtls1_stop_timer(s); - - if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) - S3I(s)->hs.state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; - else - S3I(s)->hs.state = SSL3_ST_SW_SRVR_HELLO_A; - - s->internal->init_num = 0; - - /* Reflect ClientHello sequence to remain stateless while listening */ - if (listen) { - memcpy(S3I(s)->write_sequence, S3I(s)->read_sequence, sizeof(S3I(s)->write_sequence)); - } - - /* If we're just listening, stop here */ - if (listen && S3I(s)->hs.state == SSL3_ST_SW_SRVR_HELLO_A) { - ret = 2; - D1I(s)->listen = 0; - /* Set expected sequence numbers - * to continue the handshake. - */ - D1I(s)->handshake_read_seq = 2; - D1I(s)->handshake_write_seq = 1; - D1I(s)->next_handshake_write_seq = 1; - goto end; - } - - break; - - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: - case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: - ret = dtls1_send_hello_verify_request(s); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_FLUSH; - S3I(s)->hs.next_state = SSL3_ST_SR_CLNT_HELLO_A; - - /* HelloVerifyRequest resets Finished MAC */ - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_SRVR_HELLO_A: - case SSL3_ST_SW_SRVR_HELLO_B: - s->internal->renegotiate = 2; - dtls1_start_timer(s); - ret = ssl3_send_server_hello(s); - if (ret <= 0) - goto end; - if (s->internal->hit) { - if (s->internal->tlsext_ticket_expected) - S3I(s)->hs.state = SSL3_ST_SW_SESSION_TICKET_A; - else - S3I(s)->hs.state = SSL3_ST_SW_CHANGE_A; - } else { - S3I(s)->hs.state = SSL3_ST_SW_CERT_A; - } - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_A: - case SSL3_ST_SW_CERT_B: - /* Check if it is anon DH or anon ECDH. */ - if (!(S3I(s)->hs.new_cipher->algorithm_auth & - SSL_aNULL)) { - dtls1_start_timer(s); - ret = ssl3_send_server_certificate(s); - if (ret <= 0) - goto end; - if (s->internal->tlsext_status_expected) - S3I(s)->hs.state = SSL3_ST_SW_CERT_STATUS_A; - else - S3I(s)->hs.state = SSL3_ST_SW_KEY_EXCH_A; - } else { - skip = 1; - S3I(s)->hs.state = SSL3_ST_SW_KEY_EXCH_A; - } - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_KEY_EXCH_A: - case SSL3_ST_SW_KEY_EXCH_B: - alg_k = S3I(s)->hs.new_cipher->algorithm_mkey; - - /* - * Only send if using a DH key exchange. - * - * For ECC ciphersuites, we send a ServerKeyExchange - * message only if the cipher suite is ECDHE. In other - * cases, the server certificate contains the server's - * public key for key exchange. - */ - if (alg_k & (SSL_kDHE|SSL_kECDHE)) { - dtls1_start_timer(s); - ret = ssl3_send_server_key_exchange(s); - if (ret <= 0) - goto end; - } else - skip = 1; - - S3I(s)->hs.state = SSL3_ST_SW_CERT_REQ_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_REQ_A: - case SSL3_ST_SW_CERT_REQ_B: - /* - * Determine whether or not we need to request a - * certificate. - * - * Do not request a certificate if: - * - * - We did not ask for it (SSL_VERIFY_PEER is unset). - * - * - SSL_VERIFY_CLIENT_ONCE is set and we are - * renegotiating. - * - * - We are using an anonymous ciphersuites - * (see section "Certificate request" in SSL 3 drafts - * and in RFC 2246) ... except when the application - * insists on verification (against the specs, but - * s3_clnt.c accepts this for SSL 3). - */ - if (!(s->verify_mode & SSL_VERIFY_PEER) || - ((s->session->peer != NULL) && - (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - ((S3I(s)->hs.new_cipher->algorithm_auth & - SSL_aNULL) && !(s->verify_mode & - SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) { - /* No cert request. */ - skip = 1; - S3I(s)->tmp.cert_request = 0; - S3I(s)->hs.state = SSL3_ST_SW_SRVR_DONE_A; - } else { - S3I(s)->tmp.cert_request = 1; - dtls1_start_timer(s); - ret = ssl3_send_certificate_request(s); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_SRVR_DONE_A; - s->internal->init_num = 0; - } - break; - - case SSL3_ST_SW_SRVR_DONE_A: - case SSL3_ST_SW_SRVR_DONE_B: - dtls1_start_timer(s); - ret = ssl3_send_server_done(s); - if (ret <= 0) - goto end; - S3I(s)->hs.next_state = SSL3_ST_SR_CERT_A; - S3I(s)->hs.state = SSL3_ST_SW_FLUSH; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_FLUSH: - /* - * This code originally checked to see if - * any data was pending using BIO_CTRL_INFO - * and then flushed. This caused problems - * as documented in PR#1939. The proposed - * fix doesn't completely resolve this issue - * as buggy implementations of BIO_CTRL_PENDING - * still exist. So instead we just flush - * unconditionally. - */ - s->internal->rwstate = SSL_WRITING; - if (BIO_flush(s->wbio) <= 0) { - /* If the write error was fatal, stop trying */ - if (!BIO_should_retry(s->wbio)) { - s->internal->rwstate = SSL_NOTHING; - S3I(s)->hs.state = S3I(s)->hs.next_state; - } - - ret = -1; - goto end; - } - s->internal->rwstate = SSL_NOTHING; - S3I(s)->hs.state = S3I(s)->hs.next_state; - break; - - case SSL3_ST_SR_CERT_A: - case SSL3_ST_SR_CERT_B: - if (S3I(s)->tmp.cert_request) { - ret = ssl3_get_client_certificate(s); - if (ret <= 0) - goto end; - } - s->internal->init_num = 0; - S3I(s)->hs.state = SSL3_ST_SR_KEY_EXCH_A; - break; - - case SSL3_ST_SR_KEY_EXCH_A: - case SSL3_ST_SR_KEY_EXCH_B: - ret = ssl3_get_client_key_exchange(s); - if (ret <= 0) - goto end; - - S3I(s)->hs.state = SSL3_ST_SR_CERT_VRFY_A; - s->internal->init_num = 0; - - if (ret == 2) { - /* - * For the ECDH ciphersuites when - * the client sends its ECDH pub key in - * a certificate, the CertificateVerify - * message is not sent. - * Also for GOST ciphersuites when - * the client uses its key from the certificate - * for key exchange. - */ - S3I(s)->hs.state = SSL3_ST_SR_FINISHED_A; - s->internal->init_num = 0; - } else if (SSL_USE_SIGALGS(s)) { - S3I(s)->hs.state = SSL3_ST_SR_CERT_VRFY_A; - s->internal->init_num = 0; - if (!s->session->peer) - break; - /* - * For sigalgs freeze the handshake buffer - * at this point and digest cached records. - */ - if (!S3I(s)->handshake_buffer) { - SSLerror(s, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; - if (!tls1_digest_cached_records(s)) { - ret = -1; - goto end; - } - } else { - S3I(s)->hs.state = SSL3_ST_SR_CERT_VRFY_A; - s->internal->init_num = 0; - - /* - * We need to get hashes here so if there is - * a client cert, it can be verified. - */ - if (S3I(s)->handshake_buffer) { - if (!tls1_digest_cached_records(s)) { - ret = -1; - goto end; - } - } - if (!tls1_handshake_hash_value(s, - S3I(s)->tmp.cert_verify_md, - sizeof(S3I(s)->tmp.cert_verify_md), - NULL)) { - ret = -1; - goto end; - } - } - break; - - case SSL3_ST_SR_CERT_VRFY_A: - case SSL3_ST_SR_CERT_VRFY_B: - D1I(s)->change_cipher_spec_ok = 1; - /* we should decide if we expected this one */ - ret = ssl3_get_cert_verify(s); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SR_FINISHED_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SR_FINISHED_A: - case SSL3_ST_SR_FINISHED_B: - D1I(s)->change_cipher_spec_ok = 1; - ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A, - SSL3_ST_SR_FINISHED_B); - if (ret <= 0) - goto end; - dtls1_stop_timer(s); - if (s->internal->hit) - S3I(s)->hs.state = SSL_ST_OK; - else if (s->internal->tlsext_ticket_expected) - S3I(s)->hs.state = SSL3_ST_SW_SESSION_TICKET_A; - else - S3I(s)->hs.state = SSL3_ST_SW_CHANGE_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_SESSION_TICKET_A: - case SSL3_ST_SW_SESSION_TICKET_B: - ret = ssl3_send_newsession_ticket(s); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_CHANGE_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_cert_status(s); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_KEY_EXCH_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CHANGE_A: - case SSL3_ST_SW_CHANGE_B: - s->session->cipher = S3I(s)->hs.new_cipher; - if (!tls1_setup_key_block(s)) { - ret = -1; - goto end; - } - - ret = ssl3_send_change_cipher_spec(s, - SSL3_ST_SW_CHANGE_A, SSL3_ST_SW_CHANGE_B); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_FINISHED_A; - s->internal->init_num = 0; - - if (!tls1_change_cipher_state(s, - SSL3_CHANGE_CIPHER_SERVER_WRITE)) { - ret = -1; - goto end; - } - - dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); - break; - - 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, - TLS_MD_SERVER_FINISH_CONST, - TLS_MD_SERVER_FINISH_CONST_SIZE); - if (ret <= 0) - goto end; - S3I(s)->hs.state = SSL3_ST_SW_FLUSH; - if (s->internal->hit) - S3I(s)->hs.next_state = SSL3_ST_SR_FINISHED_A; - else - S3I(s)->hs.next_state = SSL_ST_OK; - s->internal->init_num = 0; - break; - - case SSL_ST_OK: - /* clean a few things up */ - tls1_cleanup_key_block(s); - - /* remove buffering on output */ - ssl_free_wbio_buffer(s); - - s->internal->init_num = 0; - - /* Skipped if we just sent a HelloRequest. */ - if (s->internal->renegotiate == 2) { - s->internal->renegotiate = 0; - s->internal->new_session = 0; - - ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - - s->ctx->internal->stats.sess_accept_good++; - /* s->server=1; */ - s->internal->handshake_func = dtls1_accept; - - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - } - - ret = 1; - - /* done handshaking, next message is client hello */ - D1I(s)->handshake_read_seq = 0; - /* next message is server hello */ - D1I(s)->handshake_write_seq = 0; - D1I(s)->next_handshake_write_seq = 0; - goto end; - /* break; */ - - default: - SSLerror(s, SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - /* break; */ - } - - if (!S3I(s)->tmp.reuse_message && !skip) { - if (s->internal->debug) { - if ((ret = BIO_flush(s->wbio)) <= 0) - goto end; - } - - if ((cb != NULL) && (S3I(s)->hs.state != state)) { - new_state = S3I(s)->hs.state; - S3I(s)->hs.state = state; - cb(s, SSL_CB_ACCEPT_LOOP, 1); - S3I(s)->hs.state = new_state; - } - } - skip = 0; - } -end: - /* BIO_flush(s->wbio); */ - s->internal->in_handshake--; - if (cb != NULL) - cb(s, SSL_CB_ACCEPT_EXIT, ret); - - return (ret); -} - -int dtls1_send_hello_verify_request(SSL *s) { CBB cbb, verify, cookie; diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index 5e3872ba49d..044822c32c8 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.199 2017/10/12 15:44:18 jsing Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.200 2017/10/12 15:52:50 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1209,6 +1209,7 @@ int ssl3_check_cert_and_algorithm(SSL *s); int ssl3_check_finished(SSL *s); /* some server-only functions */ +int dtls1_send_hello_verify_request(SSL *s); int ssl3_get_client_hello(SSL *s); int ssl3_send_server_hello(SSL *s); int ssl3_send_hello_request(SSL *s); @@ -1224,7 +1225,6 @@ void tls1_free(SSL *s); void tls1_clear(SSL *s); int dtls1_new(SSL *s); -int dtls1_accept(SSL *s); void dtls1_free(SSL *s); void dtls1_clear(SSL *s); long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg); diff --git a/lib/libssl/ssl_srvr.c b/lib/libssl/ssl_srvr.c index 5e10fa01f45..5d741cdc811 100644 --- a/lib/libssl/ssl_srvr.c +++ b/lib/libssl/ssl_srvr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_srvr.c,v 1.25 2017/10/11 16:51:39 jsing Exp $ */ +/* $OpenBSD: ssl_srvr.c,v 1.26 2017/10/12 15:52:50 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -175,6 +175,7 @@ ssl3_accept(SSL *s) unsigned long alg_k; int ret = -1; int new_state, state, skip = 0; + int listen; ERR_clear_error(); errno = 0; @@ -184,11 +185,17 @@ ssl3_accept(SSL *s) else if (s->ctx->internal->info_callback != NULL) cb = s->ctx->internal->info_callback; + if (SSL_IS_DTLS(s)) + listen = D1I(s)->listen; + /* init things to blank */ s->internal->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); + if (SSL_IS_DTLS(s)) + D1I(s)->listen = listen; + if (s->cert == NULL) { SSLerror(s, SSL_R_NO_CERTIFICATE_SET); ret = -1; @@ -211,10 +218,18 @@ ssl3_accept(SSL *s) if (cb != NULL) cb(s, SSL_CB_HANDSHAKE_START, 1); - if ((s->version >> 8) != 3) { - SSLerror(s, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; + if (SSL_IS_DTLS(s)) { + if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) { + SSLerror(s, ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } + } else { + if ((s->version >> 8) != 3) { + SSLerror(s, ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } } s->internal->type = SSL_ST_ACCEPT; @@ -246,7 +261,7 @@ ssl3_accept(SSL *s) S3I(s)->hs.state = SSL3_ST_SR_CLNT_HELLO_A; s->ctx->internal->stats.sess_accept++; - } else if (!S3I(s)->send_connection_binding) { + } else if (!SSL_IS_DTLS(s) && !S3I(s)->send_connection_binding) { /* * Server attempting to renegotiate with * client that doesn't support secure @@ -270,10 +285,17 @@ ssl3_accept(SSL *s) case SSL3_ST_SW_HELLO_REQ_A: case SSL3_ST_SW_HELLO_REQ_B: s->internal->shutdown = 0; + if (SSL_IS_DTLS(s)) { + dtls1_clear_record_buffer(s); + dtls1_start_timer(s); + } ret = ssl3_send_hello_request(s); if (ret <= 0) goto end; - S3I(s)->hs.next_state = SSL3_ST_SW_HELLO_REQ_C; + if (SSL_IS_DTLS(s)) + S3I(s)->hs.next_state = SSL3_ST_SR_CLNT_HELLO_A; + else + S3I(s)->hs.next_state = SSL3_ST_SW_HELLO_REQ_C; S3I(s)->hs.state = SSL3_ST_SW_FLUSH; s->internal->init_num = 0; @@ -291,19 +313,77 @@ ssl3_accept(SSL *s) case SSL3_ST_SR_CLNT_HELLO_B: case SSL3_ST_SR_CLNT_HELLO_C: s->internal->shutdown = 0; - if (s->internal->rwstate != SSL_X509_LOOKUP) { + if (SSL_IS_DTLS(s)) { ret = ssl3_get_client_hello(s); if (ret <= 0) goto end; + dtls1_stop_timer(s); + + if (ret == 1 && + (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) + S3I(s)->hs.state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; + else + S3I(s)->hs.state = SSL3_ST_SW_SRVR_HELLO_A; + + s->internal->init_num = 0; + + /* + * Reflect ClientHello sequence to remain + * stateless while listening. + */ + if (listen) { + memcpy(S3I(s)->write_sequence, + S3I(s)->read_sequence, + sizeof(S3I(s)->write_sequence)); + } + + /* If we're just listening, stop here */ + if (listen && S3I(s)->hs.state == SSL3_ST_SW_SRVR_HELLO_A) { + ret = 2; + D1I(s)->listen = 0; + /* + * Set expected sequence numbers to + * continue the handshake. + */ + D1I(s)->handshake_read_seq = 2; + D1I(s)->handshake_write_seq = 1; + D1I(s)->next_handshake_write_seq = 1; + goto end; + } + } else { + if (s->internal->rwstate != SSL_X509_LOOKUP) { + ret = ssl3_get_client_hello(s); + if (ret <= 0) + goto end; + } + + s->internal->renegotiate = 2; + S3I(s)->hs.state = SSL3_ST_SW_SRVR_HELLO_A; + s->internal->init_num = 0; } + break; - s->internal->renegotiate = 2; - S3I(s)->hs.state = SSL3_ST_SW_SRVR_HELLO_A; - s->internal->init_num = 0; + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: + ret = dtls1_send_hello_verify_request(s); + if (ret <= 0) + goto end; + S3I(s)->hs.state = SSL3_ST_SW_FLUSH; + S3I(s)->hs.next_state = SSL3_ST_SR_CLNT_HELLO_A; + + /* HelloVerifyRequest resets Finished MAC. */ + if (!tls1_init_finished_mac(s)) { + ret = -1; + goto end; + } break; case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: + if (SSL_IS_DTLS(s)) { + s->internal->renegotiate = 2; + dtls1_start_timer(s); + } ret = ssl3_send_server_hello(s); if (ret <= 0) goto end; @@ -323,6 +403,8 @@ ssl3_accept(SSL *s) /* Check if it is anon DH or anon ECDH. */ if (!(S3I(s)->hs.new_cipher->algorithm_auth & SSL_aNULL)) { + if (SSL_IS_DTLS(s)) + dtls1_start_timer(s); ret = ssl3_send_server_certificate(s); if (ret <= 0) goto end; @@ -350,6 +432,8 @@ ssl3_accept(SSL *s) * public key for key exchange. */ if (alg_k & (SSL_kDHE|SSL_kECDHE)) { + if (SSL_IS_DTLS(s)) + dtls1_start_timer(s); ret = ssl3_send_server_key_exchange(s); if (ret <= 0) goto end; @@ -389,7 +473,7 @@ ssl3_accept(SSL *s) skip = 1; S3I(s)->tmp.cert_request = 0; S3I(s)->hs.state = SSL3_ST_SW_SRVR_DONE_A; - if (S3I(s)->handshake_buffer) { + if (!SSL_IS_DTLS(s) && S3I(s)->handshake_buffer) { if (!tls1_digest_cached_records(s)) { ret = -1; goto end; @@ -397,6 +481,8 @@ ssl3_accept(SSL *s) } } else { S3I(s)->tmp.cert_request = 1; + if (SSL_IS_DTLS(s)) + dtls1_start_timer(s); ret = ssl3_send_certificate_request(s); if (ret <= 0) goto end; @@ -407,6 +493,8 @@ ssl3_accept(SSL *s) case SSL3_ST_SW_SRVR_DONE_A: case SSL3_ST_SW_SRVR_DONE_B: + if (SSL_IS_DTLS(s)) + dtls1_start_timer(s); ret = ssl3_send_server_done(s); if (ret <= 0) goto end; @@ -428,6 +516,13 @@ ssl3_accept(SSL *s) */ s->internal->rwstate = SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { + if (SSL_IS_DTLS(s)) { + /* If the write error was fatal, stop trying. */ + if (!BIO_should_retry(s->wbio)) { + s->internal->rwstate = SSL_NOTHING; + S3I(s)->hs.state = S3I(s)->hs.next_state; + } + } ret = -1; goto end; } @@ -451,6 +546,12 @@ ssl3_accept(SSL *s) ret = ssl3_get_client_key_exchange(s); if (ret <= 0) goto end; + + if (SSL_IS_DTLS(s)) { + S3I(s)->hs.state = SSL3_ST_SR_CERT_VRFY_A; + s->internal->init_num = 0; + } + alg_k = S3I(s)->hs.new_cipher->algorithm_mkey; if (ret == 2) { /* @@ -509,7 +610,10 @@ ssl3_accept(SSL *s) case SSL3_ST_SR_CERT_VRFY_A: case SSL3_ST_SR_CERT_VRFY_B: - s->s3->flags |= SSL3_FLAGS_CCS_OK; + if (SSL_IS_DTLS(s)) + D1I(s)->change_cipher_spec_ok = 1; + else + s->s3->flags |= SSL3_FLAGS_CCS_OK; /* we should decide if we expected this one */ ret = ssl3_get_cert_verify(s); @@ -521,11 +625,16 @@ ssl3_accept(SSL *s) case SSL3_ST_SR_FINISHED_A: case SSL3_ST_SR_FINISHED_B: - s->s3->flags |= SSL3_FLAGS_CCS_OK; + if (SSL_IS_DTLS(s)) + D1I(s)->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); if (ret <= 0) goto end; + if (SSL_IS_DTLS(s)) + dtls1_stop_timer(s); if (s->internal->hit) S3I(s)->hs.state = SSL_ST_OK; else if (s->internal->tlsext_ticket_expected) @@ -574,6 +683,8 @@ ssl3_accept(SSL *s) goto end; } + if (SSL_IS_DTLS(s)) + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); break; case SSL3_ST_SW_FINISHED_A: @@ -596,8 +707,10 @@ ssl3_accept(SSL *s) /* clean a few things up */ tls1_cleanup_key_block(s); - BUF_MEM_free(s->internal->init_buf); - s->internal->init_buf = NULL; + if (!SSL_IS_DTLS(s)) { + BUF_MEM_free(s->internal->init_buf); + s->internal->init_buf = NULL; + } /* remove buffering on output */ ssl_free_wbio_buffer(s); @@ -620,6 +733,14 @@ ssl3_accept(SSL *s) } ret = 1; + + if (SSL_IS_DTLS(s)) { + /* Done handshaking, next message is client hello. */ + D1I(s)->handshake_read_seq = 0; + /* Next message is server hello. */ + D1I(s)->handshake_write_seq = 0; + D1I(s)->next_handshake_write_seq = 0; + } goto end; /* break; */ |