Example #1
0
int sftp_mac_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
    const char *h, uint32_t hlen) {
  const unsigned char *id = NULL;
  char *buf, *ptr;
  uint32_t buflen, bufsz, id_len;
  char letter;
  size_t blocksz;
  struct sftp_mac *mac;
  HMAC_CTX *mac_ctx;

  switch_read_mac();

  mac = &(read_macs[read_mac_idx]);
  mac_ctx = &(read_ctxs[read_mac_idx]);

  bufsz = buflen = 1024;
  ptr = buf = sftp_msg_getbuf(p, bufsz);

  /* Need to use SSH2-style format of K for the key. */
  sftp_msg_write_mpint(&buf, &buflen, k);

  id_len = sftp_session_get_id(&id);

  /* HASH(K || H || "E" || session_id) */
  letter = 'E';
  set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len);

#if OPENSSL_VERSION_NUMBER > 0x000907000L
  HMAC_CTX_init(mac_ctx);

# if OPENSSL_VERSION_NUMBER >= 0x10000001L
  if (HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL) != 1) {
    pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error initializing HMAC: %s", sftp_crypto_get_errors());
    errno = EPERM;
    return -1;
  }

# else
  HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL);
# endif /* OpenSSL-1.0.0 and later */

#else
  /* Reset the HMAC context. */
  HMAC_Init(mac_ctx, NULL, 0, NULL);
  HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest);
#endif

  if (mac->mac_len == 0) {
    blocksz = EVP_MD_size(mac->digest);

  } else {
    blocksz = mac->mac_len;
  }

  pr_memscrub(ptr, bufsz);
  sftp_mac_set_block_size(blocksz);
  return 0;
}
Example #2
0
static void clear_cipher(struct sftp_cipher *cipher) {
  if (cipher->iv) {
    pr_memscrub(cipher->iv, cipher->iv_len);
    free(cipher->iv);
    cipher->iv = NULL;
    cipher->iv_len = 0;
  }

  if (cipher->key) {
    pr_memscrub(cipher->key, cipher->key_len);
    free(cipher->key);
    cipher->key = NULL;
    cipher->key_len = 0;
  }

  cipher->cipher = NULL;
  cipher->algo = NULL;
}
Example #3
0
static void clear_mac(struct sftp_mac *mac) {
  if (mac->key) {
    pr_memscrub(mac->key, mac->keysz);
    free(mac->key);
    mac->key = NULL;
    mac->keysz = 0;
    mac->key_len = 0;
  }

  mac->digest = NULL;
  mac->algo = NULL;
}
Example #4
0
static int cleanup_bf_ctr(EVP_CIPHER_CTX *ctx) {
  struct bf_ctr_ex *bce;

  bce = EVP_CIPHER_CTX_get_app_data(ctx);
  if (bce != NULL) {
    pr_memscrub(bce, sizeof(struct bf_ctr_ex));
    free(bce);
    EVP_CIPHER_CTX_set_app_data(ctx, NULL);
  }

  return 1;
}
Example #5
0
END_TEST

START_TEST (memscrub_test) {
  size_t len;
  char *expected, *text;

  mark_point();
  pr_memscrub(NULL, 1);

  expected = "Hello, World!";
  text = pstrdup(p, expected);

  mark_point();
  pr_memscrub(text, 0);

  len = strlen(text);

  mark_point();
  pr_memscrub(text, len);
  fail_unless(strncmp(text, expected, len + 1) != 0,
    "Expected other than '%s'", expected);
}
Example #6
0
/* If the chosen cipher requires that we discard some of the initial bytes of
 * the cipher stream, then do so.  (This is mostly for any RC4 ciphers.)
 */
static int set_cipher_discarded(struct sftp_cipher *cipher,
    EVP_CIPHER_CTX *cipher_ctx) {
  unsigned char *garbage_in, *garbage_out;

  if (cipher->discard_len == 0) {
    return 0;
  }

  garbage_in = malloc(cipher->discard_len);
  if (garbage_in == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    _exit(1);
  }

  garbage_out = malloc(cipher->discard_len);
  if (garbage_out == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    free(garbage_in);
    _exit(1);
  }

  if (EVP_Cipher(cipher_ctx, garbage_out, garbage_in,
      cipher->discard_len) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error ciphering discard data: %s", sftp_crypto_get_errors());
    free(garbage_in);
    pr_memscrub(garbage_out, cipher->discard_len);
    free(garbage_out);

    return -1;
  }

  free(garbage_in);
  pr_memscrub(garbage_out, cipher->discard_len);
  free(garbage_out);

  return 0;
}
Example #7
0
void proxy_conn_clear_password(struct proxy_conn *pconn) {
  size_t len;

  if (pconn == NULL) {
    return;
  }

  if (pconn->pconn_password == NULL) {
    return;
  }

  len = strlen(pconn->pconn_password);
  pr_memscrub(pconn->pconn_password, len);
  pconn->pconn_password = NULL;
}
Example #8
0
void proxy_conn_clear_username(struct proxy_conn *pconn) {
  size_t len;

  if (pconn == NULL) {
    return;
  }

  if (pconn->pconn_username == NULL) {
    return;
  }

  len = strlen(pconn->pconn_username);
  pr_memscrub(pconn->pconn_username, len);
  pconn->pconn_username = NULL;
}
Example #9
0
int sftp_mac_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
    const char *h, uint32_t hlen) {
  const unsigned char *id = NULL;
  char *buf, *ptr;
  uint32_t buflen, bufsz, id_len;
  char letter;
  struct sftp_mac *mac;
  HMAC_CTX *mac_ctx;

  switch_write_mac();

  mac = &(write_macs[write_mac_idx]);
  mac_ctx = &(write_ctxs[write_mac_idx]);

  bufsz = buflen = 1024;
  ptr = buf = sftp_msg_getbuf(p, bufsz);

  /* Need to use SSH2-style format of K for the key. */
  sftp_msg_write_mpint(&buf, &buflen, k);

  id_len = sftp_session_get_id(&id);

  /* HASH(K || H || "F" || session_id) */
  letter = 'F';
  set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len);

#if OPENSSL_VERSION_NUMBER > 0x000907000L
  HMAC_CTX_init(mac_ctx);
#else
  /* Reset the HMAC context. */
  HMAC_Init(mac_ctx, NULL, 0, NULL);
#endif
  HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest);

  pr_memscrub(ptr, bufsz);
  return 0;
}
Example #10
0
int sftp_auth_password(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
                       const char *orig_user, const char *user, const char *service,
                       unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) {
    const char *cipher_algo, *mac_algo;
    char *passwd;
    int have_new_passwd, res;
    struct passwd *pw;

    cipher_algo = sftp_cipher_get_read_algo();
    mac_algo = sftp_mac_get_read_algo();

    if (strncmp(cipher_algo, "none", 5) == 0 ||
            strncmp(mac_algo, "none", 5) == 0) {

        if (sftp_opts & SFTP_OPT_ALLOW_INSECURE_LOGIN) {
            (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                    "WARNING: cipher algorithm '%s' or MAC algorithm '%s' INSECURE for "
                                    "password authentication (SFTPOption AllowInsecureLogin in effect)",
                                    cipher_algo, mac_algo);

        } else {
            (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                    "cipher algorithm '%s' or MAC algorithm '%s' unacceptable for "
                                    "password authentication, denying password authentication request",
                                    cipher_algo, mac_algo);
            *send_userauth_fail = TRUE;
            errno = EPERM;
            return 0;
        }
    }

    /* XXX We currently don't do anything with this. */
    have_new_passwd = sftp_msg_read_bool(pkt->pool, buf, buflen);
    if (have_new_passwd) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s",
                                "client says they have provided a new password; this functionality "
                                "is not currently supported");
    }

    passwd = sftp_msg_read_string(pkt->pool, buf, buflen);
    passwd = sftp_utf8_decode_str(pkt->pool, passwd);

    pass_cmd->arg = passwd;

    if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "authentication request for user '%s' blocked by '%s' handler",
                                orig_user, (char *) pass_cmd->argv[0]);

        pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
        pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);

        pr_memscrub(passwd, strlen(passwd));

        *send_userauth_fail = TRUE;
        errno = EPERM;
        return 0;
    }

    pw = pr_auth_getpwnam(pkt->pool, user);
    if (pw == NULL) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "no account for user '%s' found", user);

        pr_log_auth(PR_LOG_NOTICE,
                    "USER %s: no such user found from %s [%s] to %s:%d", user,
                    session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr),
                    pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);

        pr_memscrub(passwd, strlen(passwd));

        *send_userauth_fail = TRUE;
        errno = ENOENT;
        return 0;
    }

    res = pr_auth_authenticate(pkt->pool, user, passwd);
    pr_memscrub(passwd, strlen(passwd));

    switch (res) {
    case PR_AUTH_OK:
        break;

    case PR_AUTH_NOPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: No such user", user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found",
                    user);
        *send_userauth_fail = TRUE;
        errno = ENOENT;
        return 0;

    case PR_AUTH_BADPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Incorrect password",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    case PR_AUTH_AGEPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Password expired",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    case PR_AUTH_DISABLEDPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Account disabled",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    default:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "unknown authentication value (%d), returning error", res);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;
    }

    return 1;
}
Example #11
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;
}
Example #12
0
int sftp_cipher_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
    const char *h, uint32_t hlen) {
  const unsigned char *id = NULL;
  unsigned char *buf, *ptr;
  char letter;
  uint32_t buflen, bufsz, id_len;
  int key_len;
  struct sftp_cipher *cipher;
  EVP_CIPHER_CTX *cipher_ctx;

  switch_write_cipher();

  cipher = &(write_ciphers[write_cipher_idx]);
  cipher_ctx = write_ctxs[write_cipher_idx];

  /* XXX EVP_CIPHER_CTX_init() first appeared in OpenSSL 0.9.7.  What to do
   * for older OpenSSL installations?
   */
  EVP_CIPHER_CTX_init(cipher_ctx);

  bufsz = buflen = SFTP_CIPHER_BUFSZ;
  ptr = buf = sftp_msg_getbuf(p, bufsz);

  /* Need to use SSH2-style format of K for the IV and key. */
  sftp_msg_write_mpint(&buf, &buflen, k);

  id_len = sftp_session_get_id(&id);

  /* IV: HASH(K || H || "B" || session_id) */
  letter = 'B';
  if (set_cipher_iv(cipher, hash, ptr, (bufsz - buflen), h, hlen, &letter, id,
      id_len) < 0) {
    pr_memscrub(ptr, bufsz);
    return -1;
  }

  key_len = (int) cipher->key_len;

  /* Key: HASH(K || H || "D" || session_id) */
  letter = 'D';
  if (set_cipher_key(cipher, hash, ptr, (bufsz - buflen), h, hlen, &letter,
      id, id_len) < 0) {
    pr_memscrub(ptr, bufsz);
    return -1;
  }

  if (EVP_CipherInit(cipher_ctx, cipher->cipher, cipher->key,
      cipher->iv, 1) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error initializing %s cipher for encryption: %s", cipher->algo,
      sftp_crypto_get_errors());
    pr_memscrub(ptr, bufsz);
    return -1;
  }

  if (key_len > 0) {
    /* Next, set the key length. */
    if (EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error setting key length (%d bytes) for %s cipher for decryption: %s",
        key_len, cipher->algo, sftp_crypto_get_errors());
      pr_memscrub(ptr, bufsz);
      return -1;
    }
  }

  if (set_cipher_discarded(cipher, cipher_ctx) < 0) {
    pr_memscrub(ptr, bufsz);
    return -1;
  }

  pr_memscrub(ptr, bufsz);
  return 0;
}