/* accept_KE * * Check and accept DH public value (Gi or Gr) from peer's message. * According to RFC2409 "The Internet key exchange (IKE)" 5: * The Diffie-Hellman public value passed in a KE payload, in either * a phase 1 or phase 2 exchange, MUST be the length of the negotiated * Diffie-Hellman group enforced, if necessary, by pre-pending the * value with zeros. */ notification_t accept_KE(chunk_t *dest, const char *val_name, const struct oakley_group_desc *gr, pb_stream *pbs) { if (pbs_left(pbs) != gr->bytes) { loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required", (unsigned) pbs_left(pbs), (unsigned) gr->bytes); /* XXX Could send notification back */ return INVALID_KEY_INFORMATION; } clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name); DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); return NOTHING_WRONG; }
notification_t accept_nonce(struct msg_digest *md, chunk_t *dest , const char *name, enum next_payload_types paynum) { pb_stream *nonce_pbs = &md->chain[paynum]->pbs; size_t len = pbs_left(nonce_pbs); if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) { loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); return PAYLOAD_MALFORMED; /* ??? */ } clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce"); return NOTHING_WRONG; }
static stf_status aggr_inI1_outR1_common(struct msg_digest *md, int authtype) { /* With Aggressive Mode, we get an ID payload in this, the first * message, so we can use it to index the preshared-secrets * when the IP address would not be meaningful (i.e. Road * Warrior). So our first task is to unravel the ID payload. */ struct state *st; struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct connection *c = find_host_connection(&md->iface->ip_addr, md->iface->port, &md->sender, md->sender_port, LEMPTY); #if 0 if (c == NULL && md->iface->ike_float) { c = find_host_connection(&md->iface->addr, pluto_nat_port, &md->sender, md->sender_port, LEMPTY); } #endif if (c == NULL) { /* see if a wildcarded connection can be found */ pb_stream pre_sa_pbs = sa_pd->pbs; lset_t policy = preparse_isakmp_sa_body(&pre_sa_pbs) | POLICY_AGGRESSIVE; c = find_host_connection(&md->iface->ip_addr, pluto_port, (ip_address*)NULL, md->sender_port, policy); if (c == NULL || (c->policy & POLICY_AGGRESSIVE) == 0) { ipstr_buf b; loglog(RC_LOG_SERIOUS, "initial Aggressive Mode message from %s" " but no (wildcard) connection has been configured%s%s", ipstr(&md->sender, &b), (policy != LEMPTY) ? " with policy=" : "", (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); /* XXX notification is in order! */ return STF_IGNORE; } /* Create a temporary connection that is a copy of this one. * His ID isn't declared yet. */ c = rw_instantiate(c, &md->sender, NULL, NULL); } /* Set up state */ cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */ st->st_connection = c; st->st_remoteaddr = md->sender; st->st_remoteport = md->sender_port; st->st_localaddr = md->iface->ip_addr; st->st_localport = md->iface->port; st->st_interface = md->iface; change_state(st, STATE_AGGR_R1); /* until we have clue who this is, then be conservative about allocating * them any crypto bandwidth */ st->st_import = pcim_stranger_crypto; st->st_policy |= POLICY_AGGRESSIVE; st->st_oakley.auth = authtype; if (!ikev1_decode_peer_id(md, FALSE, TRUE)) { char buf[IDTOA_BUF]; ipstr_buf b; (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "initial Aggressive Mode packet claiming to be from %s" " on %s but no connection has been authorized", buf, ipstr(&md->sender, &b)); /* XXX notification is in order! */ return STF_FAIL + INVALID_ID_INFORMATION; } c = st->st_connection; extra_debugging(c); st->st_try = 0; /* Not our job to try again from start */ st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); insert_state(st); /* needs cookies, connection, and msgid (0) */ st->st_doi = ISAKMP_DOI_IPSEC; st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ { ipstr_buf b; libreswan_log("responding to Aggressive Mode, state #%lu, connection \"%s\" from %s", st->st_serialno, st->st_connection->name, ipstr(&c->spd.that.host_addr, &b)); } merge_quirks(st, md); set_nat_traversal(st, md); /* save initiator SA for HASH */ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in aggr_inI1_outR1()"); /* * parse_isakmp_sa picks the right group, which we need to know * before we do any calculations. We will call it again to have it * emit the winning SA into the output. */ /* SA body in */ { pb_stream sabs = sa_pd->pbs; RETURN_STF_FAILURE(parse_isakmp_sa_body(&sabs, &sa_pd->payload.sa, NULL, FALSE, st)); } /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, &md->chain[ISAKMP_NEXT_KE]->pbs)); /* Ni in */ RETURN_STF_FAILURE(accept_v1_nonce(md, &st->st_ni, "Ni")); { struct ke_continuation *ke = alloc_thing( struct ke_continuation, "outI2 KE"); ke->ke_md = md; set_suspended(st, md); if (!st->st_sec_in_use) { /* need to calculate KE and Nonce */ pcrc_init(&ke->ke_pcrc, aggr_inI1_outR1_continue1); return build_ke(&ke->ke_pcrc, st, st->st_oakley.group, st->st_import); } else { /* KE and Nonce calculated */ ke->ke_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ return aggr_inI1_outR1_tail(&ke->ke_pcrc, NULL); } } }