Пример #1
0
static int set_cipher_key(struct sftp_cipher *cipher, const EVP_MD *hash,
    const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen,
    char *letter, const unsigned char *id, uint32_t id_len) {
  EVP_MD_CTX *ctx;
  unsigned char *key = NULL;
  size_t key_sz = 0;
  uint32_t key_len = 0;

  if (strncmp(cipher->algo, "none", 5) == 0) {
    cipher->key = key;
    cipher->key_len = key_len;

    return 0;
  }

  key_sz = sftp_crypto_get_size(cipher->key_len > 0 ?
      cipher->key_len : EVP_CIPHER_key_length(cipher->cipher),
    EVP_MD_size(hash));

  if (key_sz == 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to determine key length for cipher '%s'", cipher->algo);
    errno = EINVAL;
    return -1;
  }

  key = malloc(key_sz);
  if (key == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    _exit(1);
  }

  ctx = EVP_MD_CTX_create();
  EVP_DigestInit(ctx, hash);
  EVP_DigestUpdate(ctx, k, klen);
  EVP_DigestUpdate(ctx, h, hlen);
  EVP_DigestUpdate(ctx, letter, sizeof(char));
  EVP_DigestUpdate(ctx, (char *) id, id_len);
  EVP_DigestFinal(ctx, key, &key_len);
  EVP_MD_CTX_destroy(ctx);

  /* If we need more, keep hashing, as per RFC, until we have enough
   * material.
   */
  while (key_sz > key_len) {
    uint32_t len = key_len;

    pr_signals_handle();

    ctx = EVP_MD_CTX_create();
    EVP_DigestInit(ctx, hash);
    EVP_DigestUpdate(ctx, k, klen);
    EVP_DigestUpdate(ctx, h, hlen);
    EVP_DigestUpdate(ctx, key, len);
    EVP_DigestFinal(ctx, key + len, &len);
    EVP_MD_CTX_destroy(ctx);

    key_len += len;
  }

  cipher->key = key;
  cipher->key_len = key_len;

  return 0;
}
Пример #2
0
static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash,
    const char *k, uint32_t klen, const char *h, uint32_t hlen, char *letter,
    const unsigned char *id, uint32_t id_len) {
 
  EVP_MD_CTX ctx;
  unsigned char *key = NULL;
  size_t key_sz;
  uint32_t key_len = 0;
 
  key_sz = sftp_crypto_get_size(EVP_MD_block_size(mac->digest),
    EVP_MD_size(hash)); 

  if (key_sz == 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to determine key length for MAC '%s'", mac->algo);
    errno = EINVAL;
    return -1;
  }

  key = malloc(key_sz);
  if (key == NULL) {
    pr_log_pri(PR_LOG_CRIT, MOD_SFTP_VERSION ": Out of memory!");
    _exit(1);
  }

  /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
   * int.  Without these ugly OpenSSL version preprocessor checks, the
   * compiler will error out with "void value not ignored as it ought to be".
   */

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestInit(&ctx, hash) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error initializing message digest: %s", sftp_crypto_get_errors());
    free(key);
    return -1;
  }
#else
  EVP_DigestInit(&ctx, hash);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestUpdate(&ctx, k, klen) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error updating message digest with K: %s", sftp_crypto_get_errors());
    free(key);
    return -1;
  }
#else
  EVP_DigestUpdate(&ctx, k, klen);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestUpdate(&ctx, h, hlen) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error updating message digest with H: %s", sftp_crypto_get_errors());
    free(key);
    return -1;
  }
#else
  EVP_DigestUpdate(&ctx, h, hlen);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestUpdate(&ctx, letter, sizeof(char)) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error updating message digest with '%c': %s", *letter,
      sftp_crypto_get_errors());
    free(key);
    return -1;
  }
#else
  EVP_DigestUpdate(&ctx, letter, sizeof(char));
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestUpdate(&ctx, (char *) id, id_len) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error updating message digest with ID: %s", sftp_crypto_get_errors());
    free(key);
    return -1;
  }
#else
  EVP_DigestUpdate(&ctx, (char *) id, id_len);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
  if (EVP_DigestFinal(&ctx, key, &key_len) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error finalizing message digest: %s", sftp_crypto_get_errors());
    pr_memscrub(key, key_sz);
    free(key);
    return -1;
  }
#else
  EVP_DigestFinal(&ctx, key, &key_len);
#endif

  /* If we need more, keep hashing, as per RFC, until we have enough
   * material.
   */
  while (key_sz > key_len) {
    uint32_t len = key_len;

    pr_signals_handle();

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
    if (EVP_DigestInit(&ctx, hash) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error initializing message digest: %s", sftp_crypto_get_errors());
      pr_memscrub(key, key_sz);
      free(key);
      return -1;
    }
#else
    EVP_DigestInit(&ctx, hash);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
    if (EVP_DigestUpdate(&ctx, k, klen) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error updating message digest with K: %s", sftp_crypto_get_errors());
      pr_memscrub(key, key_sz);
      free(key);
      return -1;
    }
#else
    EVP_DigestUpdate(&ctx, k, klen);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
    if (EVP_DigestUpdate(&ctx, h, hlen) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error updating message digest with H: %s", sftp_crypto_get_errors());
      pr_memscrub(key, key_sz);
      free(key);
      return -1;
    }
#else
    EVP_DigestUpdate(&ctx, h, hlen);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
    if (EVP_DigestUpdate(&ctx, key, len) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error updating message digest with data: %s",
        sftp_crypto_get_errors());
      pr_memscrub(key, key_sz);
      free(key);
      return -1;
    }
#else
    EVP_DigestUpdate(&ctx, key, len);
#endif

#if OPENSSL_VERSION_NUMBER >= 0x000907000L
    if (EVP_DigestFinal(&ctx, key + len, &len) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error finalizing message digest: %s", sftp_crypto_get_errors());
      pr_memscrub(key, key_sz);
      free(key);
      return -1;
    }
#else
    EVP_DigestFinal(&ctx, key + len, &len);
#endif

    key_len += len;
  }

  mac->key = key;
  mac->keysz = key_sz;

  mac->key_len = EVP_MD_size(mac->digest);
  if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_MAC_LEN)) {
    mac->key_len = 16;
  }

  return 0;
}
Пример #3
0
static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
    const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen,
    char *letter, const unsigned char *id, uint32_t id_len) {
  EVP_MD_CTX *ctx;
  unsigned char *iv = NULL;
  size_t cipher_iv_len = 0, iv_sz = 0;
  uint32_t iv_len = 0;

  if (strncmp(cipher->algo, "none", 5) == 0) {
    cipher->iv = iv;
    cipher->iv_len = iv_len;

    return 0;
  }

   /* Some ciphers do not use IVs; handle this case. */
  cipher_iv_len = EVP_CIPHER_iv_length(cipher->cipher);
  if (cipher_iv_len != 0) {
    iv_sz = sftp_crypto_get_size(cipher_iv_len, EVP_MD_size(hash));

  } else {
    iv_sz = EVP_MD_size(hash);
  }

  if (iv_sz == 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to determine IV length for cipher '%s'", cipher->algo);
     errno = EINVAL;
    return -1;
  }

  iv = malloc(iv_sz);
  if (iv == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    _exit(1);
  }

  ctx = EVP_MD_CTX_create();
  EVP_DigestInit(ctx, hash);
  if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_CIPHER_USE_K)) {
    EVP_DigestUpdate(ctx, k, klen);
  }
  EVP_DigestUpdate(ctx, h, hlen);
  EVP_DigestUpdate(ctx, letter, sizeof(char));
  EVP_DigestUpdate(ctx, (char *) id, id_len);
  EVP_DigestFinal(ctx, iv, &iv_len);
  EVP_MD_CTX_destroy(ctx);

  /* If we need more, keep hashing, as per RFC, until we have enough
   * material.
   */
  while (iv_sz > iv_len) {
    uint32_t len = iv_len;

    pr_signals_handle();

    ctx = EVP_MD_CTX_create();
    EVP_DigestInit(ctx, hash);
    if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_CIPHER_USE_K)) {
      EVP_DigestUpdate(ctx, k, klen);
    }
    EVP_DigestUpdate(ctx, h, hlen);
    EVP_DigestUpdate(ctx, iv, len);
    EVP_DigestFinal(ctx, iv + len, &len);
    EVP_MD_CTX_destroy(ctx);

    iv_len += len;
  }

  cipher->iv = iv;
  cipher->iv_len = iv_len;

  return 0;
}