Ejemplo n.º 1
0
/* Calculated prf+ from given prf, and key and data. The
   output will be stored to the `output' buffer, and this
   will generate `output_len' bytes of output. */
SshCryptoStatus ssh_prf_plus(const unsigned char *prf,
			     const unsigned char *key,
			     size_t key_len,
			     const unsigned char *data,
			     size_t data_len,
			     unsigned char *output,
			     size_t output_len)
{
  unsigned char buffer[SSH_MAX_HASH_DIGEST_LENGTH];
  SshCryptoStatus status;
  unsigned char ch;
  size_t mac_len;
  SshMac mac;
  
  /* Allocate mac. */
  status = ssh_mac_allocate(ssh_csstr(prf), key, key_len, &mac);
  if (status != SSH_CRYPTO_OK)
    return status;

  /* Get the MAC len. */
  mac_len = ssh_mac_length(ssh_csstr(prf));

  ch = 1;
  while (1)
    {
      ssh_mac_reset(mac);
      if (ch != 1)
	{
	  ssh_mac_update(mac, buffer, mac_len);
	}
      ssh_mac_update(mac, data, data_len);
      ssh_mac_update(mac, &ch, 1);
      status = ssh_mac_final(mac, buffer);
      if (status != SSH_CRYPTO_OK)
	{
	  ssh_mac_free(mac);
	  return status;
	}
	
      if (output_len < mac_len)
	{
	  memcpy(output, buffer, output_len);
	  break;
	}
      memcpy(output, buffer, mac_len);
      output_len -= mac_len;
      output += mac_len;

      if (ch == 255)
	{
	  ssh_mac_free(mac);
	  return SSH_CRYPTO_DATA_TOO_LONG;
	}
      ch++;
    }
  ssh_mac_free(mac);
  return SSH_CRYPTO_OK;
}
Ejemplo n.º 2
0
static Boolean prf_xor(unsigned char *dest, int dest_len,
		       SshMac mac, int mac_len, unsigned char *seed,
		       int seed_len)
{
  unsigned char A[20];
  unsigned char digest[20];
  int i;

  SSH_ASSERT(mac_len <= 20);

  /* Calculate A(1). (Notation from RFC 2246.) */
  ssh_mac_reset(mac);
  ssh_mac_update(mac, seed, seed_len);
  if (ssh_mac_final(mac, A) != SSH_CRYPTO_OK)
    return FALSE;
  
  while (1)
    {
      SSH_ASSERT(dest_len > 0);
      
      ssh_mac_reset(mac);
      ssh_mac_update(mac, A, mac_len);
      ssh_mac_update(mac, seed, seed_len);
      if (ssh_mac_final(mac, digest) != SSH_CRYPTO_OK)
	return FALSE;

      for (i = 0; i < mac_len; i++)
        {
          *dest ^= digest[i];
          dest++;
          dest_len--;
          if (dest_len == 0)
            {
              memset(A, 0, 20); 
	      memset(digest, 0, 20);
              return TRUE;
            }
        }
      
      /* Compute A(i+1) (see RFC 2246. `i' is induction variable, not
         the loop variable above. */
      ssh_mac_reset(mac);
      ssh_mac_update(mac, A, mac_len);
      if (ssh_mac_final(mac, A) != SSH_CRYPTO_OK)
	return FALSE;
      
    }

  return TRUE;
}
Ejemplo n.º 3
0
Archivo: dh.c Proyecto: mwgoldsmith/ssh
static int generate_one_key(ssh_string k,
    struct ssh_crypto_struct *crypto, unsigned char **output, char letter, size_t requested_size) {
  ssh_mac_ctx ctx;
  unsigned char *tmp;
  size_t size = crypto->digest_len;
  ctx=ssh_mac_ctx_init(crypto->mac_type);

  if (ctx == NULL) {
    return -1;
  }

  ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
  ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
  ssh_mac_update(ctx, &letter, 1);
  ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
  ssh_mac_final(*output, ctx);

  while(requested_size > size) {
    tmp = realloc(*output, size + crypto->digest_len);
    if (tmp == NULL) {
      return -1;
    }
    *output = tmp;

    ctx = ssh_mac_ctx_init(crypto->mac_type);
    if (ctx == NULL) {
      return -1;
    }
    ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
    ssh_mac_update(ctx, crypto->secret_hash,
        crypto->digest_len);
    ssh_mac_update(ctx, tmp, size);
    ssh_mac_final(tmp + size, ctx);
    size += crypto->digest_len;
  }

  return 0;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}