Example #1
0
/*  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;
}
Example #2
0
/* 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);
}
Example #3
0
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;
}
Example #4
0
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);
	});
Example #5
0
/*
 * 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;
}
Example #6
0
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);
}
Example #7
0
/* 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 */
	}
}
Example #8
0
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);
	    });
Example #9
0
/*
 * 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;
}
Example #10
0
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);
	    );
Example #11
0
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?)");
		}
	}
Example #12
0
/* 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));
}
Example #13
0
/* 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);
	    });
Example #14
0
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);
}
Example #15
0
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);
		    });
Example #16
0
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 */
}