/* IPsec DOI and Oakley resolution routines * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998, 1999 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: ipsec_doi.c,v 1.105 2000/06/21 18:24:32 dhr Exp $ */ #include #include #include #include #include #include #include #include #include "constants.h" #include "defs.h" #include "state.h" #include "id.h" #include "connections.h" /* needs id.h */ #include "preshared.h" #include "packet.h" #include "demux.h" /* needs packet.h */ #include "kernel.h" #include "log.h" #include "cookie.h" #include "server.h" #include "spdb.h" #include "timer.h" #include "rnd.h" #include "ipsec_doi.h" /* needs demux.h and state.h */ #include "whack.h" #include "sha1.h" #include "md5.h" #include "crypto.h" /* requires sha1.h and md5.h */ /* MAGIC: perform f, a function that returns notification_t * and return from the ENCLOSING stf_status returning function if it fails. */ #define RETURN_STF_FAILURE(f) \ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; } /* if we haven't already done so, compute a local DH secret (st->st_sec) and * the corresponding public value (g). This is emitted as a KE payload. */ static bool build_and_ship_KE(struct state *st, chunk_t *g , const struct oakley_group_desc *group, pb_stream *outs, u_int8_t np) { if (!st->st_sec_in_use) { u_char tmp[LOCALSECRETSIZE]; MP_INT mp_g; get_rnd_bytes(tmp, LOCALSECRETSIZE); st->st_sec_in_use = TRUE; n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE); mpz_init(&mp_g); mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus); *g = mpz_to_n(&mp_g, group->bytes); mpz_clear(&mp_g); #ifdef DODGE_DH_MISSING_ZERO_BUG if (g->ptr[0] == 0) { /* generate a new secret to avoid this situation */ loglog(RC_LOG_SERIOUS, "regenerating DH private secret to avoid Pluto 1.0 bug" " handling public value with leading zero"); mpz_clear(&st->st_sec); st->st_sec_in_use = FALSE; freeanychunk(*g); return build_and_ship_KE(st, g, group, outs, np); } #endif DBG(DBG_CRYPT, DBG_dump("Local DH secret:\n", tmp, LOCALSECRETSIZE); DBG_dump_chunk("Public DH value sent:\n", *g)); } return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); } /* Compute DH shared secret from our local secret and the peer's public value. * We make the leap that the length should be that of the group * (see quoted passage at start of ACCEPT_KE). */ static void compute_dh_shared(struct state *st, const chunk_t g , const struct oakley_group_desc *group) { MP_INT mp_g, mp_shared; passert(st->st_sec_in_use); n_to_mpz(&mp_g, g.ptr, g.len); mpz_init(&mp_shared); mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus); mpz_clear(&mp_g); st->st_shared = mpz_to_n(&mp_shared, group->bytes); mpz_clear(&mp_shared); #ifdef DODGE_DH_MISSING_ZERO_BUG if (st->st_shared.ptr[0] == 0) loglog(RC_LOG_SERIOUS, "shared DH secret has leading zero -- triggers Pluto 1.0 bug"); #endif DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared); } /* 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. * ??? For now, if DODGE_DH_MISSING_ZERO_BUG is defined, we accept shorter * values to interoperate with old Plutos. This should change some day. */ static 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 */ #ifdef DODGE_DH_MISSING_ZERO_BUG if (pbs_left(pbs) > gr->bytes) #endif 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; } /* accept_PFS_KE * * Check and accept optional Quick Mode KE payload for PFS. * Extends ACCEPT_PFS to check whether KE is allowed or required. */ static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, const char *val_name, const char *msg_name) { struct state *st = md->st; struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE]; if (ke_pd == NULL) { if (st->st_pfs_group != NULL) { loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); return INVALID_KEY_INFORMATION; } } else { if (st->st_pfs_group == NULL) { loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" , msg_name); return INVALID_KEY_INFORMATION; } if (ke_pd->next != NULL) { loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); return INVALID_KEY_INFORMATION; /* ??? */ } return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); } return NOTHING_WRONG; } static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, const char *name) { setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE); get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE); return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name); } /* * Send a notification to the peer. We could make a decision on * whether to send the notification, based on the type and the * destination, if we care to. * XXX It doesn't handle DELETE notifications (which are also * XXX informational exchanges). */ #if 0 /* not currently used */ //static void //send_notification(int sock, // u_int16_t type, // u_char *spi, // u_char spilen, // u_char protoid, // u_char *icookie, // u_char *rcookie, // msgid_t /*network order*/ msgid, // struct sockaddr sa) //{ // u_char buffer[sizeof(struct isakmp_hdr) + // sizeof(struct isakmp_notification)]; // struct isakmp_hdr *isa = (struct isakmp_hdr *) buffer; // struct isakmp_notification *isan = (struct isakmp_notification *) // (buffer + sizeof(struct isakmp_hdr)); // // memset(buffer, '\0', sizeof(struct isakmp_hdr) + // sizeof(struct isakmp_notification)); // // if (icookie != (u_char *) NULL) // memcpy(isa->isa_icookie, icookie, COOKIE_SIZE); // // if (rcookie != (u_char *) NULL) // memcpy(isa->isa_rcookie, rcookie, COOKIE_SIZE); // // /* Standard header */ // isa->isa_np = ISAKMP_NEXT_N; // isa->isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; // isa->isa_xchg = ISAKMP_XCHG_INFO; // isa->isa_msgid = msgid; // isa->isa_length = htonl(sizeof(struct isakmp_hdr) + // sizeof(struct isakmp_notification) + // spilen); // // /* Notification header */ // isan->isan_type = htons(type); // isan->isan_doi = htonl(ISAKMP_DOI_IPSEC); // isan->isan_length = htons(sizeof(struct isakmp_notification) + spilen); // isan->isan_spisize = spilen; // memcpy((u_char *)isan + sizeof(struct isakmp_notification), spi, spilen); // isan->isan_protoid = protoid; // // DBG(DBG_CONTROL, DBG_log("sending INFO type %s to %s", // enum_show(¬ification_names, type), // show_sa(&sa))); // // if (sendto(sock, buffer, ntohl(isa->isa_length), 0, &sa, // sizeof(sa)) != ntohl(isa->isa_length)) // log_errno((e, "sendto() failed in send_notification() to %s", // show_sa(&sa))); // else // { // DBG(DBG_CONTROL, DBG_log("transmitted %d bytes", ntohl(isa->isa_length))); // } //} #endif /* not currently used */ /* The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! */ static void close_message(pb_stream *pbs) { size_t padding = pad_up(pbs_offset(pbs), 4); if (padding != 0) (void) out_zero(padding, pbs, "message padding"); close_output_pbs(pbs); } /* Initiate an Oakley Main Mode exchange. * --> HDR;SA */ static stf_status main_outI1( int whack_sock, struct connection *c, bool pending_quick, lset_t policy, unsigned long try) { u_char space[8192]; /* NOTE: we assume 8192 is big enough to build the packet */ pb_stream reply; /* not actually a reply, but you know what I mean */ pb_stream rbody; struct state *st; /* set up new state */ cur_state = st = new_state(); st->st_connection = c; #ifdef DEBUG extra_debugging(c); #endif st->st_pending_quick = pending_quick; st->st_policy = policy; st->st_whack_sock = whack_sock; st->st_try = try; st->st_state = STATE_MAIN_I1; get_cookie(ISAKMP_INITIATOR, st->st_icookie, COOKIE_SIZE, c->that.host_addr); insert_state(st); /* needs cookies, connection, and msgid (0) */ /* put a very short fuse on this state object * in case things don't work out. */ event_schedule(EVENT_SO_DISCARD, 0, st); log("initiating Main Mode"); /* set up reply */ init_pbs(&reply, space, sizeof(space), "reply packet"); /* HDR out */ { struct isakmp_hdr hdr; memset(&hdr, '\0', sizeof(hdr)); /* default to 0 */ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_SA; hdr.isa_xchg = ISAKMP_XCHG_IDPROT; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); /* R-cookie, flags and MessageID are left zero */ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) { cur_state = NULL; return STF_INTERNAL_ERROR; } } /* SA out */ { u_char *sa_start = rbody.cur; lset_t auth_policy = policy & POLICY_ISAKMP_MASK; if (auth_policy == LEMPTY) { /* unspecified: figure out what we can manage */ if (get_preshared_secret(c) != NULL) auth_policy |= POLICY_PSK; if (get_RSA_private_key(c) != NULL && get_RSA_public_key(&c->that.id) != NULL) auth_policy |= POLICY_RSASIG; /* Not clear what we should do if neither is possible. * Perhaps we should not have entered negotiations at all. */ if (auth_policy == LEMPTY) { loglog(RC_LOG_SERIOUS, "we don't know how to authenticate this connection"); cur_state = NULL; return STF_INTERNAL_ERROR; } } if (!out_sa(&rbody , &oakley_sadb[auth_policy >> POLICY_ISAKMP_SHIFT] , st, TRUE, ISAKMP_NEXT_NONE)) { cur_state = NULL; return STF_INTERNAL_ERROR; } /* save initiator SA for later HASH */ passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */ clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start , "sa in main_outI1"); } close_message(&rbody); close_output_pbs(&reply); clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply) , "reply packet for main_outI1"); /* Transmit */ send_packet(st, "main_outI1"); /* Set up a retransmission event, half a minute henceforth */ delete_event(st); event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); whack_log(RC_NEW_STATE + STATE_MAIN_I1 , "%s: initiate", enum_name(&state_names, st->st_state)); cur_state = NULL; return STF_NO_REPLY; } void ipsecdoi_initiate( int whack_sock, struct connection *c, bool pending_quick, lset_t policy, unsigned long try) { /* If there's already an ISAKMP SA established, use that and * go directly to Quick Mode. * Note: there is no way to initiate with a Road Warrior. * XXX If an ISAKMP SA is *being* established, we foolishly * XXX try to establish another one, in parallel. We could * XXX issue an event to wait for it to finish and then try * XXX to establish it. */ struct state *st = find_isakmp_sa(c); if (st == NULL) { (void) main_outI1(whack_sock, c, pending_quick, policy, try); } else if (pending_quick) { /* ??? 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); } else if (whack_sock != NULL_FD) { close(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. */ void ipsecdoi_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)) { (void) main_outI1(whack_sock, st->st_connection, st->st_pending_quick , policy, try); } 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; } ipsecdoi_initiate(whack_sock, st->st_connection, TRUE, policy, try); } } /* SKEYID for preshared keys. * See draft-ietf-ipsec-ike-01.txt 4.1 */ static bool skeyid_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; 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); return TRUE; } } static bool skeyid_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 bool generate_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: exit_log("generate_skeyids_iv(): unsupported authentication method %s", enum_show(&oakley_auth_names, 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)); 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 draft-ietf-ipsec-isakmp-oakley-07.txt Appendix B */ { const size_t keysize = st->st_oakley.encrypter->keysize; 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 */ static void main_mode_hash_body(struct state *st, bool hashi, bool hashus , union hash_ctx *ctx , void (*hash_update)(union hash_ctx *, const u_char *input, unsigned int len)) { #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 %d bytes of SA" , 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)); /* IDio_b (o stands for originator: i or r) */ { /* Hash identification payload, without generic payload header. * Note: the part of header and body used must be in network order! */ struct connection *c = st->st_connection; struct isakmp_ipsec_id id_hd; chunk_t id_b; build_id_payload(&id_hd, &id_b, hashus? &c->this : &c->that); if (!hashus) { /* ugly feature *we* don't use */ id_hd.isaiid_protoid = st->st_peeridentity_protocol; id_hd.isaiid_port = htons(st->st_peeridentity_port); } DBG(DBG_CRYPT, DBG_log("Hashing %s ID: Type %s, Protocol %d, Port %d" , hashus? "my" : "his" , enum_show(&ident_names, id_hd.isaiid_idtype) , id_hd.isaiid_protoid, htons(id_hd.isaiid_port))); /* NOTE: hash does NOT include the generic payload part of * Identity Payload */ hash_update(ctx , (u_char *)&id_hd + sizeof(struct isakmp_generic) , sizeof(id_hd) - sizeof(struct isakmp_generic)); hash_update_chunk(ctx, id_b); } # undef hash_update_chunk # undef hash_update } static size_t main_mode_hash(struct state *st, u_char *hash_val , bool hashi, bool hashus) { struct hmac_ctx ctx; hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid); main_mode_hash_body(st, hashi, hashus, &ctx.hash_ctx, ctx.h->hash_update); hmac_final(hash_val, &ctx); return ctx.hmac_digest_len; } #if 0 /* only needed for DSS */ static void main_mode_sha1(struct state *st, u_char *hash_val, size_t *hash_len , bool hashi, bool hashus) { 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, hashus, &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_t RSA_sign_hash(struct connection *c , u_char sig_val[RSA_MAX_OCTETS] , const u_char *hash_val, size_t hash_len) { const struct RSA_private_key *k = get_RSA_private_key(c); size_t sz; u_char *p = sig_val; size_t padlen; mpz_t t1, t2; chunk_t ch; 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); /* PKCS#1 v1.5 8.1 encryption-block formatting */ *p++ = 0x00; *p++ = 0x01; /* BT (block type) 01 */ padlen = sz - 3 - hash_len; memset(p, 0xFF, padlen); p += padlen; *p++ = 0x00; memcpy(p, hash_val, hash_len); passert(p + hash_len - sig_val == (ptrdiff_t)sz); /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */ n_to_mpz(t1, sig_val, sz); /* (could skip leading 0x00) */ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n * Better described in PKCS#1 v2.0 5.1 RSADP. * There are two methods, depending on the form of the private key. * We use the one based on the Chinese Remainder Theorem. */ mpz_init(t2); mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */ mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ mpz_mod(t2, t2, &k->p); mpz_mul(t2, t2, &k->qInv); mpz_mod(t2, t2, &k->p); mpz_mul(t2, t2, &k->q); /* m = m2 + h q */ mpz_add(t1, t1, t2); /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */ ch = mpz_to_n(t1, sz); memcpy(sig_val, ch.ptr, sz); pfree(ch.ptr); mpz_clear(t1); mpz_clear(t2); return sz; } /* Check a Main Mode RSA Signature * 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 notification_t RSA_check_signature(struct state *st , u_char hash_val[MAX_DIGEST_LEN], size_t hash_len , const pb_stream *sig_pbs) { const u_char *sig_val = sig_pbs->cur; size_t sig_len = pbs_left(sig_pbs); const struct RSA_public_key *k; u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */ u_char *hash_in_s = &s[sig_len - hash_len]; /* find the public key for peer id */ k = get_RSA_public_key(&st->st_connection->that.id); if (k == NULL) { char buf[200]; (void) idtoa(&st->st_connection->that.id, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'", buf); /* ??? is this the best code there is? */ return INVALID_KEY_INFORMATION; } /* decrypt the signature -- reversing RSA_sign_hash */ if (sig_len != k->k) { loglog(RC_LOG_SERIOUS, "SIG length does not match public key length"); return INVALID_KEY_INFORMATION; } /* actual exponentiation; see PKCS#1 v2.0 5.1 */ { chunk_t temp_s; mpz_t c; n_to_mpz(c, sig_val, sig_len); mpz_powm(c, c, &k->e, &k->n); temp_s = mpz_to_n(c, sig_len); /* back to octets */ memcpy(s, temp_s.ptr, sig_len); pfree(temp_s.ptr); mpz_clear(c); } /* sanity check on signature: see if it matches * PKCS#1 v1.5 8.1 encryption-block formatting */ { complaint_t ugh = NULL; if (s[0] != 0x00) ugh = "no leading 00"; else if (hash_in_s[-1] != 0x00) ugh = "00 separator not present"; else if (s[1] == 0x01) { const u_char *p; for (p = &s[2]; p != hash_in_s - 1; p++) { if (*p != 0xFF) { ugh = "invalid Padding String"; break; } } } else if (s[1] == 0x02) { const u_char *p; for (p = &s[2]; p != hash_in_s - 1; p++) { if (*p == 0x00) { ugh = "invalid Padding String"; break; } } } else ugh = "Block Type not 01 or 02"; if (ugh != NULL) { /* note: it might be a good idea to make sure that * an observer cannot tell what kind of failure happened. * I don't know what this means in practice. */ loglog(RC_LOG_SERIOUS, "SIG did not decrypt into good ECB: %s. Bad key?", ugh); return INVALID_KEY_INFORMATION; } } /* We have the decoded hash: see if it matches. */ if (memcmp(hash_val, hash_in_s, hash_len)) { DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len); DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len); loglog(RC_LOG_SERIOUS, "received SIG does not match computed HASH (but key is probably correct)"); /* XXX Could send notification back */ return INVALID_HASH_INFORMATION; } return NOTHING_WRONG; } /* check Main Mode authenticator (Hash or Signature Payload) */ static notification_t check_main_authenticator(struct msg_digest *md, bool hashi) { struct state *st = md->st; u_char hash_val[MAX_DIGEST_LEN]; size_t hash_len = main_mode_hash(st, hash_val, hashi, FALSE); switch (st->st_oakley.auth) { case OAKLEY_PRESHARED_KEY: { pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; if (pbs_left(hash_pbs) != hash_len || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) { DBG_cond_dump(DBG_CRYPT, "received HASH:" , hash_pbs->cur, pbs_left(hash_pbs)); loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value"); /* XXX Could send notification back */ return INVALID_HASH_INFORMATION; } return NOTHING_WRONG; } break; case OAKLEY_RSA_SIG: return RSA_check_signature(st, hash_val, hash_len , &md->chain[ISAKMP_NEXT_SIG]->pbs); default: passert(FALSE); } } /* CHECK_QUICK_HASH * * This macro is magic -- it cannot be expressed as a function. * - it causes the caller to return! * - it declares local variables and expects the "do_hash" argument * expression to reference them (hash_val, hash_pbs) */ #define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \ pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \ u_char hash_val[MAX_DIGEST_LEN]; \ size_t hash_len = do_hash; \ if (pbs_left(hash_pbs) != hash_len \ || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \ { \ DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \ loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \ /* XXX Could send notification back */ \ return STF_FAIL + INVALID_HASH_INFORMATION; \ } \ } static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name) { pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->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; } /* START_HASH_PAYLOAD * * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) * and the start of the part of the message to be hashed (r_hash_start). * This macro is magic. * - it can cause the caller to return * - it references variables local to the caller (r_hashval, r_hash_start, st) */ #define START_HASH_PAYLOAD(rbody, np) { \ pb_stream hash_pbs; \ if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \ return STF_INTERNAL_ERROR; \ r_hashval = hash_pbs.cur; /* remember where to plant value */ \ if (!out_zero(st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH")) \ return STF_INTERNAL_ERROR; \ close_output_pbs(&hash_pbs); \ r_hash_start = (rbody).cur; /* hash from after HASH payload */ \ } /* encrypt message, sans fixed part of header * IV is fetched from st->st_new_iv and stored into st->st_iv. * The theory is that there will be no "backing out", so we commit to IV. * We also close the pbs. */ static bool encrypt_message(pb_stream *pbs, struct state *st) { const struct encrypt_desc *e = st->st_oakley.encrypter; u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); /* pad up to multiple of encryption blocksize */ { size_t padding = pad_up(enc_len, e->blocksize); if (padding != 0) { if (!out_zero(padding, pbs, "encryption padding")) return FALSE; enc_len += padding; } } DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); e->crypt(TRUE, enc_start, enc_len, st); update_iv(st); DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); close_message(pbs); return TRUE; } /* Compute HASH(1), HASH(2) of Quick Mode. * HASH(1) is part of Quick I1 message. * HASH(2) is part of Quick R1 message. * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 * (see draft-ietf-ipsec-isakmp-oakley-07.txt 5.5) */ static size_t quick_mode_hash12(u_char *dest, const u_char *start, const u_char *roof , const struct state *st, bool hash2) { struct hmac_ctx ctx; hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid)); if (hash2) hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */ hmac_update(&ctx, start, roof-start); hmac_final(dest, &ctx); DBG(DBG_CRYPT, DBG_log("HASH(%d) computed:", hash2 + 1); DBG_dump("", dest, ctx.hmac_digest_len)); return ctx.hmac_digest_len; } /* Compute HASH(3) in Quick Mode (part of Quick I2 message). * Used by: quick_inR1_outI2, quick_inI2 * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the * Message ID and Nonces. This is a mistake. */ static size_t quick_mode_hash3(u_char *dest, struct state *st) { struct hmac_ctx ctx; hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); hmac_update(&ctx, "\0", 1); hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid)); hmac_update_chunk(&ctx, st->st_ni); hmac_update_chunk(&ctx, st->st_nr); hmac_final(dest, &ctx); DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_len); return ctx.hmac_digest_len; } /* Compute Phase 2 IV. * Uses Phase 1 IV from st_iv; puts result in st_new_iv. */ void init_phase2_iv(struct state *st, const msgid_t *msgid) { const struct hash_desc *h = st->st_oakley.hasher; union hash_ctx ctx; st->st_new_iv_len = h->hash_digest_len; passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); h->hash_init(&ctx); h->hash_update(&ctx, st->st_iv, st->st_iv_len); passert(*msgid != 0); h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid)); h->hash_final(st->st_new_iv, &ctx); DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:" , st->st_new_iv, st->st_new_iv_len); } /* Initiate quick mode. * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] * (see draft-ietf-ipsec-isakmp-oakley-07.txt 5.5) */ stf_status quick_outI1( int whack_sock, struct state *isakmp_sa, struct connection *c, lset_t policy, unsigned long try) { struct state *st = duplicate_state(isakmp_sa); u_char space[8192]; /* NOTE: we assume 8192 is big enough to build the packet */ pb_stream reply; /* not really a reply */ pb_stream rbody; u_char *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* start of what is to be hashed */ bool has_client = c->this.has_client || c->that.has_client; cur_state = st; st->st_whack_sock = whack_sock; st->st_connection = c; #ifdef DEBUG extra_debugging(c); #endif st->st_policy = policy; st->st_try = try; st->st_myuserprotoid = st->st_peeruserprotoid = 0; st->st_myuserport = st->st_peeruserport = 0; st->st_msgid = generate_msgid(isakmp_sa); st->st_state = STATE_QUICK_I1; insert_state(st); /* needs cookies, connection, and msgid */ /* an event will be scheduled for st before we return */ log("initiating Quick Mode %s", bitnamesof(sa_policy_bit_names, policy)); /* set up reply */ init_pbs(&reply, space, sizeof(space), "reply packet"); /* HDR* out */ { struct isakmp_hdr hdr; hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_HASH; hdr.isa_xchg = ISAKMP_XCHG_QUICK; hdr.isa_msgid = st->st_msgid; hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) return STF_INTERNAL_ERROR; } /* HASH(1) -- create and note space to be filled later */ START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); /* SA out */ /* If PFS specified, use the same group as during Phase 1: * since no negotiation is possible, we pick one that is * very likely supported. */ st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; if (!out_sa(&rbody , &ipsec_sadb[(st->st_policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE | POLICY_TUNNEL)) >> POLICY_IPSEC_SHIFT] , st, FALSE, ISAKMP_NEXT_NONCE)) return STF_INTERNAL_ERROR; /* Ni out */ if (!build_and_ship_nonce(&st->st_ni, &rbody , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE , "Ni")) return STF_INTERNAL_ERROR; /* [ KE ] out (for PFS) */ if (st->st_pfs_group != NULL) { if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group , &rbody, has_client? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) return STF_INTERNAL_ERROR; } /* [ IDci, IDcr ] out */ if (has_client) { struct isakmp_ipsec_id id; pb_stream id_pbs; /* IDci (we are initiator) */ id.isaiid_np = ISAKMP_NEXT_ID; id.isaiid_idtype = ID_IPV4_ADDR_SUBNET; id.isaiid_protoid = st->st_myuserprotoid; id.isaiid_port = st->st_myuserport; if (!out_struct(&id, &isakmp_ipsec_identification_desc, &rbody, &id_pbs)) return STF_INTERNAL_ERROR; if (!out_raw(&c->this.client_net , sizeof(c->this.client_net) , &id_pbs, "initiator's client network")) return STF_INTERNAL_ERROR; if (!out_raw(&c->this.client_mask.s_addr , sizeof(c->this.client_mask.s_addr) , &id_pbs, "initiator's client mask")) return STF_INTERNAL_ERROR; close_output_pbs(&id_pbs); /* IDcr (peer is responder) */ id.isaiid_np = ISAKMP_NEXT_NONE; id.isaiid_idtype = ID_IPV4_ADDR_SUBNET; id.isaiid_protoid = st->st_peeruserprotoid; id.isaiid_port = st->st_peeruserport; if (!out_struct(&id, &isakmp_ipsec_identification_desc, &rbody, &id_pbs)) return STF_INTERNAL_ERROR; if (!out_raw(&c->that.client_net , sizeof(c->that.client_net) , &id_pbs, "peer's client network")) return STF_INTERNAL_ERROR; if (!out_raw(&c->that.client_mask, sizeof(c->that.client_mask) , &id_pbs, "peer's client mask")) return STF_INTERNAL_ERROR; close_output_pbs(&id_pbs); } /* finish computing HASH(1), inserting it in output */ (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur, st, FALSE); /* encrypt message, except for fixed part of header */ init_phase2_iv(isakmp_sa, &st->st_msgid); st->st_new_iv_len = isakmp_sa->st_new_iv_len; memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len); if (!encrypt_message(&rbody, st)) return STF_INTERNAL_ERROR; /* save packet, now that we know its size */ clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply) , "reply packet from quick_outI1"); /* send the packet */ send_packet(st, "quick_outI1"); event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); whack_log(RC_NEW_STATE + STATE_QUICK_I1 , "%s: initiate", enum_name(&state_names, st->st_state)); cur_state = NULL; return STF_NO_REPLY; } /* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3) * Note: we may change connections as a result. */ static bool decode_peer_id(struct msg_digest *md, bool initiator) { struct state *const st = md->st; struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; pb_stream *const id_pbs = &id_pld->pbs; struct isakmp_id *const id = &id_pld->payload.id; struct id peer; /* XXX Check for valid ID types? */ peer.kind = id->isaid_idtype; switch (peer.kind) { case ID_IPV4_ADDR: /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. * It talks about the protocol ID and Port fields of the ID * Payload, but they don't exist as such in Phase 1. * We use more appropriate names. * isaid_doi_specific_a is in place of Protocol ID. * isaid_doi_specific_b is in place of Port. * Besides, there is no good reason for allowing these to be * other than 0 in Phase 1. */ if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0) && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT)) { loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d" " but are %d/%d" , IPPROTO_UDP, IKE_UDP_PORT , id->isaid_doi_specific_a, id->isaid_doi_specific_b); return FALSE; } if (pbs_left(id_pbs) != sizeof(struct in_addr)) { loglog(RC_LOG_SERIOUS, "size of ID_IPV4_ADDR identification should be %u" " but is %d in ID payload" , (unsigned) sizeof(struct in_addr) , (unsigned) pbs_left(id_pbs)); /* XXX Could send notification back */ return FALSE; } memcpy(&peer.ip_addr, id_pbs->cur, sizeof(peer.ip_addr)); break; case ID_USER_FQDN: if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL) { loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @"); return FALSE; } /* FALLTHROUGH */ case ID_FQDN: if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0)) { loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0" " but are %d/%d" , id->isaid_doi_specific_a, id->isaid_doi_specific_b); return FALSE; } if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL) { loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL" , enum_show(&ident_names, peer.kind)); return FALSE; } /* ??? ought to do some more sanity check, but what? */ setchunk(peer.name, id_pbs->cur, pbs_left(id_pbs)); break; default: /* XXX Could send notification back */ loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload" , enum_show(&ident_names, peer.kind)); return FALSE; } /* crazy stuff, must be kept for hash */ st->st_peeridentity_protocol = id->isaid_doi_specific_a; st->st_peeridentity_port = id->isaid_doi_specific_b; DBG(DBG_PARSING, { char buf[200]; idtoa(&peer, buf, sizeof(buf)); DBG_log("Peer's ID is %s: '%s'", enum_show(&ident_names, id->isaid_idtype), buf); }); /* now that we've decoded the ID payload, let's see if we * need to switch connections. */ { struct connection *c = st->st_connection; struct connection *r; r = refine_host_connection(st, &peer, initiator); if (r == NULL) { char buf[200]; idtoa(&peer, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf); return FALSE; } else if (r != c) { /* apparently, r is an improvement on c -- replace */ DBG(DBG_CONTROL , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name)); if (HasWildcardIP(*r)) { /* instantiate it */ r = rw_connection(r, c->that.host_addr); } st->st_connection = r; /* kill reference to c */ SET_CUR_CONNECTION(r); rw_connection_discard(c); } } return TRUE; } /* Decode the variable part of an ID packet in (during Quick Mode). * This is designed for packets that identify clients, not peers. * Currently this will only accept two forms. */ static bool decode_net_id( struct isakmp_ipsec_id *id, pb_stream *id_pbs, struct in_addr *net, struct in_addr *mask, const char *which) { switch (id->isaiid_idtype) { case ID_IPV4_ADDR: if (pbs_left(id_pbs) != sizeof(*net)) { loglog(RC_LOG_SERIOUS, "%s ID payload ID_IPV4_ADDR wrong length in Quick I1" , which); /* XXX Could send notification back */ return FALSE; } memcpy(net, id_pbs->cur, sizeof(*net)); *mask = mask32.sin_addr; DBG(DBG_PARSING | DBG_CONTROL, DBG_log("%s is IP address %s", which, inet_ntoa(*net))); break; case ID_IPV4_ADDR_SUBNET: if (pbs_left(id_pbs) != sizeof(*net) + sizeof(*mask)) { loglog(RC_LOG_SERIOUS, "%s ID payload ID_IPV4_ADDR_SUBNET wrong length in Quick I1" , which); /* XXX Could send notification back */ return FALSE; } memcpy(net, id_pbs->cur, sizeof(*net)); memcpy(mask, id_pbs->cur + sizeof(*net), sizeof(*mask)); DBG(DBG_PARSING | DBG_CONTROL, { char buf[SUBNETTOA_BUF]; subnettoa(*net, *mask, 0, buf, sizeof(buf)); DBG_log("%s is IP subnet %s", which, buf); }); break; case ID_IPV4_ADDR_RANGE: if (pbs_left(id_pbs) != sizeof(*net) + sizeof(*mask)) { loglog(RC_LOG_SERIOUS, "%s ID payload ID_IPV4_ADDR_RANGE wrong length in Quick I1" , which); /* XXX Could send notification back */ return FALSE; } memcpy(net, id_pbs->cur, sizeof(*net)); memcpy(mask, id_pbs->cur + sizeof(*net), sizeof(*mask)); /* temporary */ /* check that range is really a subnet -- all we can handle. * (a) range is a power of 2 * (b) start is a multiple of range */ { u_int32_t start = ntohl(net->s_addr); u_int32_t end = ntohl(mask->s_addr); u_int32_t imask = end - start; /* inverted mask */ if (start > end) { char buf[SUBNETTOA_BUF]; /* length is overkill, but what is right? */ char *lwbs = strncpy(buf, inet_ntoa(*net), sizeof(buf)); loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, ID_IPV4_ADDR_RANGE %s-%s improper: start is greater than end" , which, lwbs, inet_ntoa(*mask)); return FALSE; } /* (a) iff imask is one less than a power of two (i.e. good), * adding one will yield a number with no bits in common. * (b) start must not have bits in common with imask. * We are too polite to optimize the whole test to * ((imask+1) | start) & imask. */ if (((imask+1) & imask) != 0 || (start & imask) != 0) { char buf[SUBNETTOA_BUF]; /* length is overkill, but what is right? */ char *lwbs = strncpy(buf, inet_ntoa(*net), sizeof(buf)); loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1," " ID_IPV4_ADDR_RANGE %s-%s unacceptable:" " not equivalent to a subnet" , which, lwbs, inet_ntoa(*mask)); return FALSE; } mask->s_addr = htonl(~imask); } DBG(DBG_PARSING | DBG_CONTROL, { char buf[SUBNETTOA_BUF]; subnettoa(*net, *mask, 0, buf, sizeof(buf)); DBG_log("%s is IP subnet %s (received as range)" , which, buf); }); break; default: /* XXX support more */ loglog(RC_LOG_SERIOUS, "unsupported ID type %s" , enum_show(&ident_names, id->isaiid_idtype)); /* XXX Could send notification back */ return FALSE; } return TRUE; } /* like decode, but checks that what is received matches what was sent */ static bool check_net_id( struct isakmp_ipsec_id *id, pb_stream *id_pbs, u_int8_t *protoid, u_int16_t *port, struct in_addr *net, struct in_addr *mask, const char *which) { struct in_addr net_temp, mask_temp; if (!decode_net_id(id, id_pbs, &net_temp, &mask_temp, which)) return FALSE; if (!same_subnet(*net, *mask, net_temp, mask_temp) || *protoid != id->isaiid_protoid || *port != id->isaiid_port) { loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which); return FALSE; } return TRUE; } /* * Produce the new key material of Quick Mode. * draft-ietf-ipsec-isakmp-oakley-06.txt section 5.5 * specifies how this is to be done. */ static void compute_proto_keymat( struct state *st, u_int8_t protoid, struct ipsec_proto_info *pi) { size_t needed_len; /* bytes of keying material needed */ /* Add up the requirements for keying material * (It probably doesn't matter if we produce too much!) */ switch (protoid) { case PROTO_IPSEC_ESP: switch (pi->attrs.transid) { case ESP_NULL: needed_len = 0; break; case ESP_DES: needed_len = DES_CBC_BLOCK_SIZE; break; case ESP_3DES: needed_len = DES_CBC_BLOCK_SIZE * 3; break; default: exit_log("transform %s not implemented yet", enum_show(&esp_transformid_names, pi->attrs.transid)); } switch (pi->attrs.auth) { case AUTH_ALGORITHM_NONE: break; case AUTH_ALGORITHM_HMAC_MD5: needed_len += HMAC_MD5_KEY_LEN; break; case AUTH_ALGORITHM_HMAC_SHA1: needed_len += HMAC_SHA1_KEY_LEN; break; case AUTH_ALGORITHM_DES_MAC: default: exit_log("AUTH algorithm %s not implemented yet", enum_show(&auth_alg_names, pi->attrs.auth)); } break; case PROTO_IPSEC_AH: switch (pi->attrs.transid) { case AH_MD5: needed_len = HMAC_MD5_KEY_LEN; break; case AH_SHA: needed_len = HMAC_SHA1_KEY_LEN; break; default: exit_log("transform %s not implemented yet", enum_show(&ah_transformid_names, pi->attrs.transid)); } break; default: exit_log("protocol %s not implemented yet", enum_show(&protocol_names, protoid)); break; } pi->keymat_len = needed_len; /* Allocate space for the keying material. * Although only needed_len bytes are desired, we * must round up to a multiple of ctx.hmac_digest_len * so that our buffer isn't overrun. */ { struct hmac_ctx ctx_me, ctx_peer; size_t needed_space; /* space needed for keying material (rounded up) */ size_t i; hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d); ctx_peer = ctx_me; /* duplicate initial conditions */ needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_len); replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()")); replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()")); for (i = 0;; ) { if (st->st_shared.ptr != NULL) { /* PFS: include the g^xy */ hmac_update_chunk(&ctx_me, st->st_shared); hmac_update_chunk(&ctx_peer, st->st_shared); } hmac_update(&ctx_me, &protoid, sizeof(protoid)); hmac_update(&ctx_peer, &protoid, sizeof(protoid)); hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi)); hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi)); hmac_update_chunk(&ctx_me, st->st_ni); hmac_update_chunk(&ctx_peer, st->st_ni); hmac_update_chunk(&ctx_me, st->st_nr); hmac_update_chunk(&ctx_peer, st->st_nr); hmac_final(pi->our_keymat + i, &ctx_me); hmac_final(pi->peer_keymat + i, &ctx_peer); i += ctx_me.hmac_digest_len; if (i >= needed_space) break; /* more keying material needed: prepare to go around again */ hmac_reinit(&ctx_me); hmac_reinit(&ctx_peer); hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_len, ctx_me.hmac_digest_len); hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_len, ctx_peer.hmac_digest_len); } } DBG(DBG_CRYPT, DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len); DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len)); } static void compute_keymats(struct state *st) { if (st->st_ah.present) compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah); if (st->st_esp.present) compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp); } /* State Transition Functions. * - Called from comm_handle; * - state_check[state].processor points to these * - these routines are in state-order * - these routines must be restartable from any point of error return. * - output HDR is handled by comm_handle(). */ /* Handle a Main Mode Oakley first packet (responder side). * HDR;SA --> HDR;SA */ stf_status main_inI1_outR1(struct msg_digest *md) { struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct state *st; struct connection *c = find_host_connection(md->iface->addr, pluto_port , md->sin.sin_addr, ntohs(md->sin.sin_port)); pb_stream r_sa_pbs; if (c == NULL) { /* see if a wildcarded connection can be found */ c = find_host_connection(md->iface->addr, pluto_port , mask0.sin_addr, ntohs(md->sin.sin_port)); if (c != NULL) { /* create a temporary connection that is a copy of this one */ c = rw_connection(c, md->sin.sin_addr); } else { loglog(RC_LOG_SERIOUS, "initial Main Mode message from %s" " but no connection has been authorized" , inet_ntoa(md->sin.sin_addr)); /* XXX notification is in order! */ return STF_IGNORE; } } /* Set up state */ cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */ st->st_connection = c; #ifdef DEBUG extra_debugging(c); #endif st->st_try = 0; /* not our job to try again from start */ st->st_policy = c->policy; /* only as accurate as connection */ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); get_cookie(ISAKMP_RESPONDER, st->st_rcookie, COOKIE_SIZE, md->sin.sin_addr); insert_state(st); /* needs cookies, connection, and msgid (0) */ /* put a very short fuse on this state object * in case things don't work out. */ event_schedule(EVENT_SO_DISCARD, 0, st); st->st_doi = ISAKMP_DOI_IPSEC; st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ st->st_state = STATE_MAIN_R1; if (c->rw_state == rwcs_instance) { log("responding to Main Mode from Road Warrior %s" , inet_ntoa(c->that.host_addr)); } else { log("responding to Main Mode"); } /* parse_isakmp_sa also spits out a winning SA into our reply, * so we have to build our md->reply and emit HDR before calling it. */ /* HDR out. * We can't leave this to comm_handle() because we must * fill in the cookie. */ { struct isakmp_hdr r_hdr = md->hdr; memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); r_hdr.isa_np = ISAKMP_NEXT_SA; if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) return STF_INTERNAL_ERROR; } /* start of SA out */ { struct isakmp_sa r_sa = sa_pd->payload.sa; r_sa.isasa_np = ISAKMP_NEXT_NONE; if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) return STF_INTERNAL_ERROR; } /* SA body in and out */ RETURN_STF_FAILURE(parse_isakmp_sa_body(&sa_pd->pbs, &sa_pd->payload.sa, &r_sa_pbs , FALSE, st)); close_message(&md->rbody); /* save initiator SA for HASH */ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in main_inI1_outR1()"); return STF_REPLY; } /* STATE_MAIN_I1: HDR, SA --> auth dependent * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni * * The following are not yet implemented: * PKE_AUTH: --> HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r * RPKE_AUTH: --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, * Ke_i [,<Ke_i] * * We must verify that the proposal received matches one we sent. */ stf_status main_inR1_outI2(struct msg_digest *md) { struct state *const st = md->st; /* verify echoed SA */ { struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; RETURN_STF_FAILURE(parse_isakmp_sa_body(&sapd->pbs , &sapd->payload.sa, NULL, TRUE, st)); } /**************** build output packet HDR;KE;Ni ****************/ /* HDR out. * We can't leave this to comm_handle() because the isa_np * depends on the type of Auth (eventually). */ { struct isakmp_hdr r_hdr = md->hdr; r_hdr.isa_np = ISAKMP_NEXT_KE; if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) return STF_INTERNAL_ERROR; } /* KE out */ if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group , &md->rbody, ISAKMP_NEXT_NONCE)) return STF_INTERNAL_ERROR; /* Ni out */ if (!build_and_ship_nonce(&st->st_ni, &md->rbody, ISAKMP_NEXT_NONE, "Ni")) return STF_INTERNAL_ERROR; /* finish message */ close_message(&md->rbody); /* Reinsert the state, using the responder cookie we just received */ unhash_state(st); memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE); insert_state(st); /* needs cookies, connection, and msgid (0) */ st->st_state = STATE_MAIN_I2; return STF_REPLY; } /* STATE_MAIN_R1: * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr * * The following are not yet implemented: * PKE_AUTH: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r * --> HDR, KE, PubKey_i, PubKey_i * RPKE_AUTH: * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] * --> HDR, PubKey_i, Ke_r, Ke_r */ stf_status main_inI2_outR2(struct msg_digest *md) { struct state *const st = md->st; pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); /* Ni in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); /**************** build output packet HDR;KE;Nr ****************/ /* HDR out done */ /* KE out */ if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group , &md->rbody, ISAKMP_NEXT_NONCE)) return STF_INTERNAL_ERROR; /* Nr out */ if (!build_and_ship_nonce(&st->st_nr, &md->rbody, ISAKMP_NEXT_NONE, "Nr")) return STF_INTERNAL_ERROR; /* finish message */ close_message(&md->rbody); /* next message will be encrypted, but not this one. * We could defer this calculation. */ compute_dh_shared(st, st->st_gi, st->st_oakley.group); #ifdef DODGE_DH_MISSING_ZERO_BUG if (st->st_shared.ptr[0] == 0) return STF_DROP_DOOMED_EXCHANGE; #endif if (!generate_skeyids_iv(st)) return STF_FAIL + AUTHENTICATION_FAILED; update_iv(st); /* Advance state */ st->st_state = STATE_MAIN_R2; return STF_REPLY; } /* STATE_MAIN_I2: * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I * * The following are not yet implemented. * SMF_PKE_AUTH: HDR, KE, PubKey_i, PubKey_i * --> HDR*, HASH_I * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, Ke_r * --> HDR*, HASH_I */ stf_status main_inR2_outI3(struct msg_digest *md) { struct state *const st = md->st; pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs)); /* Nr in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); /* done parsing; initialize crypto */ compute_dh_shared(st, st->st_gr, st->st_oakley.group); #ifdef DODGE_DH_MISSING_ZERO_BUG if (st->st_shared.ptr[0] == 0) return STF_REPLACE_DOOMED_EXCHANGE; #endif if (!generate_skeyids_iv(st)) return STF_FAIL + AUTHENTICATION_FAILED; /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/ /* ??? NOTE: this is almost the same as main_inI3_outR3's code */ /* HDR* out done */ /* IDii out */ { struct isakmp_ipsec_id id_hd; chunk_t id_b; pb_stream id_pbs; build_id_payload(&id_hd, &id_b, &st->st_connection->this); id_hd.isaiid_np = auth_payload; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) || !out_chunk(id_b, &id_pbs, "my identity")) return STF_INTERNAL_ERROR; close_output_pbs(&id_pbs); } /* HASH_I or SIG_I out */ { u_char hash_val[MAX_DIGEST_LEN]; size_t hash_len = main_mode_hash(st, hash_val, TRUE, TRUE); if (auth_payload == ISAKMP_NEXT_HASH) { /* HASH_I out */ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody , hash_val, hash_len, "HASH_I")) return STF_INTERNAL_ERROR; } else { /* SIG_I out */ u_char sig_val[RSA_MAX_OCTETS]; size_t sig_len = RSA_sign_hash(st->st_connection , sig_val, hash_val, hash_len); if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); return STF_FAIL + AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc , &md->rbody, sig_val, sig_len, "SIG_I")) return STF_INTERNAL_ERROR; } } /* encrypt message, except for fixed part of header */ /* st_new_iv was computed by generate_skeyids_iv */ if (!encrypt_message(&md->rbody, st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* Advance state */ st->st_state = STATE_MAIN_I3; return STF_REPLY; } /* STATE_MAIN_R2: * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R */ stf_status main_inI3_outR3(struct msg_digest *md) { struct state *const st = md->st; int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; /* input code similar to main_inR3 -- should be factored */ /* IDii in */ if (!decode_peer_id(md, FALSE)) return STF_FAIL + INVALID_ID_INFORMATION; /* HASH_I or SIG_I in */ RETURN_STF_FAILURE(check_main_authenticator(md, TRUE)); /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ /* ??? NOTE: this is almost the same as main_inR2_outI3's code */ /* IDir out */ { struct isakmp_ipsec_id id_hd; chunk_t id_b; pb_stream r_id_pbs; build_id_payload(&id_hd, &id_b, &st->st_connection->this); id_hd.isaiid_np = auth_payload; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs) || !out_chunk(id_b, &r_id_pbs, "my identity")) return STF_INTERNAL_ERROR; close_output_pbs(&r_id_pbs); } /* HASH_R or SIG_R out */ { u_char hash_val[MAX_DIGEST_LEN]; size_t hash_len = main_mode_hash(st, hash_val, FALSE, TRUE); if (auth_payload == ISAKMP_NEXT_HASH) { /* HASH_R out */ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody , hash_val, hash_len, "HASH_R")) return STF_INTERNAL_ERROR; } else { /* SIG_R out */ u_char sig_val[RSA_MAX_OCTETS]; size_t sig_len = RSA_sign_hash(st->st_connection , sig_val, hash_val, hash_len); if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); return STF_FAIL + AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc , &md->rbody, sig_val, sig_len, "SIG_R")) return STF_INTERNAL_ERROR; } } /* encrypt message, sans fixed part of header */ if (!encrypt_message(&md->rbody, st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */ DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:" , st->st_new_iv, st->st_new_iv_len); /* Advance state */ st->st_state = STATE_MAIN_R3; st->st_connection->newest_isakmp_sa = st->st_serialno; return STF_REPLY; } /* STATE_MAIN_I3: * Handle HDR*;IDir;HASH/SIG_R from responder. */ stf_status main_inR3(struct msg_digest *md) { struct state *const st = md->st; struct connection *c = st->st_connection; /* input code similar to main_inI3_outR3 -- should be factored */ /* IDir in */ if (!decode_peer_id(md, TRUE)) return STF_FAIL + INVALID_ID_INFORMATION; /* HASH_R or SIG_R in */ RETURN_STF_FAILURE(check_main_authenticator(md, FALSE)); /**************** done input ****************/ /* Advance state */ st->st_state = STATE_MAIN_I4; c->newest_isakmp_sa = st->st_serialno; update_iv(st); /* finalize our Phase 1 IV */ return STF_UNPEND_QUICK; } /* Handle first message of Phase 2 -- Quick Mode. * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] * (see draft-ietf-ipsec-isakmp-oakley-07.txt 5.5) * Installs inbound IPsec SAs. * Although this seems early, we know enough to do so, and * this way we know that it is soon enough to catch all * packets that other side could send using this IPsec SA. */ stf_status quick_inI1_outR1(struct msg_digest *md) { /* we build reply packet as we parse the message since * the parse_ipsec_sa_body emits the reply SA */ struct state *st = duplicate_state(md->st); struct connection *c = st->st_connection; struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; struct in_addr our_net, our_mask, peer_net, peer_mask; u_char *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* from where to start hashing */ /* first: fill in missing bits of our new state object */ st->st_try = 0; /* not our job to try again from start */ st->st_msgid = md->hdr.isa_msgid; insert_state(st); /* needs cookies, connection, and msgid */ st->st_new_iv_len = md->st->st_new_iv_len; memcpy(st->st_new_iv, md->st->st_new_iv, st->st_new_iv_len); cur_state = st; /* (caller will reset) */ #ifdef DEBUG extra_debugging(c); #endif md->st = st; /* feed back new state */ st->st_policy = c->policy; /* somebody has got to do it */ /* put a very short fuse on this state object * in case things don't work out. */ event_schedule(EVENT_SO_DISCARD, 0, st); /* HASH(1) in */ CHECK_QUICK_HASH(md, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof, st, FALSE) , "HASH(1)", "Quick I1"); /* HDR* out done */ /* HASH(2) out -- first pass */ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); /* process SA (in and out) */ { struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; pb_stream r_sa_pbs; struct isakmp_sa sa = sapd->payload.sa; /* sa header is unchanged -- except for np */ sa.isasa_np = ISAKMP_NEXT_NONCE; if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) return STF_INTERNAL_ERROR; /* parse and accept body */ st->st_pfs_group = &unset_group; RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs , &sapd->payload.sa, &r_sa_pbs, FALSE, st)); } passert(st->st_pfs_group != &unset_group); if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) { loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION"); return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */ } /* Ni in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); /* [ KE ] in (for PFS) */ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1")); /* [ IDci, IDcr ] in */ if (id_pd != NULL) { /* ??? we are assuming IPSEC_DOI */ /* IDci (initiator is peer) */ if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs , &peer_net, &peer_mask, "peer client")) return STF_FAIL + INVALID_ID_INFORMATION; st->st_peeruserprotoid = id_pd->payload.ipsec_id.isaiid_protoid; st->st_peeruserport = id_pd->payload.ipsec_id.isaiid_port; /* IDcr (we are responder) */ if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs , &our_net, &our_mask, "our client")) return STF_FAIL + INVALID_ID_INFORMATION; st->st_myuserprotoid = id_pd->next->payload.ipsec_id.isaiid_protoid; st->st_myuserport = id_pd->next->payload.ipsec_id.isaiid_port; } else { /* implicit IDci and IDcr: peer and self */ our_net = c->this.host_addr; our_mask = mask32.sin_addr; peer_net = c->that.host_addr; peer_mask = mask32.sin_addr; } /* Now that we have identities of client subnets, we must look for * a suitable connection (our current one only matches for hosts). */ { struct connection *p = find_client_connection(c , our_net, our_mask, peer_net, peer_mask); if (p == NULL) { /* This message occurs in very puzzling circumstances * so we must add as much information and beauty as we can. */ struct end me = c->this, he = c->that; char buf[200]; size_t l; me.client_net = our_net; me.client_mask = our_mask; he.client_net = peer_net; he.client_mask = peer_mask; l = format_end(buf, sizeof(buf), &me, NULL, TRUE); l += snprintf(buf + l, sizeof(buf) - l, "..."); (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE); log("cannot respond to IPsec SA request" " because no connection is known for %s" , buf); return STF_FAIL + INVALID_ID_INFORMATION; } else if (p != c) { /* use p, not c */ if (HasWildcardIP(*p)) p = rw_connection(p, c->that.host_addr); /* instantiate */ #ifdef DEBUG /* temporarily bump up cur_debugging to get "using..." message * printed if we'd want it with new connection. */ { unsigned int old_cur_debugging = cur_debugging; cur_debugging |= p->extra_debugging; DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name)); cur_debugging = old_cur_debugging; } #endif st->st_connection = p; SET_CUR_CONNECTION(p); rw_connection_discard(c); c = p; } } log("responding to Quick Mode"); /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ /* Nr out */ if (!build_and_ship_nonce(&st->st_nr, &md->rbody , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE , "Nr")) return STF_INTERNAL_ERROR; /* [ KE ] out (for PFS) */ if (st->st_pfs_group != NULL) { if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) return STF_INTERNAL_ERROR; /* MPZ-Operations might be done after sending the packet... */ compute_dh_shared(st, st->st_gi, st->st_pfs_group); #ifdef DODGE_DH_MISSING_ZERO_BUG if (st->st_shared.ptr[0] == 0) return STF_DROP_DOOMED_EXCHANGE; #endif } /* [ IDci, IDcr ] out */ if (id_pd != NULL) { struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) return STF_INTERNAL_ERROR; p->isaiid_np = ISAKMP_NEXT_ID; p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) return STF_INTERNAL_ERROR; p->isaiid_np = ISAKMP_NEXT_NONE; } /* Compute reply HASH(2) and insert in output */ (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur, st, TRUE); /* Derive new keying material */ compute_keymats(st); /* Tell the kernel to establish the new inbound SA * (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_inbound_ipsec_sa(st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* encrypt message, except for fixed part of header */ if (!encrypt_message(&md->rbody, st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* Update state of exchange */ st->st_state = STATE_QUICK_R1; return STF_REPLY; } /* Handle (the single) message from Responder in Quick Mode. * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> * HDR*, HASH(3) * (see draft-ietf-ipsec-isakmp-oakley-07.txt 5.5) * Installs inbound and outbound IPsec SAs, routing, etc. */ stf_status quick_inR1_outI2(struct msg_digest *md) { struct state *const st = md->st; /* HASH(2) in */ CHECK_QUICK_HASH(md, quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof, st, TRUE) , "HASH(2)", "Quick R1"); /* SA in */ { struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs , &sa_pd->payload.sa, NULL, TRUE, st)); } /* Nr in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); /* [ KE ] in (for PFS) */ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); if (st->st_pfs_group != NULL) { compute_dh_shared(st, st->st_gr, st->st_pfs_group); #ifdef DODGE_DH_MISSING_ZERO_BUG if (st->st_shared.ptr[0] == 0) return STF_REPLACE_DOOMED_EXCHANGE; #endif } /* [ IDci, IDcr ] in; these must match what we sent */ { struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; if (id_pd != NULL) { /* ??? we are assuming IPSEC_DOI */ /* IDci (we are initiator) */ if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs , &st->st_myuserprotoid, &st->st_myuserport , &st->st_connection->this.client_net , &st->st_connection->this.client_mask , "our client")) return STF_FAIL + INVALID_ID_INFORMATION; /* IDcr (responder is peer) */ if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs , &st->st_peeruserprotoid, &st->st_peeruserport , &st->st_connection->that.client_net , &st->st_connection->that.client_mask , "peer client")) return STF_FAIL + INVALID_ID_INFORMATION; } else { /* No IDci, IDcr: we must check that the defaults match our proposal. * Parallels a sequence of assignments in quick_outI1. */ const struct connection *c = st->st_connection; if (!self_client(c->this) || !self_client(c->that)) { loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" " but default does not match proposal"); return STF_FAIL + INVALID_ID_INFORMATION; } } } /* ??? We used to copy the accepted proposal into the state, but it was * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). */ /**************** build reply packet HDR*, HASH(3) ****************/ /* HDR* out done */ /* HASH(3) out -- since this is the only content, no passes needed */ { u_char *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* start of what is to be hashed */ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); (void)quick_mode_hash3(r_hashval, st); } /* Derive new keying material */ compute_keymats(st); /* Tell the kernel to establish the inbound, outbound, and routing part * of the new SA (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_ipsec_sa(st, TRUE)) return STF_INTERNAL_ERROR; /* encrypt message, except for fixed part of header */ if (!encrypt_message(&md->rbody, st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* Update state of exchange */ st->st_state = STATE_QUICK_I2; st->st_connection->newest_ipsec_sa = st->st_serialno; return STF_REPLY; } /* Handle last message of Quick Mode. * HDR*, HASH(3) -> done * (see draft-ietf-ipsec-isakmp-oakley-07.txt 5.5) * Installs outbound IPsec SAs, routing, etc. */ stf_status quick_inI2(struct msg_digest *md) { struct state *const st = md->st; /* HASH(3) in */ CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) , "HASH(3)", "Quick I2"); /* Tell the kernel to establish the outbound and routing part of the new SA * (the previous state established inbound) * (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_ipsec_sa(st, FALSE)) return STF_INTERNAL_ERROR; /* Advance state */ st->st_state = STATE_QUICK_R2; st->st_connection->newest_ipsec_sa = st->st_serialno; update_iv(st); /* not actually used, but tidy */ return STF_NO_REPLY; }