int tls1_change_cipher_state(SSL *s, int which) { /* 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; const uint8_t *client_write_mac_secret, *server_write_mac_secret, *mac_secret; const uint8_t *client_write_key, *server_write_key, *key; const uint8_t *client_write_iv, *server_write_iv, *iv; const EVP_AEAD *aead = s->s3->tmp.new_aead; size_t key_len, iv_len, mac_secret_len; const uint8_t *key_data; /* Reset sequence number to zero. */ if (!SSL_IS_DTLS(s)) { memset(is_read ? s->s3->read_sequence : s->s3->write_sequence, 0, 8); } mac_secret_len = s->s3->tmp.new_mac_secret_len; iv_len = s->s3->tmp.new_fixed_iv_len; if (aead == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } 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 and IV key bytes. */ if (key_len < mac_secret_len + iv_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + iv_len; } key_data = s->s3->tmp.key_block; client_write_mac_secret = key_data; key_data += mac_secret_len; server_write_mac_secret = key_data; key_data += mac_secret_len; client_write_key = key_data; key_data += key_len; server_write_key = key_data; key_data += key_len; client_write_iv = key_data; key_data += iv_len; server_write_iv = key_data; key_data += iv_len; 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; } if (key_data - s->s3->tmp.key_block != s->s3->tmp.key_block_length) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } if (is_read) { SSL_AEAD_CTX_free(s->aead_read_ctx); s->aead_read_ctx = SSL_AEAD_CTX_new( evp_aead_open, ssl3_version_from_wire(s, s->version), s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); return s->aead_read_ctx != NULL; } SSL_AEAD_CTX_free(s->aead_write_ctx); s->aead_write_ctx = SSL_AEAD_CTX_new( evp_aead_seal, ssl3_version_from_wire(s, s->version), s->s3->tmp.new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); if (s->aead_write_ctx == NULL) { return 0; } s->s3->need_record_splitting = 0; if (!SSL_USE_EXPLICIT_IV(s) && (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && SSL_CIPHER_is_block_cipher(s->s3->tmp.new_cipher)) { /* Enable 1/n-1 record-splitting to randomize the IV. See * https://www.openssl.org/~bodo/tls-cbc.txt and the BEAST attack. */ s->s3->need_record_splitting = 1; } return 1; }
int tls1_setup_key_block(SSL *s) { uint8_t *p; const EVP_AEAD *aead = NULL; int ret = 0; size_t mac_secret_len, fixed_iv_len, variable_iv_len, key_len; size_t key_block_len; if (s->s3->tmp.key_block_length != 0) { return 1; } if (s->session->cipher == NULL) { goto cipher_unavailable_err; } if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, s->session->cipher, ssl3_version_from_wire(s, s->version))) { goto cipher_unavailable_err; } key_len = EVP_AEAD_key_length(aead); variable_iv_len = EVP_AEAD_nonce_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; } else { /* The nonce is split into a fixed portion and a variable portion. */ if (variable_iv_len < fixed_iv_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } variable_iv_len -= fixed_iv_len; } assert(mac_secret_len < 256); assert(fixed_iv_len < 256); assert(variable_iv_len < 256); s->s3->tmp.new_aead = aead; s->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len; s->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len; s->s3->tmp.new_variable_iv_len = (uint8_t)variable_iv_len; key_block_len = key_len + mac_secret_len + fixed_iv_len; key_block_len *= 2; ssl3_cleanup_key_block(s); p = (uint8_t *)OPENSSL_malloc(key_block_len); if (p == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } s->s3->tmp.key_block_length = key_block_len; s->s3->tmp.key_block = p; if (!tls1_generate_key_block(s, p, key_block_len)) { goto err; } ret = 1; err: return ret; cipher_unavailable_err: OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; }
int tls1_setup_key_block(SSL *s) { uint8_t *p; const EVP_AEAD *aead = NULL; int ret = 0; size_t mac_secret_len, fixed_iv_len, variable_iv_len, key_len; size_t key_block_len; if (s->s3->tmp.key_block_length != 0) { return 1; } if (s->session->cipher == NULL) { goto cipher_unavailable_err; } if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, s->session->cipher, ssl3_version_from_wire(s, s->version))) { goto cipher_unavailable_err; } key_len = EVP_AEAD_key_length(aead); variable_iv_len = EVP_AEAD_nonce_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, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } key_len -= mac_secret_len + fixed_iv_len; } else { /* The nonce is split into a fixed portion and a variable portion. */ if (variable_iv_len < fixed_iv_len) { OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_INTERNAL_ERROR); return 0; } variable_iv_len -= fixed_iv_len; } assert(mac_secret_len < 256); assert(fixed_iv_len < 256); assert(variable_iv_len < 256); s->s3->tmp.new_aead = aead; s->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len; s->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len; s->s3->tmp.new_variable_iv_len = (uint8_t)variable_iv_len; key_block_len = key_len + mac_secret_len + fixed_iv_len; key_block_len *= 2; ssl3_cleanup_key_block(s); p = (uint8_t *)OPENSSL_malloc(key_block_len); if (p == NULL) { OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, ERR_R_MALLOC_FAILURE); goto err; } s->s3->tmp.key_block_length = key_block_len; s->s3->tmp.key_block = p; if (!tls1_generate_key_block(s, p, key_block_len)) { goto err; } if (!SSL_USE_EXPLICIT_IV(s) && (s->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0) { /* enable vulnerability countermeasure for CBC ciphers with known-IV * problem (http://www.openssl.org/~bodo/tls-cbc.txt). */ s->s3->need_record_splitting = 1; if (s->session->cipher != NULL && s->session->cipher->algorithm_enc == SSL_RC4) { s->s3->need_record_splitting = 0; } } ret = 1; err: return ret; cipher_unavailable_err: OPENSSL_PUT_ERROR(SSL, tls1_setup_key_block, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); return 0; }