+ if (s->publickey_blob && !s->tried_publickey) {
+ /*
+ * Try public key authentication with the specified
+ * key file.
+ */
+ int got_passphrase; /* need not be kept over crReturn */
+ if (flags & FLAG_VERBOSE)
+ c_write_str(ssh, "Trying public key authentication.\r\n");
+ s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);
+ logeventf(ssh, "Trying public key \"%s\"",
+ filename_to_str(s->keyfile));
+ s->tried_publickey = 1;
+ got_passphrase = FALSE;
+ while (!got_passphrase) {
+ /*
+ * Get a passphrase, if necessary.
+ */
+ char *passphrase = NULL; /* only written after crReturn */
+ const char *error;
+ if (!s->publickey_encrypted) {
+ if (flags & FLAG_VERBOSE)
+ c_write_str(ssh, "No passphrase required.\r\n");
+ passphrase = NULL;
+ } else {
+ int ret; /* need not be kept over crReturn */
+ s->cur_prompt = new_prompts(ssh->frontend);
+ s->cur_prompt->to_server = FALSE;
+ s->cur_prompt->name = dupstr("SSH key passphrase");
+ add_prompt(s->cur_prompt,
+ dupprintf("Passphrase for key \"%.100s\": ",
+ s->publickey_comment), FALSE);
+ ret = get_userpass_input(s->cur_prompt, NULL, 0);
+ while (ret < 0) {
+ ssh->send_ok = 1;
+ crWaitUntil(!pktin);
+ ret = get_userpass_input(s->cur_prompt, in, inlen);
+ ssh->send_ok = 0;
+ }
+ if (!ret) {
+ /* Failed to get a passphrase. Terminate. */
+ free_prompts(s->cur_prompt);
+ ssh_disconnect(ssh, NULL, "Unable to authenticate",
+ 0, TRUE);
+ crStop(0);
+ }
+ passphrase = dupstr(s->cur_prompt->prompts[0]->result);
+ free_prompts(s->cur_prompt);
+ }
+ /*
+ * Try decrypting key with passphrase.
+ */
+ s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);
+ ret = loadrsakey(s->keyfile, &s->key, passphrase,
+ &error);
+ if (passphrase) {
+ memset(passphrase, 0, strlen(passphrase));
+ sfree(passphrase);
+ }
+ if (ret == 1) {
+ /* Correct passphrase. */
+ got_passphrase = TRUE;
+ } else if (ret == 0) {
+ c_write_str(ssh, "Couldn't load private key from ");
+ c_write_str(ssh, filename_to_str(s->keyfile));
+ c_write_str(ssh, " (");
+ c_write_str(ssh, error);
+ c_write_str(ssh, ").\r\n");
+ got_passphrase = FALSE;
+ break; /* go and try something else */
+ } else if (ret == -1) {
+ c_write_str(ssh, "Wrong passphrase.\r\n"); /* FIXME */
+ got_passphrase = FALSE;
+ /* and try again */
+ } else {
+ assert(0 && "unexpected return from loadrsakey()");
+ got_passphrase = FALSE; /* placate optimisers */
+ }
+ }
+
+ if (got_passphrase) {
+
+ /*
+ * Send a public key attempt.
+ */
+ send_packet(ssh, SSH1_CMSG_AUTH_RSA,
+ PKT_BIGNUM, s->key.modulus, PKT_END);
+
+ crWaitUntil(pktin);
+ if (pktin->type == SSH1_SMSG_FAILURE) {
+ c_write_str(ssh, "Server refused our public key.\r\n");
+ continue; /* go and try something else */
+ }
+ if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+ bombout(("Bizarre response to offer of public key"));
+ crStop(0);
+ }
+
+ {
+ int i;
+ unsigned char buffer[32];
+ Bignum challenge, response;
+
+ if ((challenge = ssh1_pkt_getmp(pktin)) == NULL) {
+ bombout(("Server's RSA challenge was badly formatted"));
+ crStop(0);
+ }
+ response = rsadecrypt(challenge, &s->key);
+ freebn(s->key.private_exponent);/* burn the evidence */
+
+ for (i = 0; i < 32; i++) {
+ buffer[i] = bignum_byte(response, 31 - i);
+ }
+
+ MD5Init(&md5c);
+ MD5Update(&md5c, buffer, 32);
+ MD5Update(&md5c, s->session_id, 16);
+ MD5Final(buffer, &md5c);
+
+ send_packet(ssh, SSH1_CMSG_AUTH_RSA_RESPONSE,
+ PKT_DATA, buffer, 16, PKT_END);
+
+ freebn(challenge);
+ freebn(response);
+ }
+
+ crWaitUntil(pktin);
+ if (pktin->type == SSH1_SMSG_FAILURE) {
+ if (flags & FLAG_VERBOSE)
+ c_write_str(ssh, "Failed to authenticate with"
+ " our public key.\r\n");
+ continue; /* go and try something else */
+ } else if (pktin->type != SSH1_SMSG_SUCCESS) {
+ bombout(("Bizarre response to RSA authentication response"));
+ crStop(0);
+ }
+
+ break; /* we're through! */
+ }
+
+ }