Example #1
0
/* For a self-signed certificates the subject identifier should match
   the value in the authority key id, if present. */
void
ssh_x509_cert_set_subject_key_id(SshX509Certificate c,
                                 const unsigned char *key_id,
                                 size_t key_id_len,
                                 Boolean critical)
{
  SshX509ExtKeyId subject_id;

  /* Build the subject key id. */
  if ((subject_id = ssh_malloc(sizeof(*subject_id))) != NULL)
    {
      ssh_x509_key_id_init(subject_id);
      if ((subject_id->key_id = ssh_memdup(key_id, key_id_len)) != NULL)
        {
          subject_id->key_id_len = key_id_len;
          if (c->extensions.subject_key_id != NULL)
            ssh_x509_key_id_free(c->extensions.subject_key_id);
          c->extensions.subject_key_id = subject_id;
          ssh_x509_ext_info_set(&c->extensions.ext_available,
                                &c->extensions.ext_critical,
                                SSH_X509_EXT_SUBJECT_KEY_ID, critical);
        }
      else
        ssh_free(subject_id);
    }
}
/* Completion callback for SshPmAuthorizationCB. */
void
ssh_pm_authorization_cb(SshUInt32 *group_ids,
			SshUInt32 num_group_ids,
			void *context)
{
  SshFSMThread thread = (SshFSMThread) context;
  SshPm pm = (SshPm) ssh_fsm_get_gdata(thread);
  SshPmQm qm = (SshPmQm) ssh_fsm_get_tdata(thread);
  SshPmP1 p1 = qm->p1;

  /* Check qm->error in case qm->p1 has been freed */
  if (p1 != NULL && qm->error == SSH_IKEV2_ERROR_OK)
    {
      ssh_free(p1->authorization_group_ids);
      p1->authorization_group_ids = NULL;
      p1->num_authorization_group_ids = 0;
      if (num_group_ids > 0)
	{
	  p1->authorization_group_ids =
	    ssh_memdup(group_ids, sizeof(group_ids[0]) * num_group_ids);
	  p1->num_authorization_group_ids = num_group_ids;
	}
      p1->auth_group_ids_set = 1;

      /* The IKE SA is updated. */
      ssh_pm_ike_sa_event_updated(pm, p1);
    }

  SSH_FSM_CONTINUE_AFTER_CALLBACK(thread);
}
Example #3
0
SshCMStatus ssh_cm_crl_set_ber(SshCMCrl crl,
                               const unsigned char *ber, size_t ber_length)
{
  SshBERFile bf;

  SSH_DEBUG(5, ("Set CRL in ber."));

  if (crl->ber != NULL)
    return SSH_CM_STATUS_FAILURE;

  if (crl->cm &&
      ber_length > crl->cm->config->max_crl_length)
    {
      SSH_DEBUG(SSH_D_FAIL,
                ("CRL (%zd bytes) too long (max %zd bytes)",
                 ber_length, crl->cm->config->max_crl_length));
      return SSH_CM_STATUS_FAILURE;
    }

  if (ssh_ber_file_create(ber, ber_length, &bf) != SSH_BER_FILE_ERR_OK)
    return SSH_CM_STATUS_FAILURE;
  ber_length -= ssh_ber_file_get_free_space(bf);
  ssh_ber_file_destroy(bf);

  if (ssh_x509_crl_decode(ber, ber_length, crl->crl) != SSH_X509_OK)
    return SSH_CM_STATUS_DECODE_FAILED;

  /* Copy the BER encoded part too. */
  crl->ber_length = 0;
  if ((crl->ber = ssh_memdup(ber, ber_length)) != NULL)
    crl->ber_length = ber_length;

  return SSH_CM_STATUS_OK;
}
Example #4
0
static void
pkix_tcp_receive_data(SshPacketType type,
                      const unsigned char *data, size_t len,
                      void *context)
{
  SshFSMThread thread = (SshFSMThread)context;
  SshPkiThreadData tdata = ssh_fsm_get_tdata(thread);
  SshPkiGlobalData gdata = ssh_fsm_get_gdata(thread);

  SSH_DEBUG(SSH_D_HIGHOK, ("thread %p %zd bytes from CA", thread, len));

  if (type < 10)
    {
      tdata->input_version = SSH_PKI_VERSION_0;
      tdata->input_flags = 0;
      tdata->input_type = type;
      tdata->input_len = len;
      tdata->input = ssh_memdup(data, len);
    }
  else
    {
      switch (type)
        {
        case 10:
          tdata->input_version = SSH_PKI_VERSION_1;
          tdata->input_flags = data[0];
          tdata->input_type = data[1];
          tdata->input_len = len - 2;
          tdata->input = ssh_memdup(data + 2, tdata->input_len);
          break;
        default:
          return;
        }
    }

  if (tdata->input == NULL)
    tdata->input_type = SSH_PKI_MSG_ERRORREP;

  SSH_DEBUG_HEXDUMP(SSH_D_UNCOMMON,
                    ("DATA %d bytes", tdata->input_len),
                    tdata->input, tdata->input_len);
  ssh_fsm_continue(gdata->input_thread);
}
void
ssh_eap_protocol_master_session_key(SshEap eap,
				    const unsigned char *session_key,
				    size_t session_key_len)
{
  SSH_PRECOND(eap->msk == NULL);

  eap->msk = ssh_memdup(session_key, session_key_len);
  eap->msk_len = session_key_len;
}
Example #6
0
/*                                                              shade{0.9}
 * ike_policy_reply_private_payload_out
 * Process policy managers reply to add private payloads.       shade{1.0}
 */
void ike_policy_reply_private_payload_out(int private_payload_id,
        unsigned char *data,
        size_t data_len,
        void *context)
{
    SshIkeNegotiation negotiation = (SshIkeNegotiation) context;
    SshIkePayload pl;

    SSH_DEBUG(5, ("Start"));

    if (ike_reply_check_deleted(negotiation))
        return;

    if (private_payload_id == 0)
    {
        ike_reply_done(negotiation);
        return;
    }

    pl = ike_append_payload(negotiation->sa->server_context->isakmp_context,
                            negotiation->ed->isakmp_packet_out,
                            negotiation->sa, negotiation,
                            SSH_IKE_PAYLOAD_TYPE_PRV);
    if (pl == NULL)
    {
        ike_reply_return_error(negotiation,
                               SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
        return;
    }
    /* Store the information to private payload */
    pl->pl.prv.prv_payload_id = private_payload_id;
    pl->pl.prv.data = ssh_memdup(data, data_len);
    if (pl->pl.prv.data == NULL)
    {
        ike_reply_return_error(negotiation,
                               SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
        return;
    }
    pl->payload_length = data_len;
    /* Register allocated data */
    if (!ike_register_item(negotiation->ed->isakmp_packet_out, pl->pl.prv.data))
    {
        ike_reply_return_error(negotiation,
                               SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
        return;
    }
    return;
}
Example #7
0
/* REQUEST */
static void
scep_encode_request_done(SshX509Status status,
                         const unsigned char *der, size_t der_len,
                         void *context)
{
  SshScepEncode tdata = context;

  if (status == SSH_X509_OK)
    {
      tdata->request = ssh_memdup(der, der_len);
      tdata->request_len = der_len;
    }
  else
    {
      tdata->status = SSH_SCEP_FAILURE;
      ssh_fsm_set_next(tdata->thread, scep_encode_done);
    }
  SSH_FSM_CONTINUE_AFTER_CALLBACK(tdata->thread);
}
Example #8
0
SshIkev2PayloadID ssh_pm_ikev2_payload_id_dup(SshIkev2PayloadID id)
{
  SshIkev2PayloadID dup = NULL;

  if (id == NULL)
    return NULL;

  if ((dup = ssh_calloc(1, sizeof(*dup))) == NULL)
    return NULL;

  if ((dup->id_data = ssh_memdup(id->id_data, id->id_data_size)) == NULL)
    {
      ssh_free(dup);
      return NULL;
    }

  dup->id_type = id->id_type;
  dup->id_data_size = id->id_data_size;
  return dup;
}
Example #9
0
SshIkev2PayloadID
ssh_pm_decode_identity(SshPmIdentityType id_type,
                       const unsigned char *identity,
		       size_t identity_len,
                       Boolean *malformed_id_return)
{
  SshIkev2PayloadID id;
  SshIpAddrStruct ip;
  const unsigned char *cp;
#ifdef SSHDIST_CERT
  SshDNStruct dn;
#endif /* SSHDIST_CERT */
#ifdef WITH_MSCAPI
  SshIkev2PayloadID tmp_id;
#endif /* WITH_MSCAPI */
  *malformed_id_return = FALSE;


  if (identity == NULL)
    return NULL;

  id = NULL;

  switch (id_type)
    {
    case SSH_PM_IDENTITY_DN:
    case SSH_PM_IDENTITY_IP:
    case SSH_PM_IDENTITY_FQDN:
    case SSH_PM_IDENTITY_RFC822:
    case SSH_PM_IDENTITY_KEY_ID:
#ifdef SSHDIST_IKE_ID_LIST
    case SSH_PM_IDENTITY_ID_LIST:
#endif /* SSHDIST_IKE_ID_LIST */
      id = ssh_calloc(1, sizeof(*id));
      if (id == NULL)
        {
          SSH_DEBUG(SSH_D_ERROR, ("Could not allocate IKE ID"));
	  return NULL;
        }
      break;

    case SSH_PM_IDENTITY_ANY:
    default:
      return NULL;
    }

  /* Decode identity. */

  SSH_DEBUG_HEXDUMP(SSH_D_LOWSTART, ("Decoding identity of type %d", id_type),
		    identity, identity_len);

  switch (id_type)
    {
    case SSH_PM_IDENTITY_DN:
#ifdef SSHDIST_CERT
      id->id_type = SSH_IKEV2_ID_TYPE_ASN1_DN;

      ssh_dn_init(&dn);

      if (!ssh_dn_decode_ldap(identity, &dn))
        {
          SSH_DEBUG(SSH_D_FAIL, ("Malformed DN identity `%s'", identity));
          *malformed_id_return = TRUE;
	  ssh_dn_clear(&dn);
          goto error;
        }

      if (!ssh_dn_encode_der(&dn, &id->id_data, &id->id_data_size, NULL))
        {
          SSH_DEBUG(SSH_D_ERROR, ("Could not store ASN.1 data"));
	  ssh_dn_clear(&dn);
          goto error;
        }

      ssh_dn_clear(&dn);
      break;
#endif /* SSHDIST_CERT */
#ifdef SSHDIST_MSCAPI
#ifdef WITH_MSCAPI
      if (!(tmp_id = ssh_pm_mscapi_str_to_dn(identity)))
        {
          SSH_DEBUG(SSH_D_FAIL, ("Malformed DN identity `%s'", identity));
          *malformed_id_return = TRUE;
          goto error;
        }
      memcpy(id, tmp_id, sizeof *id);
      ssh_free(tmp_id);
      break;
#endif /* WITH_MSCAPI */
#endif /* SSHDIST_MSCAPI */
      goto error;

      break;

    case SSH_PM_IDENTITY_IP:
      if (!ssh_ipaddr_parse(&ip, identity))
        {
          SSH_DEBUG(SSH_D_ERROR, ("Malformed IP address `%s'", identity));
          *malformed_id_return = TRUE;
          goto error;
        }
      if (SSH_IP_IS4(&ip))
	{
	  id->id_type = SSH_IKEV2_ID_TYPE_IPV4_ADDR;
	  id->id_data_size = 4;
	}
      else
	{
	  id->id_type = SSH_IKEV2_ID_TYPE_IPV6_ADDR;
	  id->id_data_size = 16;
	}

      if ((id->id_data = ssh_malloc(id->id_data_size)) == NULL)
	goto error;

      SSH_IP_ENCODE(&ip, id->id_data, id->id_data_size);
      break;

    case SSH_PM_IDENTITY_FQDN:
      id->id_type = SSH_IKEV2_ID_TYPE_FQDN;
      id->id_data_size = identity_len;
      if ((id->id_data = ssh_memdup(identity, identity_len)) == NULL)
	goto error;

      break;

    case SSH_PM_IDENTITY_RFC822:
      id->id_type = SSH_IKEV2_ID_TYPE_RFC822_ADDR;

      cp = ssh_ustrchr(identity, '@');
      if (cp == NULL)
        {
          SSH_DEBUG(SSH_D_FAIL, ("Malformed RFC822 identity `%s'", identity));
          *malformed_id_return = TRUE;
          goto error;
        }

      id->id_data_size = identity_len;
      if ((id->id_data = ssh_memdup(identity, identity_len)) == NULL)
	goto error;
      break;

    case SSH_PM_IDENTITY_KEY_ID:

      id->id_type =  SSH_IKEV2_ID_TYPE_KEY_ID;
      id->id_data_size = identity_len;
      if ((id->id_data = ssh_memdup(identity, identity_len)) == NULL)
	goto error;

      break;

#ifdef SSHDIST_IKE_ID_LIST
    case SSH_PM_IDENTITY_ID_LIST:
      id->id_type = IPSEC_ID_LIST;
      id->id_data_size = identity_len;

      /* Just copy the input string repesentation of the ID. The fallback
	 code will convert this to an IKEv1 ID data structure. */
      if ((id->id_data = ssh_memdup(identity, identity_len)) == NULL)
	goto error;
      break;
#endif /* SSHDIST_IKE_ID_LIST */

    default:
      SSH_NOTREACHED;
    }

  SSH_DEBUG(SSH_D_LOWOK, ("IKE ID %@", ssh_pm_ike_id_render, id));

  /* All done. */
  return id;

  /* Error handling. */

 error:
  ssh_pm_ikev2_payload_id_free(id);
  return NULL;
}
Example #10
0
/*                                                              shade{0.9}
 * ike_qm_sa_reply
 * Process policy managers reply to sa query.                   shade{1.0}
 */
void ike_qm_sa_reply(SshIkeIpsecSelectedSAIndexes return_value,
                     void *context)
{
    SshIkeNegotiation negotiation = (SshIkeNegotiation) context;
    int i, j;
    SshIkePayloadSA sa;
    SshIkePayloadPProtocol proto;
    SshIkePayloadT t;
    SshIkeIpsecSelectedSAIndexes sel;
    SshIkeIpsecSelectedProtocol sel_pro;

    SSH_DEBUG(5, ("Start"));

    negotiation->qm_ed->indexes = return_value;

    if (ike_reply_check_deleted(negotiation))
        return;

    if (return_value == NULL)
    {
        negotiation->qm_ed->indexes =
            ssh_calloc(negotiation->qm_ed->number_of_sas,
                       sizeof(struct SshIkeIpsecSelectedSAIndexesRec));
        if (negotiation->qm_ed->indexes == NULL)
        {
            ike_reply_return_error(negotiation,
                                   SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
            return;
        }
        ike_reply_done(negotiation);
        return;
    }

    /* Copy / read selected sa information from sa proposals to selected_sas
       table */
    /* Allocate table */
    negotiation->qm_ed->selected_sas =
        ssh_calloc(negotiation->qm_ed->number_of_sas,
                   sizeof(struct SshIkeIpsecSelectedSARec));
    if (negotiation->qm_ed->selected_sas == NULL)
    {
        ike_reply_return_error(negotiation,
                               SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
        return;
    }
    for (i = 0; i < negotiation->qm_ed->number_of_sas; i++)
    {
        sa = &(negotiation->qm_ed->sas_i[i]->pl.sa);
        sel = &(negotiation->qm_ed->indexes[i]);
        /* No proposal selected */
        if (sel->proposal_index == -1)
        {
            negotiation->qm_ed->selected_sas[i].number_of_protocols = 0;
            negotiation->qm_ed->selected_sas[i].protocols = NULL;
            SSH_DEBUG(5, ("No proposal selected for sa %d", i));
            continue;
        }

        negotiation->qm_ed->selected_sas[i].number_of_protocols =
            negotiation->qm_ed->indexes[i].number_of_protocols;
        negotiation->qm_ed->selected_sas[i].protocols =
            ssh_calloc(negotiation->qm_ed->selected_sas[i].number_of_protocols,
                       sizeof(struct SshIkeIpsecSelectedProtocolRec));
        if (negotiation->qm_ed->selected_sas[i].protocols == NULL)
        {
            ike_reply_return_error(negotiation,
                                   SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
            return;
        }
        /* Loop through all protocols */
        for (j = 0;
                j < negotiation->qm_ed->selected_sas[i].number_of_protocols;
                j++)
        {
            SSH_DEBUG(5,
                      ("Selected proposal %d, and transform %d for protocol %d",
                       sel->proposal_index,
                       sel->transform_indexes[j], j));
            proto = &(sa->proposals[sel->proposal_index].protocols[j]);
            sel_pro = &(negotiation->qm_ed->selected_sas[i].protocols[j]);
            sel_pro->protocol_id = proto->protocol_id;
            sel_pro->spi_size_out = proto->spi_size;
            sel_pro->spi_out = ssh_memdup(proto->spi, proto->spi_size);
            if (sel_pro->spi_out == NULL)
            {
                ike_reply_return_error(negotiation,
                                       SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
                return;
            }
            sel_pro->spi_size_in = sel->spi_sizes[j];
            sel_pro->spi_in = ssh_memdup(sel->spis[j], sel_pro->spi_size_in);
            if (sel_pro->spi_in == NULL)
            {
                ike_reply_return_error(negotiation,
                                       SSH_IKE_NOTIFY_MESSAGE_OUT_OF_MEMORY);
                return;
            }
            t = &(proto->transforms[sel->transform_indexes[j]]);
            sel_pro->transform_id.generic = t->transform_id.generic;
            ssh_ike_clear_ipsec_attrs(&(sel_pro->attributes));
            if (!ssh_ike_read_ipsec_attrs(negotiation, t,
                                          &(sel_pro->attributes)))
            {
                SSH_IKE_DEBUG(3, negotiation,
                              ("Internal policy manager error, "
                               "policy manager selected proposal, "
                               "that contains unsupported values"));
                for (i = 0; i < negotiation->qm_ed->number_of_sas; i++)
                {
                    if (negotiation->qm_ed->selected_sas[i].protocols)
                    {
                        for (j = 0; j < negotiation->qm_ed->
                                selected_sas[i].number_of_protocols; j++)
                        {
                            ssh_free(negotiation->qm_ed->
                                     selected_sas[i].protocols[j].spi_in);
                            ssh_free(negotiation->qm_ed->
                                     selected_sas[i].protocols[j].spi_out);
                        }
                        ssh_free(negotiation->qm_ed->selected_sas[i].protocols);
                    }
                }
                ssh_free(negotiation->qm_ed->selected_sas);
                negotiation->qm_ed->selected_sas = NULL;
                ike_reply_return_error(negotiation,
                                       SSH_IKE_NOTIFY_MESSAGE_ATTRIBUTES_NOT_SUPPORTED);
                return;
            }
        }
    }

    ike_reply_done(negotiation);
    return;
}
Boolean
ssh_virtual_adapter_param_decode(SshVirtualAdapterParams params,
				 const unsigned char *data, size_t len)
{
  unsigned char *dns;
  size_t dns_len;
  unsigned char *wins;
  size_t wins_len;
  unsigned char *win_domain;
  size_t win_domain_len;
  SshUInt32 netbios_node_type;
  SshUInt32 i;
  size_t decode_len;

  SSH_ASSERT(params != NULL);
  SSH_ASSERT(data != NULL);
  SSH_ASSERT(len > 0);

  memset(params, 0, sizeof(*params));
  
  if (ssh_decode_array(data, len,
		       SSH_DECODE_UINT32(&params->mtu),
		       SSH_DECODE_UINT32(&params->dns_ip_count),
		       SSH_DECODE_UINT32_STR_NOCOPY(&dns, &dns_len),
		       SSH_DECODE_UINT32(&params->wins_ip_count),
		       SSH_DECODE_UINT32_STR_NOCOPY(&wins, &wins_len),
		       SSH_DECODE_UINT32_STR_NOCOPY(
		       &win_domain, &win_domain_len),
		       SSH_DECODE_UINT32(&netbios_node_type),
		       SSH_FORMAT_END) != len)
    return FALSE;

  /* DNS. */
  if (params->dns_ip_count)
    {
      params->dns_ip = ssh_calloc(params->dns_ip_count, 
				  sizeof(*params->dns_ip));
      if (params->dns_ip == NULL)
	goto error;
      
      for (i = 0; i < params->dns_ip_count; i++)
	{
	  decode_len = ssh_decode_ipaddr_array(dns, dns_len, 
					       &params->dns_ip[i]);
	  if (decode_len == 0)
	    goto error;	  
	  dns += decode_len;
	  dns_len -= decode_len;
	}
    }
  
      /* WINS. */
  if (params->wins_ip_count)
    {
      params->wins_ip = ssh_calloc(params->wins_ip_count, 
				   sizeof(*params->wins_ip));
      if (params->wins_ip == NULL)
	goto error;
      
      for (i = 0; i < params->wins_ip_count; i++)
	{
	  decode_len = ssh_decode_ipaddr_array(wins, wins_len, 
					       &params->wins_ip[i]);
	  if (decode_len == 0)
	    goto error;	  
	  wins += decode_len;
	  wins_len -= decode_len;
	}
    }
  
  if (win_domain_len)
    {
      params->win_domain = ssh_memdup(win_domain, win_domain_len);
      if (params->win_domain == NULL)
	goto error;
    }
  
  params->netbios_node_type = (SshUInt8) netbios_node_type;

  return TRUE;

 error:
  ssh_free(params->dns_ip);
  ssh_free(params->wins_ip);
  ssh_free(params->win_domain);
  memset(params, 0, sizeof(*params));
  return FALSE;
}
Example #12
0
/* This function reads complete payload from the HTTP stream described
   at the context argument (also the thread running this session is
   identified b the context's upper context), and calls the input
   processing thread when done. This gets called when the CA replies
   to the clients message or poll. */
static void
pkix_http_stream_callback(SshStreamNotification not, void *context)
{
  int i;
  size_t len;
  SshUInt8 type_or_version;
  unsigned char input[256], *data;
  PkixHttpReadContext c = (PkixHttpReadContext)context;
  SshFSMThread thread = (SshFSMThread) c->upper_context;
  SshPkiThreadData tdata = ssh_fsm_get_tdata(thread);
  SshPkiGlobalData gdata = ssh_fsm_get_gdata(thread);

  while (TRUE)
    {
      i = ssh_stream_read(c->http_stream, input, sizeof(input));
      if (i == 0)
        {
          if ((len = ssh_buffer_len(c->input)) > 5)
            {
              data = ssh_buffer_ptr(c->input);
              len = SSH_GET_32BIT(data);
              type_or_version = data[4];

              if (type_or_version < 10)
                {
                  tdata->input_version = SSH_PKI_VERSION_0;
                  tdata->input_flags = 0;
                  tdata->input_type = type_or_version;
                  tdata->input_len = len - 1;
                  tdata->input = ssh_memdup(data + 5, tdata->input_len);
                }
              else
                {
                  if (type_or_version == 10)
                    {
                      data += 4; /* skip to end of length */
                      tdata->input_version = SSH_PKI_VERSION_1;
                      tdata->input_len = len - 3;
                      tdata->input_flags = data[1];
                      tdata->input_type  = data[2];
                      data += 3;
                      tdata->input = ssh_memdup(data, tdata->input_len);
                    }
                  else
                    {
                      tdata->input_version = type_or_version;
                      tdata->input_type = SSH_PKI_MSG_ERRORREP;
                    }
                }

              if (tdata->input == NULL)
                tdata->input_type = SSH_PKI_MSG_ERRORREP;

              ssh_buffer_free(c->input);
              ssh_stream_destroy(c->http_stream);
              ssh_fsm_continue(gdata->input_thread);
              ssh_free(c);
              return;
            }
          else
            {
            error:
              tdata->input_type = SSH_PKI_MSG_ERRORREP;
              ssh_fsm_set_next(thread, pkix_aborted);
              ssh_fsm_continue(gdata->input_thread);
              ssh_stream_destroy(c->http_stream);
              ssh_buffer_free(c->input);
              ssh_free(c);
              return;
            }
        }
      else if (i < 0)
        {
          return;
        }
      else
        {
          if (ssh_buffer_append(c->input, input, i) != SSH_BUFFER_OK)
            {
              goto error;
            }
        }

    }
}
Example #13
0
SshEapToken
ssh_eap_dup_token(SshEapToken src)
{
  SshEapToken dst;

  dst = ssh_calloc(1, sizeof(*dst));

  if (dst == NULL)
    return NULL;

  dst->type = src->type;

  switch (src->type)
    {



















    case SSH_EAP_TOKEN_PRIVATE_KEY:
   if (src->token.prvkey.private_key != NULL)
     {
       if (ssh_private_key_copy(src->token.prvkey.private_key, 
				&dst->token.prvkey.private_key) 
	   != SSH_CRYPTO_OK)
	 {
	   ssh_free(dst);
	   return NULL;
	 }
       if (src->token.prvkey.id_data != NULL)
         {
           dst->token.prvkey.id_data 
             = ssh_memdup(src->token.prvkey.id_data,
                          src->token.prvkey.id_data_size);
           if (dst->token.prvkey.id_data == NULL)
             {
               ssh_private_key_free(dst->token.prvkey.private_key);
               ssh_free(dst);
               return NULL;
             }
           dst->token.prvkey.id_data_size = src->token.prvkey.id_data_size;
         }
     }
   break;

    case SSH_EAP_TOKEN_CERTIFICATE_AUTHORITY:
      {
        int cnt;
        int i;

        /* Count the ca count. */
        for (cnt = 0; src->token.cas && src->token.cas[cnt]; cnt++)
          ;

        if (cnt == 0)
          {
            SSH_DEBUG(SSH_D_ERROR, ("Cannot duplicate token, no"
                                    " CA's to duplicate."));
            ssh_free(dst);
            return NULL;
          }

        dst->token.cas = ssh_calloc(cnt + 1, sizeof(unsigned char *));
        if (dst->token.cas == NULL)
          {
            ssh_free(dst);
            return NULL;
          }

        for (i = 0; i < cnt; i++)
          dst->token.cas[i] = src->token.cas[i];

        break;
      }

#ifdef SSHDIST_EAP_SIM
    case SSH_EAP_TOKEN_SIM_CHALLENGE:
#endif /* SSHDIST_EAP_SIM */
#ifdef SSHDIST_EAP_AKA
    case SSH_EAP_TOKEN_AKA_CHALLENGE:
    case SSH_EAP_TOKEN_AKA_SYNCH_REQ:
#endif /* SSHDIST_EAP_AKA */
    case SSH_EAP_TOKEN_USERNAME:
    case SSH_EAP_TOKEN_SHARED_SECRET:
    case SSH_EAP_TOKEN_SALT:

      if (src->token.buffer.dptr != NULL)
        {
          dst->token.buffer.dptr = ssh_malloc(src->token.buffer.len);
          if (dst->token.buffer.dptr == NULL)
            {
              ssh_free(dst);
              return NULL;
            }
	  
          dst->token.buffer.len = src->token.buffer.len;
          memcpy(dst->token.buffer.dptr, src->token.buffer.dptr,
                 src->token.buffer.len);
        }
      else
        {
          dst->token.buffer.dptr = NULL;
          dst->token.buffer.len = 0;
        }
      break;
    case SSH_EAP_TOKEN_COUNTER32:
      dst->token.counter32 = src->token.counter32;
      break;
      
#ifdef SSHDIST_EAP_AKA_DASH
    case SSH_EAP_TOKEN_AKA_DASH_KDF_INPUT:
      dst->token.success = src->token.success;
      break;
#endif /* SSHDIST_EAP_AKA_DASH */

#ifdef SSHDIST_EAP_AKA
    case SSH_EAP_TOKEN_AKA_AUTH_REJECT:
#endif /* SSHDIST_EAP_AKA */
    case SSH_EAP_TOKEN_NONE:
      break;
    default:
      SSH_NOTREACHED;
    }

  SSH_DEBUG(SSH_D_MY, ("duplicated token at %p", dst));

  return dst;
}
Example #14
0
/*
 * Parse incoming socks connection from buffer. Consume the request
 * packet data from buffer. If everything is ok it allocates SocksInfo
 * strcture and store the request fields in it (sets
 * socks_version_number, command_code, ip, port, username). Returns
 * SSH_SOCKS_SUCCESS, SSH_SOCKS_TRY_AGAIN, or SSH_SOCKS_ERROR_*. If
 * anything other than SSH_SOCKS_SUCCESS is returned the socksinfo is
 * set to NULL.  Use ssh_socks_free to free socksinfo data.
 */
SocksError ssh_socks_server_parse_open(SshBuffer buffer, SocksInfo *socksinfo)
{
  unsigned char *data, *ip;
  unsigned long i, port;
  unsigned int version, cmd, ip_addr_len, atyp;
  unsigned char *username = NULL;
  size_t ret, len, bytes = 0;

  *socksinfo = NULL;
  len = ssh_buffer_len(buffer);
  data = ssh_buffer_ptr(buffer);

  if (len < 1)
    return SSH_SOCKS_TRY_AGAIN;

  version = data[0];
  bytes++;

  if (version != 4 && version != 5)
    {
      SSH_DEBUG(2, ("Server gave us version %d.", version));
      return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION;
    }

  if (version == 4)
    {
      /* Check if enough data for header and name */
      if (len < SOCKS4_COMMAND_SIZE + 1)
        {
          return SSH_SOCKS_TRY_AGAIN;
        }


      /* Find the end of username */
      for (i = SOCKS4_COMMAND_SIZE; i < len; i++)
        {
          if (data[i] == '\0')
            break;
        }

      /* End of username not found, return either error or try_again */
      if (i == len || data[i] != '\0')
        {
          if (len > SOCKS4_COMMAND_SIZE + SOCKS4_MAX_NAME_LEN)
            {
              return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
            }
          return SSH_SOCKS_TRY_AGAIN;
        }

      cmd = data[1];

      port = SSH_GET_16BIT(&data[2]);

      ip_addr_len = 4;
      ip = ssh_memdup(&data[4], ip_addr_len);
      atyp = SSH_SOCKS5_ATYP_IPV4;

      if (ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate IP-address buffer."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }

      username = ssh_strdup((char *)(data + SOCKS4_COMMAND_SIZE));
      bytes = SOCKS4_COMMAND_SIZE +
        strlen((char *) data + SOCKS4_COMMAND_SIZE) + 1;
    }
  else
    {
      unsigned char port_buf[2];

      if (len - bytes < 3)
        return SSH_SOCKS_TRY_AGAIN;

      ret = ssh_decode_array(data + bytes, len - bytes,
                             SSH_DECODE_CHAR(&cmd),
                             SSH_DECODE_CHAR(NULL), /* RSV */
                             SSH_DECODE_CHAR(&atyp),
                             SSH_FORMAT_END);
      if (ret <= 0)
        {
          SSH_DEBUG(2, ("Failed to decode command packet."));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      bytes += ret;
      if (atyp == SSH_SOCKS5_ATYP_IPV4)
        {
          SSH_DEBUG(4, ("SOCKS5 received address type IPV4."));
          ip_addr_len = 4;
        }
      else if (atyp == SSH_SOCKS5_ATYP_IPV6)
        {
          SSH_DEBUG(4, ("SOCKS5 received address type IPV6."));
          ip_addr_len = 16;
        }
      else if (atyp == SSH_SOCKS5_ATYP_FQDN)
        {
          if (len - bytes < 1)
            return SSH_SOCKS_TRY_AGAIN;

          ip_addr_len = *(data + bytes);
          if (ip_addr_len <= 0 || ip_addr_len >= 255)
            {
              SSH_DEBUG(2, ("Invalid FQDN address len %d.", ip_addr_len));
              return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
            }
          SSH_DEBUG(4, ("SOCKS5 received address type FQDN, len %d.",
                        ip_addr_len));
          bytes++;
        }
      else
        {
          SSH_DEBUG(2, ("Invalid address type %d.", atyp));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      /* ip addr len + port */
      if (len - bytes < ip_addr_len + 2)
        return SSH_SOCKS_TRY_AGAIN;

      ip = ssh_calloc(ip_addr_len + 1, sizeof(unsigned char));
      if (ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate IP-address buffer."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }
      ret = ssh_decode_array(data + bytes, len - bytes,
                             SSH_DECODE_DATA(ip, ip_addr_len),
                             SSH_DECODE_DATA(port_buf, 2),
                             SSH_FORMAT_END);
      if (ret <= 0)
        {
          SSH_DEBUG(2, ("Failed to decode command packet."));
          ssh_free(ip);
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      port = SSH_GET_16BIT(port_buf);
      bytes += ret;
    }

  if ((*socksinfo = ssh_calloc(1, sizeof(struct SocksInfoRec))) == NULL)
    {
      SSH_DEBUG(2, ("Failed to allocate SocksInfo."));
      ssh_free(ip);
      return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
    }

  if (atyp == SSH_SOCKS5_ATYP_FQDN)
    {
      (*socksinfo)->ip = ip;
    }
  else
    {
      SshIpAddrStruct ip_addr;
      unsigned char buf[SSH_IP_ADDR_STRING_SIZE];

      SSH_IP_DECODE(&ip_addr, ip, ip_addr_len);

      ssh_ipaddr_print(&ip_addr, buf, sizeof(buf));
      (*socksinfo)->ip = ssh_memdup(buf, ssh_ustrlen(buf));
      ssh_free(ip);
      if ((*socksinfo)->ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate final IP-addr buf."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }
    }

  (*socksinfo)->socks_version_number = version;
  (*socksinfo)->command_code = cmd;
  ssh_dsprintf(&(*socksinfo)->port, "%lu", port);
  (*socksinfo)->username = username;
  ssh_buffer_consume(buffer, bytes);
  SSH_DEBUG(5, ("Decoded %zd bytes.", bytes));
  return SSH_SOCKS_SUCCESS;
}
void ikev2_fb_get_cas_kid_cb(SshIkev2Error error_code,
			     int number_of_cas,
			     SshIkev2CertEncoding *ca_encodings,
			     const unsigned char **ca_authority_data,
			     size_t *ca_authority_size,
			     void *context)
{
  SshIkev2FbNegotiation neg = (SshIkev2FbNegotiation) context;
  SshIkeCertificateEncodingType *ikev1_ca_encodings = NULL;
  unsigned char **ikev1_ca_names = NULL;
  size_t *ikev1_ca_name_lens = NULL;
  int i, j;

  SSH_IKEV2_FB_V2_COMPLETE_CALL(neg);

  if (error_code != SSH_IKEV2_ERROR_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("CA lookup failed, error '%s'",
			     ssh_ikev2_error_to_string(error_code)));
      goto error;
    }

  SSH_DEBUG(SSH_D_LOWOK, ("Got %d CA's from the policy manager", 
			  number_of_cas));

  /* Allocate memory for IKEv1 CA names, name lengths and CA encodings. */
  ikev1_ca_encodings = ssh_calloc(number_of_cas,
				  sizeof(SshIkeCertificateEncodingType));
  ikev1_ca_names = ssh_calloc(number_of_cas, sizeof(unsigned char *));
  ikev1_ca_name_lens = ssh_calloc(number_of_cas, sizeof(size_t));

  if (ikev1_ca_encodings == NULL || ikev1_ca_names == NULL ||
      ikev1_ca_name_lens == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Could not allocate memory to return CAs"));
      goto error;
    }

  /* Map the IKEv2 CA encoding to IKEv1 encoding. */
  for (i = 0; i < number_of_cas; i++)
    {
      ikev1_ca_encodings[i] = ikev2_fb_v1_cert_encoding_to_v2(ca_encodings[i]);
      ikev1_ca_names[i] = 
	ssh_memdup(ca_authority_data[i], ca_authority_size[i]);
      ikev1_ca_name_lens[i] = ca_authority_size[i];

      if (ikev1_ca_names[i] == NULL)
	goto error;
    }

  (*neg->callbacks.u.get_cas)(number_of_cas, ikev1_ca_encodings,
			      ikev1_ca_names, ikev1_ca_name_lens,
			      neg->callbacks.callback_context);
  return;

 error:

  if (ikev1_ca_names)
    for (j = 0; j < number_of_cas; j++)
      ssh_free(ikev1_ca_names[j]);
  ssh_free(ikev1_ca_names);

  ssh_free(ikev1_ca_name_lens);
  ssh_free(ikev1_ca_encodings);

  (*neg->callbacks.u.get_cas)(0, NULL, NULL, NULL,
			      neg->callbacks.callback_context);
  return;
}
void ikev2_fb_request_certificates_cb(SshIkev2Error error_code,
				      SshPrivateKey private_key_out,
				      int number_of_certificates,
				      SshIkev2CertEncoding *cert_encs,
				      const unsigned char **certs,
				      size_t *cert_lengths,
				      void *context)
{
  SshIkev2FbNegotiation neg = (SshIkev2FbNegotiation) context;
  SshIkeCertificateEncodingType *ikev1_cert_encodings = NULL;
  SshPrivateKey private_key_copy = NULL;
  unsigned char **ikev1_certs = NULL;
  size_t *ikev1_cert_lengths = NULL;
  int i;

  SSH_IKEV2_FB_V2_COMPLETE_CALL(neg);

  if (error_code != SSH_IKEV2_ERROR_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Private key/Certificate lookup failed, "
			     "error '%s'",
			     ssh_ikev2_error_to_string(error_code)));
      goto error;
    }

  if (number_of_certificates == 0)
    {
      SSH_DEBUG(SSH_D_FAIL, ("No certificates found"));
      goto error;
    }

  SSH_ASSERT(private_key_out != NULL);

  if (ssh_private_key_copy(private_key_out, &private_key_copy)
      != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Private key copy failed"));
      goto error;
    }

  /* Copy the returned certificates */
  ikev1_cert_encodings = ssh_calloc(number_of_certificates,
				    sizeof(SshIkeCertificateEncodingType));
  ikev1_certs = ssh_calloc(number_of_certificates,
			   sizeof(unsigned char *));
  ikev1_cert_lengths = ssh_calloc(number_of_certificates,
				  sizeof(size_t));

  if (ikev1_cert_encodings == NULL || ikev1_certs == NULL ||
      ikev1_cert_lengths == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Memory allocation failure"));
      goto error;
    }

  for (i = 0; i < number_of_certificates; i++)
    {
      ikev1_cert_encodings[i] =
	ikev2_fb_v2_cert_encoding_to_v1(cert_encs[i]);
      ikev1_cert_lengths[i] = cert_lengths[i];
      if (!(ikev1_certs[i] = ssh_memdup(certs[i], cert_lengths[i])))
	{
	  SSH_DEBUG(SSH_D_FAIL, ("Certificate copy failed"));
	  goto error;
	}
    }

  /* Save the certificates and private key. */
  neg->number_of_certificates = number_of_certificates;
  neg->cert_encodings = ikev1_cert_encodings;
  neg->certs = ikev1_certs;
  neg->cert_lengths = ikev1_cert_lengths;
  neg->private_key = private_key_copy;

  SSH_DEBUG(SSH_D_LOWOK, ("Found %d certificates", number_of_certificates));

  SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread);
  return;

 error:

  if (private_key_copy)
    ssh_private_key_free(private_key_copy);

  if (ikev1_certs)
    for (i = 0; i < number_of_certificates; i++)
      ssh_free(ikev1_certs[i]);

  ssh_free(ikev1_certs);
  ssh_free(ikev1_cert_encodings);
  ssh_free(ikev1_cert_lengths);

  SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread);
}
Example #17
0
/* Does the name server lookup using internal dns resolver. */
SshOperationHandle
ssh_tcp_get_host_by_addr_dns(const unsigned char *name,
			     SshLookupCallback callback,
			     void *context)
{
  SshNameServerOperation operation;
  unsigned char *dns_name, *p;
  unsigned char buffer[16];
  size_t len;
  int i;

  len = 16;
  if (!ssh_inet_strtobin(name, buffer, &len))
    {
      callback(SSH_TCP_FAILURE, NULL, context);
      return NULL;
    }

  operation = ssh_calloc(1, sizeof(*operation));
  if (operation == NULL)
    {
      callback(SSH_TCP_FAILURE, NULL, context);
      return NULL;
    }

  operation->dns_name = ssh_memdup(buffer, len);
  if (operation->dns_name == NULL)
    {
      ssh_free(operation);
      callback(SSH_TCP_FAILURE, NULL, context);
      return NULL;
    }

  if (len == 4)
    {
      /* IPv4 address, convert a.b.c.d to d.c.b.a.in-addr.arpa. Buffer size
	 needed is 15 + 13 + 1 = 29. */
      dns_name = ssh_malloc(32);
      if (dns_name == NULL)
	{
	  ssh_free(operation);
	  callback(SSH_TCP_FAILURE, NULL, context);
	  return NULL;
	}
      p = dns_name;
      for(i = 3; i >= 0; i--)
	{
	  if (buffer[i] >= 100)
	    *p = 3;
	  else if (buffer[i] >= 10)
	    *p = 2;
	  else
	    *p = 1;
	  ssh_snprintf(p + 1, dns_name + 32 - p - 1,
		       "%d", buffer[i]);
	  p += (*p) + 1;
	}
      strcpy((char *)p, "\7in-addr\4arpa");
    }
  else
    {
      /* IPv6 address, convert it to
	 p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.p.o.n.m.l.k.j.i.h.g.f.e.d.c.b.a.
	 ip6.arpa.
	 Buffer size needed is 32 * 2 + 9 = 73. */
      dns_name = ssh_malloc(80);
      if (dns_name == NULL)
	{
	  ssh_free(operation);
	  callback(SSH_TCP_FAILURE, NULL, context);
	  return NULL;
	}
      p = dns_name;
      for(i = 15; i >= 0; i--)
	{
	  *p++ = 1;
	  *p++ = "0123456789abcdef"[buffer[i] & 0xf];
	  *p++ = 1;
	  *p++ = "0123456789abcdef"[buffer[i] >> 4];
	}
      strcpy((char *)p, "\3ip6\4arpa");
    }

  operation->callback = callback;
  operation->context = context;
  operation->length = len;
  operation->timed_out = FALSE;
  operation->flags = ssh_name_server_data->resolver_find_flags;

  ssh_operation_register_no_alloc(operation->operation_handle,
				  ssh_name_server_result_abort,
				  operation);

  /* Ok, the name is now ready, start query. */
  operation->handle =  ssh_dns_resolver_find(ssh_name_server_data->resolver,
					     dns_name, SSH_DNS_RESOURCE_PTR,
					     ssh_name_server_data->timeout,
					     operation->flags,
					     ssh_name_server_result_ptr,
					     operation);
  ssh_free(dns_name);
  return operation->operation_handle;
}
Example #18
0
char *ssh_buffer_make_str(SshBuffer buffer)
{
  return ssh_memdup(ssh_buffer_ptr(buffer), ssh_buffer_len(buffer));
}
SshOperationHandle
ssh_pm_cfgmode_client_store_register(SshPm pm,
				     SshPmTunnel tunnel,
                                     SshPmActiveCfgModeClient client,
                                     SshIpAddr address,
				     void *address_context,
                                     SshPmRemoteAccessAttrsFreeCB free_cb,
                                     void *free_cb_context,
				     SshPmStatusCB status_cb,
				     void *status_cb_context)
{
  SSH_DEBUG(SSH_D_LOWOK,
	    ("Registering address `%@'", ssh_ipaddr_render, address));

  SSH_ASSERT(client->status_cb == NULL_FNPTR);

  if (client->flags & SSH_PM_CFGMODE_CLIENT_ADDING_ARP)
    goto error;

  if (!SSH_IP_DEFINED(address))
    goto error;
  
  if (SSH_IP_IS4(address))
    {
      SSH_ASSERT(client->ip4 == NULL);
      client->ip4 = ssh_memdup(address, sizeof(*address));
      if (client->ip4 == NULL)
	goto error;
      client->ip4_address_context = address_context;
    }
  else
    {
      SSH_ASSERT(client->ip6 == NULL);
      client->ip6 = ssh_memdup(address, sizeof(*address));
      if (client->ip6 == NULL)
	goto error;
      client->ip6_address_context = address_context;
    }

  client->free_cb = free_cb;
  client->free_cb_context = free_cb_context;
  
  /* Check if we should add a proxy ARP entry for the remote access client. */
  if (tunnel->flags & SSH_PM_TR_PROXY_ARP)
    {
      unsigned char media_addr[SSH_ETHERH_ADDRLEN];
      SshUInt32 flags;
      
      /* Create a fake ethernet address. */
      memset(media_addr, 0, sizeof(media_addr));
      if (SSH_IP_IS4(address))
	{
	  media_addr[1] = 2;
	  SSH_IP4_ENCODE(address, media_addr + 2);

	  client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_PROXY_ARP;
	}
      else
	{
	  SshUInt32 value;
	  
	  value = SSH_IP6_WORD0_TO_INT(address);
	  value ^= SSH_IP6_WORD1_TO_INT(address);
	  value ^= SSH_IP6_WORD2_TO_INT(address);
	  value ^= SSH_IP6_WORD3_TO_INT(address);
	  
	  media_addr[1] = 2;
	  SSH_PUT_32BIT(media_addr + 2, value);

	  client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_PROXY_ARP;
	}
      
      /* Flags for ARP entry. */
      flags = SSH_PME_ARP_PERMANENT | SSH_PME_ARP_GLOBAL | SSH_PME_ARP_PROXY;

      /* Store status_cb. */
      client->status_cb = status_cb;
      client->status_cb_context = status_cb_context;
      if (SSH_IP_IS4(address))
	client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_REGISTERING;
      else
	client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_REGISTERING;

      /* Register an abort callback for the engine operation. */
      ssh_operation_register_no_alloc(&client->operation,
				      pm_cfgmode_client_store_arp_abort,
				      client);

      /* Take a reference to the client and mark ARP ongoing. */
      ssh_pm_cfgmode_client_store_take_reference(pm, client);
      client->flags |= SSH_PM_CFGMODE_CLIENT_ADDING_ARP;

      /* Add ARP entry. */
      SSH_DEBUG(SSH_D_LOWSTART, ("Adding ARP entry"));
      ssh_pme_arp_add(pm->engine, address, 0,
		      media_addr, sizeof(media_addr),
		      flags, pm_cfgmode_client_store_arp_cb, client);

      return &client->operation;
    }

  if (status_cb) 
    (*status_cb)(pm, TRUE, status_cb_context);
  
  return NULL;

 error:
  if (status_cb) 
    (*status_cb)(pm, FALSE, status_cb_context);

  return NULL;
}
Example #20
0
/* Find pre shared secret for local or remote host. When 'local' is FALSE
   the primary selector is the remote id field. Call reply_callback when
   the data is available (it can also be called immediately).

   If `local' is true then we search for the local pre-shared key. */
SshOperationHandle
ssh_pm_ike_pre_shared_key(SshSADHandle sad_handle,
                          SshIkev2ExchangeData ed,
                          Boolean local,
                          SshIkev2PadSharedKeyCB reply_callback,
                          void *reply_callback_context)
{
    SshPm pm = sad_handle->pm;
    SshPmP1 p1 = (SshPmP1)ed->ike_sa;
    unsigned char *key = NULL;
    size_t key_len = 0;

    SSH_PM_ASSERT_P1(p1);
    SSH_PM_ASSERT_P1N(p1);

    /* If policymanager is not in active state, we wan't to reject this. */
    if (ssh_pm_get_status(pm) == SSH_PM_STATUS_SUSPENDED)
    {
        (*reply_callback)(SSH_IKEV2_ERROR_SUSPENDED,
                          NULL, 0, reply_callback_context);
        return NULL;
    }

    if (!SSH_PM_P1_USABLE(p1))
    {
        (*reply_callback)(SSH_IKEV2_ERROR_SA_UNUSABLE,
                          NULL, 0, reply_callback_context);
        return NULL;
    }

    SSH_DEBUG(SSH_D_MIDSTART, ("Enter SA %p ED %p Asking for %s preshared key",
                               ed->ike_sa, ed, local ? "local" : "remote"));

    /* Select a tunnel for the reponder if not already done */
    if (!(p1->ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_INITIATOR) &&
            !ssh_pm_select_ike_responder_tunnel(pm, p1, ed))
    {
        (*reply_callback)(SSH_IKEV2_ERROR_NO_PROPOSAL_CHOSEN,
                          NULL, 0, reply_callback_context);
        return NULL;
    }

    /* If the IKE initiator has used the "me Tarzan, you Jane" option, then
       check here that that responder has replied with an acceptable identity. */
    if (!local && !ssh_pm_ike_check_requested_identity(pm, p1, ed->ike_ed->id_r))
    {
        p1->n->failure_mask |= SSH_PM_E_REMOTE_ID_MISMATCH;
        (*reply_callback)(SSH_IKEV2_ERROR_AUTHENTICATION_FAILED, NULL, 0,
                          reply_callback_context);
        return NULL;
    }

    if (p1->n->ed == NULL)
        p1->n->ed = ed;

    if (!ssh_pm_auth_domain_check_by_ed(pm, ed))
    {
        (*reply_callback)(SSH_IKEV2_ERROR_AUTHENTICATION_FAILED, NULL, 0,
                          reply_callback_context);
        return NULL;
    }

#ifdef SSHDIST_IKE_EAP_AUTH
    /* Check if EAP is configured for the tunnels authentication domain
       and this is an IKEv2 SA */
    if (p1->auth_domain->num_eap_protocols
#ifdef SSHDIST_IKEV1
            && ((ed->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1) == 0)
#endif /* SSHDIST_IKEV1 */
       )
    {
        /* To use EAP, the initiator omits the AUTH payload by returning
        a NULL Pre Shared Key. */
        if (local && (ed->ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_INITIATOR))
        {
            (*reply_callback)(SSH_IKEV2_ERROR_OK, NULL, 0,
                              reply_callback_context);
            return NULL;
        }

        /* RFC 4306 forbids EAP with pre shared key responder authentication.
        Fail authentication here, as we end up here only if configuration
         for certicate based responder authentication was missing. */
        if (!local && (ed->ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_INITIATOR))
        {
            SSH_DEBUG(SSH_D_FAIL,
                      ("EAP authentication cannot be used with pre shared key "
                       "based responder authentication."));
            p1->n->failure_mask |= SSH_PM_E_AUTH_METHOD_MISMATCH;
            (*reply_callback)(SSH_IKEV2_ERROR_AUTHENTICATION_FAILED, NULL, 0,
                              reply_callback_context);
            return NULL;
        }
    }
#endif /* SSHDIST_IKE_EAP_AUTH */

#ifdef SSHDIST_IKEV1
    if (p1->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1 &&
            ed->ike_ed->exchange_type == SSH_IKE_XCHG_TYPE_AGGR)
        p1->ike_sa->flags |= SSH_IKEV2_FB_IKE_AGGRESSIVE_MODE;
#endif /* SSHDIST_IKEV1 */

    /* Take local secret from tunnel for IKEv2 and IKEv1 main mode. */
    if (local
#ifdef SSHDIST_IKEV1
            /* In IKEv1 aggressive mode responder, we'll use the remote
            secret by requestor ID, and for initiator the one from tunnel
             local identity. */
            && ((p1->ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_INITIATOR)
                || !(ed->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1)
                || (ed->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1
                    && ed->ike_ed->exchange_type != SSH_IKE_XCHG_TYPE_AGGR))
#endif /* SSHDIST_IKEV1 */
       )
    {
        /* Always use the first available secret. */
        if (p1->n->tunnel->u.ike.num_secrets)
        {
            key = p1->n->tunnel->u.ike.secrets->secret;
            key_len = p1->n->tunnel->u.ike.secrets->secret_len;

            /* Save the copy of the local secret to the Phase-1 object. */
            p1->local_secret_len = key_len;
            p1->local_secret = ssh_memdup(key, key_len);

            if (!p1->local_secret)
            {
                p1->local_secret_len = 0;
                key = NULL;
                key_len = 0;
            }
        }

        /* If we have key, or if we are using IKEv1 (main mode
        return key or error). */
        if (key != NULL
#ifdef SSHDIST_IKEV1
                || (ed->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1)
#endif /* SSHDIST_IKEV1 */
           )
        {
            /* Record the local authentication method */
            p1->local_auth_method = SSH_PM_AUTH_PSK;
#ifdef SSHDIST_IKEV1
            /* For IKEv1 negotiations this policy call is not called for 'local'
               equal to FALSE, so we set 'p1->remote_auth_method' here. */
            if (p1->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1)
                p1->remote_auth_method = SSH_PM_AUTH_PSK;
#endif /* SSHDIST_IKEV1 */

            (*reply_callback)((key != NULL) ? SSH_IKEV2_ERROR_OK :
                              SSH_IKEV2_ERROR_AUTHENTICATION_FAILED,
                              key, key_len,
                              reply_callback_context);
            return NULL;
        }
    }

    /* Store the reply callback and context */
    p1->callbacks.aborted = FALSE;
    p1->callbacks.u.pre_shared_key_cb = reply_callback;
    p1->callbacks.callback_context = reply_callback_context;

    /* Record the remote authentication method */
    p1->remote_auth_method = SSH_PM_AUTH_PSK;

#ifdef SSHDIST_IKEV1
    /* Set the local auth method for IKEv1 agressive mode responders */
    if (p1->ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1)
        p1->local_auth_method = SSH_PM_AUTH_PSK;
#endif /* SSHDIST_IKEV1 */

    ssh_operation_register_no_alloc(p1->callbacks.operation,
                                    pm_ike_psk_abort, p1);

    ssh_fsm_thread_init(&pm->fsm, &p1->n->sub_thread,
                        pm_ike_id_psk_lookup_start,
                        NULL_FNPTR, NULL_FNPTR, p1);

    ssh_fsm_set_thread_name(&p1->n->sub_thread, "IKE PSK");
    return p1->callbacks.operation;
}