static void torture_pubkey_generate_from_privkey(void **state) {
    ssh_session session = *state;
    ssh_private_key privkey = NULL;
    ssh_public_key pubkey = NULL;
    ssh_string pubkey_orig = NULL;
    ssh_string pubkey_new = NULL;
    char pubkey_line_orig[512] = {0};
    char pubkey_line_new[512] = {0};
    int type_orig = 0;
    int type_new = 0;
    int rc;

    /* read the publickey */
    rc = ssh_try_publickey_from_file(session, LIBSSH_RSA_TESTKEY, &pubkey_orig,
        &type_orig);
    assert_true(rc == 0);
    assert_true(pubkey_orig != NULL);

    rc = torture_read_one_line(LIBSSH_RSA_TESTKEY ".pub", pubkey_line_orig,
        sizeof(pubkey_line_orig));
    assert_true(rc == 0);

    /* remove the public key, generate it from the private key and write it. */
    unlink(LIBSSH_RSA_TESTKEY ".pub");

    privkey = privatekey_from_file(session, LIBSSH_RSA_TESTKEY, 0, NULL);
    assert_true(privkey != NULL);

    pubkey = publickey_from_privatekey(privkey);
    assert_true(pubkey != NULL);
    type_new = privkey->type;
    privatekey_free(privkey);

    pubkey_new = publickey_to_string(pubkey);
    publickey_free(pubkey);

    assert_true(pubkey_new != NULL);

    assert_true(ssh_string_len(pubkey_orig) == ssh_string_len(pubkey_new));
    assert_memory_equal(ssh_string_data(pubkey_orig),
                        ssh_string_data(pubkey_new),
                        ssh_string_len(pubkey_orig));

    rc = ssh_publickey_to_file(session, LIBSSH_RSA_TESTKEY ".pub", pubkey_new, type_new);
    assert_true(rc == 0);

    rc = torture_read_one_line(LIBSSH_RSA_TESTKEY ".pub", pubkey_line_new,
        sizeof(pubkey_line_new));
    assert_true(rc == 0);

    assert_string_equal(pubkey_line_orig, pubkey_line_new);

    ssh_string_free(pubkey_orig);
    ssh_string_free(pubkey_new);
}
Example #2
0
/**
 * @brief Tries to automaticaly authenticate with public key and "none"
 *
 * It may fail, for instance it doesn't ask for a password and uses a default
 * asker for passphrases (in case the private key is encrypted).
 *
 * @param session       The ssh session to authenticate with.
 *
 * @param passphrase    Use this passphrase to unlock the privatekey. Use NULL
 *                      if you don't want to use a passphrase or the user
 *                      should be asked.
 *
 * @returns SSH_AUTH_ERROR:   A serious error happened\n
 *          SSH_AUTH_DENIED:  Authentication failed: use another method\n
 *          SSH_AUTH_PARTIAL: You've been partially authenticated, you still
 *                            have to use another method\n
 *          SSH_AUTH_SUCCESS: Authentication success
 *
 * @see ssh_userauth_kbdint()
 * @see ssh_userauth_password()
 */
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
  struct ssh_iterator *it;
  ssh_private_key privkey;
  ssh_public_key pubkey;
  ssh_string pubkey_string;
  int type = 0;
  int rc;

  enter_function();

  /* Always test none authentication */
  rc = ssh_userauth_none(session, NULL);
  if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
    leave_function();
    return rc;
  }

  /* Try authentication with ssh-agent first */
#ifndef _WIN32
  if (agent_is_running(session)) {
    char *privkey_file = NULL;

    ssh_log(session, SSH_LOG_RARE,
        "Trying to authenticate with SSH agent keys as user: %s",
        session->username);

    for (pubkey = agent_get_first_ident(session, &privkey_file);
        pubkey != NULL;
        pubkey = agent_get_next_ident(session, &privkey_file)) {

      ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkey_file);

      pubkey_string = publickey_to_string(pubkey);
      if (pubkey_string) {
        rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string);
        string_free(pubkey_string);
        if (rc == SSH_AUTH_ERROR) {
          SAFE_FREE(privkey_file);
          publickey_free(pubkey);
          leave_function();

          return rc;
        } else if (rc != SSH_AUTH_SUCCESS) {
          ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server");
          SAFE_FREE(privkey_file);
          publickey_free(pubkey);
          continue;
        }
        ssh_log(session, SSH_LOG_RARE, "Public key accepted");
        /* pubkey accepted by server ! */
        rc = ssh_userauth_agent_pubkey(session, NULL, pubkey);
        if (rc == SSH_AUTH_ERROR) {
          SAFE_FREE(privkey_file);
          publickey_free(pubkey);
          leave_function();

          return rc;
        } else if (rc != SSH_AUTH_SUCCESS) {
          ssh_log(session, SSH_LOG_RARE,
              "Server accepted public key but refused the signature ;"
              " It might be a bug of libssh");
          SAFE_FREE(privkey_file);
          publickey_free(pubkey);
          continue;
        }
        /* auth success */
        ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success",
            privkey_file);
        SAFE_FREE(privkey_file);
        publickey_free(pubkey);

        leave_function();

        return SSH_AUTH_SUCCESS;
      } /* if pubkey */
      SAFE_FREE(privkey_file);
      publickey_free(pubkey);
    } /* for each privkey */
  } /* if agent is running */
#endif


  for (it = ssh_list_get_iterator(session->identity);
       it != NULL;
       it = it->next) {
    const char *privkey_file = it->data;
    int privkey_open = 0;

    privkey = NULL;

    ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file);

    rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type);
    if (rc == 1) {
      char *publickey_file;
      size_t len;

      privkey = privatekey_from_file(session, privkey_file, type, passphrase);
      if (privkey == NULL) {
        ssh_log(session, SSH_LOG_RARE,
          "Reading private key %s failed (bad passphrase ?)",
          privkey_file);
        leave_function();
        return SSH_AUTH_ERROR;
      }
      privkey_open = 1;

      pubkey = publickey_from_privatekey(privkey);
      if (pubkey == NULL) {
        privatekey_free(privkey);
        ssh_set_error_oom(session);
        leave_function();
        return SSH_AUTH_ERROR;
      }

      pubkey_string = publickey_to_string(pubkey);
      type = pubkey->type;
      publickey_free(pubkey);
      if (pubkey_string == NULL) {
        ssh_set_error_oom(session);
        leave_function();
        return SSH_AUTH_ERROR;
      }

      len = strlen(privkey_file) + 5;
      publickey_file = malloc(len);
      if (publickey_file == NULL) {
        ssh_set_error_oom(session);
        leave_function();
        return SSH_AUTH_ERROR;
      }
      snprintf(publickey_file, len, "%s.pub", privkey_file);
      rc = ssh_publickey_to_file(session, publickey_file, pubkey_string, type);
      if (rc < 0) {
        ssh_log(session, SSH_LOG_PACKET,
            "Could not write public key to file: %s", publickey_file);
      }
      SAFE_FREE(publickey_file);
    } else if (rc < 0) {
      continue;
    }

    rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey_string);
    if (rc == SSH_AUTH_ERROR){
      string_free(pubkey_string);
      ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
      leave_function();
      return rc;
    } else {
      if (rc != SSH_AUTH_SUCCESS){
        ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server");
        string_free(pubkey_string);
        continue;
      }
    }

    /* Public key accepted by server! */
    if (!privkey_open) {
      ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s",
          privkey_file);
      privkey = privatekey_from_file(session, privkey_file, type, passphrase);
      if (privkey == NULL) {
        ssh_log(session, SSH_LOG_RARE,
            "Reading private key %s failed (bad passphrase ?)",
            privkey_file);
        string_free(pubkey_string);
        continue; /* continue the loop with other pubkey */
      }
    }

    rc = ssh_userauth_pubkey(session, NULL, pubkey_string, privkey);
    if (rc == SSH_AUTH_ERROR) {
      string_free(pubkey_string);
      privatekey_free(privkey);
      leave_function();
      return rc;
    } else {
      if (rc != SSH_AUTH_SUCCESS){
        ssh_log(session, SSH_LOG_FUNCTIONS,
            "The server accepted the public key but refused the signature");
        string_free(pubkey_string);
        privatekey_free(privkey);
        continue;
      }
    }

    /* auth success */
    ssh_log(session, SSH_LOG_PROTOCOL,
        "Successfully authenticated using %s", privkey_file);
    string_free(pubkey_string);
    privatekey_free(privkey);

    leave_function();
    return SSH_AUTH_SUCCESS;
  }

  /* at this point, pubkey is NULL and so is privkeyfile */
  ssh_log(session, SSH_LOG_FUNCTIONS,
      "Tried every public key, none matched");
  ssh_set_error(session,SSH_NO_ERROR,"No public key matched");

  leave_function();
  return SSH_AUTH_DENIED;
}