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