void GSR(const int n, double **A) { int i, j, k; /* counters */ double dot; for(k=0; k<n; k++) { /* orthogonalisation */ for(j=(k+1); j<n; j++) { dot=0.0; /* dot product <Aj, Ak> */ for(i=0; i<n; i++) dot+=A[i][j]*A[i][k]; for(i=0; i<n; i++) A[i][j]-=A[i][k]/dot; } /* for j */ } /* for k */ for(k=0; k<n; k++) { /* normalisation */ dot=0.0; /* Compute (L2 norm) */ for(i=0; i<n; i++) dot+=A[i][k]*A[i][k]; dot=sqrt(dot); if (dot==0.0) SSLerror("Norm = 0 in routine GSR"); for(i=0; i<n; i++) A[i][k]/=dot; } /* for k */ } /* GSR */
int SSL_use_certificate(SSL *ssl, X509 *x) { if (x == NULL) { SSLerror(ssl, ERR_R_PASSED_NULL_PARAMETER); return (0); } return (ssl_set_cert(ssl->cert, x)); }
SSL_Complex *SSL_ComplexVectorAlloc(const int n) { SSL_Complex *temp; temp=(SSL_Complex *)calloc(n, sizeof(SSL_Complex)); if (temp==NULL) SSLerror("No memory available in routine SSL_ComplexVectorAlloc"); return temp; } /* SSL_ComplexVectorAlloc */
double *VectorAlloc(const int n) { double *temp; temp=(double *)calloc(n, sizeof(double)); if (temp==NULL) SSLerror("No memory available in routine VectorAlloc"); return temp; } /* VectorAlloc */
int *IntVectorAlloc(const int n) { int *temp; temp=(int *)calloc(n, sizeof(int)); if (temp==NULL) SSLerror("No memory available in routine IntVectorAlloc"); return temp; } /* IntVectorAlloc */
int dtls1_get_hello_verify(SSL *s) { long n; int al, ok = 0; size_t cookie_len; uint16_t ssl_version; CBS hello_verify_request, cookie; n = s->method->internal->ssl_get_message(s, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, -1, s->internal->max_cert_list, &ok); if (!ok) return ((int)n); if (S3I(s)->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) { D1I(s)->send_cookie = 0; S3I(s)->tmp.reuse_message = 1; return (1); } if (n < 0) goto truncated; CBS_init(&hello_verify_request, s->internal->init_msg, n); if (!CBS_get_u16(&hello_verify_request, &ssl_version)) goto truncated; if (ssl_version != s->version) { SSLerror(s, SSL_R_WRONG_SSL_VERSION); s->version = (s->version & 0xff00) | (ssl_version & 0xff); al = SSL_AD_PROTOCOL_VERSION; goto f_err; } if (!CBS_get_u8_length_prefixed(&hello_verify_request, &cookie)) goto truncated; if (!CBS_write_bytes(&cookie, D1I(s)->cookie, sizeof(D1I(s)->cookie), &cookie_len)) { D1I(s)->cookie_len = 0; al = SSL_AD_ILLEGAL_PARAMETER; goto f_err; } D1I(s)->cookie_len = cookie_len; D1I(s)->send_cookie = 1; return 1; truncated: al = SSL_AD_DECODE_ERROR; f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); return -1; }
int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { int j; BIO *in; int ret = 0; X509 *x = NULL; in = BIO_new(BIO_s_file_internal()); if (in == NULL) { SSLerror(ssl, ERR_R_BUF_LIB); goto end; } if (BIO_read_filename(in, file) <= 0) { SSLerror(ssl, ERR_R_SYS_LIB); goto end; } if (type == SSL_FILETYPE_ASN1) { j = ERR_R_ASN1_LIB; x = d2i_X509_bio(in, NULL); } else if (type == SSL_FILETYPE_PEM) { j = ERR_R_PEM_LIB; x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback, ssl->ctx->default_passwd_callback_userdata); } else { SSLerror(ssl, SSL_R_BAD_SSL_FILETYPE); goto end; } if (x == NULL) { SSLerror(ssl, j); goto end; } ret = SSL_use_certificate(ssl, x); end: X509_free(x); BIO_free(in); return (ret); }
int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { int ret; if (pkey == NULL) { SSLerror(ssl, ERR_R_PASSED_NULL_PARAMETER); return (0); } ret = ssl_set_pkey(ssl->cert, pkey); return (ret); }
int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) { int j, ret = 0; BIO *in; EVP_PKEY *pkey = NULL; in = BIO_new(BIO_s_file_internal()); if (in == NULL) { SSLerror(ssl, ERR_R_BUF_LIB); goto end; } if (BIO_read_filename(in, file) <= 0) { SSLerror(ssl, ERR_R_SYS_LIB); goto end; } if (type == SSL_FILETYPE_PEM) { j = ERR_R_PEM_LIB; pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback, ssl->ctx->default_passwd_callback_userdata); } else if (type == SSL_FILETYPE_ASN1) { j = ERR_R_ASN1_LIB; pkey = d2i_PrivateKey_bio(in, NULL); } else { SSLerror(ssl, SSL_R_BAD_SSL_FILETYPE); goto end; } if (pkey == NULL) { SSLerror(ssl, j); goto end; } ret = SSL_use_PrivateKey(ssl, pkey); EVP_PKEY_free(pkey); end: BIO_free(in); return (ret); }
int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { EVP_PKEY *pkey; int ret; if (rsa == NULL) { SSLerror(ssl, ERR_R_PASSED_NULL_PARAMETER); return (0); } if ((pkey = EVP_PKEY_new()) == NULL) { SSLerror(ssl, ERR_R_EVP_LIB); return (0); } RSA_up_ref(rsa); EVP_PKEY_assign_RSA(pkey, rsa); ret = ssl_set_pkey(ssl->cert, pkey); EVP_PKEY_free(pkey); return (ret); }
int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d, long len) { int ret; RSA *rsa; if ((rsa = d2i_RSAPrivateKey(NULL, &d, (long)len)) == NULL) { SSLerror(ssl, ERR_R_ASN1_LIB); return (0); } ret = SSL_use_RSAPrivateKey(ssl, rsa); RSA_free(rsa); return (ret); }
int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len) { int ret; EVP_PKEY *pkey; if ((pkey = d2i_PrivateKey(type, NULL, &d, (long)len)) == NULL) { SSLerror(ssl, ERR_R_ASN1_LIB); return (0); } ret = SSL_use_PrivateKey(ssl, pkey); EVP_PKEY_free(pkey); return (ret); }
int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len) { X509 *x; int ret; x = d2i_X509(NULL, &d, (long)len); if (x == NULL) { SSLerror(ssl, ERR_R_ASN1_LIB); return (0); } ret = SSL_use_certificate(ssl, x); X509_free(x); return (ret); }
int SSL_set_session(SSL *s, SSL_SESSION *session) { int ret = 0; const SSL_METHOD *meth; if (session != NULL) { meth = s->ctx->method->internal->get_ssl_method(session->ssl_version); if (meth == NULL) meth = s->method->internal->get_ssl_method(session->ssl_version); if (meth == NULL) { SSLerror(s, SSL_R_UNABLE_TO_FIND_SSL_METHOD); return (0); } if (meth != s->method) { if (!SSL_set_ssl_method(s, meth)) return (0); } /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/ CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION); if (s->session != NULL) SSL_SESSION_free(s->session); s->session = session; s->verify_result = s->session->verify_result; /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/ ret = 1; } else { if (s->session != NULL) { SSL_SESSION_free(s->session); s->session = NULL; } meth = s->ctx->method; if (meth != s->method) { if (!SSL_set_ssl_method(s, meth)) return (0); } ret = 1; } return (ret); }
int dtls1_check_timeout_num(SSL *s) { D1I(s)->timeout.num_alerts++; /* Reduce MTU after 2 unsuccessful retransmissions */ if (D1I(s)->timeout.num_alerts > 2) { D1I(s)->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL); } if (D1I(s)->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) { /* fail the connection, enough alerts have been sent */ SSLerror(SSL_R_READ_TIMEOUT_EXPIRED); return -1; } return 0; }
int ssl_get_new_session(SSL *s, int session) { unsigned int tmp; SSL_SESSION *ss = NULL; GEN_SESSION_CB cb = def_generate_session_id; /* This gets used by clients and servers. */ if ((ss = SSL_SESSION_new()) == NULL) return (0); /* If the context has a default timeout, use it */ if (s->session_ctx->session_timeout == 0) ss->timeout = SSL_get_default_timeout(s); else ss->timeout = s->session_ctx->session_timeout; if (s->session != NULL) { SSL_SESSION_free(s->session); s->session = NULL; } if (session) { switch (s->version) { case TLS1_VERSION: case TLS1_1_VERSION: case TLS1_2_VERSION: case DTLS1_VERSION: ss->ssl_version = s->version; ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; break; default: SSLerror(s, SSL_R_UNSUPPORTED_SSL_VERSION); SSL_SESSION_free(ss); return (0); } /* If RFC4507 ticket use empty session ID. */ if (s->internal->tlsext_ticket_expected) { ss->session_id_length = 0; goto sess_id_done; } /* Choose which callback will set the session ID. */ CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); if (s->internal->generate_session_id) cb = s->internal->generate_session_id; else if (s->session_ctx->internal->generate_session_id) cb = s->session_ctx->internal->generate_session_id; CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); /* Choose a session ID. */ tmp = ss->session_id_length; if (!cb(s, ss->session_id, &tmp)) { /* The callback failed */ SSLerror(s, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); SSL_SESSION_free(ss); return (0); } /* * Don't allow the callback to set the session length to zero. * nor set it higher than it was. */ if (!tmp || (tmp > ss->session_id_length)) { /* The callback set an illegal length */ SSLerror(s, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); SSL_SESSION_free(ss); return (0); } ss->session_id_length = tmp; /* Finally, check for a conflict. */ if (SSL_has_matching_session_id(s, ss->session_id, ss->session_id_length)) { SSLerror(s, SSL_R_SSL_SESSION_ID_CONFLICT); SSL_SESSION_free(ss); return (0); } sess_id_done: if (s->tlsext_hostname) { ss->tlsext_hostname = strdup(s->tlsext_hostname); if (ss->tlsext_hostname == NULL) { SSLerror(s, ERR_R_INTERNAL_ERROR); SSL_SESSION_free(ss); return 0; } } } else { ss->session_id_length = 0; } if (s->sid_ctx_length > sizeof ss->sid_ctx) { SSLerror(s, ERR_R_INTERNAL_ERROR); SSL_SESSION_free(ss); return 0; } memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length); ss->sid_ctx_length = s->sid_ctx_length; s->session = ss; ss->ssl_version = s->version; ss->verify_result = X509_V_OK; return (1); }
/* * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this * connection. It is only called by servers. * * session_id: points at the session ID in the ClientHello. This code will * read past the end of this in order to parse out the session ticket * extension, if any. * len: the length of the session ID. * limit: a pointer to the first byte after the ClientHello. * * Returns: * -1: error * 0: a session may have been found. * * Side effects: * - If a session is found then s->session is pointed at it (after freeing * an existing session if need be) and s->verify_result is set from the * session. * - Both for new and resumed sessions, s->internal->tlsext_ticket_expected is set * to 1 if the server should issue a new session ticket (to 0 otherwise). */ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, const unsigned char *limit) { SSL_SESSION *ret = NULL; int fatal = 0; int try_session_cache = 1; int r; /* This is used only by servers. */ if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) goto err; if (len == 0) try_session_cache = 0; /* Sets s->internal->tlsext_ticket_expected. */ r = tls1_process_ticket(s, session_id, len, limit, &ret); switch (r) { case -1: /* Error during processing */ fatal = 1; goto err; case 0: /* No ticket found */ case 1: /* Zero length ticket found */ break; /* Ok to carry on processing session id. */ case 2: /* Ticket found but not decrypted. */ case 3: /* Ticket decrypted, *ret has been set. */ try_session_cache = 0; break; default: abort(); } if (try_session_cache && ret == NULL && !(s->session_ctx->internal->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; data.ssl_version = s->version; data.session_id_length = len; memcpy(data.session_id, session_id, len); CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); ret = lh_SSL_SESSION_retrieve(s->session_ctx->internal->sessions, &data); if (ret != NULL) { /* Don't allow other threads to steal it. */ CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); } CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); if (ret == NULL) s->session_ctx->internal->stats.sess_miss++; } if (try_session_cache && ret == NULL && s->session_ctx->internal->get_session_cb != NULL) { int copy = 1; if ((ret = s->session_ctx->internal->get_session_cb(s, session_id, len, ©))) { s->session_ctx->internal->stats.sess_cb_hit++; /* * Increment reference count now if the session * callback asks us to do so (note that if the session * structures returned by the callback are shared * between threads, it must handle the reference count * itself [i.e. copy == 0], or things won't be * thread-safe). */ if (copy) CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); /* * Add the externally cached session to the internal * cache as well if and only if we are supposed to. */ if (!(s->session_ctx->internal->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE)) /* * The following should not return 1, * otherwise, things are very strange. */ SSL_CTX_add_session(s->session_ctx, ret); } } if (ret == NULL) goto err; /* Now ret is non-NULL and we own one of its reference counts. */ if (ret->sid_ctx_length != s->sid_ctx_length || timingsafe_memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length) != 0) { /* We have the session requested by the client, but we don't * want to use it in this context. */ goto err; /* treat like cache miss */ } if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) { /* * We can't be sure if this session is being used out of * context, which is especially important for SSL_VERIFY_PEER. * The application should have used * SSL[_CTX]_set_session_id_context. * * For this error case, we generate an error instead of treating * the event like a cache miss (otherwise it would be easy for * applications to effectively disable the session cache by * accident without anyone noticing). */ SSLerror(s, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); fatal = 1; goto err; } if (ret->cipher == NULL) { ret->cipher = ssl3_get_cipher_by_id(ret->cipher_id); if (ret->cipher == NULL) goto err; } if (ret->timeout < (time(NULL) - ret->time)) { /* timeout */ s->session_ctx->internal->stats.sess_timeout++; if (try_session_cache) { /* session was from the cache, so remove it */ SSL_CTX_remove_session(s->session_ctx, ret); } goto err; } s->session_ctx->internal->stats.sess_hit++; if (s->session != NULL) SSL_SESSION_free(s->session); s->session = ret; s->verify_result = s->session->verify_result; return 1; err: if (ret != NULL) { SSL_SESSION_free(ret); if (!try_session_cache) { /* * The session was from a ticket, so we should * issue a ticket for the new session. */ s->internal->tlsext_ticket_expected = 1; } } if (fatal) return -1; else return 0; }
int dtls1_connect(SSL *s) { void (*cb)(const SSL *ssl, int type, int val) = NULL; int ret = -1; int new_state, state, skip = 0; 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; s->internal->in_handshake++; if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); 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_CONNECT; s->ctx->internal->stats.sess_connect_renegotiate++; /* break */ case SSL_ST_BEFORE: case SSL_ST_CONNECT: case SSL_ST_BEFORE|SSL_ST_CONNECT: case SSL_ST_OK|SSL_ST_CONNECT: s->server = 0; 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->version=SSL3_VERSION; */ s->internal->type = SSL_ST_CONNECT; if (!ssl3_setup_init_buffer(s)) { ret = -1; goto end; } if (!ssl3_setup_buffers(s)) { ret = -1; goto end; } if (!ssl_init_wbio_buffer(s, 0)) { ret = -1; goto end; } /* don't push the buffering BIO quite yet */ S3I(s)->hs.state = SSL3_ST_CW_CLNT_HELLO_A; s->ctx->internal->stats.sess_connect++; s->internal->init_num = 0; /* mark client_random uninitialized */ memset(s->s3->client_random, 0, sizeof(s->s3->client_random)); D1I(s)->send_cookie = 0; s->internal->hit = 0; break; case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: s->internal->shutdown = 0; /* every DTLS ClientHello resets Finished MAC */ if (!tls1_init_finished_mac(s)) { ret = -1; goto end; } dtls1_start_timer(s); ret = ssl3_client_hello(s); if (ret <= 0) goto end; if (D1I(s)->send_cookie) { S3I(s)->hs.state = SSL3_ST_CW_FLUSH; S3I(s)->hs.next_state = SSL3_ST_CR_SRVR_HELLO_A; } else S3I(s)->hs.state = SSL3_ST_CR_SRVR_HELLO_A; s->internal->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); break; case SSL3_ST_CR_SRVR_HELLO_A: case SSL3_ST_CR_SRVR_HELLO_B: ret = ssl3_get_server_hello(s); if (ret <= 0) goto end; else { if (s->internal->hit) { S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A; } else S3I(s)->hs.state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; } s->internal->init_num = 0; break; case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: ret = dtls1_get_hello_verify(s); if (ret <= 0) goto end; dtls1_stop_timer(s); if ( D1I(s)->send_cookie) /* start again, with a cookie */ S3I(s)->hs.state = SSL3_ST_CW_CLNT_HELLO_A; else S3I(s)->hs.state = SSL3_ST_CR_CERT_A; s->internal->init_num = 0; break; case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: ret = ssl3_check_finished(s); if (ret <= 0) goto end; if (ret == 2) { s->internal->hit = 1; if (s->internal->tlsext_ticket_expected) S3I(s)->hs.state = SSL3_ST_CR_SESSION_TICKET_A; else S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A; s->internal->init_num = 0; break; } /* Check if it is anon DH. */ if (!(S3I(s)->hs.new_cipher->algorithm_auth & SSL_aNULL)) { ret = ssl3_get_server_certificate(s); if (ret <= 0) goto end; if (s->internal->tlsext_status_expected) S3I(s)->hs.state = SSL3_ST_CR_CERT_STATUS_A; else S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A; } else { skip = 1; S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A; } s->internal->init_num = 0; break; case SSL3_ST_CR_KEY_EXCH_A: case SSL3_ST_CR_KEY_EXCH_B: ret = ssl3_get_server_key_exchange(s); if (ret <= 0) goto end; S3I(s)->hs.state = SSL3_ST_CR_CERT_REQ_A; s->internal->init_num = 0; /* at this point we check that we have the * required stuff from the server */ if (!ssl3_check_cert_and_algorithm(s)) { ret = -1; goto end; } break; case SSL3_ST_CR_CERT_REQ_A: case SSL3_ST_CR_CERT_REQ_B: ret = ssl3_get_certificate_request(s); if (ret <= 0) goto end; S3I(s)->hs.state = SSL3_ST_CR_SRVR_DONE_A; s->internal->init_num = 0; break; case SSL3_ST_CR_SRVR_DONE_A: case SSL3_ST_CR_SRVR_DONE_B: ret = ssl3_get_server_done(s); if (ret <= 0) goto end; dtls1_stop_timer(s); if (S3I(s)->tmp.cert_req) S3I(s)->hs.next_state = SSL3_ST_CW_CERT_A; else S3I(s)->hs.next_state = SSL3_ST_CW_KEY_EXCH_A; s->internal->init_num = 0; S3I(s)->hs.state = S3I(s)->hs.next_state; break; case SSL3_ST_CW_CERT_A: case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: case SSL3_ST_CW_CERT_D: dtls1_start_timer(s); ret = ssl3_send_client_certificate(s); if (ret <= 0) goto end; S3I(s)->hs.state = SSL3_ST_CW_KEY_EXCH_A; s->internal->init_num = 0; break; case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: dtls1_start_timer(s); ret = ssl3_send_client_key_exchange(s); if (ret <= 0) goto end; /* EAY EAY EAY need to check for DH fix cert * sent back */ /* For TLS, cert_req is set to 2, so a cert chain * of nothing is sent, but no verify packet is sent */ if (S3I(s)->tmp.cert_req == 1) { S3I(s)->hs.state = SSL3_ST_CW_CERT_VRFY_A; } else { S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A; S3I(s)->change_cipher_spec = 0; } s->internal->init_num = 0; break; case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: dtls1_start_timer(s); ret = ssl3_send_client_verify(s); if (ret <= 0) goto end; S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A; s->internal->init_num = 0; S3I(s)->change_cipher_spec = 0; break; case SSL3_ST_CW_CHANGE_A: case SSL3_ST_CW_CHANGE_B: if (!s->internal->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; S3I(s)->hs.state = SSL3_ST_CW_FINISHED_A; s->internal->init_num = 0; s->session->cipher = S3I(s)->hs.new_cipher; if (!tls1_setup_key_block(s)) { ret = -1; goto end; } if (!tls1_change_cipher_state(s, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { ret = -1; goto end; } dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); break; case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: if (!s->internal->hit) dtls1_start_timer(s); ret = ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A, SSL3_ST_CW_FINISHED_B, TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE); if (ret <= 0) goto end; S3I(s)->hs.state = SSL3_ST_CW_FLUSH; /* clear flags */ s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER; if (s->internal->hit) { S3I(s)->hs.next_state = SSL_ST_OK; if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { S3I(s)->hs.state = SSL_ST_OK; s->s3->flags |= SSL3_FLAGS_POP_BUFFER; S3I(s)->delay_buf_pop_ret = 0; } } else { /* Allow NewSessionTicket if ticket expected */ if (s->internal->tlsext_ticket_expected) S3I(s)->hs.next_state = SSL3_ST_CR_SESSION_TICKET_A; else S3I(s)->hs.next_state = SSL3_ST_CR_FINISHED_A; } s->internal->init_num = 0; break; 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; S3I(s)->hs.state = SSL3_ST_CR_FINISHED_A; s->internal->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; S3I(s)->hs.state = SSL3_ST_CR_KEY_EXCH_A; s->internal->init_num = 0; break; case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: D1I(s)->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->internal->hit) S3I(s)->hs.state = SSL3_ST_CW_CHANGE_A; else S3I(s)->hs.state = SSL_ST_OK; s->internal->init_num = 0; break; case SSL3_ST_CW_FLUSH: 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 SSL_ST_OK: /* clean a few things up */ tls1_cleanup_key_block(s); /* 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->internal->init_num = 0; s->internal->renegotiate = 0; s->internal->new_session = 0; ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); if (s->internal->hit) s->ctx->internal->stats.sess_hit++; ret = 1; /* s->server=0; */ s->internal->handshake_func = dtls1_connect; s->ctx->internal->stats.sess_connect_good++; if (cb != NULL) cb(s, SSL_CB_HANDSHAKE_DONE, 1); /* done with handshaking */ D1I(s)->handshake_read_seq = 0; D1I(s)->next_handshake_write_seq = 0; goto end; /* break; */ default: SSLerror(s, SSL_R_UNKNOWN_STATE); ret = -1; goto end; /* break; */ } /* did we do anything */ 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_CONNECT_LOOP, 1); S3I(s)->hs.state = new_state; } } skip = 0; } end: s->internal->in_handshake--; if (cb != NULL) cb(s, SSL_CB_CONNECT_EXIT, ret); return (ret); }