- {
- SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- d = dtls1_set_message_header(s, d,
- SSL3_MT_CERTIFICATE_VERIFY, n, 0, n) ;
-
- s->init_num=(int)n+DTLS1_HM_HEADER_LENGTH;
- s->init_off=0;
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
-
- s->state = SSL3_ST_CW_CERT_VRFY_B;
- }
-
- /* s->state = SSL3_ST_CW_CERT_VRFY_B */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
-err:
- return(-1);
- }
-
-int dtls1_send_client_certificate(SSL *s)
- {
- X509 *x509=NULL;
- EVP_PKEY *pkey=NULL;
- int i;
- unsigned long l;
-
- if (s->state == SSL3_ST_CW_CERT_A)
- {
- if ((s->cert == NULL) ||
- (s->cert->key->x509 == NULL) ||
- (s->cert->key->privatekey == NULL))
- s->state=SSL3_ST_CW_CERT_B;
- else
- s->state=SSL3_ST_CW_CERT_C;
- }
-
- /* We need to get a client cert */
- if (s->state == SSL3_ST_CW_CERT_B)
- {
- /* If we get an error, we need to
- * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
- * We then get retied later */
- i=0;
- if (s->ctx->client_cert_cb != NULL)
- i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
- if (i < 0)
- {
- s->rwstate=SSL_X509_LOOKUP;
- return(-1);
- }
- s->rwstate=SSL_NOTHING;
- if ((i == 1) && (pkey != NULL) && (x509 != NULL))
- {
- s->state=SSL3_ST_CW_CERT_B;
- if ( !SSL_use_certificate(s,x509) ||
- !SSL_use_PrivateKey(s,pkey))
- i=0;
- }
- else if (i == 1)
- {
- i=0;
- SSLerr(SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE,SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
- }
-
- if (x509 != NULL) X509_free(x509);
- if (pkey != NULL) EVP_PKEY_free(pkey);
- if (i == 0)
- {
- if (s->version == SSL3_VERSION)
- {
- s->s3->tmp.cert_req=0;
- ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_NO_CERTIFICATE);
- return(1);
- }
- else
- {
- s->s3->tmp.cert_req=2;
- }
- }
-
- /* Ok, we have a cert */
- s->state=SSL3_ST_CW_CERT_C;
- }
-
- if (s->state == SSL3_ST_CW_CERT_C)
- {
- 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->init_num=(int)l;
- s->init_off=0;
-
- /* set header called by dtls1_output_cert_chain() */
-
- /* buffer the message to handle re-xmits */
- dtls1_buffer_message(s, 0);
- }
- /* SSL3_ST_CW_CERT_D */
- return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
- }
+ s->state = SSL3_ST_CW_CHANGE_A;
+ s->init_num = 0;
+ break;
+
+ case SSL3_ST_CW_CHANGE_A:
+ case SSL3_ST_CW_CHANGE_B:
+ 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;
+
+ s->state = SSL3_ST_CW_FINISHED_A;
+ s->init_num = 0;
+
+ s->session->cipher = s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+ s->session->compress_meth = 0;
+#else
+ if (s->s3->tmp.new_compression == NULL)
+ s->session->compress_meth = 0;
+ else
+ s->session->compress_meth = s->s3->tmp.new_compression->id;
+#endif
+ if (!s->method->ssl3_enc->setup_key_block(s)) {
+ ret = -1;
+ goto end;
+ }
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+ {
+ ret = -1;
+ goto end;
+ }
+#ifndef OPENSSL_NO_SCTP
+ if (s->hit) {
+ /*
+ * 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
+
+ dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+ break;
+
+ case SSL3_ST_CW_FINISHED_A:
+ case SSL3_ST_CW_FINISHED_B:
+ if (!s->hit)
+ dtls1_start_timer(s);
+ ret = ssl3_send_finished(s,
+ SSL3_ST_CW_FINISHED_A,
+ SSL3_ST_CW_FINISHED_B,
+ s->method->
+ ssl3_enc->client_finished_label,
+ s->method->
+ ssl3_enc->client_finished_label_len);
+ if (ret <= 0)
+ goto end;
+ s->state = SSL3_ST_CW_FLUSH;
+
+ /* clear flags */
+ s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER;
+ 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_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
+
+#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;
+ dtls1_stop_timer(s);
+
+ if (s->hit)
+ 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:
+ s->rwstate = SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0) {
+ /*
+ * 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;
+
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+
+#if 0
+ if (s->init_buf != NULL) {
+ BUF_MEM_free(s->init_buf);
+ s->init_buf = NULL;
+ }
+#endif
+
+ /*
+ * If we are not 'joining' the last two packets, remove the
+ * buffering now
+ */
+ if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
+ ssl_free_wbio_buffer(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);
+ if (s->hit)
+ s->ctx->stats.sess_hit++;
+
+ ret = 1;
+ /* s->server=0; */
+ s->handshake_func = dtls1_connect;
+ s->ctx->stats.sess_connect_good++;
+
+ if (cb != NULL)
+ cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+
+ /* done with handshaking */
+ s->d1->handshake_read_seq = 0;
+ s->d1->next_handshake_write_seq = 0;
+ goto end;
+ /* break; */
+
+ default:
+ SSLerr(SSL_F_DTLS1_CONNECT, SSL_R_UNKNOWN_STATE);
+ ret = -1;
+ goto end;
+ /* break; */
+ }
+
+ /* did we do anything */
+ if (!s->s3->tmp.reuse_message && !skip) {
+ if (s->debug) {
+ if ((ret = BIO_flush(s->wbio)) <= 0)
+ goto end;
+ }
+
+ if ((cb != NULL) && (s->state != state)) {
+ new_state = s->state;
+ s->state = state;
+ cb(s, SSL_CB_CONNECT_LOOP, 1);
+ s->state = new_state;
+ }
+ }
+ skip = 0;
+ }
+ 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)
+ cb(s, SSL_CB_CONNECT_EXIT, ret);
+ return (ret);
+}
+
+static int dtls1_get_hello_verify(SSL *s)
+{
+ int n, al, ok = 0;
+ unsigned char *data;
+ unsigned int cookie_len;
+
+ s->first_packet = 1;
+ n = s->method->ssl_get_message(s,
+ DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A,
+ DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B,
+ -1, s->max_cert_list, &ok);
+ s->first_packet = 0;
+
+ if (!ok)
+ return ((int)n);
+
+ if (s->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+ s->d1->send_cookie = 0;
+ s->s3->tmp.reuse_message = 1;
+ return (1);
+ }
+
+ data = (unsigned char *)s->init_msg;
+#if 0
+ if (s->method->version != DTLS_ANY_VERSION &&
+ ((data[0] != (s->version >> 8)) || (data[1] != (s->version & 0xff))))
+ {
+ SSLerr(SSL_F_DTLS1_GET_HELLO_VERIFY, SSL_R_WRONG_SSL_VERSION);
+ s->version = (s->version & 0xff00) | data[1];
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+#endif
+ data += 2;
+
+ cookie_len = *(data++);
+ if (cookie_len > sizeof(s->d1->cookie)) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ goto f_err;
+ }
+
+ memcpy(s->d1->cookie, data, cookie_len);
+ s->d1->cookie_len = cookie_len;