⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipsec_doi.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* If there's already an ISAKMP SA established, use that and     * go directly to Quick Mode.  We are even willing to use one     * that is still being negotiated, but only if we are the Initiator     * (thus we can be sure that the IDs are not going to change;     * other issues around intent might matter).     * Note: there is no way to initiate with a Road Warrior.     */    struct state *st = find_phase1_state(c	, ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES);    if (st == NULL)    {	initiator_function *initiator = c->policy & POLICY_AGGRESSIVE					? aggr_outI1 : main_outI1;	(void) initiator(whack_sock, c, NULL, policy, try, importance);    }    else if (HAS_IPSEC_POLICY(policy)) {      /* boost priority if necessary */      if(st->st_import < importance) st->st_import = importance;      if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {	/* leave our Phase 2 negotiation pending */	add_pending(whack_sock, st, c, policy, try		    , replacing);      }      else {	/* ??? we assume that peer_nexthop_sin isn't important:	 * we already have it from when we negotiated the ISAKMP SA!	 * It isn't clear what to do with the error return.	 */	(void) quick_outI1(whack_sock, st, c, policy, try			   , replacing);      }    }    else    {	close_any(whack_sock);    }}/* Replace SA with a fresh one that is similar * * Shares some logic with ipsecdoi_initiate, but not the same! * - we must not reuse the ISAKMP SA if we are trying to replace it! * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build *   ISAKMP SA if needed. * - duplicate whack fd, if live. * Does not delete the old state -- someone else will do that. */voidipsecdoi_replace(struct state *st, unsigned long try){    int whack_sock = dup_any(st->st_whack_sock);    lset_t policy = st->st_policy;    if (IS_PHASE1(st->st_state) || IS_PHASE15(st->st_state))    {	initiator_function *initiator = policy & POLICY_AGGRESSIVE					? aggr_outI1 : main_outI1;	passert(!HAS_IPSEC_POLICY(policy));	(void) initiator(whack_sock, st->st_connection, st, policy			 , try, st->st_import);    }    else    {	/* Add features of actual old state to policy.  This ensures	 * that rekeying doesn't downgrade security.  I admit that	 * this doesn't capture everything.	 */	if (st->st_pfs_group != NULL)	    policy |= POLICY_PFS;	if (st->st_ah.present)	{	    policy |= POLICY_AUTHENTICATE;	    if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)		policy |= POLICY_TUNNEL;	}	if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL)	{	    policy |= POLICY_ENCRYPT;	    if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)		policy |= POLICY_TUNNEL;	}	if (st->st_ipcomp.present)	{	    policy |= POLICY_COMPRESS;	    if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)		policy |= POLICY_TUNNEL;	}	passert(HAS_IPSEC_POLICY(policy));	ipsecdoi_initiate(whack_sock, st->st_connection, policy, try			  , st->st_serialno, st->st_import);    }}/* SKEYID for preshared keys. * See draft-ietf-ipsec-ike-01.txt 4.1 */static boolskeyid_preshared(struct state *st){    const chunk_t *pss = get_preshared_secret(st->st_connection);    if (pss == NULL)    {	loglog(RC_LOG_SERIOUS, "preshared secret disappeared!");	return FALSE;    }    else    {	struct hmac_ctx ctx;	DBG(DBG_CRYPT,	    DBG_log("Skey inputs (PSK+NI+NR)");	    DBG_dump_chunk("ni: ", st->st_ni);	    DBG_dump_chunk("nr: ", st->st_nr));	hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss);	hmac_update_chunk(&ctx, st->st_ni);	hmac_update_chunk(&ctx, st->st_nr);	hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_preshared()", &ctx);	DBG(DBG_CRYPT,	    DBG_dump_chunk("keyid: ", st->st_skeyid));	return TRUE;    }}static boolskeyid_digisig(struct state *st){    struct hmac_ctx ctx;    chunk_t nir;    /* We need to hmac_init with the concatenation of Ni_b and Nr_b,     * so we have to build a temporary concatentation.     */    nir.len = st->st_ni.len + st->st_nr.len;    nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig");    memcpy(nir.ptr, st->st_ni.ptr, st->st_ni.len);    memcpy(nir.ptr+st->st_ni.len, st->st_nr.ptr, st->st_nr.len);    hmac_init_chunk(&ctx, st->st_oakley.hasher, nir);    pfree(nir.ptr);    hmac_update_chunk(&ctx, st->st_shared);    hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx);    return TRUE;}/* Generate the SKEYID_* and new IV * See draft-ietf-ipsec-ike-01.txt 4.1 */static boolgenerate_skeyids_iv(struct state *st){    /* Generate the SKEYID */    switch (st->st_oakley.auth)    {	case OAKLEY_PRESHARED_KEY:	    if (!skeyid_preshared(st))		return FALSE;	    break;	case OAKLEY_RSA_SIG:	    if (!skeyid_digisig(st))		return FALSE;	    break;	case OAKLEY_DSS_SIG:	    /* XXX */	case OAKLEY_RSA_ENC:	case OAKLEY_RSA_ENC_REV:	case OAKLEY_ELGAMAL_ENC:	case OAKLEY_ELGAMAL_ENC_REV:	    /* XXX */	default:	    bad_case(st->st_oakley.auth);    }    /* generate SKEYID_* from SKEYID */    {	struct hmac_ctx ctx;	hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);	/* SKEYID_D */	hmac_update_chunk(&ctx, st->st_shared);	hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);	hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);	hmac_update(&ctx, "\0", 1);	hmac_final_chunk(st->st_skeyid_d, "st_skeyid_d in generate_skeyids_iv()", &ctx);	/* SKEYID_A */	hmac_reinit(&ctx);	hmac_update_chunk(&ctx, st->st_skeyid_d);	hmac_update_chunk(&ctx, st->st_shared);	hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);	hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);	hmac_update(&ctx, "\1", 1);	hmac_final_chunk(st->st_skeyid_a, "st_skeyid_a in generate_skeyids_iv()", &ctx);	/* SKEYID_E */	hmac_reinit(&ctx);	hmac_update_chunk(&ctx, st->st_skeyid_a);	hmac_update_chunk(&ctx, st->st_shared);	hmac_update(&ctx, st->st_icookie, COOKIE_SIZE);	hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE);	hmac_update(&ctx, "\2", 1);	hmac_final_chunk(st->st_skeyid_e, "st_skeyid_e in generate_skeyids_iv()", &ctx);    }    /* generate IV */    {	union hash_ctx hash_ctx;	const struct hash_desc *h = st->st_oakley.hasher;	st->st_new_iv_len = h->hash_digest_len;	passert(st->st_new_iv_len <= sizeof(st->st_new_iv));        DBG(DBG_CRYPT,            DBG_dump_chunk("DH_i:", st->st_gi);            DBG_dump_chunk("DH_r:", st->st_gr);        );	h->hash_init(&hash_ctx);	h->hash_update(&hash_ctx, st->st_gi.ptr, st->st_gi.len);	h->hash_update(&hash_ctx, st->st_gr.ptr, st->st_gr.len);	h->hash_final(st->st_new_iv, &hash_ctx);    }    /* Oakley Keying Material     * Derived from Skeyid_e: if it is not big enough, generate more     * using the PRF.     * See RFC 2409 "IKE" Appendix B     */    {	/* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */	const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;	u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];	u_char *k = st->st_skeyid_e.ptr;	if (keysize > st->st_skeyid_e.len)	{	    struct hmac_ctx ctx;	    size_t i = 0;	    hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_e);	    hmac_update(&ctx, "\0", 1);	    for (;;)	    {		hmac_final(&keytemp[i], &ctx);		i += ctx.hmac_digest_len;		if (i >= keysize)		    break;		hmac_reinit(&ctx);		hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_len], ctx.hmac_digest_len);	    }	    k = keytemp;	}	clonereplacechunk(st->st_enc_key, k, keysize, "st_enc_key");    }    DBG(DBG_CRYPT,	DBG_dump_chunk("Skeyid:  ", st->st_skeyid);	DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d);	DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a);	DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e);	DBG_dump_chunk("enc key:", st->st_enc_key);	DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len));    return TRUE;}/* Generate HASH_I or HASH_R for ISAKMP Phase I. * This will *not* generate other hash payloads (eg. Phase II or Quick Mode, * New Group Mode, or ISAKMP Informational Exchanges). * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R. * If hashus argument is TRUE, we're generating a hash for our end. * See RFC2409 IKE 5. * * Generating the SIG_I and SIG_R for DSS is an odd perversion of this: * Most of the logic is the same, but SHA-1 is used in place of HMAC-whatever. * The extensive common logic is embodied in main_mode_hash_body(). * See draft-ietf-ipsec-ike-01.txt 4.1 and 6.1.1.2 */typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ;static voidmain_mode_hash_body(struct state *st, bool hashi	/* Initiator? */, const pb_stream *idpl	/* ID payload, as PBS */, union hash_ctx *ctx, void (*hash_update_void)(void *, const u_char *input, size_t)){#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len)    hash_update_t hash_update=(hash_update_t)  hash_update_void;#if 0	/* if desperate to debug hashing */#   define hash_update(ctx, input, len) { \	DBG_dump("hash input", input, len); \	(hash_update)(ctx, input, len); \	}#endif#   define hash_update_chunk(ctx, ch) hash_update((ctx), (ch).ptr, (ch).len)    if (hashi)    {	hash_update_chunk(ctx, st->st_gi);	hash_update_chunk(ctx, st->st_gr);	hash_update(ctx, st->st_icookie, COOKIE_SIZE);	hash_update(ctx, st->st_rcookie, COOKIE_SIZE);    }    else    {	hash_update_chunk(ctx, st->st_gr);	hash_update_chunk(ctx, st->st_gi);	hash_update(ctx, st->st_rcookie, COOKIE_SIZE);	hash_update(ctx, st->st_icookie, COOKIE_SIZE);    }    DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA"	, (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic))));    /* SA_b */    hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic)	, st->st_p1isa.len - sizeof(struct isakmp_generic));    /* Hash identification payload, without generic payload header.     * We used to reconstruct ID Payload for this purpose, but now     * we use the bytes as they appear on the wire to avoid     * "spelling problems".     */    hash_update(ctx	, idpl->start + sizeof(struct isakmp_generic)	, pbs_offset(idpl) - sizeof(struct isakmp_generic));#   undef hash_update_chunk#   undef hash_update}static size_t	/* length of hash */main_mode_hash(struct state *st, u_char *hash_val	/* resulting bytes */, bool hashi	/* Initiator? */, const pb_stream *idpl)	/* ID payload, as PBS; cur must be at end */{    struct hmac_ctx ctx;    hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);    main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);    hmac_final(hash_val, &ctx);    return ctx.hmac_digest_len;}#if 0	/* only needed for DSS */static voidmain_mode_sha1(struct state *st, u_char *hash_val	/* resulting bytes */, size_t *hash_len	/* length of hash */, bool hashi	/* Initiator? */, const pb_stream *idpl)	/* ID payload, as PBS */{    union hash_ctx ctx;    SHA1Init(&ctx.ctx_sha1);    SHA1Update(&ctx.ctx_sha1, st->st_skeyid.ptr, st->st_skeyid.len);    *hash_len = SHA1_DIGEST_SIZE;    main_mode_hash_body(st, hashi, idpl, &ctx	, (void (*)(union hash_ctx *, const u_char *, unsigned int))&SHA1Update);    SHA1Final(hash_val, &ctx.ctx_sha1);}#endif/* Create an RSA signature of a hash. * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2. * Use PKCS#1 version 1.5 encryption of hash (called * RSAES-PKCS1-V1_5) in PKCS#2. */static size_tRSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS], const u_char *hash_val, size_t hash_len){    size_t sz = 0;    smartcard_t *sc = c->spd.this.sc;    if (sc == NULL)		/* no smartcard */    {	const struct RSA_private_key *k = get_RSA_private_key(c);	if (k == NULL)	    return 0;	/* failure: no key to use */	sz = k->pub.k;	passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);	sign_hash(k, hash_val, hash_len, sig_val, sz);    }    else if (sc->valid) /* if valid pin then sign hash on the smartcard */    {#ifdef SMARTCARD 	lock_certs_and_keys("RSA_sign_hash");	if (!scx_establish_context(sc->reader))	{	    scx_release_context();	    unlock_certs_and_keys("RSA_sign_hash");	    unlock_certs_and_keys("RSA_sign_hash");	    return 0;	}	sz = scx_get_keylength(sc) / BITS_PER_BYTE;	if (sz == 0)	{	    openswan_log("failed to get keylength from smartcard");	    scx_release_context();	    return 0;	}	DBG(DBG_CONTROL | DBG_CRYPT,	    DBG_log("signing hash with RSA key from smartcard (reader: %d, id: %s)"		, sc->reader, sc->id)	)	sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;	scx_release_context();        unlock_certs_and_keys("RSA_sign_hash");#else	openswan_log("smartcard not configured");#endif	    }    return sz;}/* Check a Main Mode RSA Signature against computed hash using RSA public key k. * * As a side effect, on success, the public key is copied into the * state object to record the authenticator. * * Can fail because wrong public key is used or because hash disagrees. * We distinguish because diagnostics should also. * * The result is NULL if the Signature checked out. * Otherwise, the first character of the result indicates * how far along failure occurred.  A greater character signifies * greater progress. * * Classes: * 0	reserved for caller * 1	SIG length doesn't match key length -- wrong key * 2-8	malformed ECB after decryption -- probably wrong key * 9	decrypted hash != computed hash -- probably correct key * * Although the math should be the same for generating and checking signatures, * it is not: the knowledge of the private key allows more efficient (i.e. * different) computation for encryption. */static err_ttry_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len, const pb_stream *sig_pbs, struct pubkey *kr, struct state *st){    const u_char *sig_val = sig_pbs->cur;    size_t sig_len = pbs_left(sig_pbs);    u_char s[RSA_MAX_OCTETS];	/* for decrypted sig_val */    u_char *hash_in_s = &s[sig_len - hash_len];    const struct RSA_public_key *k = &kr->u.rsa;    /* decrypt the signature -- reversing RSA_sign_hash */    if (sig_len != k->k)    {	/* XXX notification: INVALID_KEY_INFORMATION */	return "1" "SIG length does not match public key length";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -