예제 #1
0
/* Receive HASH and check that the exchange has been consistent.  */
int
ike_phase_1_recv_AUTH (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct ipsec_exch *ie = exchange->data;
    struct prf *prf;
    struct hash *hash = ie->hash;
    char header[80];
    size_t hashsize = hash->hashsize;
    int initiator = exchange->initiator;
    u_int8_t **hash_p, *id;
    size_t id_len;

    /* Choose the right fields to fill in */
    hash_p = initiator ? &ie->hash_r : &ie->hash_i;
    id = initiator ? exchange->id_r : exchange->id_i;
    id_len = initiator ? exchange->id_r_len : exchange->id_i_len;

    /* The decoded hash will be in ie->hash_r or ie->hash_i */
    if (ie->ike_auth->decode_hash (msg))
    {
        message_drop (msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, 0);
        return -1;
    }

    /* Allocate the prf and start calculating his HASH.  */
    prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
    if (!prf)
    {
        /* XXX Log?  */
        return -1;
    }
    prf->Init (prf->prfctx);
    prf->Update (prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
    prf->Update (prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
    prf->Update (prf->prfctx,
                 exchange->cookies
                 + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
                 ISAKMP_HDR_ICOOKIE_LEN);
    prf->Update (prf->prfctx,
                 exchange->cookies
                 + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
                 ISAKMP_HDR_ICOOKIE_LEN);
    prf->Update (prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
    prf->Update (prf->prfctx, id, id_len);
    prf->Final (hash->digest, prf->prfctx);
    prf_free (prf);
    snprintf (header, sizeof header, "ike_phase_1_recv_AUTH: computed HASH_%c",
              initiator ? 'R' : 'I');
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80, header, hash->digest, hashsize));

    /* Check that the hash we got matches the one we computed.  */
    if (memcmp (*hash_p, hash->digest, hashsize) != 0)
    {
        /* XXX Log?  */
        return -1;
    }

    return 0;
}
예제 #2
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
/*
 * Both standard and revised RSA encryption authentication use this SKEYID
 * computation.
 */
static u_int8_t *
enc_gen_skeyid (struct exchange *exchange, size_t *sz)
{
  struct prf *prf;
  struct ipsec_exch *ie = exchange->data;
  struct hash *hash = ie->hash;
  u_int8_t *skeyid;

  hash->Init (hash->ctx);
  hash->Update (hash->ctx, exchange->nonce_i, exchange->nonce_i_len);
  hash->Update (hash->ctx, exchange->nonce_r, exchange->nonce_r_len);
  hash->Final (hash->digest, hash->ctx);
  prf = prf_alloc (ie->prf_type, hash->type, hash->digest, *sz);
  if (!prf)
    return 0;

  *sz = prf->blocksize;
  skeyid = malloc (*sz);
  if (!skeyid)
    {
      log_error ("enc_gen_skeyid: malloc (%d) failed", *sz);
      prf_free (prf);
      return 0;
    }

  prf->Init (prf->prfctx);
  prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
  prf->Final (skeyid, prf->prfctx);
  prf_free (prf);

  return skeyid;
}
예제 #3
0
int
cfg_verify_hash(struct message *msg)
{
	struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH);
	struct ipsec_sa *isa = msg->isakmp_sa->data;
	struct prf     *prf;
	u_int8_t       *hash, *comp_hash;
	size_t          hash_len;

	if (!hashp) {
		log_print("cfg_verify_hash: phase 2 message missing HASH");
		message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
		    0, 1, 0);
		return -1;
	}
	hash = hashp->p;
	hash_len = GET_ISAKMP_GEN_LENGTH(hash);
	comp_hash = malloc(hash_len - ISAKMP_GEN_SZ);
	if (!comp_hash) {
		log_error("cfg_verify_hash: malloc (%lu) failed",
		    (unsigned long)hash_len - ISAKMP_GEN_SZ);
		return -1;
	}
	/* Verify hash.  */
	prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
	    isa->skeyid_len);
	if (!prf) {
		free(comp_hash);
		return -1;
	}
	prf->Init(prf->prfctx);
	prf->Update(prf->prfctx, msg->exchange->message_id,
	    ISAKMP_HDR_MESSAGE_ID_LEN);
	prf->Update(prf->prfctx, hash + hash_len,
	    msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
	prf->Final(comp_hash, prf->prfctx);
	prf_free(prf);

	if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ)
	    != 0) {
		message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
		    0, 1, 0);
		free(comp_hash);
		return -1;
	}
	free(comp_hash);

	/* Mark the HASH as handled.  */
	hashp->flags |= PL_MARK;

	/* Mark message authenticated. */
	msg->flags |= MSG_AUTHENTICATED;

	return 0;
}
예제 #4
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
/* Both DSS & RSA signature authentication use this algorithm.  */
static u_int8_t *
sig_gen_skeyid (struct exchange *exchange, size_t *sz)
{
  struct prf *prf;
  struct ipsec_exch *ie = exchange->data;
  u_int8_t *skeyid;
  unsigned char *key;

  key = malloc (exchange->nonce_i_len + exchange->nonce_r_len);
  if (!key)
    return 0;
  memcpy (key, exchange->nonce_i, exchange->nonce_i_len);
  memcpy (key + exchange->nonce_i_len, exchange->nonce_r,
	  exchange->nonce_r_len);

  LOG_DBG ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d",
	    ie->prf_type, ie->hash->type));
  LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID initialized with",
		(u_int8_t *)key,
		exchange->nonce_i_len + exchange->nonce_r_len));

  prf = prf_alloc (ie->prf_type, ie->hash->type, key,
		   exchange->nonce_i_len + exchange->nonce_r_len);
  free (key);
  if (!prf)
    return 0;

  *sz = prf->blocksize;
  skeyid = malloc (*sz);
  if (!skeyid)
    {
      log_error ("sig_gen_skeyid: malloc (%lu) failed",
	(unsigned long)*sz);
      prf_free (prf);
      return 0;
    }

  LOG_DBG ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu",
	    (unsigned long)ie->g_x_len));
  LOG_DBG_BUF ((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID fed with g^xy",
		ie->g_xy, ie->g_x_len));

  prf->Init (prf->prfctx);
  prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
  prf->Final (skeyid, prf->prfctx);
  prf_free (prf);

  return skeyid;
}
예제 #5
0
int
cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data,
    u_int16_t length)
{
	struct ipsec_sa *isa = msg->isakmp_sa->data;
	struct prf     *prf;

	prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a,
	    isa->skeyid_len);
	if (!prf)
		return -1;

	prf->Init(prf->prfctx);
	prf->Update(prf->prfctx, msg->exchange->message_id,
	    ISAKMP_HDR_MESSAGE_ID_LEN);
	prf->Update(prf->prfctx, data, length);
	prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx);
	prf_free(prf);
	return 0;
}
예제 #6
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
int
ike_auth_hash (struct exchange *exchange, u_int8_t *buf)
{
  struct ipsec_exch *ie = exchange->data;
  struct prf *prf;
  struct hash *hash = ie->hash;
  int initiator = exchange->initiator;
  u_int8_t *id;
  size_t id_len;

  /* Choose the right fields to fill-in.  */
  id = initiator ? exchange->id_i : exchange->id_r;
  id_len = initiator ? exchange->id_i_len : exchange->id_r_len;

  /* Allocate the prf and start calculating our HASH.  */
  prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
  if (!prf)
    return -1;

  prf->Init (prf->prfctx);
  prf->Update (prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
  prf->Update (prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
  prf->Update (prf->prfctx,
	       exchange->cookies
	       + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
	       ISAKMP_HDR_ICOOKIE_LEN);
  prf->Update (prf->prfctx,
	       exchange->cookies
	       + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
	       ISAKMP_HDR_ICOOKIE_LEN);
  prf->Update (prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
  prf->Update (prf->prfctx, id, id_len);
  prf->Final (buf, prf->prfctx);
  prf_free (prf);

  return 0;
}
예제 #7
0
/*
 * Compute DH values and key material.  This is done in a post-send function
 * as that means we can do parallel work in both the initiator and responder
 * thus speeding up exchanges.
 */
int
ike_phase_1_post_exchange_KE_NONCE (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct ipsec_exch *ie = exchange->data;
    struct prf *prf;
    struct hash *hash = ie->hash;
    enum cryptoerr err;

    /* Compute Diffie-Hellman shared value.  */
    ie->g_xy = malloc (ie->g_x_len);
    if (!ie->g_xy)
    {
        /* XXX How to notify peer?  */
        log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed",
                   (unsigned long)ie->g_x_len);
        return -1;
    }
    if (dh_create_shared (ie->group, ie->g_xy,
                          exchange->initiator ? ie->g_xr : ie->g_xi))
    {
        log_print ("ike_phase_1_post_exchange_KE_NONCE: "
                   "dh_create_shared failed");
        return -1;
    }
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80,
                  "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy,
                  ie->g_x_len));

    /* Compute the SKEYID depending on the authentication method.  */
    ie->skeyid = ie->ike_auth->gen_skeyid (exchange, &ie->skeyid_len);
    if (!ie->skeyid)
    {
        /* XXX Log and teardown?  */
        return -1;
    }
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80,
                  "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid,
                  ie->skeyid_len));

    /* SKEYID_d.  */
    ie->skeyid_d = malloc (ie->skeyid_len);
    if (!ie->skeyid_d)
    {
        /* XXX How to notify peer?  */
        log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed",
                   (unsigned long)ie->skeyid_len);
        return -1;
    }
    prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
    if (!prf)
    {
        /* XXX Log and teardown?  */
        return -1;
    }
    prf->Init (prf->prfctx);
    prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
    prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
    prf->Update (prf->prfctx, (unsigned char *)"\0", 1);
    prf->Final (ie->skeyid_d, prf->prfctx);
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80,
                  "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d",	ie->skeyid_d,
                  ie->skeyid_len));

    /* SKEYID_a.  */
    ie->skeyid_a = malloc (ie->skeyid_len);
    if (!ie->skeyid_a)
    {
        log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed",
                   (unsigned long)ie->skeyid_len);
        prf_free (prf);
        return -1;
    }
    prf->Init (prf->prfctx);
    prf->Update (prf->prfctx, ie->skeyid_d, ie->skeyid_len);
    prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
    prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
    prf->Update (prf->prfctx, (unsigned char *)"\1", 1);
    prf->Final (ie->skeyid_a, prf->prfctx);
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80,
                  "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a",	ie->skeyid_a,
                  ie->skeyid_len));

    /* SKEYID_e.  */
    ie->skeyid_e = malloc (ie->skeyid_len);
    if (!ie->skeyid_e)
    {
        /* XXX How to notify peer?  */
        log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%lu) failed",
                   (unsigned long)ie->skeyid_len);
        prf_free (prf);
        return -1;
    }
    prf->Init (prf->prfctx);
    prf->Update (prf->prfctx, ie->skeyid_a, ie->skeyid_len);
    prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
    prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
    prf->Update (prf->prfctx, (unsigned char *)"\2", 1);
    prf->Final (ie->skeyid_e, prf->prfctx);
    prf_free (prf);
    LOG_DBG_BUF ((LOG_NEGOTIATION, 80,
                  "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e",	ie->skeyid_e,
                  ie->skeyid_len));

    /* Key length determination.  */
    if (!exchange->key_length)
        exchange->key_length = exchange->crypto->keymax;

    /* Derive a longer key from skeyid_e */
    if (ie->skeyid_len < exchange->key_length)
    {
        u_int16_t len, keylen;
        u_int8_t *key, *p;

        prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid_e, ie->skeyid_len);
        if (!prf)
        {
            /* XXX - notify peer */
            return -1;
        }

        /* Make keylen a multiple of prf->blocksize */
        keylen = exchange->key_length;
        if (keylen % prf->blocksize)
            keylen += prf->blocksize - (keylen % prf->blocksize);

        key = malloc (keylen);
        if (!key)
        {
            /* XXX - Notify peer.  */
            log_error ("ike_phase_1_post_exchange_KE_NONCE: malloc (%d) failed",
                       keylen);
            return -1;
        }

        prf->Init (prf->prfctx);
        prf->Update (prf->prfctx, (unsigned char *)"\0", 1);
        prf->Final (key, prf->prfctx);

        for (len = prf->blocksize, p = key; len < exchange->key_length;
                len += prf->blocksize, p += prf->blocksize)
        {
            prf->Init (prf->prfctx);
            prf->Update (prf->prfctx, p, prf->blocksize);
            prf->Final (p + prf->blocksize, prf->prfctx);
        }
        prf_free (prf);

        /* Setup our keystate using the derived encryption key.  */
        exchange->keystate
            = crypto_init (exchange->crypto, key, exchange->key_length, &err);

        free (key);
    }
    else
        /* Setup our keystate using the raw skeyid_e.  */
        exchange->keystate = crypto_init (exchange->crypto, ie->skeyid_e,
                                          exchange->key_length, &err);

    /* Special handling for DES weak keys.  */
    if (!exchange->keystate && err == EWEAKKEY
            && (exchange->key_length << 1) <= ie->skeyid_len)
    {
        log_print ("ike_phase_1_post_exchange_KE_NONCE: "
                   "weak key, trying subseq. skeyid_e");
        exchange->keystate
            = crypto_init (exchange->crypto, ie->skeyid_e + exchange->key_length,
                           exchange->key_length, &err);
    }

    if (!exchange->keystate)
    {
        log_print ("ike_phase_1_post_exchange_KE_NONCE: "
                   "exchange->crypto->init () failed: %d", err);

        /*
         * XXX We really need to know if problems are of transient nature
         * or fatal (like failed assertions etc.)
         */
        return -1;
    }

    /* Setup IV.  XXX Only for CBC transforms, no?  */
    hash->Init (hash->ctx);
    hash->Update (hash->ctx, ie->g_xi, ie->g_x_len);
    hash->Update (hash->ctx, ie->g_xr, ie->g_x_len);
    hash->Final (hash->digest, hash->ctx);
    crypto_init_iv (exchange->keystate, hash->digest,
                    exchange->crypto->blocksize);

    return 0;
}
예제 #8
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
static u_int8_t *
pre_shared_gen_skeyid (struct exchange *exchange, size_t *sz)
{
  struct prf *prf;
  struct ipsec_exch *ie = exchange->data;
  u_int8_t *skeyid;
  u_int8_t *buf = 0;
  unsigned char *key;
  size_t keylen;

  /*
   * If we're the responder and have the initiator's ID (which is the
   * case in Aggressive mode), try to find the preshared key in the
   * section of the initiator's Phase 1 ID.  This allows us to do
   * mobile user support with preshared keys.
   */
  if (!exchange->initiator && exchange->id_i)
    {
      switch (exchange->id_i[0])
        {
	case IPSEC_ID_IPV4_ADDR:
	case IPSEC_ID_IPV6_ADDR:
	  util_ntoa ((char **)&buf,
		     exchange->id_i[0] == IPSEC_ID_IPV4_ADDR
		     ? AF_INET : AF_INET6,
		     exchange->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
	  if (!buf)
	    return 0;
	  break;

	case IPSEC_ID_FQDN:
	case IPSEC_ID_USER_FQDN:
	  buf = calloc (exchange->id_i_len - ISAKMP_ID_DATA_OFF
			+ ISAKMP_GEN_SZ + 1, sizeof (char));
	  if (!buf)
	    {
              log_print ("pre_shared_gen_skeyid: malloc (%lu) failed",
			 (unsigned long)exchange->id_i_len - ISAKMP_ID_DATA_OFF
			 + ISAKMP_GEN_SZ + 1);
	      return 0;
	    }
	  memcpy (buf, exchange->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
		  exchange->id_i_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
	  break;

	  /* XXX Support more ID types ? */
	default:
	  break;
	}
    }

  /*
   * Get the pre-shared key for our peer. This will work even if the key
   * has been passed to us through a mechanism like PFKEYv2.
   */
  key = ike_auth_get_key (IKE_AUTH_PRE_SHARED, exchange->name, (char *)buf,
			  &keylen);
  if (buf)
    free (buf);

  /* Fail if no key could be found.  */
  if (!key)
    return 0;

  /* Store the secret key for later policy processing.  */
  exchange->recv_key = calloc (keylen + 1, sizeof (char));
  exchange->recv_keytype = ISAKMP_KEY_PASSPHRASE;
  if (!exchange->recv_key)
    {
      log_error ("pre_shared_gen_skeyid: malloc (%lu) failed",
	(unsigned long)keylen);
      return 0;
    }
  memcpy (exchange->recv_key, key, keylen);
  exchange->recv_certtype = ISAKMP_CERTENC_NONE;

  prf = prf_alloc (ie->prf_type, ie->hash->type, key, keylen);
  if (!prf)
    return 0;

  *sz = prf->blocksize;
  skeyid = malloc (*sz);
  if (!skeyid)
    {
      log_error ("pre_shared_gen_skeyid: malloc (%lu) failed",
	(unsigned long)*sz);
      prf_free (prf);
      return 0;
    }

  prf->Init (prf->prfctx);
  prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
  prf->Update (prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
  prf->Final (skeyid, prf->prfctx);
  prf_free (prf);

  return skeyid;
}