Beispiel #1
0
/* Route IPv6 packet 'skbp', using the route key selectors in
   'route_selector' and the interface number 'ifnum_in'. */
Boolean
ssh_interceptor_reroute_skb_ipv6(SshInterceptor interceptor,
                                 struct sk_buff *skbp,
                                 SshUInt16 route_selector,
                                 SshUInt32 ifnum_in)
{
    /* we do not need a socket, only fake flow */
    struct flowi rt_key;
    struct dst_entry *dst;
    struct ipv6hdr *iph6;

    iph6 = (struct ipv6hdr *) SSH_SKB_GET_NETHDR(skbp);
    if (iph6 == NULL)
    {
        SSH_DEBUG(SSH_D_ERROR, ("Could not access IPv6 header"));
        return FALSE;
    }

    memset(&rt_key, 0, sizeof(rt_key));

    rt_key.fl6_dst = iph6->daddr;

    if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC)
        rt_key.fl6_src = iph6->saddr;

    if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM)
    {
        rt_key.oif = (skbp->dev ? skbp->dev->ifindex : 0);
        SSH_LINUX_ASSERT_IFNUM(rt_key.oif);
    }

#ifdef LINUX_IP6_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT
    dst = ip6_route_output(&init_net, NULL, &rt_key);
#else /* LINUX_IP6_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */
    dst = ip6_route_output(NULL, &rt_key);
#endif /* LINUX_IP6_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */

    if (dst == NULL || dst->error != 0)
    {
        SSH_DEBUG(SSH_D_FAIL,
                  ("ip6_route_output failed."));

        SSH_DEBUG_HEXDUMP(SSH_D_NICETOKNOW,
                          ("dst "),
                          (unsigned char *) &iph6->daddr, sizeof(iph6->daddr));
        SSH_DEBUG_HEXDUMP(SSH_D_NICETOKNOW,
                          ("src "),
                          (unsigned char *) &iph6->saddr, sizeof(iph6->saddr));
        SSH_DEBUG(SSH_D_NICETOKNOW,
                  ("oif %d[%s]",
                   (skbp->dev ? skbp->dev->ifindex : -1),
                   (skbp->dev ? skbp->dev->name : "none")));
        return FALSE;
    }
    if (SSH_SKB_DST(skbp))
        dst_release(SSH_SKB_DST(skbp));
    SSH_SKB_DST_SET(skbp, dst_clone(dst));

    return TRUE;
}
void ssh_engine_from_ipm_run(SshEngine engine,
                             const unsigned char *data, size_t len)
{
    SshUInt32 test_number, flags;

    if (ssh_decode_array(data, len,
                         SSH_FORMAT_UINT32, &test_number,
                         SSH_FORMAT_UINT32, &flags,
                         SSH_FORMAT_END) != len)
    {
        SSH_DEBUG_HEXDUMP(0, ("bad run packet"), data, len);
        return;
    }

    switch (test_number)
    {
    case SSH_INTERCEPTOR_TEST_BASIC:
        ssh_engine_test_basic(engine, flags);
        break;

    default:
        ssh_warning("unknown test %ld", (long)test_number);
        ssh_engine_test_fail(engine, "unknown test %ld", (long)test_number);
        break;
    }
}
/*                                                              shade{0.9}
 * Create isakmp cookie. Generate completely random
 * cookie, as checking the cookie from the hash table is
 * about as fast or faster than hashing stuff together.
 * This also makes cookies movable against multiple machines
 * (high availability or checkpointing systems).
 * The return_buffer must be SSH_IKE_COOKIE_LENGTH
 * bytes long.                                                  shade{1.0}
 */
void ike_cookie_create(SshIkeContext isakmp_context,
                       unsigned char *cookie)
{
  int i;

  for (i = 0; i < SSH_IKE_COOKIE_LENGTH; i++)
    cookie[i] = ssh_random_get_byte();

  SSH_DEBUG_HEXDUMP(SSH_D_LOWOK, ("Cookie create"), cookie, 8);
}
Beispiel #4
0
static Boolean
ssh_iodevice_name_compose(PUNICODE_STRING dest,
                          const unsigned char *prefix,
                          const unsigned char *name)
{
  USHORT prefix_len_a = (USHORT)ssh_ustrlen(prefix);
  USHORT name_len_a   = (USHORT)ssh_ustrlen(name);
  USHORT prefix_len_u = prefix_len_a * sizeof(WCHAR);
  USHORT name_len_u   = name_len_a * sizeof(WCHAR);
  ANSI_STRING ansi_name;
  Boolean status = FALSE;

  ansi_name.Length = prefix_len_a + name_len_a;
  ansi_name.MaximumLength = ansi_name.Length + 1;
  ansi_name.Buffer = ssh_calloc(1, ansi_name.MaximumLength);
  if (ansi_name.Buffer == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Out of memory!"));
      return FALSE;
    }
  memcpy(ansi_name.Buffer, prefix, prefix_len_a);
  memcpy(&ansi_name.Buffer[prefix_len_a], name, name_len_a);

  dest->Length = prefix_len_u + name_len_u;
  dest->MaximumLength = dest->Length + sizeof(UNICODE_NULL);
  dest->Buffer = ssh_calloc(1, dest->MaximumLength);
  if (dest->Buffer != NULL)
    {
      if (NT_SUCCESS(RtlAnsiStringToUnicodeString(dest, &ansi_name, FALSE)))
        {
          SSH_DEBUG_HEXDUMP(SSH_D_NICETOKNOW,
                            ("ASCII/ANSI strings '%s' + '%s' successfully "
                             "converted to UNICODE:", prefix, name),
                            (const unsigned char *)dest->Buffer, 
                            dest->Length);

          status = TRUE;
        }
      else
        {
          SSH_DEBUG(SSH_D_FAIL, ("ANSI to UNICODE conversion failed!"));
        }
    }
  else
    {
      SSH_DEBUG(SSH_D_FAIL, ("Out of memory!"));
    }

  ssh_free(ansi_name.Buffer);

  return status;
}
void acc_encrypt_done(SshCryptoStatus status,
                      const unsigned char *data,
                      size_t length,
                      void *context)
{
  SshEKTestOp tc = context, ntc;
  SshExternalKeyTestCtx ctx = tc->test_ctx;
  SshPrivateKey key;
  SshUInt32 nanos;
  SshUInt64 secs;
  SshUInt32 s;

  ctx->operations_done++;
  ssh_time_measure_get_value(tc->timer,
                             &secs, &nanos);

  s = (SshUInt32)secs;
  key = accelerator_test ? ctx->acc_prv_key : ctx->prv_key;

  ctx->accelerated_encrypts_pending--;
  SSH_DEBUG(2, ("Completed encrypt %d", tc->op_id));
  SSH_DEBUG(3, ("Time %ds %dns", s, nanos));
  ssh_time_measure_free(tc->timer);
  ssh_xfree(tc);
  SSH_DEBUG_HEXDUMP(7, ("Encrypted data of len %d:", length), data, length);


  if (status == SSH_CRYPTO_OK)
    {
      SSH_DEBUG(10, ("Got the data of len %d", length));

      SSH_DEBUG(10, ("Accelerated encrypt succesfull"));
      ctx->accelerated_decrypts_pending++;
      ntc = ssh_xcalloc(1, sizeof(*ntc));

      ntc->op_id = next_op_id++;
      ntc->test_ctx = ctx;
      ssh_private_key_decrypt_async(key,
                                    data, length,
                                    acc_decrypt_done, ntc);
    }
  else
    {
      SSH_DEBUG(1, ("Accelerated encrypt unsuccesfull"));
      ctx->operations_failed++;
    }

}
void acc_decrypt_done(SshCryptoStatus status,
                      const unsigned char *data,
                      size_t length,
                      void *context)
{
  SshEKTestOp tc = context;
  SshExternalKeyTestCtx ctx = tc->test_ctx;
  ctx->operations_done++;

  SSH_DEBUG(2, ("Completed decrypt %d", tc->op_id));
  ssh_xfree(tc);
  if (status == SSH_CRYPTO_OK)
    {
      SSH_DEBUG_HEXDUMP(7, ("Decrypted data of len %d:",
                            length), data, length);
      if (memcmp(ctx->big_buf, data, length) != 0)
        ssh_fatal("Public encrypt or private decrypt failed, data mismatch");
    }
  else
    {
      SSH_DEBUG(1, ("Could not decrypt with the accelerated private key"));
      ctx->operations_failed++;
    }

  ctx->accelerated_decrypts_pending--;
  if (ctx->accelerated_encrypts_left == 0)
    {
      SSH_DEBUG(2, ("Pending decrypts %d",
                    ctx->accelerated_decrypts_pending));

      if (!continuous_test &&
          ctx->accelerated_decrypts_pending == 0)
        {
          SshUInt64 secs;
          SshUInt32 nanos;
          SshUInt32 s;
          ssh_time_measure_get_value(ctx->timer,
                                     &secs, &nanos);
          s = (SshUInt32)secs;
          SSH_DEBUG(1, ("Whole test completed in %ds and %dns", s, nanos));
          print_stats(ctx);
          exit(0);
        }
    }


}
Beispiel #7
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_engine_from_ipm_set_debug(SshEngine engine,
                                   const unsigned char *data, size_t len)
{
    char *s;

    /* Decode the packet. */
    if (ssh_decode_array(data, len,
                         SSH_FORMAT_UINT32_STR, &s, NULL,
                         SSH_FORMAT_END) != len)
    {
        SSH_DEBUG_HEXDUMP(0, ("Bad set debug from policy manager"),
                          data, len);
        return;
    }

    /* Set debug level according to the stringl. */



    ssh_debug_set_level_string(s);
    SSH_DEBUG(1, ("Engine debug level set to %s", s));
    ssh_free(s);
}
/* Test to encrypt with the accelerated public key */
void test_acc_public_key(void *context)
{
  SshExternalKeyTestCtx ctx = context;
  SshEKTestOp test_ctx = ssh_xcalloc(1, sizeof(*test_ctx));
  SshPublicKey key;
  unsigned char *data = ctx->big_buf;
  size_t data_len = ctx->big_buf_len;

  key = accelerator_test ? ctx->acc_pub_key : ctx->pub_key;

  test_ctx->op_id = next_op_id++;
  test_ctx->test_ctx = ctx;

  test_ctx->timer = ssh_time_measure_allocate();
  ssh_time_measure_start(test_ctx->timer);
  ctx->accelerated_encrypts_pending++;
  ctx->accelerated_encrypts_left--;
  ssh_public_key_encrypt_async(key,
                               data,
                               data_len,
                               acc_encrypt_done, test_ctx);
  SSH_DEBUG_HEXDUMP(7, ("Encrypting data of len %d:", data_len),
                    data, data_len);

  if (ctx->accelerated_encrypts_left || continuous_test)
    {
      ssh_xregister_timeout(0, timeout_ms * 1000, test_acc_public_key, ctx);
    }
  else
    {
      SSH_DEBUG(2, ("All the encrypts send"));
    }

  SSH_DEBUG(2, ("Encrypts left %d, pending %d",
                ctx->accelerated_encrypts_left,
                ctx->accelerated_encrypts_pending));
}
Beispiel #10
0
/* Generate the AUTH data to be signed or MACed. It consist
   of either remote or local packet, either initiator or
   responder Nonce and either initiator or responder ID
   payload. Return NULL if failure, otherwise return
   mallocated string to be used. */
unsigned char *
ikev2_auth_data(SshIkev2Packet packet,
		Boolean local_packet,
		Boolean initiator_nonce,
		Boolean initiator_id,
		size_t *return_len)
{
  unsigned char digest[SSH_MAX_HASH_DIGEST_LENGTH];
  SshIkev2SaExchangeData ed = packet->ed->ike_ed;
  SshIkev2Sa ike_sa = packet->ike_sa;
  unsigned char buffer[4], *ret;
  SshCryptoStatus status;
  unsigned char *p1, *p2;
  size_t len1, len2, len3;
  SshIkev2PayloadID id;
  unsigned char *sk_p;
  SshMac mac;

  if (ike_sa->sk_d_len == 0)
    {
      SSH_DEBUG(SSH_D_FAIL,
		("Diffie-Hellman failed before ike-auth-data computation"));
      *return_len = 0;
      return NULL;
    }

  if (local_packet)
    {
      p1 = ed->local_ike_sa_init;
      len1 = ed->local_ike_sa_init_len;
      SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using local packet"));
    }
  else
    {
      p1 = ed->remote_ike_sa_init;
      len1 = ed->remote_ike_sa_init_len;
      SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using remote packet"));
    }

  if (initiator_nonce)
    {
      p2 = ed->ni->nonce_data;
      len2 = ed->ni->nonce_size;
      SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using initiator nonce"));
    }
  else
    {
      p2 = ed->nr->nonce_data;
      len2 = ed->nr->nonce_size;
      SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using responder nonce"));
    }

  if (initiator_id)
    {
      sk_p = ike_sa->sk_pi;

#ifdef SSH_IKEV2_MULTIPLE_AUTH
      if (ed->first_auth_done)
        {
          id = ed->second_id_i;
          SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using second IDi and sk_pi"));
        }
      else
#endif /* SSH_IKEV2_MULTIPLE_AUTH */
        {
          id = ed->id_i;
          SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using IDi and sk_pi"));
        }
    }
  else
    {
      id = ed->id_r;
      sk_p = ike_sa->sk_pr;
      SSH_IKEV2_DEBUG(SSH_D_LOWOK, ("Using IDr and sk_pr"));
    }

  len3 = ssh_mac_length(ssh_csstr(ike_sa->prf_algorithm));

  *return_len = len1 + len2 + len3;

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Allocating sk_p_mac(%s) with key",
		     ike_sa->prf_algorithm),
		    sk_p, ike_sa->sk_p_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  /* Allocate mac. */
  status = ssh_mac_allocate(ssh_csstr(ike_sa->prf_algorithm),
			    sk_p, ike_sa->sk_p_len, &mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_allocate(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return NULL;
    }
  ssh_mac_reset(mac);
  buffer[0] = id->id_type;
  buffer[1] = 0;
  buffer[2] = 0;
  buffer[3] = 0;
  ssh_mac_update(mac, buffer, 4);
  ssh_mac_update(mac, id->id_data, id->id_data_size);
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Adding to sk_p_mac(%s)", ike_sa->prf_algorithm),
		    buffer, 4);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Adding to sk_p_mac(%s)", ike_sa->prf_algorithm),
		    id->id_data, id->id_data_size);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */
  status = ssh_mac_final(mac, digest);
  ssh_mac_free(mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_final(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return NULL;
    }
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Output of sk_p_mac(%s)", ike_sa->prf_algorithm),
		    digest, len3);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  ret = ssh_malloc(len1 + len2 + len3);
  if (ret == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: Out of memory allocating auth_data"));
      return NULL;
    }

  memcpy(ret, p1, len1);
  memcpy(ret + len1, p2, len2);
  memcpy(ret + len1 + len2, digest, len3);
  memset(digest, 0, sizeof(digest));
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("Output auth data"),
		    ret, len1 + len2 + len3);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */
  return ret;
}
Beispiel #11
0
/* Generate stateless cookie based on the secret, nonce,
   spi_i and ip-address. */
SshIkev2Error ikev2_generate_cookie(SshIkev2Packet packet,
				    SshIkev2Sa ike_sa,
				    unsigned char *notify_data,
				    size_t notify_len)
{
  SshCryptoStatus status;
  unsigned char buffer[16];
  SshMac mac;
  size_t len;

  SSH_DEBUG(SSH_D_LOWOK, ("Starting cookie generation for SA %p", ike_sa));
  packet->ed->ike_ed->cookie_len = 4 +
    ssh_mac_length(IKEV2_COOKIE_MAC_ALGORITHM);
  packet->ed->ike_ed->cookie =
    ssh_obstack_alloc(packet->ed->obstack,
		      packet->ed->ike_ed->cookie_len);
  if (packet->ed->ike_ed->cookie == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: Out of memory allocating cookie"));
      return SSH_IKEV2_ERROR_OUT_OF_MEMORY;
    }

  if (notify_len > 4 && notify_data != NULL &&
      SSH_GET_32BIT(notify_data) ==
      ike_sa->server->context->cookie_version_number - 1)
    {
      ike_sa->server->context->cookie_secret_use_counter_prev++;
      SSH_PUT_32BIT(packet->ed->ike_ed->cookie,
		    ike_sa->server->context->cookie_version_number - 1);
      status = ssh_mac_allocate(IKEV2_COOKIE_MAC_ALGORITHM,
				ike_sa->server->context->cookie_secret_prev,
				IKEV2_COOKIE_SECRET_LEN, &mac);
    }
  else
    {
      ike_sa->server->context->cookie_secret_use_counter++;
      SSH_PUT_32BIT(packet->ed->ike_ed->cookie,
		    ike_sa->server->context->cookie_version_number);
      status = ssh_mac_allocate(IKEV2_COOKIE_MAC_ALGORITHM,
				ike_sa->server->context->cookie_secret,
				IKEV2_COOKIE_SECRET_LEN, &mac);
    }
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_allocate(%s) failed: %s",
			      IKEV2_COOKIE_MAC_ALGORITHM,
			      ssh_crypto_status_message(status)));
      return SSH_IKEV2_ERROR_OUT_OF_MEMORY;
    }

  ssh_mac_reset(mac);
  ssh_mac_update(mac, packet->ed->nonce->nonce_data,
		 packet->ed->nonce->nonce_size);
  SSH_IP_ENCODE(packet->remote_ip, buffer, len);
  ssh_mac_update(mac, buffer, len);
  ssh_mac_update(mac, packet->ike_spi_i, 8);
  status = ssh_mac_final(mac, packet->ed->ike_ed->cookie + 4);
  ssh_mac_free(mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_final(%s) failed: %s",
			      IKEV2_COOKIE_MAC_ALGORITHM,
			      ssh_crypto_status_message(status)));
      return SSH_IKEV2_ERROR_CRYPTO_FAIL;
    }
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Cookie generated"),
		    packet->ed->ike_ed->cookie,
		    packet->ed->ike_ed->cookie_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */
  return SSH_IKEV2_ERROR_OK;
}
Beispiel #12
0
/* Calculate IKE SA rekey keymat. */
SshCryptoStatus
ikev2_calculate_rekey_skeyseed(SshIkev2ExchangeData ed)
{
  unsigned char digest[SSH_MAX_HASH_DIGEST_LENGTH];
  SshCryptoStatus status;
  SshIkev2Sa new_ike_sa;
  size_t mac_len;
  SshMac mac;

  new_ike_sa = ed->ipsec_ed->new_ike_sa;
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Shared secret from Diffie-Hellman"),
		    ed->ipsec_ed->shared_secret_buffer,
		    ed->ipsec_ed->shared_secret_buffer_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Key for PRF (SK_d(old))"), ed->ike_sa->sk_d,
		    ed->ike_sa->sk_d_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  /* Allocate mac. */
  status = ssh_mac_allocate(ssh_csstr(ed->ike_sa->prf_algorithm),
			    ed->ike_sa->sk_d,
			    ed->ike_sa->sk_d_len, &mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_allocate(%s) failed: %s",
			      ed->ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return status;
    }

  /* Calculate SKEYSEED. */
  ssh_mac_reset(mac);
  if (ed->ipsec_ed->shared_secret_buffer_len != 0)
    ssh_mac_update(mac, ed->ipsec_ed->shared_secret_buffer,
		   ed->ipsec_ed->shared_secret_buffer_len);
  ssh_mac_update(mac, ed->ipsec_ed->ni->nonce_data,
		 ed->ipsec_ed->ni->nonce_size);
  ssh_mac_update(mac, ed->ipsec_ed->nr->nonce_data,
		 ed->ipsec_ed->nr->nonce_size);
  status = ssh_mac_final(mac, digest);
  ssh_mac_free(mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_final(%s) failed: %s",
			      ed->ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return status;
    }

  mac_len = ssh_mac_length(ssh_csstr(ed->ike_sa->prf_algorithm));
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("SKEYSEED"), digest, mac_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  status = ikev2_calculate_keys(new_ike_sa, digest, mac_len,
				ed->ipsec_ed->ni,
				ed->ipsec_ed->nr);
  memset(digest, 0, sizeof(digest));
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ikev2_calculate_keys(%s) failed: %s",
			      ed->ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return status;
    }

  SSH_DEBUG(SSH_D_LOWOK, ("SKEYSEED calculation done"));
  return SSH_CRYPTO_OK;
}
Beispiel #13
0
/* IKEv2 SA Diffie-Hellman Agree. */
void ikev2_skeyseed_agree(SshCryptoStatus status,
			  const unsigned char *shared_secret_buffer,
			  size_t shared_secret_buffer_len,
			  void *context)
{
  unsigned char digest[SSH_MAX_HASH_DIGEST_LENGTH];
  unsigned char *buffer;
  SshIkev2Sa ike_sa;
  Boolean truncate;
  size_t mac_len;
  SshMac mac;
  size_t len;

  ike_sa = context;

  if (ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_ABORTED)
    {
      SSH_DEBUG(SSH_D_UNCOMMON, ("DH agree callback called for aborted SA %p",
				 ike_sa));
      return;
    }

  ike_sa->initial_ed->operation = NULL;

  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_FAIL, ("Error: DH agree for SA %p failed: %s",
			     ike_sa,
			     ssh_crypto_status_message(status)));
      goto error;
    }

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Shared secret from Diffie-Hellman"),
		    shared_secret_buffer,
		    shared_secret_buffer_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  len = ssh_mac_get_max_key_length(ssh_csstr(ike_sa->prf_algorithm));

  truncate = TRUE;

  if (len == 0 ||
      len > ike_sa->initial_ed->ike_ed->ni->nonce_size +
      ike_sa->initial_ed->ike_ed->nr->nonce_size)
    {
      len = ike_sa->initial_ed->ike_ed->ni->nonce_size +
	ike_sa->initial_ed->ike_ed->nr->nonce_size;
      truncate = FALSE;
    }

  buffer = ssh_malloc(len);
  if (buffer == NULL)
    {
      /* Error. */
      status = SSH_CRYPTO_NO_MEMORY;
      SSH_DEBUG(SSH_D_ERROR, ("Error: Out of memory allocating temp buffer"));
      goto error;
    }
  memset(buffer, 0, len);
  /* XXX What should we do if the nonce 1 is 128 bytes, and nonce 2 is 32
     bytes, and the mac only takes 128 bytes as input. Currently we take 64
     bytes from nonce 1 and 32 bytes from nonce 2. Perhaps we should take 96
     bytes from nonce 1 and 32 bytes of nonce 2. */
  if (truncate)
    {
      memcpy(buffer, ike_sa->initial_ed->ike_ed->ni->nonce_data,
	     (len / 2) > ike_sa->initial_ed->ike_ed->ni->nonce_size ?
	     ike_sa->initial_ed->ike_ed->ni->nonce_size : len / 2);
      memcpy(buffer + len / 2,
	     ike_sa->initial_ed->ike_ed->nr->nonce_data,
	     (len / 2) > ike_sa->initial_ed->ike_ed->nr->nonce_size ?
	     ike_sa->initial_ed->ike_ed->nr->nonce_size : len / 2);
    }
  else
    {
      memcpy(buffer, ike_sa->initial_ed->ike_ed->ni->nonce_data,
	     ike_sa->initial_ed->ike_ed->ni->nonce_size);
      memcpy(buffer + ike_sa->initial_ed->ike_ed->ni->nonce_size,
	     ike_sa->initial_ed->ike_ed->nr->nonce_data,
	     ike_sa->initial_ed->ike_ed->nr->nonce_size);
    }


#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("Key for PRF (Ni | Nr)"), buffer, len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  /* Allocate mac. */
  status = ssh_mac_allocate(ssh_csstr(ike_sa->prf_algorithm),
			    buffer, len, &mac);
  memset(buffer, 0, len);
  ssh_free(buffer);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_allocate(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      goto error;
    }

  /* Calculate SKEYSEED. */
  ssh_mac_reset(mac);
  ssh_mac_update(mac, shared_secret_buffer, shared_secret_buffer_len);
  status = ssh_mac_final(mac, digest);
  ssh_mac_free(mac);
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_mac_final(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      goto error;
    }

  mac_len = ssh_mac_length(ssh_csstr(ike_sa->prf_algorithm));
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("SKEYSEED"), digest, mac_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  status = ikev2_calculate_keys(ike_sa, digest, mac_len,
				ike_sa->initial_ed->ike_ed->ni,
				ike_sa->initial_ed->ike_ed->nr);
  memset(digest, 0, sizeof(digest));
  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ikev2_calculate_keys(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      goto error;
    }

  if (ike_sa->initial_ed->packet_to_process)
    ikev2_restart_packet(ike_sa->initial_ed->packet_to_process);
  SSH_DEBUG(SSH_D_LOWOK, ("SKEYSEED calculation done"));
  return;
 error:
  /* Mark the failure in the agree operation. The non NULL
     sk_d will indicate that we have finished the operation,
     but zero length sk_d_len will tell that it failed. The
     actual error code will be sent to the other end after
     the next packet comes in. */
  ike_sa->sk_d = (void *) 1;
  ike_sa->sk_d_len = 0;
  if (ike_sa->initial_ed->packet_to_process)
    ikev2_restart_packet(ike_sa->initial_ed->packet_to_process);
  return;
}
Beispiel #14
0
/* Calculate IKE SA keying material. */
SshCryptoStatus ikev2_calculate_keys(SshIkev2Sa ike_sa,
				     unsigned char *digest,
				     size_t digest_len,
				     SshIkev2PayloadNonce ni,
				     SshIkev2PayloadNonce nr)
{
  unsigned char *buffer, *data;
  SshCryptoStatus status;
  size_t data_len;
  size_t mac_len;
  size_t len;

  mac_len = ssh_mac_length(ssh_csstr(ike_sa->prf_algorithm));

  /* Now we have SKEYSEED, calculate the full length needed
     for the output. */
  ike_sa->sk_d_len =
    ssh_mac_get_max_key_length(ssh_csstr(ike_sa->prf_algorithm));
  if (ike_sa->sk_d_len == 0)
    ike_sa->sk_d_len = mac_len;

  ike_sa->sk_p_len = ike_sa->sk_d_len;

  ike_sa->sk_a_len =
    ssh_mac_get_max_key_length(ssh_csstr(ike_sa->mac_algorithm));
  if (ike_sa->sk_a_len == 0)
    {
      int key_len;

      key_len =
	ssh_find_keyword_number(ssh_ikev2_mac_key_lengths,
				ssh_csstr(ike_sa->mac_algorithm));
      if (key_len == -1)
	ike_sa->sk_a_len = ssh_mac_length(ssh_csstr(ike_sa->mac_algorithm));
      else
	ike_sa->sk_a_len = key_len;
    }

  ike_sa->sk_e_len =
    ssh_cipher_get_key_length(ssh_csstr(ike_sa->encrypt_algorithm));

  len = ike_sa->sk_d_len + 2 * ike_sa->sk_a_len + 2 * ike_sa->sk_e_len +
    2 * ike_sa->sk_p_len;

  data_len = ni->nonce_size + nr->nonce_size + 16;

  buffer = ssh_malloc(len);
  data = ssh_malloc(data_len);
  if (buffer == NULL || data == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR,
		("Error: Out of memory allocating 2nd temp buffer"));
      /* Error. */
      ssh_free(buffer);
      ssh_free(data);
      return SSH_CRYPTO_NO_MEMORY;
    }
  memcpy(data, ni->nonce_data, ni->nonce_size);
  memcpy(data + ni->nonce_size, nr->nonce_data, nr->nonce_size);
  memcpy(data + ni->nonce_size + nr->nonce_size, ike_sa->ike_spi_i, 8);
  memcpy(data + ni->nonce_size + nr->nonce_size + 8, ike_sa->ike_spi_r, 8);

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("PRF+ data"), data, data_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  status = ssh_prf_plus(ike_sa->prf_algorithm, digest, digest_len,
			data, data_len, buffer, len);
  memset(digest, 0, digest_len);
  memset(data, 0, data_len);
  ssh_free(data);

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("PRF+ output"), buffer, len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */





  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_prf_plus(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      memset(buffer, 0, len);
      ssh_free(buffer);
      return status;
    }

  ike_sa->sk_d = buffer;
  ike_sa->sk_ai = buffer + ike_sa->sk_d_len;
  ike_sa->sk_ar = ike_sa->sk_ai + ike_sa->sk_a_len;
  ike_sa->sk_ei = ike_sa->sk_ar + ike_sa->sk_a_len;
  ike_sa->sk_er = ike_sa->sk_ei + ike_sa->sk_e_len;
  ike_sa->sk_pi = ike_sa->sk_er + ike_sa->sk_e_len;
  ike_sa->sk_pr = ike_sa->sk_pi + ike_sa->sk_p_len;

#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_d"), ike_sa->sk_d, ike_sa->sk_d_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_ai"), ike_sa->sk_ai, ike_sa->sk_a_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_ar"), ike_sa->sk_ar, ike_sa->sk_a_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_ei"), ike_sa->sk_ei, ike_sa->sk_e_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_er"), ike_sa->sk_er, ike_sa->sk_e_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_pi"), ike_sa->sk_pi, ike_sa->sk_p_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
		    ("SK_pr"), ike_sa->sk_pr, ike_sa->sk_p_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */
  return SSH_CRYPTO_OK;
}
Beispiel #15
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;
}
void test_variant(const char *postfix)
{
  SshCipher cipher;
  SshCryptoStatus status;
  unsigned char *iv, *key, *src, *plain;
  unsigned char *aad, *ciph, *auth_tag, digest_len;
  size_t key_len, iv_len, aad_len, src_len, src_len_block, ciph_len, 
    auth_tag_len, orig_len;
  unsigned char *orig;
  unsigned char iv_buf[16], *digest;
  unsigned char *ciph_name;
  size_t blocklen;
  int i;

  for (i = 0; combined_test_vectors[i].key != NULL; i++)
    {
      hex_string_to_buf(combined_test_vectors[i].key, &key, &key_len);
      hex_string_to_buf(combined_test_vectors[i].iv, &iv, &iv_len);
      hex_string_to_buf(combined_test_vectors[i].aad, &aad, &aad_len);
      hex_string_to_buf(combined_test_vectors[i].plaintext, &plain, &src_len);
      hex_string_to_buf(combined_test_vectors[i].plaintext, &src, &src_len);
      orig = ssh_xmemdup(src, src_len);
      orig_len = src_len;
      hex_string_to_buf(combined_test_vectors[i].ciphertext, &ciph, &ciph_len);
      hex_string_to_buf(combined_test_vectors[i].auth_tag, &auth_tag, 
			&auth_tag_len);
      digest = NULL;

      ciph_name = ssh_string_concat_2(combined_test_vectors[i].name, postfix);
      SSH_ASSERT(ciph_name);
      status = ssh_cipher_allocate(ciph_name,
				   key, key_len, TRUE, &cipher);
      if (status != SSH_CRYPTO_OK)
	{ 
	  fprintf(stderr, "Cannot allocate cipher \"%s\" (status is %s)\n", 
		  ciph_name, ssh_crypto_status_message(status));
	  exit(1);
	}




      if (iv_len != 12)
	{
	  SSH_DEBUG(1, ("Skipping test %d with IV not equal to 12 bytes", i));
	  goto dealloc_and_continue;
	}

      if (!ssh_cipher_is_auth_cipher(combined_test_vectors[i].name))
	{
	  SSH_DEBUG(1, ("Skipping test %d with non-auth cipher", i));
	  goto dealloc_and_continue;
	}

      digest_len = 
	ssh_cipher_auth_digest_length(combined_test_vectors[i].name);
      digest = ssh_xmalloc(digest_len);

      ssh_cipher_auth_reset(cipher);
      
      if (aad != NULL)
	ssh_cipher_auth_update(cipher, aad, aad_len);
      



      SSH_ASSERT(iv_len == 12);
      memcpy(iv_buf, iv, 12);
      SSH_PUT_32BIT(iv_buf + 12, 1);
      
      status = ssh_cipher_set_iv(cipher, iv_buf);
      SSH_VERIFY(status == SSH_CRYPTO_OK);

      blocklen = ssh_cipher_get_block_length(combined_test_vectors[i].name);

      src_len_block = src_len - (src_len % blocklen);
      status = ssh_cipher_transform(cipher, src, src, src_len_block);
	
      /* Process remaining bytes if test was not multiple of block size. */
      if (status == SSH_CRYPTO_OK && (src_len > src_len_block))
	{
	  status = ssh_cipher_transform_remaining(cipher, 
						  src + src_len_block,
						  src + src_len_block,
						  src_len - src_len_block);
	}

      SSH_VERIFY(status == SSH_CRYPTO_OK);
      
      SSH_VERIFY(ssh_cipher_auth_final(cipher, digest) == SSH_CRYPTO_OK);
      
      if (src_len != ciph_len || memcmp(src, ciph, src_len))
	{
	  fprintf(stderr, 
		  "Test vectors ciphertext (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("cipher computed"), src, src_len);
	  SSH_DEBUG_HEXDUMP(1, ("cipher expected"), ciph, ciph_len);
	  exit(1);
	}

      if (digest_len != auth_tag_len ||
	  memcmp(digest, auth_tag, digest_len)) 
	{
	  fprintf(stderr, 
		  "Test vectors digest (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("digest computed"), digest, digest_len);
	  SSH_DEBUG_HEXDUMP(1, ("digest expected"), auth_tag, auth_tag_len);
	  exit(1);
	}
      
      /* Redo operation, now decryption */
      ssh_cipher_free(cipher);

      status = ssh_cipher_allocate(ciph_name,
				   key, key_len, FALSE, &cipher);
      if (status != SSH_CRYPTO_OK)
	{ 
	  fprintf(stderr, "Cannot allocate cipher \"%s\" (status is %s)\n", 
		  ciph_name, ssh_crypto_status_message(status));
	  exit(1);
	}

      SSH_ASSERT(digest_len == 
		 ssh_cipher_auth_digest_length(combined_test_vectors[i].name));

      ssh_cipher_auth_reset(cipher);
      
      if (aad != NULL)
	ssh_cipher_auth_update(cipher, aad, aad_len);
      



      SSH_ASSERT(iv_len == 12);
      memcpy(iv_buf, iv, 12);
      SSH_PUT_32BIT(iv_buf + 12, 1);
      
      status = ssh_cipher_set_iv(cipher, iv_buf);
      SSH_VERIFY(status == SSH_CRYPTO_OK);

      src_len_block = src_len - (src_len % blocklen);
      status = ssh_cipher_transform(cipher, orig, src, src_len_block);
	
      /* Process remaining bytes if test was not multiple of block size. */
      if (status == SSH_CRYPTO_OK && (src_len > src_len_block))
	{
	  status = ssh_cipher_transform_remaining(cipher, 
						  orig + src_len_block,
						  src + src_len_block,
						  src_len - src_len_block);
	}

      SSH_VERIFY(status == SSH_CRYPTO_OK);
      
      SSH_VERIFY(ssh_cipher_auth_final(cipher, digest) == SSH_CRYPTO_OK);
      
      if (orig_len != ciph_len || memcmp(orig, plain, src_len))
	{
	  fprintf(stderr, 
		  "Test vectors plaintext (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("plain computed"), orig, orig_len);
	  SSH_DEBUG_HEXDUMP(1, ("plain expected"), plain, ciph_len);
	  exit(1);
	}

      if (digest_len != auth_tag_len ||
	  memcmp(digest, auth_tag, digest_len)) 
	{
	  fprintf(stderr, 
		  "Test vectors digest (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("digest computed"), digest, digest_len);
	  SSH_DEBUG_HEXDUMP(1, ("digest expected"), auth_tag, auth_tag_len);
	  exit(1);
	}
      
      /* Reset cipher and redo decryption */
      ssh_cipher_auth_reset(cipher);

      if (aad != NULL)
	ssh_cipher_auth_update(cipher, aad, aad_len);
      
      status = ssh_cipher_set_iv(cipher, iv_buf);
      SSH_VERIFY(status == SSH_CRYPTO_OK);

      status = ssh_cipher_transform(cipher, orig, src, src_len_block);
	
      /* Process remaining bytes if test was not multiple of block size. */
      if (status == SSH_CRYPTO_OK && (src_len > src_len_block))
	{
	  status = ssh_cipher_transform_remaining(cipher, 
						  orig + src_len_block,
						  src + src_len_block,
						  src_len - src_len_block);
	}

      SSH_VERIFY(status == SSH_CRYPTO_OK);
      
      SSH_VERIFY(ssh_cipher_auth_final(cipher, digest) == SSH_CRYPTO_OK);
      
      if (orig_len != ciph_len || memcmp(orig, plain, src_len))
	{
	  fprintf(stderr, 
		  "Test vectors plaintext (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("plain computed"), orig, orig_len);
	  SSH_DEBUG_HEXDUMP(1, ("plain expected"), plain, ciph_len);
	  exit(1);
	}

      if (digest_len != auth_tag_len ||
	  memcmp(digest, auth_tag, digest_len)) 
	{
	  fprintf(stderr, 
		  "Test vectors digest (ciph=%s) do not agree test=%d\n", 
		  ciph_name, i);
	  SSH_DEBUG_HEXDUMP(1, ("digest computed"), digest, digest_len);
	  SSH_DEBUG_HEXDUMP(1, ("digest expected"), auth_tag, auth_tag_len);
	  exit(1);
	}
      
      SSH_DEBUG(2, ("Test %d (cipher=`%s') successful", i, 
		    combined_test_vectors[i].name));

    dealloc_and_continue:
      if (cipher) 
	ssh_cipher_free(cipher);

      ssh_xfree(digest);
      ssh_xfree(key); 
      ssh_xfree(iv);  
      ssh_xfree(aad);
      ssh_xfree(src); 
      ssh_xfree(orig); 
      ssh_xfree(plain); 
      ssh_xfree(ciph); 
      ssh_xfree(auth_tag);
      ssh_xfree(ciph_name);
    }

}
Boolean
ssh_pm_manual_sa_handler(SshPm pm, SshPmQm qm)
{
  SshPmTunnel tunnel;
  SshUInt32 num_ciphers;
  SshUInt32 num_macs;
  SshUInt32 num_compressions;
  SshPmCipher cipher = NULL;
  SshPmMac mac = NULL;
  SshPmCompression compression = NULL;
  Boolean esp_has_mac = FALSE;
  size_t encr_key_len = 0;
  size_t auth_key_len = 0;
  const unsigned char *encr_key_in = NULL;
  const unsigned char *encr_key_out = NULL;
  const unsigned char *auth_key_in = NULL;
  const unsigned char *auth_key_out = NULL;
  SshUInt32 key_size;
  char keysizebuf[8] = {0};

  tunnel = qm->tunnel;
  SSH_ASSERT(tunnel != NULL);
  
  /* Initialize transform data. */
  
  /* First, general initialization. */
  SSH_ASSERT(tunnel->num_peers > 0);
  qm->sa_handler_data.trd.data.gw_addr = tunnel->peers[0];
  ssh_pm_tunnel_select_local_ip(tunnel,
				&qm->sa_handler_data.trd.data.gw_addr,
				&qm->sa_handler_data.trd.data.own_addr);
  qm->sa_handler_data.trd.data.own_ifnum = SSH_INTERCEPTOR_INVALID_IFNUM;
  
  /* Clear trigger packet selectors. */ 
  SSH_IP_UNDEFINE(&qm->sel_dst);
  SSH_IP_UNDEFINE(&qm->sel_src);
  qm->sel_src_port = 0;
  qm->sel_dst_port = 0;
  qm->sel_ipproto = SSH_IPPROTO_ANY;

  /* From which rule-set do the inbound packets arrive? */
  qm->sa_handler_data.trd.data.inbound_tunnel_id = tunnel->tunnel_id;

  if (qm->tunnel->outer_tunnel)
    {
      qm->sa_handler_data.trd.control.outer_tunnel_id = 
	qm->tunnel->outer_tunnel->tunnel_id;
      qm->sa_handler_data.trd.data.restart_after_tre = 1;
    }

  /* Check if we require transport mode. */
  if (!(tunnel->flags & SSH_PM_T_TRANSPORT_MODE))
    qm->sa_handler_data.trd.data.transform |= SSH_PM_IPSEC_TUNNEL;

  /* Set df-bit policy. */
  if (qm->rule->flags & SSH_PM_RULE_DF_SET)
    qm->sa_handler_data.trd.data.df_bit_processing = SSH_ENGINE_DF_SET;
  else if (qm->rule->flags & SSH_PM_RULE_DF_CLEAR)
    qm->sa_handler_data.trd.data.df_bit_processing = SSH_ENGINE_DF_CLEAR;
  else
    qm->sa_handler_data.trd.data.df_bit_processing = SSH_ENGINE_DF_KEEP;

  /* Get algorithms. */

  (void) ssh_pm_ipsec_num_algorithms(pm, tunnel->transform,
				     0,
                                     &num_ciphers, &num_macs,
                                     &num_compressions, NULL);

  if (num_ciphers
      && (tunnel->transform & SSH_PM_IPSEC_ESP))
    {
      cipher = ssh_pm_ipsec_cipher(pm, 0, tunnel->transform);
      SSH_ASSERT(cipher != NULL);
      ssh_pm_cipher_key_sizes(tunnel, cipher, SSH_PM_ALG_IPSEC_SA,
                              NULL, NULL, NULL, &key_size);
      encr_key_len = key_size / 8;
      ssh_snprintf(keysizebuf, sizeof(keysizebuf), "/%u",
                   (unsigned int) key_size);
    }
  else
    {
      /* Configuration specifies a cipher but no esp,
	 which does not make much sense. */
      num_ciphers = 0;
    }

  if (num_macs
      && (tunnel->transform & (SSH_PM_IPSEC_ESP | SSH_PM_IPSEC_AH)))
    {
      mac = ssh_pm_ipsec_mac(pm, 0, tunnel->transform);
      SSH_ASSERT(mac != NULL);
      ssh_pm_mac_key_sizes(tunnel, mac, SSH_PM_ALG_IPSEC_SA,
                           NULL, NULL, NULL, &key_size);
      auth_key_len = key_size / 8;
    }
  else
    {
      /* Configuration specifies a mac but no esp or ah,
	 which does not make much sense. */
      num_macs = 0;
    }

  if (num_compressions
      && (tunnel->transform & SSH_PM_IPSEC_IPCOMP))
    {
      compression = ssh_pm_compression(pm, 0, tunnel->transform);
      SSH_ASSERT(compression != NULL);
    }
  else
    {
      /* Configuration specifies a compression alg but no ipcomp,
	 which does not make much sense. */
      num_compressions = 0;
    }

  /* Store key lengths into the transform data structure. */
  qm->sa_handler_data.trd.data.cipher_key_size = encr_key_len;
  qm->sa_handler_data.trd.data.cipher_iv_size = num_ciphers ?
    cipher->iv_size / 8 : 0;
  qm->sa_handler_data.trd.data.cipher_nonce_size = 0;
  qm->sa_handler_data.trd.data.mac_key_size = auth_key_len;

  /* Split key material into sub-keys. */

  SSH_ASSERT(tunnel->u.manual.key_len == (encr_key_len + auth_key_len) * 2);

  encr_key_in = tunnel->u.manual.key;
  auth_key_in = encr_key_in + encr_key_len;
  encr_key_out = auth_key_in + auth_key_len;
  auth_key_out = encr_key_out + encr_key_len;

  if (tunnel->transform & SSH_PM_IPSEC_AH)
    {
      qm->sa_handler_data.trd.data.transform |= SSH_PM_IPSEC_AH;

      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_AH_IN]
        = tunnel->u.manual.ah_spi_in;
      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_AH_OUT]
        = tunnel->u.manual.ah_spi_out;

      /* Set the algorithm. */
      SSH_ASSERT(mac != NULL);
      qm->sa_handler_data.trd.data.transform |= mac->mask_bits[1];

      /* Get inbound key. */
      memcpy(qm->sa_handler_data.trd.data.keymat
             + SSH_IPSEC_MAX_ESP_KEY_BITS / 8,
             auth_key_in, auth_key_len);

      SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
                        ("Inbound AH MAC key:"),
                        (qm->sa_handler_data.trd.data.keymat
                         + SSH_IPSEC_MAX_ESP_KEY_BITS / 8),
                        auth_key_len);

      /* Get outbound key. */
      memcpy(qm->sa_handler_data.trd.data.keymat
             + SSH_IPSEC_MAX_KEYMAT_LEN / 2
             + SSH_IPSEC_MAX_ESP_KEY_BITS / 8,
             auth_key_out, auth_key_len);

      SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
                        ("Outbound AH MAC key:"),
                        (qm->sa_handler_data.trd.data.keymat
                         + SSH_IPSEC_MAX_KEYMAT_LEN / 2
                         + SSH_IPSEC_MAX_ESP_KEY_BITS / 8),
                        auth_key_len);
    }

  if (tunnel->transform & SSH_PM_IPSEC_ESP)
    {
      qm->sa_handler_data.trd.data.transform |= SSH_PM_IPSEC_ESP;

      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_ESP_IN]
        = tunnel->u.manual.esp_spi_in;
      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_ESP_OUT]
        = tunnel->u.manual.esp_spi_out;

      /* Set the algorithms. */
      if (num_ciphers)
        {
          SSH_ASSERT(cipher != NULL);
          qm->sa_handler_data.trd.data.transform |= cipher->mask_bits;
        }
      if (num_macs && (tunnel->transform & SSH_PM_IPSEC_AH) == 0)
        {
          SSH_ASSERT(mac != NULL);
          qm->sa_handler_data.trd.data.transform |= mac->mask_bits[0];
          esp_has_mac = TRUE;
        }

      /* Get inbound keys. */
      if (num_ciphers)
        {
          memcpy(qm->sa_handler_data.trd.data.keymat,
		 encr_key_in, encr_key_len);
          SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("Inbound ESP cipher key:"),
                            qm->sa_handler_data.trd.data.keymat,
			    encr_key_len);
        }
      if (esp_has_mac)
        {
          memcpy(qm->sa_handler_data.trd.data.keymat
                 + SSH_IPSEC_MAX_ESP_KEY_BITS / 8,
                 auth_key_in, auth_key_len);
          SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
                            ("Inbound ESP MAC key:"),
                            (qm->sa_handler_data.trd.data.keymat
                             + SSH_IPSEC_MAX_ESP_KEY_BITS / 8),
                            auth_key_len);
        }

      /* Get outbound keys. */
      if (num_ciphers)
        {
          memcpy(qm->sa_handler_data.trd.data.keymat
                 + SSH_IPSEC_MAX_KEYMAT_LEN / 2,
                 encr_key_out, encr_key_len);
          SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
                            ("Outbound ESP cipher key:"),
                            (qm->sa_handler_data.trd.data.keymat
                             + SSH_IPSEC_MAX_KEYMAT_LEN / 2),
                            encr_key_len);
        }
      if (esp_has_mac)
        {
          memcpy(qm->sa_handler_data.trd.data.keymat
                 + SSH_IPSEC_MAX_KEYMAT_LEN / 2
                 + SSH_IPSEC_MAX_ESP_KEY_BITS / 8,
                 auth_key_out, auth_key_len);
          SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP,
                            ("Outbound ESP MAC key:"),
                            (qm->sa_handler_data.trd.data.keymat
                             + SSH_IPSEC_MAX_KEYMAT_LEN / 2
                             + SSH_IPSEC_MAX_ESP_KEY_BITS / 8),
                            auth_key_len);
        }

    }

  if (tunnel->transform & SSH_PM_IPSEC_IPCOMP)
    {
      qm->sa_handler_data.trd.data.transform |= SSH_PM_IPSEC_IPCOMP;
      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_IPCOMP_IN]
        = tunnel->u.manual.ipcomp_cpi_in;
      qm->sa_handler_data.trd.data.spis[SSH_PME_SPI_IPCOMP_OUT]
        = tunnel->u.manual.ipcomp_cpi_out;

      /* Set algorithm. */
      SSH_ASSERT(compression != NULL);
      qm->sa_handler_data.trd.data.transform |= compression->mask_bits;
    }

  /* Final initialization. */
  qm->sa_handler_data.trd.data.transform |= SSH_PM_IPSEC_MANUAL;

  /* Set peer handle to invalid value. */
  qm->sa_handler_data.trd.control.peer_handle = SSH_IPSEC_INVALID_INDEX;

  qm->sa_handler_data.trd.data.packet_enlargement = 
    ssh_pm_compute_trd_packet_enlargement(pm, 
			     qm->sa_handler_data.trd.data.transform,
			     SSH_IP_IS6(&qm->sa_handler_data.trd.data.gw_addr),
			     cipher, mac);












  if (mac && mac->digest_size == 0)
    {
      qm->sa_handler_data.trd.data.packet_enlargement += 32;
    }

  /* Start an SA handler thread that takes care of installing the
     transform and outbound rule. */
  ssh_fsm_thread_init(&pm->fsm, &qm->sub_thread,
                      ssh_pm_st_sa_handler_start, NULL_FNPTR, NULL_FNPTR, qm);
  ssh_fsm_set_thread_name(&qm->sub_thread, "SA handler");

  /* All done. */
  return TRUE;
}
Beispiel #18
0
/*-------------------------------------------------------------------------
  ssh_driver_set_information()

  Request changes in the state of virtual NIC. All but OID_PNP_SET_POWER,
  OID_PNP_ENABLE_WAKE_UP and OID_TCP_TASK_OFFLOAD change requests are 
  passed down to the underlaying NIC.

  
  Arguments:
  miniport_context - virtual NIC object
  oid - change request operation identifier
  info - data for change operation
  info_len - data buffer length
  bytes_read - how many bytes has been read from info buffer
  bytes_needed - how many bytes is needed to complete the set operation
                 successfully

  Returns:
  NDIS_STATUS_SUCCESS - query completed successfully,
  NDIS_STATUS_PENDING - change request completion pending,
  NDIS_STATUS_RESOURCES - resource allocation for change request failed
  
  Notes:                                                         
  
  Default IRQL: DISPATCH_LEVEL
  -------------------------------------------------------------------------*/
static NDIS_STATUS
ssh_driver_set_information(NDIS_HANDLE miniport_context,
                           NDIS_OID oid,
                           PVOID info,
                           ULONG info_len,
                           PULONG bytes_read,
                           PULONG bytes_needed)
{
  SshNdisIMAdapter adapter = (SshNdisIMAdapter)miniport_context;
  struct _SET_INFORMATION *set;
  SshRequest request;
  NDIS_STATUS status;
  PVOID info_buf = info;

  SSH_ASSERT(SSH_GET_IRQL() <= SSH_DISPATCH_LEVEL);
  SSH_ASSERT(adapter != NULL);

  if (info)
    SSH_DEBUG_HEXDUMP(SSH_D_MIDSTART,
                      ("Adapter %@ MiniportSetInformation: oid=%@, data:",
                       ssh_adapter_id_st_render, adapter, 
                       ssh_ndis_oid_render, &oid),
                      info, info_len);
  else
    SSH_DEBUG(SSH_D_MIDSTART,
              ("Adapter %@ MiniportSetInformation: oid=%@",
               ssh_adapter_id_st_render, adapter, 
               ssh_ndis_oid_render, &oid));

  /* OID_PNP_SET_POWER must be handled by us (not forwarded to underlyng
     miniport driver). */
  if (oid == OID_PNP_SET_POWER)
    {
      status = ssh_adapter_handle_set_power(adapter, info, info_len,
                                            bytes_read, bytes_needed);
      goto end;
    }

#ifdef _WIN32_WCE
  *bytes_read = 0;
  *bytes_needed = 0;
#else
  if (MmIsAddressValid(bytes_read))
    *bytes_read = 0;
  if (MmIsAddressValid(bytes_needed))
    *bytes_needed = 0;
  
  /* Check if the address for operation is within user space */ 
  if (info_len > 0 && info <= MM_HIGHEST_USER_ADDRESS)
    {
      /* Map user space address to system address */
      PMDL mdl = IoAllocateMdl(info, info_len, FALSE, FALSE, NULL);
      if (!mdl)
        {
          info_buf = NULL;
        }
      else
        {
          info_buf = MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
          IoFreeMdl(mdl);
        }
    }

  /* Check if address is valid */
  if (info_len > 0 && !MmIsAddressValid(info_buf))
    {
      status = NDIS_STATUS_NOT_ACCEPTED;
      goto end;
    }
#endif /* _WIN32_WCE */
  
  /* Allocate memory for the request */
  request = NdisAllocateFromNPagedLookasideList(&adapter->request_list);
  if (request == NULL)
    {
      status = NDIS_STATUS_RESOURCES;
      goto end;
    }

  /* Fill the data for our request */
  request->orig_request.RequestType = NdisRequestSetInformation;
  request->bytes_read_written = bytes_read;
  request->bytes_needed = bytes_needed;
  request->request_done_cb = ssh_adapter_set_request_done;
  request->asynch_completion = TRUE;
  request->queued = FALSE;

  set = &(request->orig_request.DATA.SET_INFORMATION);
  set->Oid = oid;
  set->InformationBuffer = info_buf;
  set->InformationBufferLength = info_len;
  set->BytesRead = 0;
  set->BytesNeeded = 0;

  status = ssh_adapter_handle_set_request(adapter, &request->orig_request);

 end:
  SSH_DEBUG(SSH_D_MIDOK,
            ("Adapter %@ MiniportSetInformation: status=%@", 
             ssh_adapter_id_st_render, adapter, 
             ssh_ndis_status_render, &status));

  return (status);
}
Beispiel #19
0
static NDIS_STATUS
ssh_driver_send_wan_packet(NDIS_HANDLE miniport_context,
                           NDIS_HANDLE link_handle,
                           PNDIS_WAN_PACKET packet) 
{
  SshNdisIMAdapter adapter = (SshNdisIMAdapter)miniport_context;
  NDIS_STATUS status;
  SshInterceptorProtocol protocol;

  SSH_DEBUG(SSH_D_LOWSTART, 
            ("Adapter %@ MiniportWanSend: link context 0x%p",
             ssh_adapter_id_st_render, adapter, link_handle));
  SSH_DEBUG_HEXDUMP(SSH_D_PCKDMP, ("MiniportWanSend: packet:"),
                    (unsigned char *)packet->CurrentBuffer,
                    (size_t)packet->CurrentLength);

  SSH_ASSERT(adapter != NULL);

  /* Only one channel per adapter currently supported. */
  if (link_handle != adapter->wan_link_handle)
    {
      SSH_DEBUG(SSH_D_FAIL, 
                ("Adapter %@ MiniportWanSend: unknown link handle",
                 ssh_adapter_id_st_render, adapter));
      return NDIS_STATUS_FAILURE;
    }

  /* Perform PPP decapsulation and potential drop/reject/passthrough. */
  if (!ssh_wan_intercept_from_protocol(adapter, packet, &protocol))
    {
      SSH_DEBUG(SSH_D_LOWSTART, 
                ("Adapter %@ MiniportWanSend: processing non-IP frame",
                 ssh_adapter_id_st_render, adapter));
      ssh_wan_process_from_protocol(adapter, packet, &status);
      return status;
    }

  SSH_DEBUG(SSH_D_LOWSTART, 
            ("Adapter %@ MiniportWanSend: intercepting IP packet",
             ssh_adapter_id_st_render, adapter));

  /* If there are buffered packets already, insert this one at the end
     of the queue. */
  if (!IsListEmpty(&adapter->send_wait_queue))
    {
      SshNdisIMInterceptor interceptor;

    buffer_packet:

      SSH_DEBUG(SSH_D_LOWSTART, 
                ("Adapter %@ MiniportWanSend: queuing IP packet",
                 ssh_adapter_id_st_render, adapter));

      /* Store protocol in MacReserved1 for the time the packet is in
         the queue. */
      packet->MacReserved1 = (PVOID)protocol;

      NdisAcquireSpinLock(&adapter->send_wait_queue_lock);

      /* Queue this packet. */
      InsertTailList(&adapter->send_wait_queue, &packet->WanPacketQueue);

      interceptor = (SshNdisIMInterceptor)adapter->interceptor;
      NdisReleaseSpinLock(&adapter->send_wait_queue_lock);

      InterlockedIncrement(&interceptor->delayed_sends);

      return NDIS_STATUS_PENDING;
    }

  /* Check if we are ready to process the packet */
  if (ssh_adapter_is_enabled(adapter) == FALSE)
    {
      SSH_DEBUG(SSH_D_LOWSTART, 
                ("Adapter %@ MiniportWanSend: adapter not enabled",
                 ssh_adapter_id_st_render, adapter));
      return NDIS_STATUS_FAILURE;
    }

  /* Try sending the packet and if that doesn't succeed, queue it. */
  if (!ssh_driver_copy_and_send_wan(adapter, packet, protocol))
    {
      SSH_DEBUG(SSH_D_LOWSTART,
                ("Adapter %@ MiniportWanSend: can't send IP "
                 "packet to engine",
                 ssh_adapter_id_st_render, adapter));
      goto buffer_packet;
    }

  SSH_DEBUG(SSH_D_LOWSTART, 
            ("Adapter %@ MiniportWanSend: sent IP packet to engine",
             ssh_adapter_id_st_render, adapter));

  return NDIS_STATUS_SUCCESS;
}
Beispiel #20
0
void ssh_decode_tty_flags(int fd, unsigned char *buf, size_t buf_len)
{
  SshBuffer buffer;
  
#ifdef USING_TERMIOS
  struct termios tio;
#endif /* USING_TERMIOS */
#ifdef USING_SGTTY
  struct sgttyb tio;
  struct tchars tiotc;
  struct ltchars tioltc;
  int tiolm;
#ifdef TIOCGSTAT
  struct tstatus tiots;
#endif /* TIOCGSTAT */
#endif
  int opcode, baud;

  if (!isatty(fd))
    {
      SSH_TRACE(2, ("Not a tty. (fd = %d)", fd));
      return;
    }

  if (buf_len == 0)
    return;
  
  SSH_DEBUG_HEXDUMP(5, ("received tty-flags buffer"), buf, buf_len);

  ssh_buffer_init(&buffer);

  ssh_buffer_append(&buffer, buf, buf_len);
  
  /* Get old attributes for the terminal.  We will modify these flags. 
     I am hoping that if there are any machine-specific modes, they will
     initially have reasonable values. */
#ifdef USING_TERMIOS
  if (tcgetattr(fd, &tio) < 0)
    return;
#endif /* USING_TERMIOS */
#ifdef USING_SGTTY
  if (ioctl(fd, TIOCGETP, &tio) < 0)
    return;
  if (ioctl(fd, TIOCGETC, &tiotc) < 0)
    return;
  if (ioctl(fd, TIOCLGET, &tiolm) < 0)
    return;
  if (ioctl(fd, TIOCGLTC, &tioltc) < 0)
    return;
#ifdef TIOCGSTAT
  if (ioctl(fd, TIOCGSTAT, &tiots) < 0)
    return;
#endif /* TIOCGSTAT */
#endif /* USING_SGTTY */

  for (;;)
    {
      ssh_decode_buffer(&buffer,
                    SSH_FORMAT_CHAR, &opcode,
                    SSH_FORMAT_END);
      
      switch(opcode)
        {
        case TTY_OP_END:
          goto set;

        case TTY_OP_ISPEED:
          baud = GET_UINT32();
          if (cfsetispeed(&tio, baud_to_speed(baud)) < 0)
            ssh_warning("cfsetispeed failed for %d", baud);
          break;

        case TTY_OP_OSPEED:
          baud = GET_UINT32();
          if (cfsetospeed(&tio, baud_to_speed(baud)) < 0)
            ssh_warning("cfsetospeed failed for %d", baud);
          break;

#ifdef USING_TERMIOS
#define TTYCHAR(NAME, OP)                               \
        case OP:                                        \
          tio.c_cc[NAME] = GET_UINT32();                \
          break;
#define TTYMODE(NAME, FIELD, OP)                        \
        case OP:                                        \
          if (GET_UINT32())                     \
            tio.FIELD |= NAME;                          \
          else                                          \
            tio.FIELD &= ~NAME;                         \
          break;
#define SGTTYCHAR(NAME, OP)
#define SGTTYMODE(NAME, FIELD, OP)
#define SGTTYMODEN(NAME, FIELD, OP)
#endif /* USING_TERMIOS */

#ifdef USING_SGTTY
#define TTYCHAR(NAME, OP)
#define TTYMODE(NAME, FIELD, OP)
#define SGTTYCHAR(NAME, OP)                             \
        case OP:                                        \
          NAME = GET_UINT32();                  \
          break;
#define SGTTYMODE(NAME, FIELD, OP)                      \
        case OP:                                        \
          if (GET_UINT32())                     \
            FIELD |= NAME;                              \
          else                                          \
            FIELD &= ~NAME;                             \
          break;
#define SGTTYMODEN(NAME, FIELD, OP)                     \
        case OP:                                        \
          if (GET_UINT32())                     \
            FIELD &= ~NAME;                             \
          else                                          \
            FIELD |= NAME;                              \
          break;
#endif /* USING_SGTTY */

#include "sshttyflagsi.h"

#undef TTYCHAR
#undef TTYMODE
#undef SGTTYCHAR
#undef SGTTYMODE
#undef SGTTYMODEN

        default:
          SSH_TRACE(1, ("Ignoring unsupported tty mode opcode %d (0x%x)",
                        opcode, opcode));
          /* Opcodes 0 to 160 are defined to have a uint32 argument. */
          if (opcode >= 0 && opcode < 160)
            {
              (void)GET_UINT32();
              break;
            }
          /* It is a truly undefined opcode (160 to 255).  We have no idea
             about its arguments.  So we must stop parsing.  Note that some
             data may be left in the packet; hopefully there is nothing more
             coming after the mode data. */
          ssh_warning("ssh_decode_tty_flags: unknown opcode %d", opcode);
          goto set;
        }
    }

 set:
  /* Set the new modes for the terminal. */
#ifdef USING_TERMIOS
  if (tcsetattr(fd, TCSANOW, &tio) < 0)
    ssh_warning("Setting tty modes failed: %.100s", strerror(errno));
#endif /* USING_TERMIOS */
#ifdef USING_SGTTY
  /* termio's ECHOE is really both LCRTBS and LCRTERA -
     so wire them together */
  if (tiolm & LCRTERA)
    tiolm |= LCRTBS;
  if (ioctl(fd, TIOCSETP, &tio) < 0
      || ioctl(fd, TIOCSETC, &tiotc) < 0
      || ioctl(fd, TIOCLSET, &tiolm) < 0
      || ioctl(fd, TIOCSLTC, &tioltc) < 0
#ifdef TIOCSSTAT
      || ioctl(fd, TIOCSSTAT, &tiots) < 0
#endif /* TIOCSSTAT */
     ) 
    ssh_warning("Setting tty modes failed: %.100s", strerror(errno));
#endif /* USING_SGTTY */
}
Beispiel #21
0
/* Generate keying material for the IPsec SA. The keymat is
   filled with the keying material. */
SshIkev2Error ssh_ikev2_fill_keymat(SshIkev2ExchangeData ed,
				    unsigned char *keymat,
				    size_t keymat_len)
{
  SshIkev2Sa ike_sa = ed->ike_sa;
  SshIkev2PayloadNonce ni, nr;
  SshCryptoStatus status;
  unsigned char *buffer;
  size_t len;

#ifdef SSHDIST_IKEV1
  if (ike_sa->flags & SSH_IKEV2_IKE_SA_ALLOCATE_FLAGS_IKEV1)
    {
      if (keymat_len > ed->ipsec_ed->ikev1_keymat_len)
	{
	  SSH_DEBUG(SSH_D_FAIL, ("Insufficient keying material available, "
				 "requested bytes %d, available bytes %d",
				 keymat_len, ed->ipsec_ed->ikev1_keymat_len));
	  return SSH_IKEV2_ERROR_CRYPTO_FAIL;
	}

      memcpy(keymat, ed->ipsec_ed->ikev1_keymat, keymat_len);
      return SSH_IKEV2_ERROR_OK;
    }
#endif /* SSHDIST_IKEV1 */

  if (ike_sa->initial_ed == ed)
    {
      ni = ed->ike_ed->ni;
      nr = ed->ike_ed->nr;
    }
  else if (ed->ipsec_ed != NULL)
    {
      ni = ed->ipsec_ed->ni;
      nr = ed->ipsec_ed->nr;
    }

  else
    {
      return SSH_IKEV2_ERROR_INVALID_ARGUMENT;
    }
  len = ed->ipsec_ed->shared_secret_buffer_len +  ni->nonce_size +
    nr->nonce_size;

  buffer = ssh_malloc(len);
  if (buffer == NULL)
    {
      /* Error. */
      SSH_DEBUG(SSH_D_ERROR, ("Error: Out of memory allocating buffer"));
      return SSH_IKEV2_ERROR_OUT_OF_MEMORY;
    }
  if (ed->ipsec_ed->shared_secret_buffer_len != 0)
    memcpy(buffer, ed->ipsec_ed->shared_secret_buffer,
	   ed->ipsec_ed->shared_secret_buffer_len);
  memcpy(buffer + ed->ipsec_ed->shared_secret_buffer_len,
	 ni->nonce_data, ni->nonce_size);
  memcpy(buffer + ed->ipsec_ed->shared_secret_buffer_len + ni->nonce_size,
	 nr->nonce_data, nr->nonce_size);
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("Using PRF+(%s) with key",
				     ike_sa->prf_algorithm),
		    ike_sa->sk_d, ike_sa->sk_d_len);
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("With PRF+ data"),
		    buffer, len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */

  status = ssh_prf_plus(ike_sa->prf_algorithm,
			ike_sa->sk_d, ike_sa->sk_d_len,
			buffer, len, keymat, keymat_len);
  memset(buffer, 0, len);
  ssh_free(buffer);

  if (status != SSH_CRYPTO_OK)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Error: ssh_prf_plus(%s) failed: %s",
			      ike_sa->prf_algorithm,
			      ssh_crypto_status_message(status)));
      return SSH_IKEV2_ERROR_CRYPTO_FAIL;
    }
#ifdef SSH_IKEV2_CRYPTO_KEY_DEBUG
  SSH_DEBUG_HEXDUMP(SSH_D_DATADUMP, ("Output of PRF+"),
		    keymat, keymat_len);
#endif /* SSH_IKEV2_CRYPTO_KEY_DEBUG */
  return SSH_IKEV2_ERROR_OK;
}
SshTlsTransStatus
ssh_tls_trans_read_finished(SshTlsProtocolState s,
                            SshTlsHandshakeType type,
                            unsigned char *data, int data_len)
{
    unsigned char *ptr;
    int len;
    unsigned char locally_computed_verify_data[36];
    unsigned char hashes[16 + 20];

    CHECKTYPE(SSH_TLS_HS_FINISHED);
    SSH_DEBUG(7, ("Got the (expected) finished message."));

    SSH_ASSERT(s->kex.handshake_history != NULL);

#ifdef SSH_TLS_SSL_3_0_COMPAT
    if (s->protocol_version.major == 3 && s->protocol_version.minor == 0)
    {
        if (data_len != 36)
        {
            FAIL(SSH_TLS_ALERT_DECODE_ERROR,
                 ("Invalid length verify data (%d bytes).", data_len));
        }

        ptr = ssh_buffer_ptr(s->kex.handshake_history);
        len = ssh_buffer_len(s->kex.handshake_history);

        SSH_DEBUG(7, ("Verifying SSL3 finished digest, buffer len = %d.",
                      len));

        SSH_DEBUG_HEXDUMP(10, ("Handshake buffer"), ptr, len);

        if (!ssh_tls_ssl_finished_digest(s->kex.master_secret, 48,
                                         ptr, len,
                                         s->conf.is_server,
                                         locally_computed_verify_data))
        {
            FAIL(SSH_TLS_ALERT_HANDSHAKE_FAILURE,
                 ("Local and remote verify data do not match."));
        }

        if (memcmp(data, locally_computed_verify_data, 36))
        {
            SSH_DEBUG_HEXDUMP(5, ("Local and remote verify data do not match. "
                                  "Local: "),
                              locally_computed_verify_data, 36);
            SSH_DEBUG_HEXDUMP(5, ("Remote: "),
                              data, 36);
            FAIL(SSH_TLS_ALERT_HANDSHAKE_FAILURE,
                 ("Local and remote verify data do not match."));
        }
        goto accepted;
    }

#endif /* SSH_TLS_SSL_3_0_COMPAT */

    ptr = ssh_buffer_ptr(s->kex.handshake_history);
    len = ssh_buffer_len(s->kex.handshake_history);

    if (ssh_hash_of_buffer("md5", ptr, len, hashes) != SSH_CRYPTO_OK)
        return SSH_TLS_TRANS_FAILED;
    if (ssh_hash_of_buffer("sha1", ptr, len, hashes + 16) != SSH_CRYPTO_OK)
        return SSH_TLS_TRANS_FAILED;

    ssh_tls_prf(s->kex.master_secret, 48,
                (unsigned char *)
                (s->conf.is_server ? "client finished" : "server finished"),
                15 /* strlen("client finished") */,
                hashes, 16 + 20,
                locally_computed_verify_data, 12);

    memset(hashes, 0, 16 + 20);

    if (data_len != 12)
    {
        FAIL(SSH_TLS_ALERT_DECODE_ERROR,
             ("Invalid length verify data (%d bytes).", data_len));
    }

    if (memcmp(data, locally_computed_verify_data, 12))
    {
        SSH_DEBUG_HEXDUMP(5, ("Local and remote verify data do not match. "
                              "Local: "),
                          locally_computed_verify_data, 12);
        SSH_DEBUG_HEXDUMP(5, ("Remote: "),
                          data, 12);
        FAIL(SSH_TLS_ALERT_ILLEGAL_PARAMETER,
             ("Local and remote verify data do not match."));
    }

accepted:
    memset(locally_computed_verify_data, 0,
           sizeof(locally_computed_verify_data));

    SSH_DEBUG(6, ("Verify data verified."));

    /* The order of client's and server's change_cipher and finished
       messages is different depending on whether we are resuming and
       old session or defining a new one. This is another strange
       property of the TLS protocol. */
    if ((s->conf.is_server && !(s->kex.flags & SSH_TLS_KEX_NEW_SESSION))
            ||
            (!s->conf.is_server && (s->kex.flags & SSH_TLS_KEX_NEW_SESSION)))
    {
        ssh_tls_kex_finished(s);
    }
    else
    {
        if (s->conf.is_server)
        {
            s->kex.state = SSH_TLS_KEX_SEND_S_CC;
        }
        else
        {
            s->kex.state = SSH_TLS_KEX_SEND_C_CC;
        }
    }

    return SSH_TLS_TRANS_OK;
}
static void
receive_virtual_adapter_packet_cb(SshInterceptor interceptor, 
				  const unsigned char *data, size_t len)
{
  SshUInt32 flags;
  SshUInt32 ifnum_in, ifnum_out;
  SshUInt32 protocol;
  const unsigned char *packet, *internal;
  size_t packet_len, internal_len;
  SshInterceptorVirtualAdapter va;
  SshInterceptorPacket pp;

  if (ssh_decode_array(data, len,
                       SSH_FORMAT_UINT32, &flags,
                       SSH_FORMAT_UINT32, &ifnum_in,
                       SSH_FORMAT_UINT32, &ifnum_out,
                       SSH_FORMAT_UINT32, &protocol,
                       SSH_FORMAT_UINT32_STR_NOCOPY, &packet, &packet_len,
                       SSH_FORMAT_UINT32_STR_NOCOPY, &internal, &internal_len,
                       SSH_FORMAT_END) != len)
    {
      SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter receive message"),
                        data, len);
      return;
    }

  /* Find the virtual adapter of this receive operation. */
  ssh_mutex_lock(interceptor->mutex);
  for (va = interceptor->virtual_adapters; va; va = va->next)
    if (va->adapter_ifnum == ifnum_in)
      break;
  ssh_mutex_unlock(interceptor->mutex);

  if (va == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR,
                ("virtual adapter receive for unknown adapter %d",
		 (int) ifnum_in));
      return;
    }

  if (va->packet_cb == NULL_FNPTR)
    return;

  /* Assert that the interface numbers fit into SshInterceptorIfnum. */
  SSH_ASSERT(ifnum_in <= SSH_INTERCEPTOR_MAX_IFNUM);
  SSH_ASSERT(ifnum_out <= SSH_INTERCEPTOR_MAX_IFNUM);

  /* Allocate a packet object. */
  pp = ssh_interceptor_packet_alloc(interceptor, 
				    SSH_PACKET_FROMADAPTER, 
				    protocol,
                                    (SshInterceptorIfnum) ifnum_in, 
				    (SshInterceptorIfnum) ifnum_out, 
				    packet_len);

  if (pp == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR,
                ("could not allocate packet for virtual adapter receive"));
      return;
    }

  if (!ssh_interceptor_packet_import_internal_data(pp, internal, internal_len))
    {
      SSH_DEBUG(SSH_D_ERROR, ("import failed"));
      return;
    }

  pp->flags = flags;

  if (!ssh_interceptor_packet_copyin(pp, 0, packet, packet_len))
    {
      SSH_DEBUG(SSH_D_ERROR, ("copyin failed, dropping packet"));
      return;
    }

  SSH_DEBUG(SSH_D_NICETOKNOW, 
	    ("received packet callback for virtual adapter %d from forwarder.",
	     (int) ifnum_in));

  /* Pass the packet to the user-supplied packet callback. */
  (*va->packet_cb)(interceptor, pp, va->adapter_context);
}
static void
receive_virtual_adapter_status_cb(SshInterceptor interceptor, 
				  const unsigned char *data,
				  size_t len)
{
  SshUInt32 operation_id;
  SshUInt32 error;
  SshUInt32 adapter_ifnum;
  char *adapter_name;
  SshUInt32 adapter_state;
  SshInterceptorVirtualAdapterOp op;
  SshInterceptorVirtualAdapter va;
  void *adapter_context;
  
  if (ssh_decode_array(data, len,
                       SSH_FORMAT_UINT32, &operation_id,
                       SSH_FORMAT_UINT32, &error,
                       SSH_FORMAT_UINT32, &adapter_ifnum,
                       SSH_FORMAT_UINT32_STR_NOCOPY, &adapter_name, NULL,
                       SSH_FORMAT_UINT32, &adapter_state,
                       SSH_FORMAT_END) != len)
    {
      SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter status message"),
                        data, len);
      return;
    }

  /* Lookup the pending operation. */
  op = lookup_virtual_adapter_op(interceptor, operation_id);
  if (op == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR, ("unknown virtual adapter operation ID %d",
                              (int) operation_id));
      return;
    }

  /* Handle attach operations separately. */
  if (op->attach)
    {
      receive_virtual_adapter_attach_cb(interceptor, error, 
					adapter_ifnum, adapter_name, 
					adapter_state, op);
      return;
    }

  /* Is the operation aborted? */
  if (op->aborted)
    {
      /* Free the operation context. */
      free_virtual_adapter_op(interceptor, op);
      return;
    }

  /* Lookup virtual adapter. */
  ssh_mutex_lock(interceptor->mutex);
  for (va = interceptor->virtual_adapters; va; va = va->next)
    if (va->adapter_ifnum == adapter_ifnum)
      break;
  ssh_mutex_unlock(interceptor->mutex);

  /* Take adapter context from virtual adapter, if it was found. */
  if (va == NULL)
    adapter_context = op->adapter_context;
  else
    adapter_context = va->adapter_context;

  SSH_DEBUG(SSH_D_NICETOKNOW, 
	    ("received status callback for virtual adapter %d from forwarder, "
	     "error %d", (int) adapter_ifnum, (int) error));

  /* Call the completion function. */
  if (op->status_cb)
    (*op->status_cb)((SshVirtualAdapterError) error,
		     (SshInterceptorIfnum) adapter_ifnum, adapter_name,
		     (SshVirtualAdapterState) adapter_state,
		     adapter_context, op->context);

  /* Free operation context if there will be no more status callbacks
     to this operation. */
  if (error != SSH_VIRTUAL_ADAPTER_ERROR_OK_MORE)
    {
      /* Unregister operation handle and free operation context. */
      ssh_operation_unregister(op->handle);
      free_virtual_adapter_op(interceptor, op);
    }
}
Beispiel #25
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;
}
Beispiel #26
0
/* Encodes terminal modes for the terminal referenced by fd in a
   portable manner, and appends the modes to a buffer being
   constructed. Stores constructed buffers len to buf_len. This call
   always succeeds, but if an error happens during encoding, buf will
   be empty and buf_len will be 0 */
void ssh_encode_tty_flags(int fd, unsigned char **buf, size_t *buf_len)
     /*void tty_make_modes(int fd)*/
{
  SshBuffer buffer;  
#ifdef USING_TERMIOS
  struct termios tio;
#endif
#ifdef USING_SGTTY
  struct sgttyb tio;
  struct tchars tiotc;
  struct ltchars tioltc;
  int tiolm;
#ifdef TIOCGSTAT
  struct tstatus tiots;
#endif /* TIOCGSTAT */
#endif /* USING_SGTTY */
  int baud;

  if (!isatty(fd))
    {
      SSH_TRACE(2, ("Not a tty. (fd = %d)", fd));
      *buf = ssh_xstrdup("");
      *buf_len = 0;
      return;
    }
  
  ssh_buffer_init(&buffer);

  /* Get the modes. */
#ifdef USING_TERMIOS
  if (tcgetattr(fd, &tio) < 0)
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("tcgetattr: %.100s", strerror(errno));
      goto error;
    }
#endif /* USING_TERMIOS */
#ifdef USING_SGTTY
  if (ioctl(fd, TIOCGETP, &tio) < 0)
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("ioctl(fd, TIOCGETP, ...): %.100s", strerror(errno));
      goto error;
    }
  if (ioctl(fd, TIOCGETC, &tiotc) < 0)
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("ioctl(fd, TIOCGETC, ...): %.100s", strerror(errno));
      goto error;
    }
  if (ioctl(fd, TIOCLGET, &tiolm) < 0)
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("ioctl(fd, TIOCLGET, ...): %.100s", strerror(errno));
      goto error;
    }
  if (ioctl(fd, TIOCGLTC, &tioltc) < 0)
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("ioctl(fd, TIOCGLTC, ...): %.100s", strerror(errno));
      goto error;
    }
#ifdef TIOCGSTAT
  if (ioctl(fd, TIOCGSTAT, &tiots) < 0) 
    {
      PUT_CHAR(TTY_OP_END);
      ssh_warning("ioctl(fd, TIOCGSTAT, ...): %.100s", strerror(errno));
      goto error;
    }
#endif /* TIOCGSTAT */
  /* termio's ECHOE is really both LCRTBS and LCRTERA - so wire them
     together */
  if (tiolm & LCRTBS)
    tiolm |= LCRTERA;
#endif /* USING_SGTTY */

  /* Store input and output baud rates. */
  baud = speed_to_baud(cfgetospeed(&tio));
  PUT_CHAR(TTY_OP_OSPEED);
  PUT_UINT32(baud);
  baud = speed_to_baud(cfgetispeed(&tio));
  PUT_CHAR(TTY_OP_ISPEED);
  PUT_UINT32(baud);

  /* Store values of mode flags. */
#ifdef USING_TERMIOS
#define TTYCHAR(NAME, OP) \
  PUT_CHAR(OP); PUT_UINT32(tio.c_cc[NAME]);
#define TTYMODE(NAME, FIELD, OP) \
  PUT_CHAR(OP); PUT_UINT32((tio.FIELD & NAME) != 0);
#define SGTTYCHAR(NAME, OP)
#define SGTTYMODE(NAME, FIELD, OP)
#define SGTTYMODEN(NAME, FIELD, OP)
#endif /* USING_TERMIOS */

#ifdef USING_SGTTY
#define TTYCHAR(NAME, OP)
#define TTYMODE(NAME, FIELD, OP)
#define SGTTYCHAR(NAME, OP) \
  PUT_CHAR(OP); PUT_UINT32(NAME);
#define SGTTYMODE(NAME, FIELD, OP) \
  PUT_CHAR(OP); PUT_UINT32((FIELD & NAME) != 0);
#define SGTTYMODEN(NAME, FIELD, OP) \
  PUT_CHAR(OP); PUT_UINT32((FIELD & NAME) == 0);
#endif /* USING_SGTTY */

#include "sshttyflagsi.h"

#undef TTYCHAR
#undef TTYMODE
#undef SGTTYCHAR
#undef SGTTYMODE
#undef SGTTYMODEN

  /* Mark end of mode data. */
  PUT_CHAR(TTY_OP_END);

  *buf_len = ssh_buffer_len(&buffer);
  *buf = ssh_xmemdup(ssh_buffer_ptr(&buffer), *buf_len);
  ssh_buffer_uninit(&buffer);

  SSH_DEBUG_HEXDUMP(5, ("encoded tty-flags buffer"), *buf, *buf_len);
  
  return;

 error:
  ssh_buffer_uninit(&buffer);
  *buf = ssh_xstrdup("");
  *buf_len = 0;
}