Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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, 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;
}
Ejemplo n.º 3
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;
}