📄 spdb_struct.c
字号:
return_out:#if defined(KERNEL_ALG) || defined(IKE_ALG) if (revised_sadb) free_sa(revised_sadb);#endif return ret;}/** Handle long form of duration attribute. * The code is can only handle values that can fit in unsigned long. * "Clamping" is probably an acceptable way to impose this limitation. * * @param pbs PB Stream * @return u_int32_t duration, in seconds. */static u_int32_tdecode_long_duration(pb_stream *pbs){ u_int32_t val = 0; /* ignore leading zeros */ while (pbs_left(pbs) != 0 && *pbs->cur == '\0') pbs->cur++; if (pbs_left(pbs) > sizeof(val)) { /* "clamp" too large value to max representable value */ val -= 1; /* portable way to get to maximum value */ DBG(DBG_PARSING, DBG_log(" too large duration clamped to: %lu" , (unsigned long)val)); } else { /* decode number */ while (pbs_left(pbs) != 0) val = (val << BITS_PER_BYTE) | *pbs->cur++; DBG(DBG_PARSING, DBG_log(" long duration: %lu", (unsigned long)val)); } return val;}/** * Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). * Various shortcuts are taken. In particular, the policy, such as * it is, is hardwired. * * If r_sa is non-NULL, the body of an SA representing the selected * proposal is emitted. * * If "selection" is true, the SA is supposed to represent the * single tranform that the peer has accepted. * ??? We only check that it is acceptable, not that it is one that we offered! * * It also means that we are inR1, and this as implications when we are * doing XAUTH, as it changes the meaning of the XAUTHInit/XAUTHResp. * * Only IPsec DOI is accepted (what is the ISAKMP DOI?). * Error response is rudimentary. * * This routine is used by main_inI1_outR1() and main_inR1_outI2(). */notification_tparse_isakmp_sa_body( pb_stream *sa_pbs, /* body of input SA Payload */ const struct isakmp_sa *sa, /* header of input SA Payload */ pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */ bool selection, /* if this SA is a selection, only one tranform * can appear. */ struct state *st) /* current state object */{ u_int32_t ipsecdoisit; pb_stream proposal_pbs; struct isakmp_proposal proposal; unsigned no_trans_left; int last_transnum; struct connection *c = st->st_connection; struct spd_route *spd, *me = &c->spd; bool xauth_init, xauth_resp; const char *role; xauth_init = xauth_resp = FALSE; /* calculate the per-end policy which might apply */ for(spd = me; spd; spd = spd->next) { if(selection) { /* this is the initiator, we have proposed, they have answered, * and we must decide if they proposed what we wanted. */ role = "initiator"; xauth_init = xauth_init | spd->this.xauth_client; xauth_resp = xauth_resp | spd->this.xauth_server; } else { /* this is the responder, they have proposed to us, what * are we willing to be? */ role = "responder"; xauth_init = xauth_init | spd->this.xauth_server; xauth_resp = xauth_resp | spd->this.xauth_client; } } /* DOI */ if (sa->isasa_doi != ISAKMP_DOI_IPSEC) { loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); /* XXX Could send notification back */ return DOI_NOT_SUPPORTED; } /* Situation */ if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) { return SITUATION_NOT_SUPPORTED; } if (ipsecdoisit != SIT_IDENTITY_ONLY) { loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" , bitnamesof(sit_bit_names, ipsecdoisit)); /* XXX Could send notification back */ return SITUATION_NOT_SUPPORTED; } /* The rules for ISAKMP SAs are scattered. * RFC 2409 "IKE" section 5 says that there * can only be one SA, and it can have only one proposal in it. * There may well be multiple transforms. */ if (!in_struct(&proposal, &isakmp_proposal_desc, sa_pbs, &proposal_pbs)) return PAYLOAD_MALFORMED; if (proposal.isap_np != ISAKMP_NEXT_NONE) { loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal" , enum_show(&payload_names, proposal.isap_np)); return PAYLOAD_MALFORMED; } if (proposal.isap_protoid != PROTO_ISAKMP) { loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal" , enum_show(&protocol_names, proposal.isap_protoid)); return INVALID_PROTOCOL_ID; } /* Just what should we accept for the SPI field? * The RFC is sort of contradictory. We will ignore the SPI * as long as it is of the proper size. * * From RFC2408 2.4 Identifying Security Associations: * During phase 1 negotiations, the initiator and responder cookies * determine the ISAKMP SA. Therefore, the SPI field in the Proposal * payload is redundant and MAY be set to 0 or it MAY contain the * transmitting entity's cookie. * * From RFC2408 3.5 Proposal Payload: * o SPI Size (1 octet) - Length in octets of the SPI as defined by * the Protocol-Id. In the case of ISAKMP, the Initiator and * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI, * therefore, the SPI Size is irrelevant and MAY be from zero (0) to * sixteen (16). If the SPI Size is non-zero, the content of the * SPI field MUST be ignored. If the SPI Size is not a multiple of * 4 octets it will have some impact on the SPI field and the * alignment of all payloads in the message. The Domain of * Interpretation (DOI) will dictate the SPI Size for other * protocols. */ if (proposal.isap_spisize == 0) { /* empty (0) SPI -- fine */ } else if (proposal.isap_spisize <= MAX_ISAKMP_SPI_SIZE) { u_char junk_spi[MAX_ISAKMP_SPI_SIZE]; if (!in_raw(junk_spi, proposal.isap_spisize, &proposal_pbs, "Oakley SPI")) return PAYLOAD_MALFORMED; } else { loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" , (unsigned)proposal.isap_spisize); return INVALID_SPI; } if (selection && proposal.isap_notrans != 1) { loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u" , (unsigned)proposal.isap_notrans); return BAD_PROPOSAL_SYNTAX; } /* for each transform payload... */ last_transnum = -1; no_trans_left = proposal.isap_notrans; for (;;) { pb_stream trans_pbs; u_char *attr_start; size_t attr_len; struct isakmp_transform trans; lset_t seen_attrs = 0 , seen_durations = 0; u_int16_t life_type; struct oakley_trans_attrs ta; err_t ugh = NULL; /* set to diagnostic when problem detected */ zero(&ta); /* initialize only optional field in ta */ ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */ if (no_trans_left == 0) { loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); return BAD_PROPOSAL_SYNTAX; } if (!in_struct(&trans, &isakmp_isakmp_transform_desc, &proposal_pbs, &trans_pbs)) return BAD_PROPOSAL_SYNTAX; if (trans.isat_transnum <= last_transnum) { /* picky, picky, picky */ loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing" " in Oakley Proposal"); return BAD_PROPOSAL_SYNTAX; } last_transnum = trans.isat_transnum; if (trans.isat_transid != KEY_IKE) { loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform" , enum_show(&isakmp_transformid_names, trans.isat_transid)); return INVALID_TRANSFORM_ID; } attr_start = trans_pbs.cur; attr_len = pbs_left(&trans_pbs); /* process all the attributes that make up the transform */ while (pbs_left(&trans_pbs) != 0) { struct isakmp_attribute a; pb_stream attr_pbs; u_int32_t val; /* room for larger values */ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) return BAD_PROPOSAL_SYNTAX; passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)) { loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u" , enum_show(&oakley_attr_names, a.isaat_af_type) , trans.isat_transnum); return BAD_PROPOSAL_SYNTAX; } seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); val = a.isaat_lv; DBG(DBG_PARSING, { enum_names *vdesc = oakley_attr_val_descs [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; if (vdesc != NULL) { const char *nm = enum_name(vdesc, val); if (nm != NULL) DBG_log(" [%u is %s]", (unsigned)val, nm); } }); switch (a.isaat_af_type) { case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV:#ifdef IKE_ALG if (ike_alg_enc_ok(val, 0, c->alg_info_ike, &ugh)) { /* if (ike_alg_enc_present(val)) { */ ta.encrypt = val; ta.encrypter = crypto_get_encrypter(val); ta.enckeylen = ta.encrypter->keydeflen; } else #endif switch (val) { case OAKLEY_3DES_CBC: ta.encrypt = val; ta.encrypter = crypto_get_encrypter(val); break; /* we don't feel DES is safe */ case OAKLEY_DES_CBC: default: ugh = builddiag("%s is not supported" , enum_show(&oakley_enc_names, val)); } break; case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV:#ifdef IKE_ALG if (ike_alg_hash_present(val)) { ta.hash = val; ta.hasher = crypto_get_hasher(val); } else #endif/* #else */ switch (val) { case OAKLEY_MD5: case OAKLEY_SHA: ta.hash = val; ta.hasher = crypto_get_hasher(val); break; default: ugh = builddiag("%s is not supported" , enum_show(&oakley_hash_names, val)); }/* #endif */ break; case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: { lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK; /* check that authentication method is acceptable */ switch (val) {#ifdef XAUTH case XAUTHInitPreShared: if(!xauth_init) { ugh = builddiag("policy does not allow Extended Authentication (XAUTH) of initiator (we are %s)", role); break; } ta.xauth = val; val = OAKLEY_PRESHARED_KEY; goto psk; case XAUTHRespPreShared: if(!xauth_resp) { ugh = builddiag("policy does not allow Extended Authentication (XAUTH) of responder (we are %s)", role); break; } ta.xauth = val; val = OAKLEY_PRESHARED_KEY; /* No break; */#endif case OAKLEY_PRESHARED_KEY:#ifdef XAUTH psk: if(xauth_init && ta.xauth == 0) { ugh = builddiag("policy mandates Extended Authentication (XAUTH) with PSK of initiator (we are %s)", role); break; } if(xauth_resp && ta.xauth == 0) { ugh = builddiag("policy mandates Extended Authentication (XAUTH) with PSK of responder (we are %s)", role); break; }#endif if ((iap & POLICY_PSK) == LEMPTY) { ugh = "policy does not allow OAKLEY_PRESHARED_KEY authentication"; } else { /* check that we can find a preshared secret */ struct connection *c = st->st_connection; if (get_preshared_secret(c) == NULL) { char mid[IDTOA_BUF] , hid[IDTOA_BUF]; idtoa(&c->spd.this.id, mid, sizeof(mid)); if (his_id_was_instantiated(c)) strcpy(hid, "%any"); else idtoa(&c->spd.that.id, hid, sizeof(hid)); ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" , mid, hid); } ta.auth = val; } break;#ifdef XAUTH case XAUTHInitRSA: if(!xauth_init) { ugh = builddiag("policy does not allow Extended Authentication (XAUTH) with RSA of initiator (we are %s)", role); break; } ta.xauth = val; val = OAKLEY_RSA_SIG; goto rsasig; case XAUTHRespRSA: if(!xauth_resp) { ugh = builddiag("policy does not allow Extended Authentication (XAUTH) with RSA of responder (we are %s)", role); break; } ta.xauth = val; val = OAKLEY_RSA_SIG; /* No break; */#endif case OAKLEY_RSA_SIG:#ifdef XAUTH rsasig: if(xauth_init && ta.xauth == 0) { ugh = builddiag("policy mandates Extended Authentication (XAUTH) with RSA of initiator (we are %s)", role); break; } if(xauth_resp && ta.xauth == 0) { ugh = builddiag("policy mandates Extended Authentication (XAUTH) with RSA of responder (we are %s)", role); break; }#endif /* Accept if policy specifies RSASIG or is default */ if ((iap & POLICY_RSASIG) == LEMPTY) { ugh = "policy does not allow OAKLEY_RSA_SIG authentication"; } else { /* We'd like to check that we can find a public * key for him and a private key for us that is * suitable, but we don't yet have his * Id Payload, so it seems futile to try. * We can assume that if he proposes it, he * thinks we've got it. If we proposed it, * perhaps we know what we're doing. */ ta.auth = val; } break; default: ugh = builddiag("Pluto does not support %s authentication" , enum_show(&oakley_auth_names, val));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -