/* * Create an SSL connection, but does not ready any post-handshake * NewSessionTicket messages. */ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want) { int retc = -1, rets = -1, err, abortctr = 0; int clienterr = 0, servererr = 0; int isdtls = SSL_is_dtls(serverssl); do { err = SSL_ERROR_WANT_WRITE; while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) { retc = SSL_connect(clientssl); if (retc <= 0) err = SSL_get_error(clientssl, retc); } if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) { TEST_info("SSL_connect() failed %d, %d", retc, err); clienterr = 1; } if (want != SSL_ERROR_NONE && err == want) return 0; err = SSL_ERROR_WANT_WRITE; while (!servererr && rets <= 0 && err == SSL_ERROR_WANT_WRITE) { rets = SSL_accept(serverssl); if (rets <= 0) err = SSL_get_error(serverssl, rets); } if (!servererr && rets <= 0 && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_X509_LOOKUP) { TEST_info("SSL_accept() failed %d, %d", rets, err); servererr = 1; } if (want != SSL_ERROR_NONE && err == want) return 0; if (clienterr && servererr) return 0; if (isdtls) { if (rets > 0 && retc <= 0) DTLSv1_handle_timeout(serverssl); if (retc > 0 && rets <= 0) DTLSv1_handle_timeout(clientssl); } if (++abortctr == MAXLOOPS) { TEST_info("No progress made"); return 0; } if (isdtls && abortctr <= 50 && (abortctr % 10) == 0) { /* * It looks like we're just spinning. Pause for a short period to * give the DTLS timer a chance to do something. We only do this for * the first few times to prevent hangs. */ ossl_sleep(50); } } while (retc <=0 || rets <= 0); return 1; }
int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) { SSL *const ssl = hs->ssl; /* Ensure the key block is set up. */ if (!tls1_setup_key_block(hs)) { return 0; } /* is_read is true if we have just read a ChangeCipherSpec message - i.e. we * need to update the read cipherspec. Otherwise we have just written one. */ const char is_read = (which & SSL3_CC_READ) != 0; /* use_client_keys is true if we wish to use the keys for the "client write" * direction. This is the case if we're a client sending a ChangeCipherSpec, * or a server reading a client's ChangeCipherSpec. */ const char use_client_keys = which == SSL3_CHANGE_CIPHER_CLIENT_WRITE || which == SSL3_CHANGE_CIPHER_SERVER_READ; size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len; size_t key_len = ssl->s3->tmp.new_key_len; size_t iv_len = ssl->s3->tmp.new_fixed_iv_len; assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block_len); const uint8_t *key_data = hs->key_block; const uint8_t *client_write_mac_secret = key_data; key_data += mac_secret_len; const uint8_t *server_write_mac_secret = key_data; key_data += mac_secret_len; const uint8_t *client_write_key = key_data; key_data += key_len; const uint8_t *server_write_key = key_data; key_data += key_len; const uint8_t *client_write_iv = key_data; key_data += iv_len; const uint8_t *server_write_iv = key_data; key_data += iv_len; const uint8_t *mac_secret, *key, *iv; if (use_client_keys) { mac_secret = client_write_mac_secret; key = client_write_key; iv = client_write_iv; } else { mac_secret = server_write_mac_secret; key = server_write_key; iv = server_write_iv; } SSL_AEAD_CTX *aead_ctx = SSL_AEAD_CTX_new( is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), SSL_is_dtls(ssl), hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); if (aead_ctx == NULL) { return 0; } if (is_read) { return ssl->method->set_read_state(ssl, aead_ctx); } return ssl->method->set_write_state(ssl, aead_ctx); }
static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (hs->key_block_len != 0) { return 1; } SSL_SESSION *session = ssl->session; if (hs->new_session != NULL) { session = hs->new_session; } const EVP_AEAD *aead = NULL; size_t mac_secret_len, fixed_iv_len; if (session->cipher == NULL || !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, session->cipher, ssl3_protocol_version(ssl), SSL_is_dtls(ssl))) { OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; } size_t key_len = EVP_AEAD_key_length(aead); if (mac_secret_len > 0) { /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the * key length reported by |EVP_AEAD_key_length| will include the MAC key * bytes and initial implicit IV. */ if (key_len < mac_secret_len + fixed_iv_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + fixed_iv_len; } assert(mac_secret_len < 256); assert(key_len < 256); assert(fixed_iv_len < 256); ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len; ssl->s3->tmp.new_key_len = (uint8_t)key_len; ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len; size_t key_block_len = SSL_get_key_block_len(ssl); uint8_t *keyblock = OPENSSL_malloc(key_block_len); if (keyblock == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return 0; } if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) { OPENSSL_free(keyblock); return 0; } assert(key_block_len < 256); hs->key_block_len = (uint8_t)key_block_len; hs->key_block = keyblock; return 1; }
/* * NOTE: Transfers control of the BIOs - this function will free them on error */ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio) { SSL *serverssl = NULL, *clientssl = NULL; BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL; if (*sssl != NULL) serverssl = *sssl; else if (!TEST_ptr(serverssl = SSL_new(serverctx))) goto error; if (*cssl != NULL) clientssl = *cssl; else if (!TEST_ptr(clientssl = SSL_new(clientctx))) goto error; if (SSL_is_dtls(clientssl)) { if (!TEST_ptr(s_to_c_bio = BIO_new(bio_s_mempacket_test())) || !TEST_ptr(c_to_s_bio = BIO_new(bio_s_mempacket_test()))) goto error; } else { if (!TEST_ptr(s_to_c_bio = BIO_new(BIO_s_mem())) || !TEST_ptr(c_to_s_bio = BIO_new(BIO_s_mem()))) goto error; } if (s_to_c_fbio != NULL && !TEST_ptr(s_to_c_bio = BIO_push(s_to_c_fbio, s_to_c_bio))) goto error; if (c_to_s_fbio != NULL && !TEST_ptr(c_to_s_bio = BIO_push(c_to_s_fbio, c_to_s_bio))) goto error; /* Set Non-blocking IO behaviour */ BIO_set_mem_eof_return(s_to_c_bio, -1); BIO_set_mem_eof_return(c_to_s_bio, -1); /* Up ref these as we are passing them to two SSL objects */ SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio); BIO_up_ref(s_to_c_bio); BIO_up_ref(c_to_s_bio); SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio); *sssl = serverssl; *cssl = clientssl; return 1; error: SSL_free(serverssl); SSL_free(clientssl); BIO_free(s_to_c_bio); BIO_free(c_to_s_bio); BIO_free(s_to_c_fbio); BIO_free(c_to_s_fbio); return 0; }
static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (!tls13_add_finished(hs) || /* Update the secret to the master secret and derive traffic keys. */ !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || !tls13_derive_application_secrets(hs) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0, hs->hash_len)) { return ssl_hs_error; } if (ssl->early_data_accepted) { /* If accepting 0-RTT, we send tickets half-RTT. This gets the tickets on * the wire sooner and also avoids triggering a write on |SSL_read| when * processing the client Finished. This requires computing the client * Finished early. See draft-ietf-tls-tls13-18, section 4.5.1. */ size_t finished_len; if (!tls13_finished_mac(hs, hs->expected_client_finished, &finished_len, 0 /* client */)) { return ssl_hs_error; } if (finished_len != hs->hash_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return ssl_hs_error; } /* Feed the predicted Finished into the transcript. This allows us to derive * the resumption secret early and send half-RTT tickets. * * TODO(davidben): This will need to be updated for DTLS 1.3. */ assert(!SSL_is_dtls(hs->ssl)); uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0, hs->hash_len}; if (!SSL_TRANSCRIPT_update(&hs->transcript, header, sizeof(header)) || !SSL_TRANSCRIPT_update(&hs->transcript, hs->expected_client_finished, hs->hash_len) || !tls13_derive_resumption_secret(hs) || !add_new_session_tickets(hs)) { return ssl_hs_error; } } hs->tls13_state = state_read_second_client_flight; return ssl_hs_flush; }
int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) { if (!SSL_is_dtls(ssl)) { return 0; } /* If no timeout is set, just return NULL */ if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) { return 0; } struct timeval timenow; ssl_get_current_time(ssl, &timenow); /* If timer already expired, set remaining time to 0 */ if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec || (ssl->d1->next_timeout.tv_sec == timenow.tv_sec && ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) { memset(out, 0, sizeof(struct timeval)); return 1; } /* Calculate time left until timer expires */ memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval)); out->tv_sec -= timenow.tv_sec; out->tv_usec -= timenow.tv_usec; if (out->tv_usec < 0) { out->tv_sec--; out->tv_usec += 1000000; } /* If remaining time is less than 15 ms, set it to 0 to prevent issues * because of small devergences with socket timeouts. */ if (out->tv_sec == 0 && out->tv_usec < 15000) { memset(out, 0, sizeof(struct timeval)); } return 1; }
int DTLSv1_handle_timeout(SSL *ssl) { ssl->rwstate = SSL_NOTHING; /* Functions which use SSL_get_error must clear the error queue on entry. */ ERR_clear_error(); if (!SSL_is_dtls(ssl)) { return -1; } /* if no timer is expired, don't do anything */ if (!dtls1_is_timer_expired(ssl)) { return 0; } dtls1_double_timeout(ssl); if (dtls1_check_timeout_num(ssl) < 0) { return -1; } dtls1_start_timer(ssl); return dtls1_retransmit_outgoing_messages(ssl); }
/* * Create an SSL connection, but does not ready any post-handshake * NewSessionTicket messages. * If |read| is set and we're using DTLS then we will attempt to SSL_read on * the connection once we've completed one half of it, to ensure any retransmits * get triggered. */ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want, int read) { int retc = -1, rets = -1, err, abortctr = 0; int clienterr = 0, servererr = 0; int isdtls = SSL_is_dtls(serverssl); do { err = SSL_ERROR_WANT_WRITE; while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) { retc = SSL_connect(clientssl); if (retc <= 0) err = SSL_get_error(clientssl, retc); } if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) { TEST_info("SSL_connect() failed %d, %d", retc, err); clienterr = 1; } if (want != SSL_ERROR_NONE && err == want) return 0; err = SSL_ERROR_WANT_WRITE; while (!servererr && rets <= 0 && err == SSL_ERROR_WANT_WRITE) { rets = SSL_accept(serverssl); if (rets <= 0) err = SSL_get_error(serverssl, rets); } if (!servererr && rets <= 0 && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_X509_LOOKUP) { TEST_info("SSL_accept() failed %d, %d", rets, err); servererr = 1; } if (want != SSL_ERROR_NONE && err == want) return 0; if (clienterr && servererr) return 0; if (isdtls && read) { unsigned char buf[20]; /* Trigger any retransmits that may be appropriate */ if (rets > 0 && retc <= 0) { if (SSL_read(serverssl, buf, sizeof(buf)) > 0) { /* We don't expect this to succeed! */ TEST_info("Unexpected SSL_read() success!"); return 0; } } if (retc > 0 && rets <= 0) { if (SSL_read(clientssl, buf, sizeof(buf)) > 0) { /* We don't expect this to succeed! */ TEST_info("Unexpected SSL_read() success!"); return 0; } } } if (++abortctr == MAXLOOPS) { TEST_info("No progress made"); return 0; } if (isdtls && abortctr <= 50 && (abortctr % 10) == 0) { /* * It looks like we're just spinning. Pause for a short period to * give the DTLS timer a chance to do something. We only do this for * the first few times to prevent hangs. */ ossl_sleep(50); } } while (retc <=0 || rets <= 0); return 1; }