/* Checks if the current certificate is revoked. It goes through the * list of revoked certificates of the corresponding crl. If the * certificate is found in the list, TRUE is returned */ bool x509_check_revocation(const x509crl_t *crl, chunk_t serial) { revokedCert_t *revokedCert = crl->revokedCertificates; char tbuf[TIMETOA_BUF]; DBG(DBG_X509, DBG_dump_chunk("serial number:", serial) ) while(revokedCert != NULL) { /* compare serial numbers */ if (revokedCert->userCertificate.len == serial.len && memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0) { openswan_log("certificate was revoked on %s", timetoa(&revokedCert->revocationDate, TRUE, tbuf, sizeof(tbuf))); return TRUE; } revokedCert = revokedCert->next; } DBG(DBG_X509, DBG_log("certificate not revoked") ) return FALSE; }
/* MUST BE THREAD-SAFE */ void calc_dh(struct pluto_crypto_req *r) { /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ struct pcr_skeyid_q dhq; memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); /* clear out the reply */ struct pcr_skeyid_r *skr = &r->pcr_d.dhr; zero(skr); /* ??? pointer fields might not be NULLed */ INIT_WIRE_ARENA(*skr); const struct oakley_group_desc *group = lookup_group(dhq.oakley_group); passert(group != NULL); SECKEYPrivateKey *ltsecret = dhq.secret; SECKEYPublicKey *pubk = dhq.pubk; /* now calculate the (g^x)(g^y) */ chunk_t g; setchunk_from_wire(g, &dhq, dhq.role == ORIGINAL_RESPONDER ? &dhq.gi : &dhq.gr); DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g)); const char *story; /* we ignore the value */ skr->shared = calc_dh_shared(g, ltsecret, group, pubk, &story); }
chunk_t extract_chunk(const char *prefix, const chunk_t input, size_t offset, size_t length) { chunk_t output; DBG(DBG_CRYPT, DBG_log("extract_chunk: %s: offset %zd length %zd", prefix, offset, length)); passert(offset + length <= input.len); clonetochunk(output, input.ptr + offset, length, prefix); DBG(DBG_CRYPT, DBG_dump_chunk(prefix, output)); return output; }
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); });
/* * Given an ASCII string, convert it onto a buffer of bytes. If the * buffer is prefixed by 0x assume the contents are hex (with spaces) * and decode it; otherwise it is assumed that the ascii (minus the * NUL) should be copied. */ chunk_t decode_to_chunk(const char *prefix, const char *original) { DBG(DBG_CRYPT, DBG_log("decode_to_chunk: %s: input \"%s\"", prefix, original)); chunk_t chunk; if (startswith(original, "0x")) { chunk = decode_hex_to_chunk(original, original + strlen("0x")); } else { chunk = zalloc_chunk(strlen(original), original); memcpy(chunk.ptr, original, chunk.len); } DBG(DBG_CRYPT, DBG_dump_chunk("decode_to_chunk: output: ", chunk)); return chunk; }
static void ikev2_calculate_sighash(struct state *st, enum phase1_role role, unsigned char *idhash, chunk_t firstpacket, unsigned char *sig_octets) { SHA1_CTX ctx_sha1; const chunk_t *nonce; const char *nonce_name; if (role == 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)"; } DBG(DBG_CRYPT, DBG_dump_chunk("inputs to hash1 (first packet)", firstpacket); DBG_dump_chunk(nonce_name, *nonce); DBG_dump("idhash", idhash, st->st_oakley.prf_hasher->hash_digest_len)); SHA1Init(&ctx_sha1); SHA1Update(&ctx_sha1, firstpacket.ptr, firstpacket.len); SHA1Update(&ctx_sha1, nonce->ptr, nonce->len); /* we took the PRF(SK_d,ID[ir]'), so length is prf hash length */ SHA1Update(&ctx_sha1, idhash, st->st_oakley.prf_hasher->hash_digest_len); SHA1Final(sig_octets, &ctx_sha1); }
/* MUST BE THREAD-SAFE */ void calc_dh_v2(struct pluto_crypto_req *r, const char **story) { struct pcr_skeycalc_v2_r *const skr = &r->pcr_d.dhv2; /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ struct pcr_skeyid_q dhq; memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); /* clear out the reply (including pointers) */ static const struct pcr_skeycalc_v2_r zero_pcr_skeycalc_v2_r; *skr = zero_pcr_skeycalc_v2_r; INIT_WIRE_ARENA(*skr); const struct oakley_group_desc *group = lookup_group(dhq.oakley_group); passert(group != NULL); SECKEYPrivateKey *ltsecret = dhq.secret; SECKEYPublicKey *pubk = dhq.pubk; /* now calculate the (g^x)(g^y) --- need gi on responder, gr on initiator */ chunk_t g; setchunk_from_wire(g, &dhq, dhq.role == ORIGINAL_RESPONDER ? &dhq.gi : &dhq.gr); DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g)); skr->shared = calc_dh_shared(g, ltsecret, group, pubk, story); if (skr->shared != NULL) { /* okay, so now all the shared key material */ calc_skeyseed_v2(&dhq, /* input */ skr->shared, /* input */ dhq.key_size, /* input */ dhq.salt_size, /* input */ &skr->skeyseed, /* output */ &skr->skeyid_d, /* output */ &skr->skeyid_ai, /* output */ &skr->skeyid_ar, /* output */ &skr->skeyid_ei, /* output */ &skr->skeyid_er, /* output */ &skr->skeyid_pi, /* output */ &skr->skeyid_pr, /* output */ &skr->skey_initiator_salt, /* output */ &skr->skey_responder_salt, /* output */ &skr->skey_chunk_SK_pi, /* output */ &skr->skey_chunk_SK_pr); /* output */ } }
void v2prfplus(struct v2prf_stuff *vps) { struct hmac_ctx ctx; hmac_init_chunk(&ctx, vps->prf_hasher, *vps->skeyseed); hmac_update_chunk(&ctx, vps->t); hmac_update_chunk(&ctx, vps->ni); hmac_update_chunk(&ctx, vps->nr); hmac_update_chunk(&ctx, vps->spii); hmac_update_chunk(&ctx, vps->spir); hmac_update(&ctx, vps->counter, 1); hmac_final_chunk(vps->t, "skeyseed_t1", &ctx); DBG(DBG_CRYPT, { char b[20]; sprintf(b, "prf+[%u]:", vps->counter[0]); DBG_dump_chunk(b, vps->t); });
/* * used by responder, for extracting PPK_ID from IKEv2 Notify * PPK_ID Payload, we store PPK_ID and its type in payl */ bool extract_ppk_id(pb_stream *pbs, struct ppk_id_payload *payl) { size_t len = pbs_left(pbs); u_char dst[PPK_ID_MAXLEN]; int idtype; if (len > PPK_ID_MAXLEN) { loglog(RC_LOG_SERIOUS, "PPK ID length is too big"); return FALSE; } if (len <= 1) { loglog(RC_LOG_SERIOUS, "PPK ID data must be at least 1 byte (received %zd bytes including ppk type byte)", len); return FALSE; } if (!in_raw(dst, len, pbs, "Unified PPK_ID Payload")) { loglog(RC_LOG_SERIOUS, "PPK ID data could not be read"); return FALSE; } DBG(DBG_CONTROL, DBG_log("received PPK_ID type: %s", enum_name(&ikev2_ppk_id_type_names, dst[0]))); idtype = (int)dst[0]; switch (idtype) { case PPK_ID_FIXED: DBG(DBG_CONTROL, DBG_log("PPK_ID of type PPK_ID_FIXED.")); break; case PPK_ID_OPAQUE: default: loglog(RC_LOG_SERIOUS, "PPK_ID type %d (%s) not supported", idtype, enum_name(&ikev2_ppk_id_type_names, idtype)); return FALSE; } /* clone ppk id data without ppk id type byte */ clonetochunk(payl->ppk_id, dst + 1, len - 1, "PPK_ID data"); DBG(DBG_CONTROL, DBG_dump_chunk("Extracted PPK_ID", payl->ppk_id)); return TRUE; }
void ikev2_derive_child_keys(struct state *st, enum phase1_role role) { struct v2prf_stuff childsacalc; chunk_t ikeymat,rkeymat; struct ipsec_proto_info *ipi = &st->st_esp; ipi->attrs.transattrs.ei=kernel_alg_esp_info( ipi->attrs.transattrs.encrypt, ipi->attrs.transattrs.enckeylen, ipi->attrs.transattrs.integ_hash); passert(ipi->attrs.transattrs.ei != NULL); memset(&childsacalc, 0, sizeof(childsacalc)); childsacalc.prf_hasher = st->st_oakley.prf_hasher; setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len); setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len); childsacalc.spii.len=0; childsacalc.spir.len=0; childsacalc.counter[0] = 1; childsacalc.skeyseed = &st->st_skey_d; st->st_esp.present = TRUE; st->st_esp.keymat_len = st->st_esp.attrs.transattrs.ei->enckeylen+ st->st_esp.attrs.transattrs.ei->authkeylen; /* * * 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. * */ v2genbytes(&ikeymat, st->st_esp.keymat_len , "initiator keys", &childsacalc); v2genbytes(&rkeymat, st->st_esp.keymat_len , "responder keys", &childsacalc); /* This should really be role == INITIATOR, but then our keys are * installed reversed. This is a workaround until we locate the * real problem. It's better not to release copies of our code * that will be incompatible with everything else, including our * own updated version * Found by Herbert Xu * if(role == INITIATOR) { */ if(role != INITIATOR) { DBG(DBG_CRYPT, DBG_dump_chunk("our keymat", ikeymat); DBG_dump_chunk("peer keymat", rkeymat); );
static void key_add_request(const struct whack_message *msg) { DBG_log("add keyid %s", msg->keyid); struct id keyid; err_t ugh = atoid(msg->keyid, &keyid, FALSE, FALSE); if (ugh != NULL) { loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh); } else { if (!msg->whack_addkey) delete_public_keys(&pluto_pubkeys, &keyid, msg->pubkey_alg); #if 0 if (msg->keyval.len == 0) { struct key_add_common *oc = alloc_thing(struct key_add_common, "key add common things"); enum key_add_attempt kaa; /* initialize state shared by queries */ oc->refCount = 0; oc->whack_fd = dup_any(whack_log_fd); oc->success = FALSE; for (kaa = ka_TXT; kaa != ka_roof; kaa++) { struct key_add_continuation *kc = alloc_thing( struct key_add_continuation, "key add continuation"); oc->diag[kaa] = NULL; oc->refCount++; kc->common = oc; kc->lookingfor = kaa; switch (kaa) { case ka_TXT: break; #ifdef USE_KEYRR case ka_KEY: break; #endif /* USE_KEYRR */ default: bad_case(kaa); /* suppress gcc warning */ } if (ugh != NULL) { oc->diag[kaa] = clone_str(ugh, "early key add failure"); oc->refCount--; } } /* Done launching queries. * Handle total failure case. */ key_add_merge(oc, &keyid); } else #endif if (msg->keyval.len != 0) { DBG_dump_chunk("add pubkey", msg->keyval); ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, &msg->keyval, &pluto_pubkeys); if (ugh != NULL) loglog(RC_LOG_SERIOUS, "%s", ugh); } else { loglog(RC_LOG_SERIOUS, "error: Key without keylength from whack not added to key list (needs DNS lookup?)"); } }
/* 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)); }
/* MUST BE THREAD-SAFE */ void calc_ke(struct pluto_crypto_req *r) { SECKEYDHParams dhp; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privk; SECKEYPublicKey *pubk; struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group = lookup_group(kn->oakley_group); chunk_t base = mpz_to_n_autosize(group->generator); chunk_t prime = mpz_to_n_autosize(group->modulus); DBG(DBG_CRYPT, DBG_dump_chunk("NSS: Value of Prime:", prime)); DBG(DBG_CRYPT, DBG_dump_chunk("NSS: Value of base:", base)); dhp.prime.data = prime.ptr; dhp.prime.len = prime.len; dhp.base.data = base.ptr; dhp.base.len = base.len; slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, lsw_return_nss_password_file_info()); if (slot == NULL) loglog(RC_LOG_SERIOUS, "NSS: slot for DH key gen is NULL"); passert(slot != NULL); for (;;) { pubk = NULL; /* ??? is this needed? Output-only from next call? */ privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, &dhp, &pubk, PR_FALSE, PR_TRUE, lsw_return_nss_password_file_info()); if (privk == NULL) { loglog(RC_LOG_SERIOUS, "NSS: DH private key creation failed (err %d)", PR_GetError()); } passert(privk != NULL && pubk != NULL); if (group->bytes == pubk->u.dh.publicValue.len) { DBG(DBG_CRYPT, DBG_log("NSS: generated dh priv and pub keys: %d", pubk->u.dh.publicValue.len)); break; } else { DBG(DBG_CRYPT, DBG_log("NSS: generating dh priv and pub keys again")); SECKEY_DestroyPrivateKey(privk); SECKEY_DestroyPublicKey(pubk); } } kn->secret = privk; kn->pubk = pubk; ALLOC_WIRE_CHUNK(*kn, gi, pubk->u.dh.publicValue.len); { unsigned char *gip = WIRE_CHUNK_PTR(*kn, gi); memcpy(gip, pubk->u.dh.publicValue.data, pubk->u.dh.publicValue.len); } DBG(DBG_CRYPT, { DBG_log("NSS: Local DH secret (pointer): %p", kn->secret); DBG_dump("NSS: Public DH value sent(computed in NSS):", WIRE_CHUNK_PTR(*kn, gi), pubk->u.dh.publicValue.len); });
void calc_ke(struct pluto_crypto_req *r) { chunk_t prime; chunk_t base; SECKEYDHParams dhp; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privk; SECKEYPublicKey *pubk; struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group; group = lookup_group(kn->oakley_group); base = mpz_to_n2(group->generator); prime = mpz_to_n2(group->modulus); DBG(DBG_CRYPT,DBG_dump_chunk("NSS: Value of Prime:\n", prime)); DBG(DBG_CRYPT,DBG_dump_chunk("NSS: Value of base:\n", base)); dhp.prime.data=prime.ptr; dhp.prime.len=prime.len; dhp.base.data=base.ptr; dhp.base.len=base.len; slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,osw_return_nss_password_file_info()); if(!slot) { loglog(RC_LOG_SERIOUS, "NSS: slot for DH key gen is NULL"); } PR_ASSERT(slot!=NULL); while(1) { privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, &dhp, &pubk, PR_FALSE, PR_TRUE, osw_return_nss_password_file_info()); if(!privk) { loglog(RC_LOG_SERIOUS, "NSS: DH private key creation failed (err %d)", PR_GetError()); } PR_ASSERT(privk!=NULL); if( group-> bytes == pubk->u.dh.publicValue.len ) { DBG(DBG_CRYPT, DBG_log("NSS: generated dh priv and pub keys: %d\n", pubk->u.dh.publicValue.len)); break; } else { DBG(DBG_CRYPT, DBG_log("NSS: generating dh priv and pub keys")); if (privk) SECKEY_DestroyPrivateKey(privk); if (pubk) SECKEY_DestroyPublicKey(pubk); } } pluto_crypto_allocchunk(&kn->thespace, &kn->secret, sizeof(SECKEYPrivateKey*)); { char *gip = wire_chunk_ptr(kn, &(kn->secret)); memcpy(gip, &privk, sizeof(SECKEYPrivateKey *)); } pluto_crypto_allocchunk(&kn->thespace, &kn->gi, pubk->u.dh.publicValue.len); { char *gip = wire_chunk_ptr(kn, &(kn->gi)); memcpy(gip, pubk->u.dh.publicValue.data, pubk->u.dh.publicValue.len); } pluto_crypto_allocchunk(&kn->thespace, &kn->pubk, sizeof(SECKEYPublicKey*)); { char *gip = wire_chunk_ptr(kn, &(kn->pubk)); memcpy(gip, &pubk, sizeof(SECKEYPublicKey*)); } DBG(DBG_CRYPT, DBG_dump("NSS: Local DH secret:\n" , wire_chunk_ptr(kn, &(kn->secret)) , sizeof(SECKEYPrivateKey*)); DBG_dump("NSS: Public DH value sent(computed in NSS):\n", wire_chunk_ptr(kn, &(kn->gi)),pubk->u.dh.publicValue.len)); DBG(DBG_CRYPT, DBG_dump("NSS: Local DH public value (pointer):\n" , wire_chunk_ptr(kn, &(kn->pubk)) , sizeof(SECKEYPublicKey*))); /* clean up after ourselves */ if (slot) { PK11_FreeSlot(slot); } /* if (privk){SECKEY_DestroyPrivateKey(privk);} */ /* if (pubk){SECKEY_DestroyPublicKey(pubk);} */ freeanychunk(prime); freeanychunk(base); }
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); });
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; }
/* * send a SCEP request via HTTP and wait for a response */ bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op , fetch_request_t req_type, chunk_t *response) { #ifdef LIBCURL char errorbuffer[CURL_ERROR_SIZE] = ""; char *complete_url = NULL; struct curl_slist *headers = NULL; CURL *curl; CURLcode res; /* initialize response */ *response = empty_chunk; /* initialize curl context */ curl = curl_easy_init(); if (curl == NULL) { plog("could not initialize curl context"); return FALSE; } if (op == SCEP_PKI_OPERATION) { const char operation[] = "PKIOperation"; if (req_type == FETCH_GET) { char *escaped_req = escape_http_request(pkcs7); /* form complete url */ int len = strlen(url) + 20 + strlen(operation) + strlen(escaped_req) + 1; complete_url = alloc_bytes(len, "complete url"); snprintf(complete_url, len, "%s?operation=%s&message=%s" , url, operation, escaped_req); pfreeany(escaped_req); curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE); headers = curl_slist_append(headers, "Pragma:"); headers = curl_slist_append(headers, "Host:"); headers = curl_slist_append(headers, "Accept:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } else /* HTTP_POST */ { /* form complete url */ int len = strlen(url) + 11 + strlen(operation) + 1; complete_url = alloc_bytes(len, "complete url"); snprintf(complete_url, len, "%s?operation=%s", url, operation); curl_easy_setopt(curl, CURLOPT_HTTPGET, FALSE); headers = curl_slist_append(headers, "Content-Type:"); headers = curl_slist_append(headers, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pkcs7.ptr); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pkcs7.len); } } else /* SCEP_GET_CA_CERT */ { const char operation[] = "GetCACert"; /* form complete url */ int len = strlen(url) + 32 + strlen(operation) + 1; complete_url = alloc_bytes(len, "complete url"); snprintf(complete_url, len, "%s?operation=%s&message=CAIdentifier" , url, operation); curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE); } curl_easy_setopt(curl, CURLOPT_URL, complete_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); DBG(DBG_CONTROL, DBG_log("sending scep request to '%s'", url) ) res = curl_easy_perform(curl); if (res == CURLE_OK) { DBG(DBG_CONTROL, DBG_log("received scep response") ) DBG(DBG_RAW, DBG_dump_chunk("SCEP response:\n", *response) ) } else { plog("failed to fetch scep response from '%s': %s", url, errorbuffer); } curl_slist_free_all(headers); curl_easy_cleanup(curl); pfreeany(complete_url); return (res == CURLE_OK); #else /* !LIBCURL */ plog("scep error: pluto wasn't compiled with libcurl support"); return FALSE; #endif /* !LIBCURL */ }