コード例 #1
0
ファイル: p_hmac.c プロジェクト: gotomypc/tiny-webrtc-gw
static int pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
  HMAC_PKEY_CTX *sctx, *dctx;
  if (!pkey_hmac_init(dst)) {
    return 0;
  }
  sctx = src->data;
  dctx = dst->data;
  dctx->md = sctx->md;
  HMAC_CTX_init(&dctx->ctx);
  if (!HMAC_CTX_copy_ex(&dctx->ctx, &sctx->ctx)) {
    return 0;
  }
  if (sctx->ktmp.data) {
    if (!ASN1_OCTET_STRING_set(&dctx->ktmp, sctx->ktmp.data,
                               sctx->ktmp.length)) {
      return 0;
    }
  }
  return 1;
}
コード例 #2
0
ファイル: e_tls.c プロジェクト: gotomypc/tiny-webrtc-gw
static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
                         size_t *out_len, size_t max_out_len,
                         const uint8_t *nonce, size_t nonce_len,
                         const uint8_t *in, size_t in_len,
                         const uint8_t *ad, size_t ad_len) {
  AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;

  if (tls_ctx->cipher_ctx.encrypt) {
    /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_OPERATION);
    return 0;

  }

  if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  if (max_out_len < in_len) {
    /* This requires that the caller provide space for the MAC, even though it
     * will always be removed on return. */
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BUFFER_TOO_SMALL);
    return 0;
  }

  if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_NONCE_SIZE);
    return 0;
  }

  if (ad_len != 13 - 2 /* length bytes */) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_AD_SIZE);
    return 0;
  }

  if (in_len > INT_MAX) {
    /* EVP_CIPHER takes int as input. */
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_TOO_LARGE);
    return 0;
  }

  /* Configure the explicit IV. */
  if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE &&
      !tls_ctx->implicit_iv &&
      !EVP_DecryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) {
    return 0;
  }

  /* Decrypt to get the plaintext + MAC + padding. */
  size_t total = 0;
  int len;
  if (!EVP_DecryptUpdate(&tls_ctx->cipher_ctx, out, &len, in, (int)in_len)) {
    return 0;
  }
  total += len;
  if (!EVP_DecryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) {
    return 0;
  }
  total += len;
  assert(total == in_len);

  /* Remove CBC padding. Code from here on is timing-sensitive with respect to
   * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */
  int padding_ok;
  unsigned data_plus_mac_len, data_len;
  if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) {
    padding_ok = EVP_tls_cbc_remove_padding(
        &data_plus_mac_len, out, total,
        EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx),
        (unsigned)HMAC_size(&tls_ctx->hmac_ctx));
    /* Publicly invalid. This can be rejected in non-constant time. */
    if (padding_ok == 0) {
      OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
      return 0;
    }
  } else {
    padding_ok = 1;
    data_plus_mac_len = total;
    /* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has
     * already been checked against the MAC size at the top of the function. */
    assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx));
  }
  data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx);

  /* At this point, |padding_ok| is 1 or -1. If 1, the padding is valid and the
   * first |data_plus_mac_size| bytes after |out| are the plaintext and
   * MAC. Either way, |data_plus_mac_size| is large enough to extract a MAC. */

  /* To allow for CBC mode which changes cipher length, |ad| doesn't include the
   * length for legacy ciphers. */
  uint8_t ad_fixed[13];
  memcpy(ad_fixed, ad, 11);
  ad_fixed[11] = (uint8_t)(data_len >> 8);
  ad_fixed[12] = (uint8_t)(data_len & 0xff);
  ad_len += 2;

  /* Compute the MAC and extract the one in the record. */
  uint8_t mac[EVP_MAX_MD_SIZE];
  size_t mac_len;
  uint8_t record_mac_tmp[EVP_MAX_MD_SIZE];
  uint8_t *record_mac;
  if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE &&
      EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx.md)) {
    if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx.md, mac, &mac_len,
                                   ad_fixed, out, data_plus_mac_len, total,
                                   tls_ctx->mac_key, tls_ctx->mac_key_len)) {
      OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
      return 0;
    }
    assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx));

    record_mac = record_mac_tmp;
    EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total);
  } else {
    /* We should support the constant-time path for all CBC-mode ciphers
     * implemented. */
    assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE);

    HMAC_CTX hmac_ctx;
    HMAC_CTX_init(&hmac_ctx);
    unsigned mac_len_u;
    if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) ||
        !HMAC_Update(&hmac_ctx, ad_fixed, ad_len) ||
        !HMAC_Update(&hmac_ctx, out, data_len) ||
        !HMAC_Final(&hmac_ctx, mac, &mac_len_u)) {
      HMAC_CTX_cleanup(&hmac_ctx);
      return 0;
    }
    mac_len = mac_len_u;
    HMAC_CTX_cleanup(&hmac_ctx);

    assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx));
    record_mac = &out[data_len];
  }

  /* Perform the MAC check and the padding check in constant-time. It should be
   * safe to simply perform the padding check first, but it would not be under a
   * different choice of MAC location on padding failure. See
   * EVP_tls_cbc_remove_padding. */
  unsigned good = constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len),
                                       0);
  good &= constant_time_eq_int(padding_ok, 1);
  if (!good) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
    return 0;
  }

  /* End of timing-sensitive code. */

  *out_len = data_len;
  return 1;
}
コード例 #3
0
ファイル: e_tls.c プロジェクト: gotomypc/tiny-webrtc-gw
static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
                         size_t *out_len, size_t max_out_len,
                         const uint8_t *nonce, size_t nonce_len,
                         const uint8_t *in, size_t in_len,
                         const uint8_t *ad, size_t ad_len) {
  AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
  size_t total = 0;

  if (!tls_ctx->cipher_ctx.encrypt) {
    /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_OPERATION);
    return 0;

  }

  if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len ||
      in_len > INT_MAX) {
    /* EVP_CIPHER takes int as input. */
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_TOO_LARGE);
    return 0;
  }

  if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_BUFFER_TOO_SMALL);
    return 0;
  }

  if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_NONCE_SIZE);
    return 0;
  }

  if (ad_len != 13 - 2 /* length bytes */) {
    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_AD_SIZE);
    return 0;
  }

  /* To allow for CBC mode which changes cipher length, |ad| doesn't include the
   * length for legacy ciphers. */
  uint8_t ad_extra[2];
  ad_extra[0] = (uint8_t)(in_len >> 8);
  ad_extra[1] = (uint8_t)(in_len & 0xff);

  /* Compute the MAC. This must be first in case the operation is being done
   * in-place. */
  uint8_t mac[EVP_MAX_MD_SIZE];
  unsigned mac_len;
  HMAC_CTX hmac_ctx;
  HMAC_CTX_init(&hmac_ctx);
  if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) ||
      !HMAC_Update(&hmac_ctx, ad, ad_len) ||
      !HMAC_Update(&hmac_ctx, ad_extra, sizeof(ad_extra)) ||
      !HMAC_Update(&hmac_ctx, in, in_len) ||
      !HMAC_Final(&hmac_ctx, mac, &mac_len)) {
    HMAC_CTX_cleanup(&hmac_ctx);
    return 0;
  }
  HMAC_CTX_cleanup(&hmac_ctx);

  /* Configure the explicit IV. */
  if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE &&
      !tls_ctx->implicit_iv &&
      !EVP_EncryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) {
    return 0;
  }

  /* Encrypt the input. */
  int len;
  if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out, &len, in,
                         (int)in_len)) {
    return 0;
  }
  total = len;

  /* Feed the MAC into the cipher. */
  if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, mac,
                         (int)mac_len)) {
    return 0;
  }
  total += len;

  unsigned block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx);
  if (block_size > 1) {
    assert(block_size <= 256);
    assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE);

    /* Compute padding and feed that into the cipher. */
    uint8_t padding[256];
    unsigned padding_len = block_size - ((in_len + mac_len) % block_size);
    memset(padding, padding_len - 1, padding_len);
    if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, padding,
                           (int)padding_len)) {
      return 0;
    }
    total += len;
  }

  if (!EVP_EncryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) {
    return 0;
  }
  total += len;

  *out_len = total;
  return 1;
}
コード例 #4
0
ファイル: t1_enc.c プロジェクト: anthonylauzon/bazel
/* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
 * section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and
 * |secret| as the secret. |seed1| through |seed3| are concatenated to form the
 * seed parameter. It returns one on success and zero on failure. */
static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md,
                       const uint8_t *secret, size_t secret_len,
                       const uint8_t *seed1, size_t seed1_len,
                       const uint8_t *seed2, size_t seed2_len,
                       const uint8_t *seed3, size_t seed3_len) {
  size_t chunk;
  HMAC_CTX ctx, ctx_tmp, ctx_init;
  uint8_t A1[EVP_MAX_MD_SIZE];
  unsigned A1_len;
  int ret = 0;

  chunk = EVP_MD_size(md);

  HMAC_CTX_init(&ctx);
  HMAC_CTX_init(&ctx_tmp);
  HMAC_CTX_init(&ctx_init);
  if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) ||
      !HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
      (seed1_len && !HMAC_Update(&ctx, seed1, seed1_len)) ||
      (seed2_len && !HMAC_Update(&ctx, seed2, seed2_len)) ||
      (seed3_len && !HMAC_Update(&ctx, seed3, seed3_len)) ||
      !HMAC_Final(&ctx, A1, &A1_len)) {
    goto err;
  }

  for (;;) {
    /* Reinit mac contexts. */
    if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
        !HMAC_Update(&ctx, A1, A1_len) ||
        (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) ||
        (seed1_len && !HMAC_Update(&ctx, seed1, seed1_len)) ||
        (seed2_len && !HMAC_Update(&ctx, seed2, seed2_len)) ||
        (seed3_len && !HMAC_Update(&ctx, seed3, seed3_len))) {
      goto err;
    }

    unsigned len;
    uint8_t hmac[EVP_MAX_MD_SIZE];
    if (!HMAC_Final(&ctx, hmac, &len)) {
      goto err;
    }
    assert(len == chunk);

    /* XOR the result into |out|. */
    if (len > out_len) {
      len = out_len;
    }
    unsigned i;
    for (i = 0; i < len; i++) {
      out[i] ^= hmac[i];
    }
    out += len;
    out_len -= len;

    if (out_len == 0) {
      break;
    }

    /* Calculate the next A1 value. */
    if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
      goto err;
    }
  }

  ret = 1;

err:
  HMAC_CTX_cleanup(&ctx);
  HMAC_CTX_cleanup(&ctx_tmp);
  HMAC_CTX_cleanup(&ctx_init);
  OPENSSL_cleanse(A1, sizeof(A1));
  return ret;
}
コード例 #5
0
ファイル: hmac.c プロジェクト: facessl/boringssl
int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src) {
  HMAC_CTX_init(dest);
  return HMAC_CTX_copy_ex(dest, src);
}
コード例 #6
0
ファイル: t1_enc.c プロジェクト: HungMingWu/libquic
/* tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
 * section 5. It writes |out_len| bytes to |out|, using |md| as the hash and
 * |secret| as the secret. |seed1| through |seed3| are concatenated to form the
 * seed parameter. It returns one on success and zero on failure. */
static int tls1_P_hash(uint8_t *out, size_t out_len, const EVP_MD *md,
                       const uint8_t *secret, size_t secret_len,
                       const uint8_t *seed1, size_t seed1_len,
                       const uint8_t *seed2, size_t seed2_len,
                       const uint8_t *seed3, size_t seed3_len) {
  size_t chunk;
  HMAC_CTX ctx, ctx_tmp, ctx_init;
  uint8_t A1[EVP_MAX_MD_SIZE];
  unsigned A1_len;
  int ret = 0;

  chunk = EVP_MD_size(md);

  HMAC_CTX_init(&ctx);
  HMAC_CTX_init(&ctx_tmp);
  HMAC_CTX_init(&ctx_init);
  if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) ||
      !HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
      (seed1_len && !HMAC_Update(&ctx, seed1, seed1_len)) ||
      (seed2_len && !HMAC_Update(&ctx, seed2, seed2_len)) ||
      (seed3_len && !HMAC_Update(&ctx, seed3, seed3_len)) ||
      !HMAC_Final(&ctx, A1, &A1_len)) {
    goto err;
  }

  for (;;) {
    /* Reinit mac contexts. */
    if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
        !HMAC_Update(&ctx, A1, A1_len) ||
        (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) ||
        (seed1_len && !HMAC_Update(&ctx, seed1, seed1_len)) ||
        (seed2_len && !HMAC_Update(&ctx, seed2, seed2_len)) ||
        (seed3_len && !HMAC_Update(&ctx, seed3, seed3_len))) {
      goto err;
    }

    if (out_len > chunk) {
      unsigned len;
      if (!HMAC_Final(&ctx, out, &len)) {
        goto err;
      }
      assert(len == chunk);
      out += len;
      out_len -= len;
      /* Calculate the next A1 value. */
      if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
        goto err;
      }
    } else {
      /* Last chunk. */
      if (!HMAC_Final(&ctx, A1, &A1_len)) {
        goto err;
      }
      memcpy(out, A1, out_len);
      break;
    }
  }

  ret = 1;

err:
  HMAC_CTX_cleanup(&ctx);
  HMAC_CTX_cleanup(&ctx_tmp);
  HMAC_CTX_cleanup(&ctx_init);
  OPENSSL_cleanse(A1, sizeof(A1));
  return ret;
}
コード例 #7
0
ファイル: kdf.c プロジェクト: MateusDeSousa/FiqueRico
// tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
// section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and
// |secret| as the secret. |label|, |seed1|, and |seed2| are concatenated to
// form the seed parameter. It returns true on success and false on failure.
static int tls1_P_hash(uint8_t *out, size_t out_len,
                       const EVP_MD *md,
                       const uint8_t *secret, size_t secret_len,
                       const char *label, size_t label_len,
                       const uint8_t *seed1, size_t seed1_len,
                       const uint8_t *seed2, size_t seed2_len) {
  HMAC_CTX ctx, ctx_tmp, ctx_init;
  uint8_t A1[EVP_MAX_MD_SIZE];
  unsigned A1_len;
  int ret = 0;

  const size_t chunk = EVP_MD_size(md);
  HMAC_CTX_init(&ctx);
  HMAC_CTX_init(&ctx_tmp);
  HMAC_CTX_init(&ctx_init);

  if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) ||
      !HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
      !HMAC_Update(&ctx, (const uint8_t *) label, label_len) ||
      !HMAC_Update(&ctx, seed1, seed1_len) ||
      !HMAC_Update(&ctx, seed2, seed2_len) ||
      !HMAC_Final(&ctx, A1, &A1_len)) {
    goto err;
  }

  for (;;) {
    unsigned len;
    uint8_t hmac[EVP_MAX_MD_SIZE];
    if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) ||
        !HMAC_Update(&ctx, A1, A1_len) ||
        // Save a copy of |ctx| to compute the next A1 value below.
        (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) ||
        !HMAC_Update(&ctx, (const uint8_t *) label, label_len) ||
        !HMAC_Update(&ctx, seed1, seed1_len) ||
        !HMAC_Update(&ctx, seed2, seed2_len) ||
        !HMAC_Final(&ctx, hmac, &len)) {
      goto err;
    }
    assert(len == chunk);

    // XOR the result into |out|.
    if (len > out_len) {
      len = out_len;
    }
    for (unsigned i = 0; i < len; i++) {
      out[i] ^= hmac[i];
    }
    out += len;
    out_len -= len;

    if (out_len == 0) {
      break;
    }

    // Calculate the next A1 value.
    if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) {
      goto err;
    }
  }

  ret = 1;

err:
  OPENSSL_cleanse(A1, sizeof(A1));
  HMAC_CTX_cleanup(&ctx);
  HMAC_CTX_cleanup(&ctx_tmp);
  HMAC_CTX_cleanup(&ctx_init);
  return ret;
}