static PK11SymKey *ikev2_prfplus(const struct prf_desc *prf_desc, PK11SymKey *key, PK11SymKey *seed, size_t required_keymat) { uint8_t count = 1; /* T1(prfplus) = prf(KEY, SEED|1) */ PK11SymKey *prfplus; { struct crypt_prf *prf = crypt_prf_init_symkey("prf+0", DBG_CRYPT, prf_desc, "key", key); crypt_prf_update_symkey("seed", prf, seed); crypt_prf_update_byte("1++", prf, count++); prfplus = crypt_prf_final(prf); } /* make a copy to keep things easy */ PK11SymKey *old_t = key_from_symkey_bytes(prfplus, 0, sizeof_symkey(prfplus)); while (sizeof_symkey(prfplus) < required_keymat) { /* Tn = prf(KEY, Tn-1|SEED|n) */ struct crypt_prf *prf = crypt_prf_init_symkey("prf+N", DBG_CRYPT, prf_desc, "key", key); crypt_prf_update_symkey("old_t", prf, old_t); crypt_prf_update_symkey("seed", prf, seed); crypt_prf_update_byte("N++", prf, count++); PK11SymKey *new_t = crypt_prf_final(prf); append_symkey_symkey(prf_desc->hasher, &prfplus, new_t); free_any_symkey("old_t[N]", &old_t); old_t = new_t; } free_any_symkey("old_t[final]", &old_t); return prfplus; }
static void run_ikev2(void) { print_number("COUNT", count); print_chunk("Ni", ni, 0); print_chunk("Nr", nr, 0); print_symkey("g^ir", g_ir, 0); print_symkey("g^ir (new)", g_ir_new, 0); print_chunk("SPIi", spi_i, 0); print_chunk("SPIr", spi_r, 0); if (hasher == NULL) { print_line(hasher_name); return; } /* SKEYSEED = prf(Ni | Nr, g^ir) */ PK11SymKey *skeyseed = ikev2_ike_sa_skeyseed(hasher, ni, nr, g_ir); print_symkey("SKEYSEED", skeyseed, 0); /* prf+(SKEYSEED, Ni | Nr | SPIi | SPIr) */ PK11SymKey *dkm = ikev2_ike_sa_keymat(hasher, skeyseed, ni, nr, spi_i, spi_r, dkm_length / 8); print_symkey("DKM", dkm, dkm_length / 8); /* prf+(SK_d, Ni | Nr) */ PK11SymKey *SK_d = key_from_symkey_bytes(dkm, 0, hasher->hash_digest_len); PK11SymKey *child_sa_dkm = ikev2_child_sa_keymat(hasher, SK_d, NULL, ni, nr, child_sa_dkm_length / 8); print_symkey("DKM(Child SA)", child_sa_dkm, child_sa_dkm_length / 8); /* prf+(SK_d, g^ir (new) | Ni | Nr) */ PK11SymKey *child_sa_dkm_dh = ikev2_child_sa_keymat(hasher, SK_d, g_ir_new, ni, nr, child_sa_dkm_length / 8); print_symkey("DKM(Child SA D-H)", child_sa_dkm_dh, child_sa_dkm_length / 8); /* prf(SK_d (old), g^ir (new) | Ni | Nr) */ PK11SymKey *skeyseed_rekey = ikev2_ike_sa_rekey_skeyseed(hasher, SK_d, g_ir_new, ni, nr); print_symkey("SKEYSEED(Rekey)", skeyseed_rekey, 0); free_any_symkey("skeyseed", &skeyseed); free_any_symkey("dkm", &dkm); free_any_symkey("SK_d", &SK_d); free_any_symkey("child_sa_dkm", &child_sa_dkm); free_any_symkey("child_sa_dkm_dh", &child_sa_dkm_dh); free_any_symkey("skeyseed_rekey", &skeyseed_rekey); }
/* MUST BE THREAD-SAFE */ static void calc_skeyseed_v2(struct pcr_skeyid_q *skq, PK11SymKey *shared, const size_t key_size, const size_t salt_size, PK11SymKey **skeyseed_out, PK11SymKey **SK_d_out, PK11SymKey **SK_ai_out, PK11SymKey **SK_ar_out, PK11SymKey **SK_ei_out, PK11SymKey **SK_er_out, PK11SymKey **SK_pi_out, PK11SymKey **SK_pr_out, chunk_t *initiator_salt_out, chunk_t *responder_salt_out, chunk_t *chunk_SK_pi_out, chunk_t *chunk_SK_pr_out) { DBG(DBG_CRYPT, DBG_log("NSS: Started key computation")); PK11SymKey *skeyseed_k, *SK_d_k, *SK_ai_k, *SK_ar_k, *SK_ei_k, *SK_er_k, *SK_pi_k, *SK_pr_k; chunk_t initiator_salt; chunk_t responder_salt; chunk_t chunk_SK_pi; chunk_t chunk_SK_pr; /* this doesn't take any memory, it's just moving pointers around */ chunk_t ni; chunk_t nr; chunk_t spii; chunk_t spir; setchunk_from_wire(ni, skq, &skq->ni); setchunk_from_wire(nr, skq, &skq->nr); setchunk_from_wire(spii, skq, &skq->icookie); setchunk_from_wire(spir, skq, &skq->rcookie); DBG(DBG_CONTROLMORE, DBG_log("calculating skeyseed using prf=%s integ=%s cipherkey-size=%zu salt-size=%zu", enum_name(&ikev2_trans_type_prf_names, skq->prf_hash), enum_name(&ikev2_trans_type_integ_names, skq->integ_hash), key_size, salt_size)); const struct hash_desc *prf_hasher = (struct hash_desc *) ikev2_alg_find(IKE_ALG_HASH, skq->prf_hash); passert(prf_hasher != NULL); const struct encrypt_desc *encrypter = skq->encrypter; passert(encrypter != NULL); /* generate SKEYSEED from key=(Ni|Nr), hash of shared */ skeyseed_k = ikev2_ike_sa_skeyseed(prf_hasher, ni, nr, shared); passert(skeyseed_k != NULL); /* now we have to generate the keys for everything */ /* need to know how many bits to generate */ /* SK_d needs PRF hasher key bytes */ /* SK_p needs PRF hasher*2 key bytes */ /* SK_e needs key_size*2 key bytes */ /* ..._salt needs salt_size*2 bytes */ /* SK_a needs integ's key size*2 bytes */ int skd_bytes = prf_hasher->hash_key_size; int skp_bytes = prf_hasher->hash_key_size; const struct hash_desc *integ_hasher = (struct hash_desc *)ikev2_alg_find(IKE_ALG_INTEG, skq->integ_hash); int integ_size = integ_hasher != NULL ? integ_hasher->hash_key_size : 0; size_t total_keysize = skd_bytes + 2*skp_bytes + 2*key_size + 2*salt_size + 2*integ_size; PK11SymKey *finalkey = ikev2_ike_sa_keymat(prf_hasher, skeyseed_k, ni, nr, spii, spir, total_keysize); size_t next_byte = 0; SK_d_k = key_from_symkey_bytes(finalkey, next_byte, skd_bytes); next_byte += skd_bytes; SK_ai_k = key_from_symkey_bytes(finalkey, next_byte, integ_size); next_byte += integ_size; SK_ar_k = key_from_symkey_bytes(finalkey, next_byte, integ_size); next_byte += integ_size; /* The encryption key and salt are extracted together. */ SK_ei_k = encrypt_key_from_symkey_bytes(finalkey, encrypter, next_byte, key_size); next_byte += key_size; PK11SymKey *initiator_salt_key = key_from_symkey_bytes(finalkey, next_byte, salt_size); initiator_salt = chunk_from_symkey("initiator salt", initiator_salt_key); free_any_symkey("initiator salt key:", &initiator_salt_key); next_byte += salt_size; /* The encryption key and salt are extracted together. */ SK_er_k = encrypt_key_from_symkey_bytes(finalkey, encrypter, next_byte, key_size); next_byte += key_size; PK11SymKey *responder_salt_key = key_from_symkey_bytes(finalkey, next_byte, salt_size); responder_salt = chunk_from_symkey("responder salt", responder_salt_key); free_any_symkey("responder salt key:", &responder_salt_key); next_byte += salt_size; SK_pi_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes); /* store copy of SK_pi_k for later use in authnull */ chunk_SK_pi = chunk_from_symkey("chunk_SK_pi", SK_pi_k); next_byte += skp_bytes; SK_pr_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes); /* store copy of SK_pr_k for later use in authnull */ chunk_SK_pr = chunk_from_symkey("chunk_SK_pr", SK_pr_k); next_byte += skp_bytes; /* next_byte not subsequently used */ DBG(DBG_CRYPT, DBG_log("NSS ikev2: finished computing individual keys for IKEv2 SA")); free_any_symkey("finalkey", &finalkey); *skeyseed_out = skeyseed_k; *SK_d_out = SK_d_k; *SK_ai_out = SK_ai_k; *SK_ar_out = SK_ar_k; *SK_ei_out = SK_ei_k; *SK_er_out = SK_er_k; *SK_pi_out = SK_pi_k; *SK_pr_out = SK_pr_k; *initiator_salt_out = initiator_salt; *responder_salt_out = responder_salt; *chunk_SK_pi_out = chunk_SK_pi; *chunk_SK_pr_out = chunk_SK_pr; DBG(DBG_CRYPT, DBG_log("calc_skeyseed_v2 pointers: shared %p, skeyseed %p, SK_d %p, SK_ai %p, SK_ar %p, SK_ei %p, SK_er %p, SK_pi %p, SK_pr %p", shared, skeyseed_k, SK_d_k, SK_ai_k, SK_ar_k, SK_ei_k, SK_er_k, SK_pi_k, SK_pr_k); DBG_dump_chunk("calc_skeyseed_v2 initiator salt", initiator_salt); DBG_dump_chunk("calc_skeyseed_v2 responder salt", responder_salt); DBG_dump_chunk("calc_skeyseed_v2 SK_pi", chunk_SK_pi); DBG_dump_chunk("calc_skeyseed_v2 SK_pr", chunk_SK_pr)); }
void ikev2_derive_child_keys(struct state *st, enum original_role role) { chunk_t ikeymat, rkeymat; /* ??? note assumption that AH and ESP cannot be combined */ struct ipsec_proto_info *ipi = st->st_esp.present? &st->st_esp : st->st_ah.present? &st->st_ah : NULL; struct esp_info *ei; passert(ipi != NULL); /* ESP or AH must be present */ passert(st->st_esp.present != st->st_ah.present); /* only one */ /* ??? there is no kernel_alg_ah_info */ /* ??? will this work if the result of kernel_alg_esp_info * is a pointer into its own static buffer (therefore ephemeral)? */ ei = kernel_alg_esp_info( ipi->attrs.transattrs.encrypt, ipi->attrs.transattrs.enckeylen, ipi->attrs.transattrs.integ_hash); passert(ei != NULL); ipi->attrs.transattrs.ei = ei; /* ipi->attrs.transattrs.integ_hasher->hash_key_size / BITS_PER_BYTE; */ unsigned authkeylen = ikev1_auth_kernel_attrs(ei->auth, NULL); /* ??? no account is taken of AH */ /* transid is same as esp_ealg_id */ switch (ei->transid) { case IKEv2_ENCR_reserved: /* AH */ ipi->keymat_len = authkeylen; break; case IKEv2_ENCR_AES_CTR: ipi->keymat_len = ei->enckeylen + authkeylen + AES_CTR_SALT_BYTES;; break; case IKEv2_ENCR_AES_GCM_8: case IKEv2_ENCR_AES_GCM_12: case IKEv2_ENCR_AES_GCM_16: /* aes_gcm does not use an integ (auth) algo - see RFC 4106 */ ipi->keymat_len = ei->enckeylen + AES_GCM_SALT_BYTES; break; case IKEv2_ENCR_AES_CCM_8: case IKEv2_ENCR_AES_CCM_12: case IKEv2_ENCR_AES_CCM_16: /* aes_ccm does not use an integ (auth) algo - see RFC 4309 */ ipi->keymat_len = ei->enckeylen + AES_CCM_SALT_BYTES; break; default: /* ordinary ESP */ ipi->keymat_len = ei->enckeylen + authkeylen; break; } DBG(DBG_CONTROL, DBG_log("enckeylen=%" PRIu32 ", authkeylen=%u, keymat_len=%" PRIu16, ei->enckeylen, authkeylen, ipi->keymat_len)); /* * * Keying material MUST be taken from the expanded KEYMAT in the * following order: * * All keys for SAs carrying data from the initiator to the responder * are taken before SAs going in the reverse direction. * * If multiple IPsec protocols are negotiated, keying material is * taken in the order in which the protocol headers will appear in * the encapsulated packet. * * If a single protocol has both encryption and authentication keys, * the encryption key is taken from the first octets of KEYMAT and * the authentication key is taken from the next octets. * * For AES GCM (RFC 4106 Section 8,1) we need to add 4 bytes for * salt (AES_GCM_SALT_BYTES) */ chunk_t ni; chunk_t nr; setchunk(ni, st->st_ni.ptr, st->st_ni.len); setchunk(nr, st->st_nr.ptr, st->st_nr.len); PK11SymKey *keymat = ikev2_child_sa_keymat(st->st_oakley.prf_hasher, st->st_skey_d_nss, NULL/*dh*/, ni, nr, ipi->keymat_len * 2); PK11SymKey *ikey = key_from_symkey_bytes(keymat, 0, ipi->keymat_len); ikeymat = chunk_from_symkey("initiator keys", ikey); free_any_symkey("ikey:", &ikey); PK11SymKey *rkey = key_from_symkey_bytes(keymat, ipi->keymat_len, ipi->keymat_len); rkeymat = chunk_from_symkey("responder keys:", rkey); free_any_symkey("rkey:", &rkey); free_any_symkey("keymat", &keymat); if (role != ORIGINAL_INITIATOR) { DBG(DBG_PRIVATE, { DBG_dump_chunk("our keymat", ikeymat); DBG_dump_chunk("peer keymat", rkeymat); });