Пример #1
0
void signer_received_packet(SshPacketType type,
                            const unsigned char *data, size_t len,
                            void *context)
{
    /* Received. */
    unsigned int msg_byte; /* This is unsigned int because
                            SSH_FORMAT_CHAR expects uint; caused a
                            rather nasty bug during development (I
                            used SshUInt8, which wasn't long
                            enough => ssh_decode_array blew the
                            stack).*/
    char *userauth_str, *hostbased_str, *recv_pubkey_alg, *recv_hostname;
    char *recv_username;
    unsigned char *recv_pubkeyblob;
    size_t recv_pubkeyblob_len;
    /* Dug up by us. */
    char *pubkey_alg, *hostname, *username;
    unsigned char *pubkeyblob;
    size_t pubkeyblob_len;
    size_t hostname_len;

    /* Internal stuff*/
    SshSigner signer = (SshSigner) context;
    char hostkeyfile[512];
    char *comment;
    SshPrivateKey privkey;
    size_t sig_len, length_return;
    unsigned char *signature_buffer;
    SshCryptoStatus result;
    SshUser real_user;

    SSH_TRACE(2, ("Packet received."));

    switch(type)
    {
    case SSH_AUTH_HOSTBASED_PACKET:
        /* Check packet out, and if it's ok, sign it and send
           signature to ssh2. */

#ifdef HEXDUMPS
        SSH_DEBUG_HEXDUMP(3, ("packet:"), \
                          data, len);
#endif /* HEXDUMPS */

        if (ssh_decode_array(data, len,
                             /* session id */
                             SSH_FORMAT_UINT32_STR, NULL, NULL,
                             /* SSH_MSG_USERAUTH_REQUEST (must be checked)*/
                             SSH_FORMAT_CHAR, &msg_byte,
                             /* user name */
                             SSH_FORMAT_UINT32_STR, NULL, NULL,
                             /* service "ssh-userauth" (must be checked)*/
                             SSH_FORMAT_UINT32_STR, &userauth_str, NULL,
                             /* "hostbased" (must be checked)*/
                             SSH_FORMAT_UINT32_STR, &hostbased_str, NULL,
                             /* public key algorithm for hostkey (must
                                be checked)*/
                             SSH_FORMAT_UINT32_STR, &recv_pubkey_alg, NULL,
                             /* public hostkey and certificates (must be
                                checked)*/
                             SSH_FORMAT_UINT32_STR, &recv_pubkeyblob,
                             &recv_pubkeyblob_len,
                             /* client host name (must be checked)*/
                             SSH_FORMAT_UINT32_STR, &recv_hostname, NULL,
                             /* user name on client host (must be checked) */
                             SSH_FORMAT_UINT32_STR, &recv_username, NULL,
                             SSH_FORMAT_END) != len || len == 0)
        {
            /* There was an error. */
            SSH_TRACE(0, ("Invalid packet."));
            goto error;
        }

        /* Get pubkeyblob, pubkeyblob_len, pubkey_alg, hostname and
           username. */

        /* Dig up hosts publickey. */
        if(signer->config->public_host_key_file[0] != '/')
        {
            snprintf(hostkeyfile, sizeof(hostkeyfile), "%s/%s", SSH_SERVER_DIR,
                     signer->config->public_host_key_file);
        }
        else
        {
            snprintf(hostkeyfile, sizeof(hostkeyfile), "%s",
                     signer->config->public_host_key_file);
        }

        SSH_TRACE(2, ("place to look for public key: %s", hostkeyfile));

        /* This pubkey*-stuff is for the client _host's_ public
           hostkey. */
        /* Getting pubkeyblob, pubkeyblob_len */
        SSH_DEBUG(4, ("Reading pubkey-blob from %s...", hostkeyfile));
        if (ssh2_key_blob_read(signer->effective_user_data, hostkeyfile, NULL,
                               &pubkeyblob,
                               &pubkeyblob_len, NULL)
                != SSH_KEY_MAGIC_PUBLIC)
        {
            SSH_TRACE(1, ("Reading public key failed."));
            goto error;
        }

        SSH_DEBUG(4, ("done."));

        if ((pubkey_alg =
                    ssh_pubkeyblob_type(pubkeyblob, pubkeyblob_len))
                == NULL)
        {
            SSH_TRACE(1, ("Couldn't figure out public key algorithm."));
            goto error;
        }

        /* Getting hostname. */
        hostname = ssh_xmalloc(MAXHOSTNAMELEN + 1);
        ssh_tcp_get_host_name(hostname, MAXHOSTNAMELEN + 1);
        hostname_len = strlen(hostname);
        /* Sanity check */
        SSH_ASSERT(hostname_len + 2 < MAXHOSTNAMELEN);
        /* We want FQDN. */
        hostname[hostname_len] = '.';
        hostname[hostname_len + 1] = '\0';

        /* Getting username. */
        real_user = ssh_user_initialize(NULL, FALSE);
        username = ssh_xstrdup(ssh_user_name(real_user));
        ssh_user_free(real_user, FALSE);

        /* Check all parameters. */
        if (msg_byte != SSH_MSG_USERAUTH_REQUEST)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("msg_byte != SSH_MSG_USERAUTH_REQUEST " \
                          "(msg_byte = %d)", msg_byte));
            goto error;
        }
        if (strcmp(userauth_str, SSH_USERAUTH_SERVICE) != 0)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("userauth_str != \"ssh-userauth\" (it was '%s')", \
                          userauth_str));
            goto error;
        }
        if (strcmp(hostbased_str, SSH_AUTH_HOSTBASED) != 0)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("hostbased_str != \"hostbased\" (it was '%s')", \
                          hostbased_str));
            goto error;
        }
        /* XXX has to be change when adding support for multiple hostkeys */
        if (strcmp(recv_pubkey_alg, pubkey_alg) != 0)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("Client gave us invalid pubkey-algorithms for our " \
                          "hostkey."));
            goto error;
        }

        if (recv_pubkeyblob_len == pubkeyblob_len)
        {
            if (memcmp(recv_pubkeyblob, pubkeyblob, pubkeyblob_len) != 0)
            {
                SSH_TRACE(1, ("Invalid packet."));
                SSH_DEBUG(1, ("client gave us wrong (or corrupted) " \
                              "public key."));
#ifdef HEXDUMPS
                SSH_DEBUG_HEXDUMP(3, ("client gave us:"), \
                                  recv_pubkeyblob, pubkeyblob_len);
                SSH_DEBUG_HEXDUMP(3, ("our pubkey:"), \
                                  recv_pubkeyblob, pubkeyblob_len);
#endif /* HEXDUMPS */
                goto error;
            }
        }
        else
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("Client gave us wrong (or corrupted) public key. " \
                          "Lengths differ (received: %d ; ours: %d)", \
                          recv_pubkeyblob_len, pubkeyblob_len));
            goto error;
        }

        if (strcmp(recv_hostname, hostname) != 0)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("Wethinks the client gave us the wrong hostname. " \
                          "(client's opinion: '%s' ours: '%s'", \
                          recv_hostname, hostname));
            goto error;
        }
        if (strcmp(recv_username, username) != 0)
        {
            SSH_TRACE(1, ("Invalid packet."));
            SSH_DEBUG(1, ("Client definitely gave us the wrong user name. " \
                          "(it says: '%s' we know: '%s')", recv_username, \
                          username));
            goto error;
        }

        /* Sign the packet and send it to client. */

        /* If we've gotten this far, the packet is ok, and it can be
           signed. */

        SSH_TRACE(0, ("Received packet ok."));
        if(signer->config->public_host_key_file[0] != '/')
        {
            snprintf(hostkeyfile, sizeof(hostkeyfile), "%s/%s", SSH_SERVER_DIR,
                     signer->config->host_key_file);
        }
        else
        {
            snprintf(hostkeyfile, sizeof(hostkeyfile), "%s",
                     signer->config->host_key_file);
        }

        SSH_TRACE(2, ("place to look for private key: %s", hostkeyfile));

        if ((privkey = ssh_privkey_read(signer->effective_user_data, hostkeyfile, "",
                                        &comment, NULL)) == NULL)
            ssh_fatal("ssh_privkey_read from %s failed.", hostkeyfile);

        /* Check how big a chunk our private key can sign (this is
           purely a sanity check, as both of our signature schemas do
           their own hashing) */
        sig_len = ssh_private_key_max_signature_input_len(privkey);

        SSH_TRACE(2, ("max input length for signing: %d", sig_len));

        if (sig_len == 0)
        {
            SSH_TRACE(0, ("private key not capable of signing! " \
                          "(definitely an error)"));
            goto error;
        }
        else if (sig_len != -1 && sig_len < len)
        {
            SSH_TRACE(0, ("private key can't sign our data. (too much " \
                          "data (data_len %d, max input len for signing " \
                          "%d))", len, sig_len));
            goto error;
        }

        /* Now check how much we much buffer we must allocate for the
           signature. */
        sig_len = ssh_private_key_max_signature_output_len(privkey);

        SSH_TRACE(2, ("max output length for signature: %d", sig_len));

        signature_buffer = ssh_xcalloc(sig_len, sizeof(unsigned char));

        /* Do the actual signing. */

#ifdef HEXDUMPS
        SSH_DEBUG_HEXDUMP(5, ("Signing following data"),
                          data + 4, len - 4);
#endif /* HEXDUMPS */

        if ((result = ssh_private_key_sign(privkey,
                                           data,
                                           len,
                                           signature_buffer,
                                           sig_len,
                                           &length_return,
                                           signer->random_state))
                != SSH_CRYPTO_OK)
        {
            SSH_TRACE(0, ("ssh_private_key_sign() returned %d.", result));
            goto error;
        }

#ifdef HEXDUMPS
        SSH_DEBUG_HEXDUMP(5, ("Signature"), signature_buffer, length_return);
#endif /* HEXDUMPS */
        /* Send it to client. */
        signer->packet_payload = signature_buffer;
        signer->packet_payload_len = length_return;
        signer->packet_waiting = TRUE;

        if (ssh_packet_wrapper_can_send(signer->wrapper))
            signer_can_send(signer);

        /* XXX free dynamically allocated data. */
        ssh_xfree(username);

        break;
    case SSH_AUTH_HOSTBASED_SIGNATURE:
        /* We shouldn't get this type of packet. This is an error.*/
        SSH_TRACE(0, ("client sent us SSH_AUTH_HOSTBASED_SIGNATURE. This " \
                      "is an error."));
        goto error;
        break;
    case SSH_AUTH_HOSTBASED_ERROR:
        /* We shouldn't be getting this either. This is an error. */
        SSH_TRACE(0, ("client sent us SSH_AUTH_HOSTBASED_SIGNATURE_ERROR. " \
                      "This is an error. (This message can be sent by " \
                      "ssh-signer2 only)"));
        goto error;
        break;
    }
    return;

    /* We come here after errors. */
error:
    /* Send error message to ssh2, and wait for ssh2 to send
       EOF. */
    ssh_packet_wrapper_send_encode(signer->wrapper, SSH_AUTH_HOSTBASED_ERROR,
                                   SSH_FORMAT_END);

    /* Init a 5 second timeout. If ssh2 hasn't disconnected at
       that time, close stream.*/
    ssh_register_timeout(5L, 0L, signer_destroy_timeout, signer);

    return;
}
Пример #2
0
void add_file(SshAgent agent, const char *filename)
{
  SshPrivateKey key = NULL;
  char *saved_comment, *comment = NULL, *pass;
  int query_cnt;
  unsigned char *certs = NULL;
  size_t certs_len;
  char privname[500], pubname[500];
  unsigned long magic;
  struct stat st;

  if (action == ADD_URL)
    {
      printf("Adding URL identity: %s\n", filename);
      snprintf(privname, sizeof(privname), "%s", filename);
      if (have_attrs)
        ssh_agent_add_with_attrs(agent, NULL, NULL, 0, privname,
                                 path_limit, path_constraint, use_limit,
                                 forbid_compat, key_timeout,
                                 agent_completion, (void *)agent);
      else
        ssh_agent_add(agent, NULL, NULL, 0, privname,
                      agent_completion, (void *)agent);
      return;
    }
  else if (action == DELETE_URL)
    {
      printf("Deleting URL identity: %s\n", filename);
      snprintf(privname, sizeof(privname), "%s", filename);
      ssh_agent_delete(agent, NULL, 0, privname,
                       agent_completion, (void *)agent);
      return;
    }
#ifdef WITH_PGP
  if (pgp_mode == PGP_KEY_NONE)
#endif /* WITH_PGP */
    {
      /* Construct the names of the public and private key files. */
      if (strlen(filename) > 4 &&
          strcmp(filename + strlen(filename) - 4, ".pub") == 0)
        {
          snprintf(pubname, sizeof(pubname), "%s", filename);
          snprintf(privname, sizeof(privname), "%s", filename);
          privname[strlen(privname) - 4] = '\0';
        }
      else
        {
          snprintf(pubname, sizeof(pubname), "%s.pub", filename);
          snprintf(privname, sizeof(privname), "%s", filename);
        }
    
      if (action == ADD)
        printf("Adding identity: %s\n", pubname);
      else if (action == DELETE)
        printf("Deleting identity: %s\n", pubname);
    
      if (stat(pubname, &st) < 0)
        {
          printf("Public key file %s does not exist.\n", pubname);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      if (stat(privname, &st) < 0)
        {
          printf("Private key file %s does not exist.\n", privname);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      /* Read the public key blob. */
      magic = ssh2_key_blob_read(user, 
                                 pubname,
                                 TRUE,
                                 &saved_comment,
                                 &certs, 
                                 &certs_len,
                                 NULL);
      if (magic != SSH_KEY_MAGIC_PUBLIC)
        {
          printf("Bad public key file %s\n", pubname);
          ssh_xfree(certs);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
    
      if (action == ADD)
        {
          /* Loop until we manage to load the file, or a maximum number of
             attempts have been made.  First try with an empty passphrase. */
          pass = ssh_xstrdup("");
          query_cnt = 0;
          while ((key = ssh_privkey_read(user, 
                                         privname,
                                         pass, 
                                         &comment, 
                                         NULL)) == NULL)
            {
              char buf[1024];
              FILE *f;
            
              /* Free the old passphrase. */
              memset(pass, 0, strlen(pass));
              ssh_xfree(pass);
            
              query_cnt++;
              if (query_cnt > 5)
                {
                  fprintf(stderr,
                          "You don't seem to know the correct passphrase.\n");
                  exit(EXIT_STATUS_BADPASS);
                }
            
              /* Ask for a passphrase. */
              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
                {
                  snprintf(buf, sizeof(buf),
                           "ssh-askpass2 '%sEnter passphrase for %.100s'", 
                           ((query_cnt <= 1) ? 
                            "" : 
                            "You entered wrong passphrase.  "), 
                           saved_comment);
                  f = popen(buf, "r");
                  if (!fgets(buf, sizeof(buf), f))
                    {
                      pclose(f);
                      ssh_xfree(saved_comment);
                      exit(EXIT_STATUS_BADPASS);
                    }
                  pclose(f);
                  if (strchr(buf, '\n'))
                    *strchr(buf, '\n') = 0;
                  pass = ssh_xstrdup(buf);
                }
              else
                {
                  if (query_cnt <= 1)
                    {
                      if ((strcmp(privname, saved_comment) == 0) ||
                          (((strlen(privname) + 4) == strlen(saved_comment)) &&
                           (strncmp(privname, 
                                    saved_comment, 
                                    strlen(privname)) == 0)))
                        {
                          printf("Need passphrase for %s.\n", 
                                 privname);
                        }
                      else
                        {
                          printf("Need passphrase for %s (%s).\n", 
                                 privname, saved_comment);
                        }
                    }
                  else
                    {
                      printf("Bad passphrase.\n");
                    }
                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
                  if (pass == NULL || strcmp(pass, "") == 0)
                    {
                      ssh_xfree(saved_comment);
                      ssh_xfree(pass);
                      exit(EXIT_STATUS_BADPASS);
                    }
                }
            }
          memset(pass, 0, strlen(pass));
          ssh_xfree(pass);
          ssh_xfree(saved_comment);
          /* Construct a comment for the key by combining file name and
             comment in the file. */
          if ((saved_comment = strrchr(privname, '/')) != NULL)
            saved_comment++;
          else
            saved_comment = privname;
          saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
        }
      else
        {
          /* Construct a comment for the key by combining file name and
             comment in the file. */
          if ((saved_comment = strrchr(privname, '/')) != NULL)
            saved_comment++;
          else
            saved_comment = privname;
          if (comment)
            saved_comment = ssh_string_concat_3(saved_comment, ": ", comment);
          else
            saved_comment = ssh_xstrdup(saved_comment);
        }
    
      if (action == ADD)
        {
          /* Send the key to the authentication agent. */
          if (have_attrs)
            ssh_agent_add_with_attrs(agent, key, certs, certs_len, 
                                     saved_comment, path_limit, 
                                     path_constraint, use_limit,
                                     forbid_compat, key_timeout,
                                     agent_completion, (void *)agent);
          else
            ssh_agent_add(agent, key, certs, certs_len, saved_comment,
                          agent_completion, (void *)agent);
          ssh_private_key_free(key);
        }
      else if (action == DELETE)
        {
          ssh_agent_delete(agent, certs, certs_len, saved_comment,
                           agent_completion, (void *)agent);
        }
      ssh_xfree(saved_comment);
    }
#ifdef WITH_PGP
  else
    {
      unsigned char *blob, *public_blob;
      size_t blob_len, public_blob_len;
      Boolean found = FALSE;
      unsigned long id;
      char *endptr;
      SshPgpSecretKey pgp_key;
      SshPrivateKey key;
      char buf[1024];
      FILE *f;

      comment = NULL;
      switch (pgp_mode)
        {
        case PGP_KEY_NAME:
          found = ssh2_find_pgp_secret_key_with_name(user,
                                                     pgp_keyring,
                                                     filename,
                                                     &blob,
                                                     &blob_len,
                                                     &comment);
          break;
          
        case PGP_KEY_FINGERPRINT:
          found = ssh2_find_pgp_secret_key_with_fingerprint(user,
                                                            pgp_keyring,
                                                            filename,
                                                            &blob,
                                                            &blob_len,
                                                            &comment);
          break;
          
        case PGP_KEY_ID:
          id = strtoul(filename, &endptr, 0);
          if ((*filename != '\0') && (*endptr == '\0'))
            {
              found = ssh2_find_pgp_secret_key_with_id(user,
                                                       pgp_keyring,
                                                       id,
                                                       &blob,
                                                       &blob_len,
                                                       &comment);
            }
          else
            {
              fprintf(stderr, "%s: invalid pgp key id \"%s\".\n", 
                      av0, filename);
              found = FALSE;
            }
          break;
          
        default:
          ssh_fatal("internal error");
        }
      if (! found)
        {
          fprintf(stderr, "%s: pgp key \"%s\" not found.\n", 
                  av0, filename);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
      if (ssh_pgp_secret_key_decode(blob, blob_len, &pgp_key) == 0)
        {
          fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                  av0, filename);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }

      if ((public_blob_len = ssh_encode_pubkeyblob(pgp_key->public_key->key,
                                                   &public_blob)) == 0)
        {
          fprintf(stderr, "%s: unable to encode pgp key \"%s\".\n", 
                  av0, filename);
          ssh_pgp_secret_key_free(pgp_key);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
          return;
        }
      if (action == ADD)
        {
          query_cnt = 0;
          while ((pgp_key->key == NULL) &&
                 (pgp_key->decryption_failed == TRUE))
            {
              query_cnt++;
              if (query_cnt > 5)
                {
                  fprintf(stderr,
                          "You don't seem to know the correct passphrase.\n");
                  exit(EXIT_STATUS_BADPASS);
                }
              /* Ask for a passphrase. */
              if (!use_stdin && getenv("DISPLAY") && !isatty(fileno(stdin)))
                {
                  snprintf(buf, sizeof(buf),
                           "ssh-askpass2 '%sEnter passphrase for \"%.100s\"'", 
                           ((query_cnt <= 1) ? 
                            "" : 
                            "You entered wrong passphrase.  "), 
                           comment);
                  f = popen(buf, "r");
                  if (!fgets(buf, sizeof(buf), f))
                    {
                      pclose(f);
                      fprintf(stderr, "No passphrase.\n");
                      exit(EXIT_STATUS_BADPASS);
                    }
                  pclose(f);
                  if (strchr(buf, '\n'))
                    *strchr(buf, '\n') = 0;
                  pass = ssh_xstrdup(buf);
                }
              else
                {
                  if (query_cnt <= 1)
                    printf("Need passphrase for \"%s\".\n", comment);
                  else
                    printf("Bad passphrase.\n");
                  pass = ssh_read_passphrase("Enter passphrase: ", use_stdin);
                  if (pass == NULL || strcmp(pass, "") == 0)
                    {
                      ssh_xfree(pass);
                      fprintf(stderr, "No passphrase.\n");
                      exit(EXIT_STATUS_BADPASS);
                    }
                }
              ssh_pgp_secret_key_free(pgp_key);
              if (ssh_pgp_secret_key_decode_with_passphrase(blob, 
                                                            blob_len, 
                                                            pass,
                                                            &pgp_key) == 0)
                {
                  memset(pass, 0, strlen(pass));
                  ssh_xfree(pass);
                  fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                          av0, filename);
                  memset(blob, 'F', blob_len);
                  ssh_xfree(blob);
                  ssh_xfree(public_blob);
                  (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
                  return;
                }
              memset(pass, 0, strlen(pass));
              ssh_xfree(pass);
            }
          if (pgp_key->key == NULL)
            {
              fprintf(stderr, "%s: unable to decode pgp key \"%s\".\n", 
                      av0, filename);
              ssh_xfree(public_blob);
              ssh_pgp_secret_key_free(pgp_key);
              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
              return;
            }
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          if (ssh_private_key_copy(pgp_key->key, &key) != SSH_CRYPTO_OK)
            {
              fprintf(stderr, "%s: unable to export pgp key \"%s\".\n", 
                      av0, filename);
              ssh_pgp_secret_key_free(pgp_key);
              (*agent_completion)(SSH_AGENT_ERROR_OK, (void *)agent);
              return;
            }
          ssh_pgp_secret_key_free(pgp_key);
          if (have_attrs)
            ssh_agent_add_with_attrs(agent, key, 
                                     public_blob, public_blob_len, 
                                     comment, path_limit, 
                                     path_constraint, use_limit,
                                     forbid_compat, key_timeout,
                                     agent_completion, (void *)agent);
          else
            ssh_agent_add(agent, key, 
                          public_blob, public_blob_len, comment, 
                          agent_completion, (void *)agent);
          ssh_xfree(comment);
          ssh_xfree(public_blob);
          ssh_private_key_free(key);
          return;
        }
      else if (action == DELETE)
        {
          ssh_agent_delete(agent, 
                           public_blob, 
                           public_blob_len, 
                           filename,
                           agent_completion,
                           (void *)agent);
          ssh_pgp_secret_key_free(pgp_key);
          memset(blob, 'F', blob_len);
          ssh_xfree(blob);
          ssh_xfree(public_blob);
          return;
        }
    }
#endif /* WITH_PGP */
}