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 ikev1_skeyid_alphabet(PK11SymKey *skeyid) { PK11SymKey *skeyid_d = ikev1_skeyid_d(hasher, skeyid, g_xy, cky_i, cky_r); print_symkey("SKEYID_d", skeyid_d, 0); PK11SymKey *skeyid_a = ikev1_skeyid_a(hasher, skeyid, skeyid_d, g_xy, cky_i, cky_r); print_symkey("SKEYID_a", skeyid_a, 0); PK11SymKey *skeyid_e = ikev1_skeyid_e(hasher, skeyid, skeyid_a, g_xy, cky_i, cky_r); print_symkey("SKEYID_e", skeyid_e, 0); free_any_symkey("skeyid_d", &skeyid_d); free_any_symkey("skeyid_e", &skeyid_e); free_any_symkey("skeyid_a", &skeyid_a); }
/* * Compute: prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) */ PK11SymKey *ikev2_ike_sa_keymat(const struct hash_desc *hasher, PK11SymKey *skeyseed, const chunk_t Ni, const chunk_t Nr, const chunk_t SPIi, const chunk_t SPIr, size_t required_bytes) { PK11SymKey *data = symkey_from_chunk(skeyseed, Ni); append_symkey_chunk(hasher, &data, Nr); append_symkey_chunk(hasher, &data, SPIi); append_symkey_chunk(hasher, &data, SPIr); PK11SymKey *prfplus = ikev2_prfplus(hasher, skeyseed, data, required_bytes); free_any_symkey(__func__, &data); return prfplus; }
/* * Compute: prf+(SK_d, [ g^ir (new) | ] Ni | Nr) */ PK11SymKey *ikev2_child_sa_keymat(const struct hash_desc *hasher, PK11SymKey *SK_d, PK11SymKey *new_dh_secret, const chunk_t Ni, const chunk_t Nr, size_t required_bytes) { PK11SymKey *data; if (new_dh_secret == NULL) { data = symkey_from_chunk(SK_d, Ni); append_symkey_chunk(hasher, &data, Nr); } else { data = concat_symkey_chunk(hasher, new_dh_secret, Ni); append_symkey_chunk(hasher, &data, Nr); } PK11SymKey *prfplus = ikev2_prfplus(hasher, SK_d, data, required_bytes); free_any_symkey(__func__, &data); 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); }
static void run_sig(void) { print_number("COUNT", count); print_chunk("CKY_I", cky_i, 0); print_chunk("CKY_R", cky_r, 0); print_chunk("Ni", ni, 0); print_chunk("Nr", nr, 0); print_symkey("g^xy", g_xy, 0); if (hasher == NULL) { print_line(hasher_name); return; } PK11SymKey *skeyid = ikev1_signature_skeyid(hasher, ni, nr, g_xy); print_symkey("SKEYID", skeyid, 0); ikev1_skeyid_alphabet(skeyid); free_any_symkey("skeyid", &skeyid); }
/* 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)); }
static bool ikev2_calculate_psk_sighash(struct state *st, enum original_role role, unsigned char *idhash, chunk_t firstpacket, unsigned char *signed_octets) { const chunk_t *nonce; const char *nonce_name; const struct connection *c = st->st_connection; const chunk_t *pss = &empty_chunk; const size_t hash_len = st->st_oakley.prf_hasher->hash_digest_len; if (!(c->policy & POLICY_AUTH_NULL)) { pss = get_preshared_secret(c); if (pss == NULL) { libreswan_log("No matching PSK found for connection:%s", st->st_connection->name); return FALSE; /* failure: no PSK to use */ } DBG(DBG_PRIVATE, DBG_dump_chunk("User PSK:", *pss)); } else { /* * draft-ietf-ipsecme-ikev2-null-auth-02 * * When using the NULL Authentication Method, the * content of the AUTH payload is computed using the * syntax of pre-shared secret authentication, * described in Section 2.15 of [RFC7296]. The values * SK_pi and SK_pr are used as shared secrets for the * content of the AUTH payloads generated by the * initiator and the responder respectively. * * We have SK_pi/SK_pr as PK11SymKey in st_skey_pi_nss * and st_skey_pr_nss */ passert(st->hidden_variables.st_skeyid_calculated); /* * This is wrong as role - we need to role for THIS exchange * But verify calls this routine with the role inverted, so we * cannot juse st->st_state either. */ if (role == ORIGINAL_INITIATOR) { /* we are sending initiator, or verifying responder */ pss = &st->st_skey_chunk_SK_pi; } else { /* we are verifying initiator, or sending responder */ pss = &st->st_skey_chunk_SK_pr; } DBG(DBG_PRIVATE, DBG_dump_chunk("AUTH_NULL PSK:", *pss)); } /* * RFC 4306 2.15: * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ /* calculate inner prf */ PK11SymKey *prf_psk; { struct crypt_prf *prf = crypt_prf_init(("<prf-psk>" " = prf(<psk>,\"Key Pad for IKEv2\")"), st->st_oakley.prf_hasher, st->st_shared_nss/*scratch*/); crypt_prf_init_chunk("shared secret", prf, *pss); crypt_prf_update(prf); crypt_prf_update_bytes(psk_key_pad_str/*name*/, prf, psk_key_pad_str, psk_key_pad_str_len); prf_psk = crypt_prf_final(prf); } /* decide nonce based on the role */ if (role == ORIGINAL_INITIATOR) { /* on initiator, we need to hash responders nonce */ nonce = &st->st_nr; nonce_name = "inputs to hash2 (responder nonce)"; } else { nonce = &st->st_ni; nonce_name = "inputs to hash2 (initiator nonce)"; } /* calculate outer prf */ { struct crypt_prf *prf = crypt_prf_init(("<signed-octets>" " = prf(<prf-psk>, <msg octets>)"), st->st_oakley.prf_hasher, st->st_shared_nss /*scratch*/); crypt_prf_init_symkey("<prf-psk>", prf, prf_psk); /* * For the responder, the octets to be signed start * with the first octet of the first SPI in the header * of the second message and end with the last octet * of the last payload in the second message. * Appended to this (for purposes of computing the * signature) are the initiator's nonce Ni (just the * value, not the payload containing it), and the * value prf(SK_pr,IDr') where IDr' is the responder's * ID payload excluding the fixed header. Note that * neither the nonce Ni nor the value prf(SK_pr,IDr') * are transmitted. */ crypt_prf_update(prf); crypt_prf_update_chunk("first-packet", prf, firstpacket); crypt_prf_update_chunk("nonce", prf, *nonce); crypt_prf_update_bytes("hash", prf, idhash, hash_len); crypt_prf_final_bytes(prf, signed_octets, hash_len); } free_any_symkey("<prf-psk>", &prf_psk); DBG(DBG_CRYPT, DBG_dump_chunk("inputs to hash1 (first packet)", firstpacket); DBG_dump_chunk(nonce_name, *nonce); DBG_dump("idhash", idhash, hash_len)); return TRUE; }
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); });
/* MUST BE THREAD-SAFE */ PK11SymKey *calc_dh_shared(const chunk_t g, /* converted to SECItem */ /*const*/ SECKEYPrivateKey *privk, /* NSS doesn't do const */ const struct oakley_group_desc *group, const SECKEYPublicKey *local_pubk, const char **story) { SECStatus status; DBG(DBG_CRYPT, DBG_log("Started DH shared-secret computation in NSS:")); PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); passert(arena != NULL); SECKEYPublicKey *remote_pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); remote_pubk->arena = arena; remote_pubk->keyType = dhKey; remote_pubk->pkcs11Slot = NULL; remote_pubk->pkcs11ID = CK_INVALID_HANDLE; SECItem nss_g = { .data = g.ptr, .len = (unsigned int)g.len, .type = siBuffer }; status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.prime, &local_pubk->u.dh.prime); passert(status == SECSuccess); status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.base, &local_pubk->u.dh.base); passert(status == SECSuccess); status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.publicValue, &nss_g); passert(status == SECSuccess); PK11SymKey *dhshared = PK11_PubDerive(privk, remote_pubk, PR_FALSE, NULL, NULL, CKM_DH_PKCS_DERIVE, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, group->bytes, lsw_return_nss_password_file_info()); if (dhshared != NULL) { unsigned int shortfall = group->bytes - PK11_GetKeyLength(dhshared); if (shortfall > 0) { /* * We've got to pad the result with [shortfall] 0x00 bytes. * The chance of shortfall being n should be 1 in 256^n. * So really zauto ought to be big enough for the zeros. * If it isn't, we allocate space on the heap * (this will likely never be executed). */ DBG(DBG_CRYPT, DBG_log("restoring %u DHshared leading zeros", shortfall)); unsigned char zauto[10]; unsigned char *z = shortfall <= sizeof(zauto) ? zauto : alloc_bytes(shortfall, "DH shortfall"); memset(z, 0x00, shortfall); CK_KEY_DERIVATION_STRING_DATA string_params = { .pData = z, .ulLen = shortfall }; SECItem params = { .data = (unsigned char *)&string_params, .len = sizeof(string_params) }; PK11SymKey *newdhshared = PK11_Derive(dhshared, CKM_CONCATENATE_DATA_AND_BASE, ¶ms, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0); passert(newdhshared != NULL); if (z != zauto) pfree(z); free_any_symkey("dhshared", &dhshared); dhshared = newdhshared; } } *story = enum_name(&oakley_group_names, group->group); SECKEY_DestroyPublicKey(remote_pubk); return dhshared; }