📄 ipsec_doi.c
字号:
/* 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 + -