예제 #1
0
파일: cipher.c 프로젝트: proftpd/proftpd
int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
    size_t *buflen) {
  struct sftp_cipher *cipher;
  EVP_CIPHER_CTX *cipher_ctx;

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

  if (cipher->key) {
    int res;
    unsigned char *data, *ptr;
    uint32_t datalen, datasz = sizeof(uint32_t) + pkt->packet_len;

    datalen = datasz;
    ptr = data = palloc(pkt->pool, datasz);

    sftp_msg_write_int(&data, &datalen, pkt->packet_len);
    sftp_msg_write_byte(&data, &datalen, pkt->padding_len);
    sftp_msg_write_data(&data, &datalen, pkt->payload, pkt->payload_len, FALSE);
    sftp_msg_write_data(&data, &datalen, pkt->padding, pkt->padding_len, FALSE);

    res = EVP_Cipher(cipher_ctx, buf, ptr, (datasz - datalen));
    if (res != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error encrypting %s data for client: %s", cipher->algo,
        sftp_crypto_get_errors());
      errno = EIO;
      return -1;
    }

    *buflen = (datasz - datalen);

#ifdef SFTP_DEBUG_PACKET
{
  unsigned int i;

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
    "encrypted packet data (len %lu):", (unsigned long) *buflen);
  for (i = 0; i < *buflen;) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "  %02x%02x %02x%02x %02x%02x %02x%02x",
      ((unsigned char *) buf)[i], ((unsigned char *) buf)[i+1],
      ((unsigned char *) buf)[i+2], ((unsigned char *) buf)[i+3],
      ((unsigned char *) buf)[i+4], ((unsigned char *) buf)[i+5],
      ((unsigned char *) buf)[i+6], ((unsigned char *) buf)[i+7]);
    i += 8;
  }
}
#endif

    return 0;
  }

  *buflen = 0;
  return 0;
}
예제 #2
0
static int send_pubkey_ok(const char *algo, const char *pubkey_data,
    uint32_t pubkey_len) {
  struct ssh2_packet *pkt;
  char *buf, *ptr;
  uint32_t buflen, bufsz;
  int res;

  /* Make sure to allocate a buffer large enough to hold the publickey
   * data we're sending back.
   */
  bufsz = buflen = pubkey_len + 1024;

  pkt = sftp_ssh2_packet_create(sftp_pool);

  buflen = bufsz;
  ptr = buf = palloc(pkt->pool, bufsz);

  sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_PK_OK);
  sftp_msg_write_string(&buf, &buflen, algo);
  sftp_msg_write_data(&buf, &buflen, pubkey_data, pubkey_len, TRUE);

  pkt->payload = ptr;
  pkt->payload_len = (bufsz - buflen);

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sending publickey OK");

  res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt);
  if (res < 0) {
    destroy_pool(pkt->pool);
    return -1;
  }

  destroy_pool(pkt->pool);
  return 0;
}
예제 #3
0
int sftp_auth_hostbased(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) {
  struct passwd *pw;
  char *hostkey_algo, *host_fqdn, *host_user, *host_user_utf8;
  const char *fp = NULL;
  unsigned char *hostkey_data, *signature_data;
  unsigned char *buf2, *ptr2;
  const unsigned char *id;
  uint32_t buflen2, bufsz2, hostkey_datalen, id_len, signature_len;
  enum sftp_key_type_e pubkey_type;

  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);

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

  hostkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
  if (hostkey_algo == NULL) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "missing required host key algorithm, rejecting request");

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

  hostkey_datalen = sftp_msg_read_int(pkt->pool, buf, buflen);
  hostkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, hostkey_datalen);

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

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

  signature_len = sftp_msg_read_int(pkt->pool, buf, buflen);
  signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len);

  pr_trace_msg(trace_channel, 9,
    "client sent '%s' host key, FQDN %s, and remote user '%s'",
    hostkey_algo, host_fqdn, host_user);

  if (strncmp(hostkey_algo, "ssh-rsa", 8) == 0) {
    pubkey_type = SFTP_KEY_RSA;

  } else if (strncmp(hostkey_algo, "ssh-dss", 8) == 0) {
    pubkey_type = SFTP_KEY_DSA;

#ifdef PR_USE_OPENSSL_ECC
  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_256;

  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_384;

  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_521;
#endif /* PR_USE_OPENSSL_ECC */

  /* XXX Need to support X509v3 certs here */

  } else {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unsupported host key algorithm '%s' requested, rejecting request",
      hostkey_algo);

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

  if (sftp_keys_verify_pubkey_type(pkt->pool, hostkey_data, hostkey_datalen,
      pubkey_type) != TRUE) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to verify that given host key matches given '%s' algorithm",
      hostkey_algo);

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

#ifdef OPENSSL_FIPS
  if (FIPS_mode()) {
    fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
      SFTP_KEYS_FP_DIGEST_SHA1);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key SHA1 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key SHA1 fingerprint: %s", strerror(errno));
    }

  } else {
#endif /* OPENSSL_FIPS */
    fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
      SFTP_KEYS_FP_DIGEST_MD5);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key MD5 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key MD5 fingerprint: %s", strerror(errno));
    }
#ifdef OPENSSL_FIPS
  }
#endif /* OPENSSL_FIPS */

  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);

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

  /* XXX Should we check the given FQDN here against the client's actual
   * DNS name and/or IP address?  Or leave that up to the keystore's
   * verify_host_key() function?
   */

  if (sftp_blacklist_reject_key(pkt->pool, hostkey_data, hostkey_datalen)) {
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  /* The client signed the request as well; we need to authenticate the
   * host with the given key now.  If that succeeds, we use the signature to
   * verify the request.  And if that succeeds, then we're done authenticating.
   */

  if (sftp_keystore_verify_host_key(pkt->pool, user, host_fqdn, host_user,
      hostkey_data, hostkey_datalen) < 0) {
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  /* Make sure the signature matches as well. */

  id_len = sftp_session_get_id(&id);

  /* XXX Is this buffer large enough?  Too large? */
  bufsz2 = buflen2 = 2048;
  ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);

  sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE);
  sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST);
  sftp_msg_write_string(&buf2, &buflen2, orig_user);

  if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_HOST_SIG)) {
    sftp_msg_write_string(&buf2, &buflen2, service);

  } else {
    sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth");
  }

  sftp_msg_write_string(&buf2, &buflen2, "hostbased");
  sftp_msg_write_string(&buf2, &buflen2, hostkey_algo);
  sftp_msg_write_data(&buf2, &buflen2, hostkey_data, hostkey_datalen, TRUE);
  sftp_msg_write_string(&buf2, &buflen2, host_fqdn);
  sftp_msg_write_string(&buf2, &buflen2, host_user_utf8);

  if (sftp_keys_verify_signed_data(pkt->pool, hostkey_algo, hostkey_data,
      hostkey_datalen, signature_data, signature_len, (unsigned char *) ptr2,
      (bufsz2 - buflen2)) < 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "failed to verify '%s' signature on hostbased auth request for "
      "user '%s', host %s", hostkey_algo, orig_user, host_fqdn);
    *send_userauth_fail = TRUE;
    return 0;
  }

  /* Make sure the user is authorized to login.  Normally this is checked
   * as part of the password verification process, but in the case of
   * hostbased authentication, there is no password to verify.
   */

  if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "authentication for user '%s' failed: User not authorized", user);
    pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized "
      "for login", user);
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  return 1;
}
예제 #4
0
int sftp_auth_publickey(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
    const char *orig_user, const char *user, const char *service, char **buf,
    uint32_t *buflen, int *send_userauth_fail) {
  int have_signature, pubkey_type;
  char *pubkey_algo = NULL, *pubkey_data;
  const char *fp = NULL;
  uint32_t pubkey_len;
  struct passwd *pw;

  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, pass_cmd->argv[0]);

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

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

  have_signature = sftp_msg_read_bool(pkt->pool, buf, buflen);

  if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
    pubkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
  }
  pubkey_len = sftp_msg_read_int(pkt->pool, buf, buflen);
  pubkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, pubkey_len);

  if (pubkey_algo == NULL) {
    /* The client did not send the string identifying the public key algorithm.
     * Thus we need to extract the algorithm string from the public key data.
     */
    pubkey_algo = sftp_msg_read_string(pkt->pool, &pubkey_data, &pubkey_len);
  }

  pr_trace_msg(trace_channel, 9, "client sent '%s' public key %s",
    pubkey_algo, have_signature ? "with signature" : "without signature");

  if (strncmp(pubkey_algo, "ssh-rsa", 8) == 0) {
    pubkey_type = EVP_PKEY_RSA;

  } else if (strncmp(pubkey_algo, "ssh-dss", 8) == 0) {
    pubkey_type = EVP_PKEY_DSA;

  /* XXX This is where we would add support for X509 public keys, e.g.:
   *
   *  x509v3-ssh-dss
   *  x509v3-ssh-rsa
   *  x509v3-sign (older)
   *
   */

  } else {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unsupported public key algorithm '%s' requested, rejecting request",
      pubkey_algo);

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

  if (sftp_keys_verify_pubkey_type(pkt->pool, pubkey_data, pubkey_len,
      pubkey_type) != TRUE) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to verify that given public key matches given '%s' algorithm",
      pubkey_algo);

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

#ifdef OPENSSL_FIPS
  if (FIPS_mode()) {
    fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len,
      SFTP_KEYS_FP_DIGEST_SHA1);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key SHA1 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key SHA1 fingerprint: %s", strerror(errno));
    }

  } else {
#endif /* OPENSSL_FIPS */
    fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len,
      SFTP_KEYS_FP_DIGEST_MD5);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key MD5 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key MD5 fingerprint: %s", strerror(errno));
    }
#ifdef OPENSSL_FIPS
  }
#endif /* OPENSSL_FIPS */

  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);

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

  if (!have_signature) {
    /* We don't perform the actual authentication just yet; we need to
     * let the client know that the pubkey algorithms are acceptable.
     */
    if (send_pubkey_ok(pubkey_algo, pubkey_data, pubkey_len) < 0) {
      return -1;
    }

    return 0;

  } else {
    const unsigned char *id;
    char *buf2, *ptr2, *signature_data;
    uint32_t buflen2, bufsz2, id_len, signature_len;

    /* XXX This should become a more generic "is this key data
     * usable/acceptable?" check (and take the pubkey_type parameter), so that
     * that is where we would check the validity/usability of an X509v3 cert
     * (if a cert), or if the key is on the blacklist (if a key).
     */

    if (sftp_blacklist_reject_key(pkt->pool, pubkey_data, pubkey_len)) {
      *send_userauth_fail = TRUE;
      errno = EPERM;
      return 0;
    }

    signature_len = sftp_msg_read_int(pkt->pool, buf, buflen);
    signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len);

    /* The client signed the request as well; we need to authenticate the
     * user with the given pubkey now.  If that succeeds, we use the
     * signature to verify the request.  And if that succeeds, then we're
     * done authenticating.
     */

    /* XXX Need to pass the pubkey_type here as well, so that the
     * verification routines can handle different databases of keys/certs.
     * 
     * For X509v3 certs, we will want a way to enforce/restrict which
     * user names can be used with the provided cert.  Perhaps a database
     * mapping cert fingerprints to user names/UIDs?  Configurable callback
     * check (HOOK?), for modules to enforce.
     */

    if (sftp_keystore_verify_user_key(pkt->pool, user, pubkey_data,
        pubkey_len) < 0) {
      *send_userauth_fail = TRUE;
      return 0;
    }

    /* Make sure the signature matches as well. */

    id_len = sftp_session_get_id(&id);

    /* Make sure to allocate a buffer large enough to hold the publickey
     * signature and data we want to send back.
     */
    bufsz2 = buflen2 = pubkey_len + 1024;
    ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);

    sftp_msg_write_data(&buf2, &buflen2, (char *) id, id_len, TRUE);
    sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST);
    sftp_msg_write_string(&buf2, &buflen2, orig_user);

    if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_PUBKEY_SIG)) {
      sftp_msg_write_string(&buf2, &buflen2, service);

    } else {
      sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth");
    }

    if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
      sftp_msg_write_string(&buf2, &buflen2, "publickey");
      sftp_msg_write_bool(&buf2, &buflen2, TRUE);
      sftp_msg_write_string(&buf2, &buflen2, pubkey_algo);

    } else {
      sftp_msg_write_bool(&buf2, &buflen2, TRUE);
    }

    sftp_msg_write_data(&buf2, &buflen2, pubkey_data, pubkey_len, TRUE);

    if (sftp_keys_verify_signed_data(pkt->pool, pubkey_algo, pubkey_data,
        pubkey_len, signature_data, signature_len, (unsigned char *) ptr2,
        (bufsz2 - buflen2)) < 0) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "failed to verify '%s' signature on public key auth request for "
        "user '%s'", pubkey_algo, orig_user);
      *send_userauth_fail = TRUE;
      return 0;
    }
  }

  /* Make sure the user is authorized to login.  Normally this is checked
   * as part of the password verification process, but in the case of
   * publickey authentication, there is no password to verify.
   */

  if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "authentication for user '%s' failed: User not authorized", user);
    pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized "
      "for login", user);
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  return 1;
}
예제 #5
0
파일: tap.c 프로젝트: Distrotech/proftpd
int sftp_tap_send_packet(void) {
  int chance;

  if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) {
    pr_trace_msg(trace_channel, 3,
      "unable to send TAP packet: IGNORE not supported by client");
    return 0;
  }

  if (curr_policy.chance_max == 0) {
    /* The "none" policy is in effect; nothing to do. */
    return 0;
  }

  /* Calculate our odds of sending a tap packet, based on the configured
   * policy.
   */
  if (curr_policy.chance_max != 1) {
    chance = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1));

  } else {
    chance = 1;
  }

  if (chance == curr_policy.chance) {
    unsigned char *rand_data;
    char *buf, *ptr;
    uint32_t bufsz, buflen, rand_datalen;
    struct ssh2_packet *pkt;
    unsigned int max_datalen = 8192;

    if (curr_policy.max_datalen) {
      max_datalen = curr_policy.max_datalen;
    }

    rand_datalen = (uint32_t) (curr_policy.min_datalen + rand() /
      (RAND_MAX / (max_datalen - curr_policy.min_datalen) + 1));

    pr_trace_msg(trace_channel, 20,  "sending random SSH2_MSG_IGNORE message "
      "(%lu bytes) based on '%s' TAP policy", (unsigned long) rand_datalen,
      curr_policy.policy);

    pkt = sftp_ssh2_packet_create(tap_pool);
    bufsz = buflen = rand_datalen + 32;
    ptr = buf = palloc(pkt->pool, bufsz);

    rand_data = palloc(pkt->pool, rand_datalen);

    /* We don't need cryptographically secure random bytes here, just
     * pseudo-random data.
     */
    RAND_pseudo_bytes(rand_data, rand_datalen);

    sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_IGNORE);
    sftp_msg_write_data(&buf, &buflen, (char *) rand_data, rand_datalen, TRUE);

    pkt->payload = ptr;
    pkt->payload_len = (bufsz - buflen);

    if (sftp_ssh2_packet_send(sftp_conn->wfd, pkt) < 0) {
      int xerrno = errno;

      pr_trace_msg(trace_channel, 12,
        "error writing TAP packet: %s", strerror(xerrno));
    }

    destroy_pool(pkt->pool);
  }
 
  return 0;
}
예제 #6
0
파일: mac.c 프로젝트: Distrotech/proftpd
int sftp_mac_write_data(struct ssh2_packet *pkt) {
  struct sftp_mac *mac;
  HMAC_CTX *mac_ctx;

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

  if (mac->key) {
    unsigned char *mac_data;
    char *buf, *ptr;
    uint32_t buflen, bufsz = (sizeof(uint32_t) * 2) + pkt->packet_len,
      mac_len = 0;

    mac_data = pcalloc(pkt->pool, EVP_MAX_MD_SIZE);

    buflen = bufsz;
    ptr = buf = sftp_msg_getbuf(pkt->pool, bufsz);

    sftp_msg_write_int(&buf, &buflen, pkt->seqno);
    sftp_msg_write_int(&buf, &buflen, pkt->packet_len);
    sftp_msg_write_byte(&buf, &buflen, pkt->padding_len);
    sftp_msg_write_data(&buf, &buflen, pkt->payload, pkt->payload_len, FALSE);
    sftp_msg_write_data(&buf, &buflen, pkt->padding, pkt->padding_len, FALSE);

#if OPENSSL_VERSION_NUMBER > 0x000907000L
# if OPENSSL_VERSION_NUMBER >= 0x10000001L
    if (HMAC_Init_ex(mac_ctx, NULL, 0, NULL, NULL) != 1) {
      pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error resetting HMAC context: %s", sftp_crypto_get_errors());
      errno = EPERM;
      return -1;
    }
# else
    HMAC_Init_ex(mac_ctx, NULL, 0, NULL, NULL);
# endif /* OpenSSL-1.0.0 and later */

#else
    HMAC_Init(mac_ctx, NULL, 0, NULL);
#endif /* OpenSSL-0.9.7 and later */

#if OPENSSL_VERSION_NUMBER >= 0x10000001L
    if (HMAC_Update(mac_ctx, (unsigned char *) ptr, (bufsz - buflen)) != 1) {
      pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error adding %lu bytes of data to  HMAC context: %s",
        (unsigned long) (bufsz - buflen), sftp_crypto_get_errors());
      errno = EPERM;
      return -1;
    }

    if (HMAC_Final(mac_ctx, mac_data, &mac_len) != 1) {
      pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error finalizing HMAC context: %s", sftp_crypto_get_errors());
      errno = EPERM;
      return -1;
    }
#else
    HMAC_Update(mac_ctx, (unsigned char *) ptr, (bufsz - buflen));
    HMAC_Final(mac_ctx, mac_data, &mac_len);
#endif /* OpenSSL-1.0.0 and later */

    if (mac_len == 0) {
      pkt->mac = NULL;
      pkt->mac_len = 0;

      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error computing MAC using %s: %s", mac->algo,
        sftp_crypto_get_errors());
      return -1;
    }

    if (mac->mac_len != 0) {
      mac_len = mac->mac_len;
    }

    pkt->mac_len = mac_len;
    pkt->mac = pcalloc(pkt->pool, pkt->mac_len);
    memcpy(pkt->mac, mac_data, mac_len);

#ifdef SFTP_DEBUG_PACKET
{
  unsigned int i;

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
    "server MAC (len %lu, seqno %lu):",
    (unsigned long) pkt->mac_len, (unsigned long) pkt->seqno);
  for (i = 0; i < mac_len;) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "  %02x%02x %02x%02x %02x%02x %02x%02x",
      ((unsigned char *) pkt->mac)[i], ((unsigned char *) pkt->mac)[i+1],
      ((unsigned char *) pkt->mac)[i+2], ((unsigned char *) pkt->mac)[i+3],
      ((unsigned char *) pkt->mac)[i+4], ((unsigned char *) pkt->mac)[i+5],
      ((unsigned char *) pkt->mac)[i+6], ((unsigned char *) pkt->mac)[i+7]);
    i += 8;
  }
}
#endif

    return 0;
  }

  pkt->mac = NULL;
  pkt->mac_len = 0;

  return 0;
}
예제 #7
0
파일: agent.c 프로젝트: UIKit0/proftpd
const unsigned char *sftp_agent_sign_data(pool *p, const char *agent_path,
    const unsigned char *key_data, uint32_t key_datalen,
    const unsigned char *data, uint32_t datalen, uint32_t *sig_datalen) {
  int fd;
  unsigned char *buf, *req, *resp, *sig_data;
  uint32_t buflen, flags, reqlen, reqsz, resplen;
  char resp_status;

  fd = agent_connect(agent_path);
  if (fd < 0) {
    return NULL;
  }

  /* XXX When to set flags to OLD_SIGNATURE? */
  flags = 0;

  /* Write out the request for signing the given data. */
  reqsz = buflen = 1 + key_datalen + 4 + datalen + 4 + 4;
  req = buf = palloc(p, reqsz);

  sftp_msg_write_byte(&buf, &buflen, SFTP_SSH_AGENT_REQ_SIGN_DATA);
  sftp_msg_write_data(&buf, &buflen, key_data, key_datalen, TRUE);
  sftp_msg_write_data(&buf, &buflen, data, datalen, TRUE);
  sftp_msg_write_int(&buf, &buflen, flags);

  reqlen = reqsz - buflen;
  resp = agent_request(p, fd, agent_path, req, reqlen, &resplen);
  if (resp == NULL) {
    int xerrno = errno;

    (void) close(fd);
    errno = xerrno;
    return NULL;
  }

  (void) close(fd);

  /* Read the response from the agent. */
 
  resp_status = sftp_msg_read_byte(p, &resp, &resplen); 
  if (agent_failure(resp_status) == TRUE) {
    pr_trace_msg(trace_channel, 5,
      "SSH agent at '%s' indicated failure (%d) for data signing request",
      agent_path, resp_status);
    errno = EPERM;
    return NULL;
  }

  if (resp_status != SFTP_SSH_AGENT_RESP_SIGN_DATA) {
    pr_trace_msg(trace_channel, 5,
      "unknown response type %d from SSH agent at '%s'", resp_status,
      agent_path);
    errno = EACCES;
    return NULL;
  }

  *sig_datalen = sftp_msg_read_int(p, &resp, &resplen);
  sig_data = sftp_msg_read_data(p, &resp, &resplen, *sig_datalen);

  return sig_data; 
}