Example #1
0
int
main(void)
{
	int len, id;
	char buf[DH_MAXSZ], buf2[DH_MAXSZ];
	char sec[DH_MAXSZ], sec2[DH_MAXSZ];
	struct group *group, *group2;
	const char *name[] = { "MODP", "EC2N", "ECP" };

	group_init();

	for (id = 0; id < 0xff; id++) {
		if ((group = group_get(id)) == NULL ||
		    (group2 = group_get(id)) == NULL)
			continue;

		printf ("Testing group %d (%s%d): ", id,
		    name[group->spec->type],
		    group->spec->bits);

		len = dh_getlen(group);

		dh_create_exchange(group, buf);
		dh_create_exchange(group2, buf2);

		dh_create_shared(group, sec, buf2);
		dh_create_shared(group2, sec2, buf);

		if (memcmp (sec, sec2, len)) {
			printf("FAILED\n");
			return (1);
		} else
			printf("OKAY\n");

		group_free(group);
		group_free(group2);
	}

	return (0);
}
Example #2
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;
}