예제 #1
0
파일: crypto.c 프로젝트: SylvestreG/bitrig
void
crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
{
	LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_encrypt: before encryption", buf,
	    len));
	ks->xf->encrypt(ks, buf, len);
	memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
	LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_encrypt: after encryption", buf,
	    len));
}
예제 #2
0
파일: crypto.c 프로젝트: SylvestreG/bitrig
void
crypto_decrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len)
{
	LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_decrypt: before decryption", buf,
	    len));
	/*
	 * XXX There is controversy about the correctness of updating the IV
	 * like this.
         */
	memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
	ks->xf->decrypt(ks, buf, len);
	LOG_DBG_BUF((LOG_CRYPTO, 70, "crypto_decrypt: after decryption", buf,
	    len));
}
예제 #3
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;
}
예제 #4
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;
}
예제 #5
0
파일: crypto.c 프로젝트: SylvestreG/bitrig
void
crypto_init_iv(struct keystate *ks, u_int8_t *buf, size_t len)
{
	memcpy(ks->riv, buf, len);

	LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv,
	    len));
}
예제 #6
0
파일: x509.c 프로젝트: appleorange1/bitrig
/* Lookup a certificate by an ID blob.  */
static X509 *
x509_hash_find(u_int8_t *id, size_t len)
{
	struct x509_hash *cert;
	u_int8_t	**cid;
	u_int32_t	*clen;
	int	n, i, id_found;

	for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert;
	    cert = LIST_NEXT(cert, link)) {
		if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen))
			continue;

		id_found = 0;
		for (i = 0; i < n; i++) {
			LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len));
			LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i],
			    clen[i]));
			/*
			 * XXX This identity predicate needs to be
			 * understood.
			 */
			if (clen[i] == len && id[0] == cid[i][0] &&
			    memcmp(id + 4, cid[i] + 4, len - 4) == 0) {
				id_found++;
				break;
			}
		}
		cert_free_subjects(n, cid, clen);
		if (!id_found)
			continue;

		LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p",
		    cert->cert));
		return cert->cert;
	}

	LOG_DBG((LOG_CRYPTO, 70,
	    "x509_hash_find: no certificate matched query"));
	return 0;
}
예제 #7
0
파일: crypto.c 프로젝트: SylvestreG/bitrig
void
crypto_update_iv(struct keystate *ks)
{
	u_int8_t       *tmp;

	tmp = ks->riv;
	ks->riv = ks->liv;
	ks->liv = tmp;

	LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv,
	    ks->xf->blocksize));
}
예제 #8
0
/* Generate the NAT-T capability marker hashes. Executed only once.  */
static int
nat_t_setup_hashes(void)
{
	struct hash *hash;
	int n = NUMNATTCAP;
	int i;

	/* The draft says to use MD5.  */
	hash = hash_get(HASH_MD5);
	if (!hash) {
		/* Should never happen.  */
		log_print("nat_t_setup_hashes: "
		    "could not find MD5 hash structure!");
		return -1;
	}

	/* Populate isakmp_nat_t_cap with hashes.  */
	for (i = 0; i < n; i++) {
		isakmp_nat_t_cap[i].hashsize = hash->hashsize;
		isakmp_nat_t_cap[i].hash = malloc(hash->hashsize);
		if (!isakmp_nat_t_cap[i].hash) {
			log_error("nat_t_setup_hashes: malloc (%lu) failed",
			    (unsigned long)hash->hashsize);
			goto errout;
		}

		hash->Init(hash->ctx);
		hash->Update(hash->ctx,
		    (unsigned char *)isakmp_nat_t_cap[i].text,
		    strlen(isakmp_nat_t_cap[i].text));
		hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);

		LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
		    "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
		    (unsigned long)hash->hashsize));
		LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
		    isakmp_nat_t_cap[i].hash, hash->hashsize));
	}

	return 0;

errout:
	for (i = 0; i < n; i++)
		free(isakmp_nat_t_cap[i].hash);
	return -1;
}
예제 #9
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
static int
pre_shared_decode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  struct payload *payload;
  size_t hashsize = ie->hash->hashsize;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t **hash_p;

  /* Choose the right fields to fill-in.  */
  hash_p = initiator ? &ie->hash_r : &ie->hash_i;

  payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
  if (!payload)
    {
      log_print ("pre_shared_decode_hash: no HASH payload found");
      return -1;
    }

  /* Check that the hash is of the correct size.  */
  if (GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ != hashsize)
    return -1;

  /* XXX Need this hash be in the SA?  */
  *hash_p = malloc (hashsize);
  if (!*hash_p)
    {
      log_error ("pre_shared_decode_hash: malloc (%lu) failed",
	(unsigned long)hashsize);
      return -1;
    }

  memcpy (*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize);
  snprintf (header, sizeof header, "pre_shared_decode_hash: HASH_%c",
	    initiator ? 'R' : 'I');
  LOG_DBG_BUF ((LOG_MISC, 80, header, *hash_p, hashsize));

  payload->flags |= PL_MARK;

  return 0;
}
예제 #10
0
/*
 * Dump the internal state of SA to the report channel, with HEADER
 * prepended to each line.
 */
void
sa_dump(int cls, int level, char *header, struct sa *sa)
{
	struct proto   *proto;
	char            spi_header[80];
	int             i;

	LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header,
	    sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id,
	    sa->flags));
	LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header,
	    decode_32(sa->cookies), decode_32(sa->cookies + 4),
	    decode_32(sa->cookies + 8), decode_32(sa->cookies + 12)));
	LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header,
	    decode_32(sa->message_id), sa->refcnt));
	LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds,
	    sa->kilobytes));
	for (proto = TAILQ_FIRST(&sa->protos); proto;
	    proto = TAILQ_NEXT(proto, link)) {
		LOG_DBG((cls, level, "%s: suite %d proto %d", header,
		    proto->no, proto->proto));
		LOG_DBG((cls, level,
		    "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p",
		    header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1],
		    proto->spi[1]));
		LOG_DBG((cls, level, "%s: %s, %s", header,
		    !sa->doi ? "<nodoi>" :
		    sa->doi->decode_ids("initiator id: %s, responder id: %s",
		    sa->id_i, sa->id_i_len,
		    sa->id_r, sa->id_r_len, 0),
		    !sa->transport ? "<no transport>" :
		    sa->transport->vtbl->decode_ids(sa->transport)));
		for (i = 0; i < 2; i++)
			if (proto->spi[i]) {
				snprintf(spi_header, sizeof spi_header,
				    "%s: spi[%d]", header, i);
				LOG_DBG_BUF((cls, level, spi_header,
				    proto->spi[i], proto->spi_sz[i]));
			}
	}
}
예제 #11
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
static int
pre_shared_encode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  size_t hashsize = ie->hash->hashsize;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t *buf;

  buf = ipsec_add_hash_payload (msg, hashsize);
  if (!buf)
    return -1;

  if (ike_auth_hash (exchange, buf + ISAKMP_HASH_DATA_OFF) == -1)
    return -1;

  snprintf (header, sizeof header, "pre_shared_encode_hash: HASH_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize));
  return 0;
}
예제 #12
0
파일: crypto.c 프로젝트: SylvestreG/bitrig
struct keystate *
crypto_init(struct crypto_xf *xf, u_int8_t *key, u_int16_t len,
    enum cryptoerr *err)
{
	struct keystate *ks;

	if (len < xf->keymin || len > xf->keymax) {
		LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d",
		    len));
		*err = EKEYLEN;
		return 0;
	}
	ks = calloc(1, sizeof *ks);
	if (!ks) {
		log_error("crypto_init: calloc (1, %lu) failed",
		    (unsigned long)sizeof *ks);
		*err = ENOCRYPTO;
		return 0;
	}
	ks->xf = xf;

	/* Setup the IV.  */
	ks->riv = ks->iv;
	ks->liv = ks->iv2;

	LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len));

	*err = xf->init(ks, key, len);
	if (*err != EOKAY) {
		LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s",
		    xf->name));
		free(ks);
		return 0;
	}
	return ks;
}
예제 #13
0
/* Receive ID.  */
int
ike_phase_1_recv_ID (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct payload *payload;
    char header[80], *rs = 0, *rid = 0, *p;
    int initiator = exchange->initiator;
    u_int8_t **id, id_type;
    size_t *id_len, sz;
    struct sockaddr *sa;

    payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]);

    if (exchange->name)
        rs = conf_get_str (exchange->name, "Remote-ID");

    if (rs)
    {
        sz = ipsec_id_size (rs, &id_type);
        if (sz == -1)
        {
            log_print ("ike_phase_1_recv_ID: could not handle specified "
                       "Remote-ID [%s]", rs);
            return -1;
        }

        rid = malloc (sz);
        if (!rid)
        {
            log_error ("ike_phase_1_recv_ID: malloc (%lu) failed",
                       (unsigned long)sz);
            return -1;
        }

        switch (id_type)
        {
        case IPSEC_ID_IPV4_ADDR:
        case IPSEC_ID_IPV6_ADDR:
            p = conf_get_str (rs, "Address");
            if (!p)
            {
                log_print ("ike_phase_1_recv_ID: "
                           "failed to get Address in Remote-ID section [%s]",
                           rs);
                free (rid);
                return -1;
            }

            if (text2sockaddr (p, 0, &sa) == -1)
            {
                log_print ("ike_phase_1_recv_ID: failed to parse address %s", p);
                free (rid);
                return -1;
            }

            if ((id_type == IPSEC_ID_IPV4_ADDR && sa->sa_family != AF_INET)
                    || (id_type == IPSEC_ID_IPV6_ADDR && sa->sa_family != AF_INET6))
            {
                log_print ("ike_phase_1_recv_ID: "
                           "address %s not of expected family", p);
                free (rid);
                free (sa);
                return -1;
            }

            memcpy (rid, sockaddr_addrdata (sa), sockaddr_addrlen (sa));
            free (sa);
            break;

        case IPSEC_ID_FQDN:
        case IPSEC_ID_USER_FQDN:
        case IPSEC_ID_KEY_ID:
            p = conf_get_str (rs, "Name");
            if (!p)
            {
                log_print ("ike_phase_1_recv_ID: "
                           "failed to get Name in Remote-ID section [%s]", rs);
                free (rid);
                return -1;
            }

            memcpy (rid, p, sz);
            break;

        default:
            log_print ("ike_phase_1_recv_ID: unsupported ID type %d", id_type);
            free (rid);
            return -1;
        }

        /* Compare expected/desired and received remote ID */
        if (bcmp (rid, payload->p + ISAKMP_ID_DATA_OFF, sz))
        {
            free (rid);
            log_print ("ike_phase_1_recv_ID: "
                       "received remote ID other than expected %s", p);
            return -1;
        }

        free (rid);
    }

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

    *id_len = GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ;
    *id = malloc (*id_len);
    if (!*id)
    {
        log_error ("ike_phase_1_recv_ID: malloc (%lu) failed",
                   (unsigned long)*id_len);
        return -1;
    }
    memcpy (*id, payload->p + ISAKMP_GEN_SZ, *id_len);
    snprintf (header, sizeof header, "ike_phase_1_recv_ID: %s",
              constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (payload->p)));
    LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, payload->p + ISAKMP_ID_DATA_OFF,
                  *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF));
    payload->flags |= PL_MARK;

    return 0;
}
예제 #14
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
/* Decrypt the HASH in SIG, we already need a parsed ID payload.  */
static int
rsa_sig_decode_hash (struct message *msg)
{
  struct cert_handler *handler;
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  struct payload *p;
  void *cert = 0;
  u_int8_t *rawcert = 0;
  u_int32_t rawcertlen;
  RSA *key = 0;
  size_t hashsize = ie->hash->hashsize;
  char header[80];
  int len;
  int initiator = exchange->initiator;
  u_int8_t **hash_p, **id_cert, *id;
  u_int32_t *id_cert_len;
  size_t id_len;
  int found = 0, n, i, id_found;
#if defined (USE_DNSSEC)
  u_int8_t *rawkey = 0;
  u_int32_t rawkeylen;
#endif

  /* 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;

  if (!id || id_len == 0)
    {
      log_print ("rsa_sig_decode_hash: ID is missing");
      return -1;
    }

  /*
   * XXX Assume we should use the same kind of certification as the remote...
   * moreover, just use the first CERT payload to decide what to use.
   */
  p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]);
  if (!p)
    handler = cert_get (ISAKMP_CERTENC_KEYNOTE);
  else
    handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p));
  if (!handler)
    {
      log_print ("rsa_sig_decode_hash: cert_get (%d) failed",
		 p ? GET_ISAKMP_CERT_ENCODING (p->p) : -1);
      return -1;
    }

#if defined (USE_POLICY) && defined (USE_KEYNOTE)
  /*
   * We need the policy session initialized now, so we can add
   * credentials etc.
   */
  exchange->policy_id = kn_init ();
  if (exchange->policy_id == -1)
    {
      log_print ("rsa_sig_decode_hash: failed to initialize policy session");
      return -1;
    }
#endif /* USE_POLICY || USE_KEYNOTE */

  /* Obtain a certificate from our certificate storage.  */
  if (handler->cert_obtain (id, id_len, 0, &rawcert, &rawcertlen))
    {
      if (handler->id == ISAKMP_CERTENC_X509_SIG)
        {
	  cert = handler->cert_get (rawcert, rawcertlen);
	  if (!cert)
	    LOG_DBG ((LOG_CRYPTO, 50,
		      "rsa_sig_decode_hash: certificate malformed"));
	  else
	    {
	      if (!handler->cert_get_key (cert, &key))
	        {
		  log_print ("rsa_sig_decode_hash: "
			     "decoding certificate failed");
		  handler->cert_free (cert);
		}
	      else
	        {
		  found++;
		  LOG_DBG ((LOG_CRYPTO, 40,
			    "rsa_sig_decode_hash: using cert of type %d",
			    handler->id));
		  exchange->recv_cert = cert;
		  exchange->recv_certtype = handler->id;
#if defined (USE_POLICY)
		  x509_generate_kn (exchange->policy_id, cert);
#endif /* USE_POLICY */
		}
	    }
	}
      else if (handler->id == ISAKMP_CERTENC_KEYNOTE)
	handler->cert_insert (exchange->policy_id, rawcert);
      free (rawcert);
    }

  /*
   * Walk over potential CERT payloads in this message.
   * XXX I believe this is the wrong spot for this.  CERTs can appear
   * anytime.
   */
  for (p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]); p;
       p = TAILQ_NEXT (p, link))
    {
      p->flags |= PL_MARK;

      /* When we have found a key, just walk over the rest, marking them.  */
      if (found)
	continue;

      handler = cert_get (GET_ISAKMP_CERT_ENCODING (p->p));
      if (!handler)
	{
	  LOG_DBG ((LOG_MISC, 30,
		    "rsa_sig_decode_hash: no handler for %s CERT encoding",
		    constant_name (isakmp_certenc_cst,
				   GET_ISAKMP_CERT_ENCODING (p->p))));
	  continue;
	}

      cert = handler->cert_get (p->p + ISAKMP_CERT_DATA_OFF,
				GET_ISAKMP_GEN_LENGTH (p->p)
				- ISAKMP_CERT_DATA_OFF);
      if (!cert)
	{
	  log_print ("rsa_sig_decode_hash: can not get data from CERT");
	  continue;
	}

      if (!handler->cert_validate (cert))
	{
	  handler->cert_free (cert);
	  log_print ("rsa_sig_decode_hash: received CERT can't be validated");
	  continue;
	}

      if (GET_ISAKMP_CERT_ENCODING (p->p) == ISAKMP_CERTENC_X509_SIG)
        {
	  if (!handler->cert_get_subjects (cert, &n, &id_cert, &id_cert_len))
	    {
	      handler->cert_free (cert);
	      log_print ("rsa_sig_decode_hash: can not get subject from CERT");
	      continue;
	    }

	  id_found = 0;
	  for (i = 0; i < n; i++)
	    if (id_cert_len[i] == id_len
		&& id[0] == id_cert[i][0]
		&& memcmp (id + 4, id_cert[i] + 4, id_len - 4) == 0)
	      {
		id_found++;
		break;
	      }
	  if (!id_found)
	    {
	      handler->cert_free (cert);
	      log_print ("rsa_sig_decode_hash: no CERT subject match the ID");
	      free (id_cert);
	      continue;
	    }

	  cert_free_subjects (n, id_cert, id_cert_len);
	}

      if (!handler->cert_get_key (cert, &key))
	{
	  handler->cert_free (cert);
	  log_print ("rsa_sig_decode_hash: decoding payload CERT failed");
	  continue;
	}

      /* We validated the cert, cache it for later use.  */
      handler->cert_insert (exchange->policy_id, cert);

      exchange->recv_cert = cert;
      exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING (p->p);

#if defined (USE_POLICY) && defined (USE_KEYNOTE)
      if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE)
        {
	  struct keynote_deckey dc;
	  char *pp;
	  int dclen;

	  dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
	  dc.dec_key = key;

	  pp = kn_encode_key (&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
			      KEYNOTE_PUBLIC_KEY);
	  if (pp == NULL)
	    {
	      kn_free_key (&dc);
	      log_print ("rsa_sig_decode_hash: failed to ASCII-encode key");
	      return -1;
	    }

	  dclen = strlen (pp) + sizeof "rsa-hex:";
	  exchange->keynote_key = calloc (dclen, sizeof (char));
	  if (!exchange->keynote_key)
	    {
	      free (pp);
	      kn_free_key (&dc);
	      log_print ("rsa_sig_decode_hash: failed to allocate %d bytes",
			 dclen);
	      return -1;
	    }

	  snprintf (exchange->keynote_key, dclen, "rsa-hex:%s", pp);
	  free (pp);
	}
#endif

      found++;
    }

#if defined (USE_DNSSEC)
  /* If no certificate provided a key, try to find a validated DNSSEC KEY.  */
  if (!found)
    {
      rawkey = dns_get_key (IKE_AUTH_RSA_SIG, msg, &rawkeylen);

      /* We need to convert 'void *rawkey' into 'RSA *key'.  */
      if (dns_RSA_dns_to_x509 (rawkey, rawkeylen, &key) == 0)
	found++;
      else
	log_print ("rsa_sig_decode_hash: KEY to RSA key conversion failed");

      if (rawkey)
	free (rawkey);
    }
#endif /* USE_DNSSEC */

#if defined (USE_RAWKEY)
  /* If we still have not found a key, try to read it from a file. */
  if (!found)
    if (get_raw_key_from_file (IKE_AUTH_RSA_SIG, id, id_len, &key) != -1)
      found++;
#endif

  if (!found)
    {
      log_print ("rsa_sig_decode_hash: no public key found");
      return -1;
    }

  p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]);
  if (!p)
    {
      log_print ("rsa_sig_decode_hash: missing signature payload");
      RSA_free (key);
      return -1;
    }

  /* Check that the sig is of the correct size.  */
  len = GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_SIG_SZ;
  if (len != RSA_size (key))
    {
      RSA_free (key);
      log_print ("rsa_sig_decode_hash: "
		 "SIG payload length does not match public key");
      return -1;
    }

  *hash_p = malloc (len);
  if (!*hash_p)
    {
      RSA_free (key);
      log_error ("rsa_sig_decode_hash: malloc (%d) failed", len);
      return -1;
    }

  len = RSA_public_decrypt (len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key,
			    RSA_PKCS1_PADDING);
  if (len == -1)
    {
      RSA_free (key);
      log_print ("rsa_sig_decode_hash: RSA_public_decrypt () failed");
      return -1;
    }

  /* Store key for later use */
  exchange->recv_key = key;
  exchange->recv_keytype = ISAKMP_KEY_RSA;

  if (len != hashsize)
    {
      free (*hash_p);
      *hash_p = 0;
      log_print ("rsa_sig_decode_hash: len %lu != hashsize %lu",
	(unsigned long)len, (unsigned long)hashsize);
      return -1;
    }

  snprintf (header, sizeof header, "rsa_sig_decode_hash: HASH_%c",
	    initiator ? 'R' : 'I');
  LOG_DBG_BUF ((LOG_MISC, 80, header, *hash_p, hashsize));

  p->flags |= PL_MARK;

  return 0;
}
예제 #15
0
파일: ike_auth.c 프로젝트: ebichu/dd-wrt
/* Encrypt the HASH into a SIG type.  */
static int
rsa_sig_encode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  size_t hashsize = ie->hash->hashsize;
  struct cert_handler *handler;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t *buf, *data, *buf2;
  u_int32_t datalen;
  u_int8_t *id;
  size_t id_len;
  int idtype;
  void *sent_key;

  id = initiator ? exchange->id_i : exchange->id_r;
  id_len = initiator ? exchange->id_i_len : exchange->id_r_len;

  /* We may have been provided these by the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "Credentials");
  if (buf
      && (idtype = conf_get_num (exchange->name, "Credential_Type", -1) != -1))
    {
      exchange->sent_certtype = idtype;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get (%d) failed", idtype);
	  return -1;
	}

      exchange->sent_cert = handler->cert_from_printable ((char *)buf);
      if (!exchange->sent_cert)
	{
	  log_print ("rsa_sig_encode_hash: failed to retrieve certificate");
	  return -1;
	}

      handler->cert_serialize (exchange->sent_cert, &data, &datalen);
      if (!data)
	{
	  log_print ("rsa_sig_encode_hash: cert serialization failed");
	  return -1;
	}

      goto aftercert; /* Skip all the certificate discovery */
    }

  /* XXX This needs to be configurable.  */
  idtype = ISAKMP_CERTENC_KEYNOTE;

  /* Find a certificate with subjectAltName = id.  */
  handler = cert_get (idtype);
  if (!handler)
    {
      idtype = ISAKMP_CERTENC_X509_SIG;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	  return -1;
	}
    }

  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
    {
      if (idtype == ISAKMP_CERTENC_KEYNOTE)
	{
	  idtype = ISAKMP_CERTENC_X509_SIG;
	  handler = cert_get (idtype);
	  if (!handler)
	    {
	      log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	      return -1;
	    }

	  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
	    {
	      LOG_DBG ((LOG_MISC, 10,
			"rsa_sig_encode_hash: no certificate to send"));
	      goto skipcert;
	    }
	}
      else
	{
	  LOG_DBG ((LOG_MISC, 10,
		    "rsa_sig_encode_hash: no certificate to send"));
	  goto skipcert;
	}
    }

  /* Let's store the certificate we are going to use */
  exchange->sent_certtype = idtype;
  exchange->sent_cert = handler->cert_get (data, datalen);
  if (!exchange->sent_cert)
    {
      free (data);
      log_print ("rsa_sig_encode_hash: failed to get certificate from wire "
		 "encoding");
      return -1;
    }

 aftercert:

  buf = realloc (data, ISAKMP_CERT_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_CERT_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_CERT_SZ, buf, datalen);
  SET_ISAKMP_CERT_ENCODING (buf, idtype);
  if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf,
			   ISAKMP_CERT_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }

 skipcert:

  /* Again, we may have these from the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "PKAuthentication");
  if (buf)
    {
      key_from_printable (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf,
			  &data, &datalen);
      if (!data || datalen == -1)
	{
	  log_print ("rsa_sig_encode_hash: badly formatted RSA private key");
	  return 0;
	}

      sent_key = key_internalize (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data,
				  datalen);
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: bad RSA private key from dynamic "
		     "SA acquisition subsystem");
	  return 0;
	}
#if defined (USE_PRIVSEP)
      {
	/* With USE_PRIVSEP, the sent_key should be a key number. */
	void *key = sent_key;
	sent_key = monitor_RSA_upload_key (key);
      }
#endif
    }
  else /* Try through the regular means.  */
    {
      switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ])
	{
	case IPSEC_ID_IPV4_ADDR:
	case IPSEC_ID_IPV6_ADDR:
	  util_ntoa ((char **)&buf2,
		     id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR
		     ? AF_INET : AF_INET6,
		     id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
	  if (!buf2)
	    return 0;
	  break;

	case IPSEC_ID_FQDN:
	case IPSEC_ID_USER_FQDN:
	  buf2 = calloc (id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1,
			 sizeof (char));
	  if (!buf2)
	    {
	      log_print ("rsa_sig_encode_hash: malloc (%lu) failed",
			 (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
	      return 0;
	    }
	  memcpy (buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
		  id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
	  break;

	  /* XXX Support more ID types?  */
	default:
	  buf2 = 0;
	  return 0;
	}

#if defined (USE_PRIVSEP)
      sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2);
#else
      sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name,
				   (char *)buf2, 0);
#endif
      free (buf2);

      /* Did we find a key?  */
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: could not get private key");
	  return -1;
	}
    }

#if !defined (USE_PRIVSEP)
  /* Enable RSA blinding.  */
  if (RSA_blinding_on (sent_key, NULL) != 1)
    {
      log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed.");
      return -1;
    }
#endif

  /* XXX hashsize is not necessarily prf->blocksize.  */
  buf = malloc (hashsize);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: malloc (%lu) failed",
	(unsigned long)hashsize);
      return -1;
    }

  if (ike_auth_hash (exchange, buf) == -1)
    {
      free (buf);
      return -1;
    }

  snprintf (header, sizeof header, "rsa_sig_encode_hash: HASH_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf, hashsize));

#if !defined (USE_PRIVSEP)
  data = malloc (RSA_size (sent_key));
  if (!data)
    {
      log_error ("rsa_sig_encode_hash: malloc (%d) failed",
		 RSA_size (sent_key));
      return -1;
    }

  datalen = RSA_private_encrypt (hashsize, buf, data, sent_key,
				 RSA_PKCS1_PADDING);
#else
  datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key,
					 RSA_PKCS1_PADDING);
#endif /* USE_PRIVSEP */
  if (datalen == -1)
    {
      log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed");
      if (data)
	free (data);
      free (buf);
      monitor_RSA_free (sent_key);
      return -1;
    }

  free (buf);

  buf = realloc (data, ISAKMP_SIG_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_SIG_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_SIG_SZ, buf, datalen);

  snprintf (header, sizeof header, "rsa_sig_encode_hash: SIG_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen));
  if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf,
			   ISAKMP_SIG_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }
  return 0;
}
예제 #16
0
int
ike_phase_1_send_ID (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    u_int8_t *buf;
    char header[80];
    ssize_t sz;
    struct sockaddr *src;
    int initiator = exchange->initiator;
    u_int8_t **id;
    size_t *id_len;
    char *my_id = 0;
    u_int8_t id_type;

    /* 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;

    if (exchange->name)
        my_id = conf_get_str (exchange->name, "ID");

    if (!my_id)
        my_id = conf_get_str ("General", "Default-phase-1-ID");

    msg->transport->vtbl->get_src (msg->transport, &src);
    sz = my_id ? ipsec_id_size (my_id, &id_type) : sockaddr_addrlen (src);
    if (sz == -1)
        return -1;

    sz += ISAKMP_ID_DATA_OFF;
    buf = malloc (sz);
    if (!buf)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)sz);
        return -1;
    }

    SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    if (my_id)
    {
        SET_ISAKMP_ID_TYPE (buf, id_type);
        switch (id_type)
        {
        case IPSEC_ID_IPV4_ADDR:
        case IPSEC_ID_IPV6_ADDR:
            /* Already in network byteorder.  */
            memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                    sockaddr_addrlen (src));
            break;

        case IPSEC_ID_FQDN:
        case IPSEC_ID_USER_FQDN:
        case IPSEC_ID_KEY_ID:
            memcpy (buf + ISAKMP_ID_DATA_OFF, conf_get_str (my_id, "Name"),
                    sz - ISAKMP_ID_DATA_OFF);
            break;

        default:
            log_print ("ike_phase_1_send_ID: unsupported ID type %d", id_type);
            free (buf);
            return -1;
        }
    }
    else
    {
        switch (src->sa_family)
        {
        case AF_INET:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR);
            break;
        case AF_INET6:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV6_ADDR);
            break;
        }
        /* Already in network byteorder.  */
        memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                sockaddr_addrlen (src));
    }

    if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1))
    {
        free (buf);
        return -1;
    }
    *id_len = sz - ISAKMP_GEN_SZ;
    *id = malloc (*id_len);
    if (!*id)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)*id_len);
        return -1;
    }
    memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len);
    snprintf (header, sizeof header, "ike_phase_1_send_ID: %s",
              constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf)));
    LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,
                  sz - ISAKMP_ID_DATA_OFF));

    return 0;
}
예제 #17
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;
}