static void ppk_recalc_one(PK11SymKey **sk /* updated */, PK11SymKey *ppk_key, const struct prf_desc *prf_desc, const char *name) { PK11SymKey *t = ikev2_prfplus(prf_desc, ppk_key, *sk, prf_desc->prf_key_size); release_symkey(__func__, name, sk); *sk = t; DBG(DBG_PRIVATE, { chunk_t chunk_sk = chunk_from_symkey("sk_chunk", *sk); DBG_dump_chunk(name, chunk_sk); freeanychunk(chunk_sk); });
/* 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); });