📄 demux.c
字号:
} else if(st->st_connection->spd.this.xauth_client && st->st_state == STATE_XAUTH_I1) { /* * in this case, we got a new MODECFG message after I0, maybe * because it wants to start over again. */ from_state = STATE_XAUTH_I0; } else if(st->st_connection->spd.this.modecfg_server && IS_PHASE1(st->st_state)) { from_state = STATE_MODE_CFG_R0; } else if(st->st_connection->spd.this.modecfg_client && IS_PHASE1(st->st_state)) { from_state = STATE_MODE_CFG_R1; } else { /* XXX check if we are being a mode config server here */ openswan_log("received MODECFG message when in state %s, and we aren't xauth client" , enum_name(&state_names, st->st_state)); return; } } else { if(st->st_connection->spd.this.xauth_server && IS_PHASE1(st->st_state)) /* Switch from Phase1 to Mode Config */ { openswan_log("We were in phase 1, with no state, so we went to XAUTH_R0"); st->st_state = STATE_XAUTH_R0; } /* otherweise, this is fine, we continue in the state we are in */ set_cur_state(st); from_state = st->st_state; } break;#endif#ifdef NOTYET case ISAKMP_XCHG_NGRP: case ISAKMP_XCHG_ACK_INFO:#endif default: openswan_log("unsupported exchange type %s in message" , enum_show(&exchange_names, md->hdr.isa_xchg)); SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE); return; } /* We have found a from_state, and perhaps a state object. * If we need to build a new state object, * we wait until the packet has been sanity checked. */ /* We don't support the Commit Flag. It is such a bad feature. * It isn't protected -- neither encrypted nor authenticated. * A man in the middle turns it on, leading to DoS. * We just ignore it, with a warning. * By placing the check here, we could easily add a policy bit * to a connection to suppress the warning. This might be useful * because the Commit Flag is expected from some peers. */ if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT) { openswan_log("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag"); } /* Set smc to describe this state's properties. * Look up the appropriate microcode based on state and * possibly Oakley Auth type. */ passert(STATE_IKE_FLOOR <= from_state && from_state <= STATE_IKE_ROOF); smc = ike_microcode_index[from_state - STATE_IKE_FLOOR]; if (st != NULL) { oakley_auth_t baseauth = xauth_calcbaseauth(st->st_oakley.auth); while (!LHAS(smc->flags, baseauth)) { smc++; passert(smc->state == from_state); } } /* Ignore a packet if the state has a suspended state transition * Probably a duplicated packet but the original packet is not yet * recorded in st->st_rpacket, so duplicate checking won't catch. * ??? Should the packet be recorded earlier to improve diagnosis? */ if (st != NULL && st->st_suspended_md != NULL) { loglog(RC_LOG, "discarding packet received during DNS lookup in %s" , enum_name(&state_names, st->st_state)); return; } /* Detect and handle duplicated packets. * This won't work for the initial packet of an exchange * because we won't have a state object to remember it. * If we are in a non-receiving state (terminal), and the preceding * state did transmit, then the duplicate may indicate that that * transmission wasn't received -- retransmit it. * Otherwise, just discard it. * ??? Notification packets are like exchanges -- I hope that * they are idempotent! */ if (st != NULL && st->st_rpacket.ptr != NULL && st->st_rpacket.len == pbs_room(&md->packet_pbs) && memcmp(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len) == 0) { if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) { if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) { st->st_retransmit++; loglog(RC_RETRANSMISSION , "retransmitting in response to duplicate packet; already %s" , enum_name(&state_names, st->st_state)); send_packet(st, "retransmit in response to duplicate"); } else { loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s" , enum_name(&state_names, st->st_state)); } } else { loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s" , enum_name(&state_names, st->st_state)); } return; } if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) { DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u" , ip_str(&md->sender), (unsigned)md->sender_port)); if (st == NULL) { openswan_log("discarding encrypted message for an unknown ISAKMP SA"); SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */); return; } if (st->st_skeyid_e.ptr == (u_char *) NULL) { loglog(RC_LOG_SERIOUS, "discarding encrypted message" " because we haven't yet negotiated keying materiel"); SEND_NOTIFICATION(INVALID_FLAGS); return; } /* Mark as encrypted */ md->encrypted = TRUE; DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" , (unsigned) pbs_left(&md->message_pbs) , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); /* do the specified decryption * * IV is from st->st_iv or (if new_iv_set) st->st_new_iv. * The new IV is placed in st->st_new_iv * * See RFC 2409 "IKE" Appendix B * * XXX The IV should only be updated really if the packet * is successfully processed. * We should keep this value, check for a success return * value from the parsing routines and then replace. * * Each post phase 1 exchange generates IVs from * the last phase 1 block, not the last block sent. */ { const struct encrypt_desc *e = st->st_oakley.encrypter; if (pbs_left(&md->message_pbs) % e->enc_blocksize != 0) { loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } /* XXX Detect weak keys */ /* grab a copy of raw packet (for duplicate packet detection) */ clonetochunk(md->raw_packet, md->packet_pbs.start , pbs_room(&md->packet_pbs), "raw packet"); /* Decrypt everything after header */ if (!new_iv_set) { /* use old IV */ passert(st->st_iv_len <= sizeof(st->st_new_iv)); st->st_new_iv_len = st->st_iv_len; init_new_iv(st); } crypto_cbc_encrypt(e, FALSE, md->message_pbs.cur, pbs_left(&md->message_pbs) , st); } DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur , md->message_pbs.roof - md->message_pbs.cur); DBG_cond_dump(DBG_CRYPT, "next IV:" , st->st_new_iv, st->st_new_iv_len); } else { /* packet was not encryped -- should it have been? */ if (smc->flags & SMF_INPUT_ENCRYPTED) { loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); SEND_NOTIFICATION(INVALID_FLAGS); return; } } /* Digest the message. * Padding must be removed to make hashing work. * Padding comes from encryption (so this code must be after decryption). * Padding rules are described before the definition of * struct isakmp_hdr in packet.h. */ { struct payload_digest *pd = md->digest; int np = md->hdr.isa_np; lset_t needed = smc->req_payloads; const char *excuse = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags) ? "probable authentication failure (mismatch of preshared secrets?): " : ""; while (np != ISAKMP_NEXT_NONE) { struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL; if (pd == &md->digest[PAYLIMIT]) { loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; }#ifdef NAT_TRAVERSAL switch (np) { case ISAKMP_NEXT_NATD_RFC: case ISAKMP_NEXT_NATOA_RFC: if ((!st) || (!(st->nat_traversal & NAT_T_WITH_RFC_VALUES))) { /* * don't accept NAT-D/NAT-OA reloc directly in message, unless * we're using NAT-T RFC */ sd = NULL; } break; }#endif if (sd == NULL) { /* payload type is out of range or requires special handling */ switch (np) { case ISAKMP_NEXT_ID: sd = IS_PHASE1(from_state) ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc; break;#ifdef NAT_TRAVERSAL case ISAKMP_NEXT_NATD_DRAFTS: np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */ sd = payload_descs[np]; break; case ISAKMP_NEXT_NATOA_DRAFTS: np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */ sd = payload_descs[np]; break;#endif default: loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or" " unexpected payload type (%s) at the outermost level" , excuse, enum_show(&payload_names, np)); SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE); return; } } { lset_t s = LELEM(np); if (LDISJOINT(s , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))) { loglog(RC_LOG_SERIOUS, "%smessage ignored because it " "contains an unexpected payload type (%s)" , excuse, enum_show(&payload_names, np)); SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE); return; } needed &= ~s; } if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs)) { loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } /* place this payload at the end of the chain for this type */ { struct payload_digest **p; for (p = &md->chain[np]; *p != NULL; p = &(*p)->next) ; *p = pd; pd->next = NULL; } np = pd->payload.generic.isag_np; pd++; /* since we've digested one payload happily, it is probably * the case that any decryption worked. So we will not suggest * encryption failure as an excuse for subsequent payload * problems. */ excuse = ""; } md->digest_roof = pd; DBG(DBG_PARSING, if (pbs_left(&md->message_pbs) != 0) DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs))); md->message_pbs.roof = md->message_pbs.cur; /* check that all mandatory payloads appeared */ if (needed != 0) { loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s" , enum_show(&state_names, from_state) , bitnamesof(payload_name, needed)); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } } /* more sanity checking: enforce most ordering constraints */ if (IS_PHASE1(from_state)) { /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges: * "The SA payload MUST precede all other payloads in a phase 1 exchange." */ if (md->chain[ISAKMP_NEXT_SA] != NULL && md->hdr.isa_np != ISAKMP_NEXT_SA) { loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload"); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } } else if (IS_QUICK(from_state)) { /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode * * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP * header and a SA payload MUST immediately follow the HASH." * [NOTE: there may be more than one SA payload, so this is not * totally reasonable. Probably all SAs should be so constrained.] * * "If ISAKMP is acting as a client negotiator on behalf of another * party, the identities of the parties MUST be passed as IDci and * then IDcr." * * "With the exception of the HASH, SA, and the optional ID payloads, * there are no payload ordering restrictions on Quick Mode." */ if (md->hdr.isa_np != ISAKMP_NEXT_HASH) { loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload"); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } { struct payload_digest *p; int i; for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL ; p = p->next, i++) { if (p != &md->digest[i]) { loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position"); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } } } /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode: * "If ISAKMP is acting as a client negotiator on behalf of another * party, the identities of the parties MUST be passed as IDci and * then IDcr." */ { struct payload_digest *id = md->chain[ISAKMP_NEXT_ID]; if (id != NULL) { if (id->next == NULL || id->next->next != NULL) { loglog(RC_LOG_SERIOUS, "malformed Quic
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -