X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=ssl%2Fd1_clnt.c;h=4af8ffda4d57f75a2e7e1ccfec5aea2a8e534d4c;hb=e83aefb3a0c645c77849f889bc166935b2cc935c;hp=2364ad2f8d148a23c6957df2c8b1e28dbea5fa84;hpb=6cf41fec7234dd19eebece79dddc87129fccb29d;p=openssl.git diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index 2364ad2f8d..4af8ffda4d 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -148,10 +148,13 @@ int dtls1_connect(SSL *s) { BUF_MEM *buf=NULL; unsigned long Time=(unsigned long)time(NULL); - long num1; void (*cb)(const SSL *ssl,int type,int val)=NULL; int ret= -1; - int new_state,state,skip=0;; + int new_state,state,skip=0; +#ifndef OPENSSL_NO_SCTP + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; +#endif RAND_add(&Time,sizeof(Time),0); ERR_clear_error(); @@ -165,6 +168,27 @@ int dtls1_connect(SSL *s) s->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); +#ifndef OPENSSL_NO_SCTP + /* Notify SCTP BIO socket to enter handshake + * mode and prevent stream identifier other + * than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL); +#endif + +#ifndef OPENSSL_NO_HEARTBEATS + /* If we're awaiting a HeartbeatResponse, pretend we + * already got and don't await it anymore, because + * Heartbeats don't make sense during handshakes anyway. + */ + if (s->tlsext_hb_pending) + { + dtls1_stop_timer(s); + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + for (;;) { state=s->state; @@ -172,7 +196,7 @@ int dtls1_connect(SSL *s) switch(s->state) { case SSL_ST_RENEGOTIATE: - s->new_session=1; + s->renegotiate=1; s->state=SSL_ST_CONNECT; s->ctx->stats.sess_connect_renegotiate++; /* break */ @@ -223,7 +247,45 @@ int dtls1_connect(SSL *s) s->init_num=0; /* mark client_random uninitialized */ memset(s->s3->client_random,0,sizeof(s->s3->client_random)); + s->d1->send_cookie = 0; + s->hit = 0; + break; + +#ifndef OPENSSL_NO_SCTP + case DTLS1_SCTP_ST_CR_READ_SOCK: + + if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) + { + s->s3->in_read_app_data=2; + s->rwstate=SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + + s->state=s->s3->tmp.next_state; + break; + + case DTLS1_SCTP_ST_CW_WRITE_SOCK: + /* read app data until dry event */ + + ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); + if (ret < 0) goto end; + + if (ret == 0) + { + s->s3->in_read_app_data=2; + s->rwstate=SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + + s->state=s->d1->next_state; break; +#endif case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: @@ -247,9 +309,17 @@ int dtls1_connect(SSL *s) s->init_num=0; - /* turn on buffering for the next lot of output */ - if (s->bbio != s->wbio) - s->wbio=BIO_push(s->bbio,s->wbio); +#ifndef OPENSSL_NO_SCTP + /* Disable buffering for SCTP */ + if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) + { +#endif + /* turn on buffering for the next lot of output */ + if (s->bbio != s->wbio) + s->wbio=BIO_push(s->bbio,s->wbio); +#ifndef OPENSSL_NO_SCTP + } +#endif break; @@ -259,9 +329,25 @@ int dtls1_connect(SSL *s) if (ret <= 0) goto end; else { - dtls1_stop_timer(s); if (s->hit) + { +#ifndef OPENSSL_NO_SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + s->state=SSL3_ST_CR_FINISHED_A; + } else s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; } @@ -284,16 +370,44 @@ int dtls1_connect(SSL *s) case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: +#ifndef OPENSSL_NO_TLSEXT + ret=ssl3_check_finished(s); + if (ret <= 0) goto end; + if (ret == 2) + { + s->hit = 1; + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_CR_SESSION_TICKET_A; + else + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + } +#endif /* Check if it is anon DH or PSK */ if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state=SSL3_ST_CR_CERT_STATUS_A; + else + s->state=SSL3_ST_CR_KEY_EXCH_A; + } + else + { + skip = 1; + s->state=SSL3_ST_CR_KEY_EXCH_A; + } +#else } else skip=1; + s->state=SSL3_ST_CR_KEY_EXCH_A; +#endif s->init_num=0; break; @@ -325,12 +439,20 @@ int dtls1_connect(SSL *s) case SSL3_ST_CR_SRVR_DONE_B: ret=ssl3_get_server_done(s); if (ret <= 0) goto end; + dtls1_stop_timer(s); if (s->s3->tmp.cert_req) - s->state=SSL3_ST_CW_CERT_A; + s->s3->tmp.next_state=SSL3_ST_CW_CERT_A; else - s->state=SSL3_ST_CW_KEY_EXCH_A; + s->s3->tmp.next_state=SSL3_ST_CW_KEY_EXCH_A; s->init_num=0; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + state == SSL_ST_RENEGOTIATE) + s->state=DTLS1_SCTP_ST_CR_READ_SOCK; + else +#endif + s->state=s->s3->tmp.next_state; break; case SSL3_ST_CW_CERT_A: @@ -349,6 +471,22 @@ int dtls1_connect(SSL *s) dtls1_start_timer(s); ret=dtls1_send_client_key_exchange(s); if (ret <= 0) goto end; + +#ifndef OPENSSL_NO_SCTP + /* Add new shared key for SCTP-Auth, + * will be ignored if no SCTP used. + */ + snprintf((char*) labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + /* EAY EAY EAY need to check for DH fix cert * sent back */ /* For TLS, cert_req is set to 2, so a cert chain @@ -359,7 +497,15 @@ int dtls1_connect(SSL *s) } else { - s->state=SSL3_ST_CW_CHANGE_A; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) + { + s->d1->next_state=SSL3_ST_CW_CHANGE_A; + s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } + else +#endif + s->state=SSL3_ST_CW_CHANGE_A; s->s3->change_cipher_spec=0; } @@ -371,17 +517,34 @@ int dtls1_connect(SSL *s) dtls1_start_timer(s); ret=dtls1_send_client_verify(s); if (ret <= 0) goto end; - s->state=SSL3_ST_CW_CHANGE_A; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) + { + s->d1->next_state=SSL3_ST_CW_CHANGE_A; + s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } + else +#endif + s->state=SSL3_ST_CW_CHANGE_A; s->init_num=0; s->s3->change_cipher_spec=0; break; case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: - dtls1_start_timer(s); + if (!s->hit) + dtls1_start_timer(s); ret=dtls1_send_change_cipher_spec(s, SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); if (ret <= 0) goto end; + +#ifndef OPENSSL_NO_SCTP + /* Change to new shared key of SCTP-Auth, + * will be ignored if no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, 0, NULL); +#endif + s->state=SSL3_ST_CW_FINISHED_A; s->init_num=0; @@ -413,7 +576,8 @@ int dtls1_connect(SSL *s) case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: - dtls1_start_timer(s); + if (!s->hit) + dtls1_start_timer(s); ret=dtls1_send_finished(s, SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B, s->method->ssl3_enc->client_finished_label, @@ -426,23 +590,62 @@ int dtls1_connect(SSL *s) if (s->hit) { s->s3->tmp.next_state=SSL_ST_OK; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) + { + s->d1->next_state = s->s3->tmp.next_state; + s->s3->tmp.next_state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { s->state=SSL_ST_OK; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) + { + s->d1->next_state = SSL_ST_OK; + s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif s->s3->flags|=SSL3_FLAGS_POP_BUFFER; s->s3->delay_buf_pop_ret=0; } } else { +#ifndef OPENSSL_NO_TLSEXT + /* Allow NewSessionTicket if ticket expected */ + if (s->tlsext_ticket_expected) + s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A; + else +#endif + s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; } s->init_num=0; break; +#ifndef OPENSSL_NO_TLSEXT + case SSL3_ST_CR_SESSION_TICKET_A: + case SSL3_ST_CR_SESSION_TICKET_B: + ret=ssl3_get_new_session_ticket(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + + case SSL3_ST_CR_CERT_STATUS_A: + case SSL3_ST_CR_CERT_STATUS_B: + ret=ssl3_get_cert_status(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_KEY_EXCH_A; + s->init_num=0; + break; +#endif + case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: - + s->d1->change_cipher_spec_ok = 1; ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A, SSL3_ST_CR_FINISHED_B); if (ret <= 0) goto end; @@ -452,20 +655,34 @@ int dtls1_connect(SSL *s) s->state=SSL3_ST_CW_CHANGE_A; else s->state=SSL_ST_OK; + +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + state == SSL_ST_RENEGOTIATE) + { + s->d1->next_state=s->state; + s->state=DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif + s->init_num=0; break; case SSL3_ST_CW_FLUSH: - /* number of bytes to be flushed */ - num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); - if (num1 > 0) + s->rwstate=SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { - s->rwstate=SSL_WRITING; - num1=BIO_flush(s->wbio); - if (num1 <= 0) { ret= -1; goto end; } - s->rwstate=SSL_NOTHING; + /* If the write error was fatal, stop trying */ + if (!BIO_should_retry(s->wbio)) + { + s->rwstate=SSL_NOTHING; + s->state=s->s3->tmp.next_state; + } + + ret= -1; + goto end; } - + s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; @@ -488,6 +705,7 @@ int dtls1_connect(SSL *s) /* else do it later in ssl3_write */ s->init_num=0; + s->renegotiate=0; s->new_session=0; ssl_update_cache(s,SSL_SESS_CACHE_CLIENT); @@ -534,6 +752,15 @@ int dtls1_connect(SSL *s) } end: s->in_handshake--; + +#ifndef OPENSSL_NO_SCTP + /* Notify SCTP BIO socket to leave handshake + * mode and allow stream identifier other + * than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL); +#endif + if (buf != NULL) BUF_MEM_free(buf); if (cb != NULL) @@ -552,8 +779,14 @@ int dtls1_client_hello(SSL *s) buf=(unsigned char *)s->init_buf->data; if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { + SSL_SESSION *sess = s->session; if ((s->session == NULL) || (s->session->ssl_version != s->version) || +#ifdef OPENSSL_NO_TLSEXT + !sess->session_id_length || +#else + (!sess->session_id_length && !sess->tlsext_tick) || +#endif (s->session->not_resumable)) { if (!ssl_get_new_session(s,0)) @@ -633,7 +866,15 @@ int dtls1_client_hello(SSL *s) *(p++)=comp->id; } *(p++)=0; /* Add the NULL method */ - + +#ifndef OPENSSL_NO_TLSEXT + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } +#endif + l=(p-d); d=buf; @@ -1353,7 +1594,7 @@ int dtls1_send_client_verify(SSL *s) SHA_DIGEST_LENGTH,&(p[2]), (unsigned int *)&j,pkey->pkey.ec)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY, ERR_R_ECDSA_LIB); goto err; } @@ -1453,7 +1694,7 @@ int dtls1_send_client_certificate(SSL *s) { s->state=SSL3_ST_CW_CERT_D; l=dtls1_output_cert_chain(s, - (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509); + (s->s3->tmp.cert_req == 2)?NULL:s->cert->key); s->init_num=(int)l; s->init_off=0;