diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2004-04-15 18:39:31 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2004-04-15 18:39:31 +0000 |
commit | b1ac98abf9e700f03d5aa5f97c06dab605d6da06 (patch) | |
tree | c08a9624b4a539b85c5650bcf09528d13eb2d039 /sbin/isakmpd/ipsec.c | |
parent | aeca45bc7d867b71e9600c7108674fae5db8ff9c (diff) |
partial move to KNF. More to come. This has happened because there
are a raft of source code auditors who are willing to help improve this
code only if this is done, and hey, isakmpd does need our standard
auditing process. ok ho hshoexer
Diffstat (limited to 'sbin/isakmpd/ipsec.c')
-rw-r--r-- | sbin/isakmpd/ipsec.c | 3676 |
1 files changed, 1788 insertions, 1888 deletions
diff --git a/sbin/isakmpd/ipsec.c b/sbin/isakmpd/ipsec.c index 189c5a8fb31..d570759467b 100644 --- a/sbin/isakmpd/ipsec.c +++ b/sbin/isakmpd/ipsec.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ipsec.c,v 1.88 2004/04/07 22:45:49 ho Exp $ */ -/* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ +/* $OpenBSD: ipsec.c,v 1.89 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. @@ -78,115 +78,117 @@ #define DEFAULT_REPLAY_WINDOW 16 struct ipsec_decode_arg { - struct message *msg; - struct sa *sa; - struct proto *proto; + struct message *msg; + struct sa *sa; + struct proto *proto; }; /* These variables hold the contacted peers ADT state. */ struct contact { - struct sockaddr *addr; - socklen_t len; -} *contacts = 0; -int contact_cnt = 0, contact_limit = 0; - -static int addr_cmp (const void *, const void *); -static int ipsec_add_contact (struct message *msg); -static int ipsec_contacted (struct message *msg); + struct sockaddr *addr; + socklen_t len; +} *contacts = 0; +int contact_cnt = 0, contact_limit = 0; + +static int addr_cmp(const void *, const void *); +static int ipsec_add_contact(struct message * msg); +static int ipsec_contacted(struct message * msg); #ifdef USE_DEBUG -static int ipsec_debug_attribute (u_int16_t, u_int8_t *, u_int16_t, void *); +static int ipsec_debug_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); #endif -static void ipsec_delete_spi (struct sa *, struct proto *, int); -static int16_t *ipsec_exchange_script (u_int8_t); -static void ipsec_finalize_exchange (struct message *); -static void ipsec_free_exchange_data (void *); -static void ipsec_free_proto_data (void *); -static void ipsec_free_sa_data (void *); -static struct keystate *ipsec_get_keystate (struct message *); -static u_int8_t *ipsec_get_spi (size_t *, u_int8_t, struct message *); -static int ipsec_handle_leftover_payload (struct message *, u_int8_t, - struct payload *); -static int ipsec_informational_post_hook (struct message *); -static int ipsec_informational_pre_hook (struct message *); -static int ipsec_initiator (struct message *); -static void ipsec_proto_init (struct proto *, char *); -static int ipsec_responder (struct message *); -static void ipsec_setup_situation (u_int8_t *); -static int ipsec_set_network (u_int8_t *, u_int8_t *, struct ipsec_sa *); -static size_t ipsec_situation_size (void); -static u_int8_t ipsec_spi_size (u_int8_t); -static int ipsec_validate_attribute (u_int16_t, u_int8_t *, u_int16_t, void *); -static int ipsec_validate_exchange (u_int8_t); -static int ipsec_validate_id_information (u_int8_t, u_int8_t *, u_int8_t *, - size_t, struct exchange *); -static int ipsec_validate_key_information (u_int8_t *, size_t); -static int ipsec_validate_notification (u_int16_t); -static int ipsec_validate_proto (u_int8_t); -static int ipsec_validate_situation (u_int8_t *, size_t *, size_t); -static int ipsec_validate_transform_id (u_int8_t, u_int8_t); +static void ipsec_delete_spi(struct sa *, struct proto *, int); +static int16_t *ipsec_exchange_script(u_int8_t); +static void ipsec_finalize_exchange(struct message *); +static void ipsec_free_exchange_data(void *); +static void ipsec_free_proto_data(void *); +static void ipsec_free_sa_data(void *); +static struct keystate *ipsec_get_keystate(struct message *); +static u_int8_t *ipsec_get_spi(size_t *, u_int8_t, struct message *); +static int +ipsec_handle_leftover_payload(struct message *, u_int8_t, + struct payload *); +static int ipsec_informational_post_hook(struct message *); +static int ipsec_informational_pre_hook(struct message *); +static int ipsec_initiator(struct message *); +static void ipsec_proto_init(struct proto *, char *); +static int ipsec_responder(struct message *); +static void ipsec_setup_situation(u_int8_t *); +static int ipsec_set_network(u_int8_t *, u_int8_t *, struct ipsec_sa *); +static size_t ipsec_situation_size(void); +static u_int8_t ipsec_spi_size(u_int8_t); +static int ipsec_validate_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); +static int ipsec_validate_exchange(u_int8_t); +static int +ipsec_validate_id_information(u_int8_t, u_int8_t *, u_int8_t *, + size_t, struct exchange *); +static int ipsec_validate_key_information(u_int8_t *, size_t); +static int ipsec_validate_notification(u_int16_t); +static int ipsec_validate_proto(u_int8_t); +static int ipsec_validate_situation(u_int8_t *, size_t *, size_t); +static int ipsec_validate_transform_id(u_int8_t, u_int8_t); static struct doi ipsec_doi = { - { 0 }, IPSEC_DOI_IPSEC, - sizeof (struct ipsec_exch), sizeof (struct ipsec_sa), - sizeof (struct ipsec_proto), + {0}, IPSEC_DOI_IPSEC, + sizeof(struct ipsec_exch), sizeof(struct ipsec_sa), + sizeof(struct ipsec_proto), #ifdef USE_DEBUG - ipsec_debug_attribute, + ipsec_debug_attribute, #endif - ipsec_delete_spi, - ipsec_exchange_script, - ipsec_finalize_exchange, - ipsec_free_exchange_data, - ipsec_free_proto_data, - ipsec_free_sa_data, - ipsec_get_keystate, - ipsec_get_spi, - ipsec_handle_leftover_payload, - ipsec_informational_post_hook, - ipsec_informational_pre_hook, - ipsec_is_attribute_incompatible, - ipsec_proto_init, - ipsec_setup_situation, - ipsec_situation_size, - ipsec_spi_size, - ipsec_validate_attribute, - ipsec_validate_exchange, - ipsec_validate_id_information, - ipsec_validate_key_information, - ipsec_validate_notification, - ipsec_validate_proto, - ipsec_validate_situation, - ipsec_validate_transform_id, - ipsec_initiator, - ipsec_responder, - ipsec_decode_ids + ipsec_delete_spi, + ipsec_exchange_script, + ipsec_finalize_exchange, + ipsec_free_exchange_data, + ipsec_free_proto_data, + ipsec_free_sa_data, + ipsec_get_keystate, + ipsec_get_spi, + ipsec_handle_leftover_payload, + ipsec_informational_post_hook, + ipsec_informational_pre_hook, + ipsec_is_attribute_incompatible, + ipsec_proto_init, + ipsec_setup_situation, + ipsec_situation_size, + ipsec_spi_size, + ipsec_validate_attribute, + ipsec_validate_exchange, + ipsec_validate_id_information, + ipsec_validate_key_information, + ipsec_validate_notification, + ipsec_validate_proto, + ipsec_validate_situation, + ipsec_validate_transform_id, + ipsec_initiator, + ipsec_responder, + ipsec_decode_ids }; -int16_t script_quick_mode[] = { - ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ - ISAKMP_PAYLOAD_SA, - ISAKMP_PAYLOAD_NONCE, - EXCHANGE_SCRIPT_SWITCH, - ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ - ISAKMP_PAYLOAD_SA, - ISAKMP_PAYLOAD_NONCE, - EXCHANGE_SCRIPT_SWITCH, - ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ - EXCHANGE_SCRIPT_END +int16_t script_quick_mode[] = { + ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ + ISAKMP_PAYLOAD_SA, + ISAKMP_PAYLOAD_NONCE, + EXCHANGE_SCRIPT_SWITCH, + ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ + ISAKMP_PAYLOAD_SA, + ISAKMP_PAYLOAD_NONCE, + EXCHANGE_SCRIPT_SWITCH, + ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ + EXCHANGE_SCRIPT_END }; -int16_t script_new_group_mode[] = { - ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ - ISAKMP_PAYLOAD_SA, - EXCHANGE_SCRIPT_SWITCH, - ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ - ISAKMP_PAYLOAD_SA, - EXCHANGE_SCRIPT_END +int16_t script_new_group_mode[] = { + ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ + ISAKMP_PAYLOAD_SA, + EXCHANGE_SCRIPT_SWITCH, + ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ + ISAKMP_PAYLOAD_SA, + EXCHANGE_SCRIPT_END }; struct dst_spi_proto_arg { - struct sockaddr *dst; - u_int32_t spi; - u_int8_t proto; + struct sockaddr *dst; + u_int32_t spi; + u_int8_t proto; }; /* @@ -195,49 +197,47 @@ struct dst_spi_proto_arg { * if "proto" arg is 0, match any proto */ static int -ipsec_sa_check (struct sa *sa, void *v_arg) +ipsec_sa_check(struct sa *sa, void *v_arg) { - struct dst_spi_proto_arg *arg = v_arg; - struct proto *proto; - struct sockaddr *dst, *src; - int incoming; - - if (sa->phase != 2 || !(sa->flags & SA_FLAG_READY)) - return 0; - - sa->transport->vtbl->get_dst (sa->transport, &dst); - if (memcmp (sockaddr_addrdata (dst), sockaddr_addrdata (arg->dst), - sockaddr_addrlen (dst)) == 0) - incoming = 0; - else - { - sa->transport->vtbl->get_src (sa->transport, &src); - if (memcmp (sockaddr_addrdata (src), sockaddr_addrdata (arg->dst), - sockaddr_addrlen (src)) == 0) - incoming = 1; - else + struct dst_spi_proto_arg *arg = v_arg; + struct proto *proto; + struct sockaddr *dst, *src; + int incoming; + + if (sa->phase != 2 || !(sa->flags & SA_FLAG_READY)) + return 0; + + sa->transport->vtbl->get_dst(sa->transport, &dst); + if (memcmp(sockaddr_addrdata(dst), sockaddr_addrdata(arg->dst), + sockaddr_addrlen(dst)) == 0) + incoming = 0; + else { + sa->transport->vtbl->get_src(sa->transport, &src); + if (memcmp(sockaddr_addrdata(src), sockaddr_addrdata(arg->dst), + sockaddr_addrlen(src)) == 0) + incoming = 1; + else + return 0; + } + + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) + if ((arg->proto == 0 || proto->proto == arg->proto) && + memcmp(proto->spi[incoming], &arg->spi, sizeof arg->spi) == 0) + return 1; return 0; - } - - for (proto = TAILQ_FIRST (&sa->protos); proto; - proto = TAILQ_NEXT (proto, link)) - if ((arg->proto == 0 || proto->proto == arg->proto) - && memcmp (proto->spi[incoming], &arg->spi, sizeof arg->spi) == 0) - return 1; - return 0; } /* Find an SA with a "name" of DST, SPI & PROTO. */ -struct sa * -ipsec_sa_lookup (struct sockaddr *dst, u_int32_t spi, u_int8_t proto) +struct sa * +ipsec_sa_lookup(struct sockaddr * dst, u_int32_t spi, u_int8_t proto) { - struct dst_spi_proto_arg arg; + struct dst_spi_proto_arg arg; - arg.dst = dst; - arg.spi = spi; - arg.proto = proto; - - return sa_find (ipsec_sa_check, &arg); + arg.dst = dst; + arg.spi = spi; + arg.proto = proto; + return sa_find(ipsec_sa_check, &arg); } /* @@ -246,32 +246,32 @@ ipsec_sa_lookup (struct sockaddr *dst, u_int32_t spi, u_int8_t proto) * XXX At some point other selectors will matter here too. */ static int -ipsec_sa_check_flow (struct sa *sa, void *v_arg) +ipsec_sa_check_flow(struct sa * sa, void *v_arg) { - struct sa *sa2 = v_arg; - struct ipsec_sa *isa = sa->data, *isa2 = sa2->data; - - if (sa == sa2 || sa->phase != 2 - || (sa->flags & (SA_FLAG_READY | SA_FLAG_REPLACED)) != SA_FLAG_READY) - return 0; - - if (isa->tproto != isa2->tproto || isa->sport != isa2->sport - || isa->dport != isa2->dport) - return 0; - - return isa->src_net->sa_family == isa2->src_net->sa_family - && memcmp (sockaddr_addrdata (isa->src_net), - sockaddr_addrdata (isa2->src_net), - sockaddr_addrlen (isa->src_net)) == 0 - && memcmp (sockaddr_addrdata (isa->src_mask), - sockaddr_addrdata (isa2->src_mask), - sockaddr_addrlen (isa->src_mask)) == 0 - && memcmp (sockaddr_addrdata (isa->dst_net), - sockaddr_addrdata (isa2->dst_net), - sockaddr_addrlen (isa->dst_net)) == 0 - && memcmp (sockaddr_addrdata (isa->dst_mask), - sockaddr_addrdata (isa2->dst_mask), - sockaddr_addrlen (isa->dst_mask)) == 0; + struct sa *sa2 = v_arg; + struct ipsec_sa *isa = sa->data, *isa2 = sa2->data; + + if (sa == sa2 || sa->phase != 2 || + (sa->flags & (SA_FLAG_READY | SA_FLAG_REPLACED)) != SA_FLAG_READY) + return 0; + + if (isa->tproto != isa2->tproto || isa->sport != isa2->sport || + isa->dport != isa2->dport) + return 0; + + return isa->src_net->sa_family == isa2->src_net->sa_family && + memcmp(sockaddr_addrdata(isa->src_net), + sockaddr_addrdata(isa2->src_net), + sockaddr_addrlen(isa->src_net)) == 0 && + memcmp(sockaddr_addrdata(isa->src_mask), + sockaddr_addrdata(isa2->src_mask), + sockaddr_addrlen(isa->src_mask)) == 0 && + memcmp(sockaddr_addrdata(isa->dst_net), + sockaddr_addrdata(isa2->dst_net), + sockaddr_addrlen(isa->dst_net)) == 0 && + memcmp(sockaddr_addrdata(isa->dst_mask), + sockaddr_addrdata(isa2->dst_mask), + sockaddr_addrlen(isa->dst_mask)) == 0; } /* @@ -279,672 +279,663 @@ ipsec_sa_check_flow (struct sa *sa, void *v_arg) * the final message. */ static void -ipsec_finalize_exchange (struct message *msg) +ipsec_finalize_exchange(struct message * msg) { - struct sa *isakmp_sa = msg->isakmp_sa; - struct ipsec_sa *isa; - struct exchange *exchange = msg->exchange; - struct ipsec_exch *ie = exchange->data; - struct sa *sa = 0, *old_sa; - struct proto *proto, *last_proto = 0; + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa; + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + struct sa *sa = 0, *old_sa; + struct proto *proto, *last_proto = 0; #ifdef USE_DEBUG - char *addr1, *addr2, *mask1, *mask2; + char *addr1, *addr2, *mask1, *mask2; #endif - switch (exchange->phase) - { - case 1: - switch (exchange->type) - { - case ISAKMP_EXCH_ID_PROT: - case ISAKMP_EXCH_AGGRESSIVE: - isa = isakmp_sa->data; - isa->hash = ie->hash->type; - isa->prf_type = ie->prf_type; - isa->skeyid_len = ie->skeyid_len; - isa->skeyid_d = ie->skeyid_d; - isa->skeyid_a = ie->skeyid_a; - /* Prevents early free of SKEYID_*. */ - ie->skeyid_a = ie->skeyid_d = 0; - - /* If a lifetime was negotiated setup the expiration timers. */ - if (isakmp_sa->seconds) - sa_setup_expirations (isakmp_sa); - break; - } - break; - - case 2: - switch (exchange->type) - { - case IKE_EXCH_QUICK_MODE: - /* - * Tell the application(s) about the SPIs and key material. - */ - for (sa = TAILQ_FIRST (&exchange->sa_list); sa; - sa = TAILQ_NEXT (sa, next)) - { - isa = sa->data; - - if (exchange->initiator) - { - /* Initiator is source, responder is destination. */ - if (ipsec_set_network (ie->id_ci, ie->id_cr, isa)) - { - log_print ("ipsec_finalize_exchange: " - "ipsec_set_network failed"); - return; - } - } - else - { - /* Responder is source, initiator is destination. */ - if (ipsec_set_network (ie->id_cr, ie->id_ci, isa)) - { - log_print ("ipsec_finalize_exchange: " - "ipsec_set_network failed"); - return; - } - } - - for (proto = TAILQ_FIRST (&sa->protos), last_proto = 0; proto; - proto = TAILQ_NEXT (proto, link)) - { - if (sysdep_ipsec_set_spi (sa, proto, 0, isakmp_sa) - || (last_proto - && sysdep_ipsec_group_spis (sa, last_proto, proto, - 0)) - || sysdep_ipsec_set_spi (sa, proto, 1, isakmp_sa) - || (last_proto - && sysdep_ipsec_group_spis (sa, last_proto, proto, - 1))) - /* XXX Tear down this exchange. */ - return; - last_proto = proto; + switch (exchange->phase) { + case 1: + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + case ISAKMP_EXCH_AGGRESSIVE: + isa = isakmp_sa->data; + isa->hash = ie->hash->type; + isa->prf_type = ie->prf_type; + isa->skeyid_len = ie->skeyid_len; + isa->skeyid_d = ie->skeyid_d; + isa->skeyid_a = ie->skeyid_a; + /* Prevents early free of SKEYID_*. */ + ie->skeyid_a = ie->skeyid_d = 0; + + /* + * If a lifetime was negotiated setup the expiration + * timers. + */ + if (isakmp_sa->seconds) + sa_setup_expirations(isakmp_sa); + break; } + break; + + case 2: + switch (exchange->type) { + case IKE_EXCH_QUICK_MODE: + /* + * Tell the application(s) about the SPIs and key material. + */ + for (sa = TAILQ_FIRST(&exchange->sa_list); sa; + sa = TAILQ_NEXT(sa, next)) { + isa = sa->data; + + if (exchange->initiator) { + /* + * Initiator is source, responder is + * destination. + */ + if (ipsec_set_network(ie->id_ci, + ie->id_cr, isa)) { + log_print("ipsec_finalize_exchange: " + "ipsec_set_network failed"); + return; + } + } else { + /* + * Responder is source, initiator is + * destination. + */ + if (ipsec_set_network(ie->id_cr, ie->id_ci, + isa)) { + log_print("ipsec_finalize_exchange: " + "ipsec_set_network failed"); + return; + } + } + + for (proto = TAILQ_FIRST(&sa->protos), + last_proto = 0; proto; + proto = TAILQ_NEXT(proto, link)) { + if (sysdep_ipsec_set_spi(sa, proto, + 0, isakmp_sa) || + (last_proto && sysdep_ipsec_group_spis(sa, + last_proto, proto, 0)) || + sysdep_ipsec_set_spi(sa, proto, + 1, isakmp_sa) || + (last_proto && sysdep_ipsec_group_spis(sa, + last_proto, proto, 1))) + /* + * XXX Tear down this + * exchange. + */ + return; + last_proto = proto; + } #ifdef USE_DEBUG - if (sockaddr2text (isa->src_net, &addr1, 0)) - addr1 = 0; - if (sockaddr2text (isa->src_mask, &mask1, 0)) - mask1 = 0; - if (sockaddr2text (isa->dst_net, &addr2, 0)) - addr2 = 0; - if (sockaddr2text (isa->dst_mask, &mask2, 0)) - mask2 = 0; - - LOG_DBG ((LOG_EXCHANGE, 50, - "ipsec_finalize_exchange: " - "src %s %s dst %s %s tproto %u sport %u dport %u", - addr1 ? addr1 : "<??\?>" , mask1 ? mask1 : "<??\?>", - addr2 ? addr2 : "<??\?>" , mask2 ? mask2 : "<??\?>", - isa->tproto, ntohs (isa->sport), ntohs (isa->dport))); - - if (addr1) - free (addr1); - if (mask1) - free (mask1); - if (addr2) - free (addr2); - if (mask2) - free (mask2); - -#endif /* USE_DEBUG */ - - /* - * If this is not an SA acquired by the kernel, it needs - * to have a SPD entry (a.k.a. flow) set up. - */ - if (!(sa->flags & SA_FLAG_ONDEMAND) - && sysdep_ipsec_enable_sa (sa, isakmp_sa)) - /* XXX Tear down this exchange. */ - return; - - /* Mark elder SAs with the same flow information as replaced. */ - while ((old_sa = sa_find (ipsec_sa_check_flow, sa)) != 0) - sa_mark_replaced (old_sa); - } - break; + if (sockaddr2text(isa->src_net, &addr1, 0)) + addr1 = 0; + if (sockaddr2text(isa->src_mask, &mask1, 0)) + mask1 = 0; + if (sockaddr2text(isa->dst_net, &addr2, 0)) + addr2 = 0; + if (sockaddr2text(isa->dst_mask, &mask2, 0)) + mask2 = 0; + + LOG_DBG((LOG_EXCHANGE, 50, + "ipsec_finalize_exchange: " + "src %s %s dst %s %s tproto %u sport %u dport %u", + addr1 ? addr1 : "<??\?>", mask1 ? mask1 : "<??\?>", + addr2 ? addr2 : "<??\?>", mask2 ? mask2 : "<??\?>", + isa->tproto, ntohs(isa->sport), ntohs(isa->dport))); + + if (addr1) + free(addr1); + if (mask1) + free(mask1); + if (addr2) + free(addr2); + if (mask2) + free(mask2); + +#endif /* USE_DEBUG */ + + /* + * If this is not an SA acquired by the kernel, it needs + * to have a SPD entry (a.k.a. flow) set up. + */ + if (!(sa->flags & SA_FLAG_ONDEMAND) && + sysdep_ipsec_enable_sa(sa, isakmp_sa)) + /* XXX Tear down this exchange. */ + return; + + /* + * Mark elder SAs with the same flow + * information as replaced. + */ + while ((old_sa = sa_find(ipsec_sa_check_flow, sa)) != 0) + sa_mark_replaced(old_sa); + } + break; + } } - } } /* Set the client addresses in ISA from SRC_ID and DST_ID. */ static int -ipsec_set_network (u_int8_t *src_id, u_int8_t *dst_id, struct ipsec_sa *isa) +ipsec_set_network(u_int8_t *src_id, u_int8_t *dst_id, struct ipsec_sa *isa) { - int id; - - /* Set source address/mask. */ - id = GET_ISAKMP_ID_TYPE (src_id); - switch (id) - { - case IPSEC_ID_IPV4_ADDR: - case IPSEC_ID_IPV4_ADDR_SUBNET: - isa->src_net = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in)); - if (!isa->src_net) - goto memfail; - isa->src_net->sa_family = AF_INET; + int id; + + /* Set source address/mask. */ + id = GET_ISAKMP_ID_TYPE(src_id); + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + isa->src_net = (struct sockaddr *) calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->src_net) + goto memfail; + isa->src_net->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR - isa->src_net->sa_len = sizeof (struct sockaddr_in); + isa->src_net->sa_len = sizeof(struct sockaddr_in); #endif - isa->src_mask = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in)); - if (!isa->src_mask) - goto memfail; - isa->src_mask->sa_family = AF_INET; + isa->src_mask = (struct sockaddr *) calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->src_mask) + goto memfail; + isa->src_mask->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR - isa->src_mask->sa_len = sizeof (struct sockaddr_in); + isa->src_mask->sa_len = sizeof(struct sockaddr_in); #endif - break; - - case IPSEC_ID_IPV6_ADDR: - case IPSEC_ID_IPV6_ADDR_SUBNET: - isa->src_net = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in6)); - if (!isa->src_net) - goto memfail; - isa->src_net->sa_family = AF_INET6; + break; + + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + isa->src_net = (struct sockaddr *) calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->src_net) + goto memfail; + isa->src_net->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR - isa->src_net->sa_len = sizeof (struct sockaddr_in6); + isa->src_net->sa_len = sizeof(struct sockaddr_in6); #endif - isa->src_mask = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in6)); - if (!isa->src_mask) - goto memfail; - isa->src_mask->sa_family = AF_INET6; + isa->src_mask = (struct sockaddr *) calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->src_mask) + goto memfail; + isa->src_mask->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR - isa->src_mask->sa_len = sizeof (struct sockaddr_in6); + isa->src_mask->sa_len = sizeof(struct sockaddr_in6); #endif - break; - - case IPSEC_ID_IPV4_RANGE: - case IPSEC_ID_IPV6_RANGE: - case IPSEC_ID_DER_ASN1_DN: - case IPSEC_ID_DER_ASN1_GN: - case IPSEC_ID_KEY_ID: - default: - log_print ("ipsec_set_network: ID type %d (%s) not supported", - id, constant_name (ipsec_id_cst, id)); - return -1; - } - - /* Net */ - memcpy (sockaddr_addrdata (isa->src_net), src_id + ISAKMP_ID_DATA_OFF, - sockaddr_addrlen (isa->src_net)); - - /* Mask */ - switch (id) - { - case IPSEC_ID_IPV4_ADDR: - case IPSEC_ID_IPV6_ADDR: - memset (sockaddr_addrdata (isa->src_mask), 0xff, - sockaddr_addrlen (isa->src_mask)); - break; - case IPSEC_ID_IPV4_ADDR_SUBNET: - case IPSEC_ID_IPV6_ADDR_SUBNET: - memcpy (sockaddr_addrdata (isa->src_mask), src_id + ISAKMP_ID_DATA_OFF + - sockaddr_addrlen (isa->src_net), - sockaddr_addrlen (isa->src_mask)); - break; - } - - memcpy (&isa->sport, src_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, - IPSEC_ID_PORT_LEN); - - /* Set destination address. */ - id = GET_ISAKMP_ID_TYPE (dst_id); - switch (id) - { - case IPSEC_ID_IPV4_ADDR: - case IPSEC_ID_IPV4_ADDR_SUBNET: - isa->dst_net = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in)); - if (!isa->dst_net) - goto memfail; - isa->dst_net->sa_family = AF_INET; + break; + + case IPSEC_ID_IPV4_RANGE: + case IPSEC_ID_IPV6_RANGE: + case IPSEC_ID_DER_ASN1_DN: + case IPSEC_ID_DER_ASN1_GN: + case IPSEC_ID_KEY_ID: + default: + log_print("ipsec_set_network: ID type %d (%s) not supported", + id, constant_name(ipsec_id_cst, id)); + return -1; + } + + /* Net */ + memcpy(sockaddr_addrdata(isa->src_net), src_id + ISAKMP_ID_DATA_OFF, + sockaddr_addrlen(isa->src_net)); + + /* Mask */ + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + memset(sockaddr_addrdata(isa->src_mask), 0xff, + sockaddr_addrlen(isa->src_mask)); + break; + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + memcpy(sockaddr_addrdata(isa->src_mask), src_id + ISAKMP_ID_DATA_OFF + + sockaddr_addrlen(isa->src_net), sockaddr_addrlen(isa->src_mask)); + break; + } + + memcpy(&isa->sport, src_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, + IPSEC_ID_PORT_LEN); + + /* Set destination address. */ + id = GET_ISAKMP_ID_TYPE(dst_id); + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + isa->dst_net = + (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); + if (!isa->dst_net) + goto memfail; + isa->dst_net->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR - isa->dst_net->sa_len = sizeof (struct sockaddr_in); + isa->dst_net->sa_len = sizeof(struct sockaddr_in); #endif - isa->dst_mask = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in)); - if (!isa->dst_mask) - goto memfail; - isa->dst_mask->sa_family = AF_INET; + isa->dst_mask = + (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); + if (!isa->dst_mask) + goto memfail; + isa->dst_mask->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR - isa->dst_mask->sa_len = sizeof (struct sockaddr_in); + isa->dst_mask->sa_len = sizeof(struct sockaddr_in); #endif - break; - - case IPSEC_ID_IPV6_ADDR: - case IPSEC_ID_IPV6_ADDR_SUBNET: - isa->dst_net = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in6)); - if (!isa->dst_net) - goto memfail; - isa->dst_net->sa_family = AF_INET6; + break; + + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + isa->dst_net = + (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in6)); + if (!isa->dst_net) + goto memfail; + isa->dst_net->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR - isa->dst_net->sa_len = sizeof (struct sockaddr_in6); + isa->dst_net->sa_len = sizeof(struct sockaddr_in6); #endif - isa->dst_mask = - (struct sockaddr *)calloc (1, sizeof (struct sockaddr_in6)); - if (!isa->dst_mask) - goto memfail; - isa->dst_mask->sa_family = AF_INET6; + isa->dst_mask = + (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in6)); + if (!isa->dst_mask) + goto memfail; + isa->dst_mask->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR - isa->dst_mask->sa_len = sizeof (struct sockaddr_in6); + isa->dst_mask->sa_len = sizeof(struct sockaddr_in6); #endif - break; - } - - /* Net */ - memcpy (sockaddr_addrdata (isa->dst_net), dst_id + ISAKMP_ID_DATA_OFF, - sockaddr_addrlen (isa->dst_net)); - - /* Mask */ - switch (id) - { - case IPSEC_ID_IPV4_ADDR: - case IPSEC_ID_IPV6_ADDR: - memset (sockaddr_addrdata (isa->dst_mask), 0xff, - sockaddr_addrlen (isa->dst_mask)); - break; - case IPSEC_ID_IPV4_ADDR_SUBNET: - case IPSEC_ID_IPV6_ADDR_SUBNET: - memcpy (sockaddr_addrdata (isa->dst_mask), dst_id + ISAKMP_ID_DATA_OFF + - sockaddr_addrlen (isa->dst_net), - sockaddr_addrlen (isa->dst_mask)); - break; - } - - memcpy (&isa->tproto, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PROTO_OFF, - IPSEC_ID_PROTO_LEN); - memcpy (&isa->dport, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, - IPSEC_ID_PORT_LEN); - return 0; - - memfail: - log_error ("ipsec_set_network: calloc () failed"); - return -1; + break; + } + + /* Net */ + memcpy(sockaddr_addrdata(isa->dst_net), dst_id + ISAKMP_ID_DATA_OFF, + sockaddr_addrlen(isa->dst_net)); + + /* Mask */ + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + memset(sockaddr_addrdata(isa->dst_mask), 0xff, + sockaddr_addrlen(isa->dst_mask)); + break; + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + memcpy(sockaddr_addrdata(isa->dst_mask), dst_id + ISAKMP_ID_DATA_OFF + + sockaddr_addrlen(isa->dst_net), + sockaddr_addrlen(isa->dst_mask)); + break; + } + + memcpy(&isa->tproto, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PROTO_OFF, + IPSEC_ID_PROTO_LEN); + memcpy(&isa->dport, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, + IPSEC_ID_PORT_LEN); + return 0; + +memfail: + log_error("ipsec_set_network: calloc () failed"); + return -1; } /* Free the DOI-specific exchange data pointed to by VIE. */ static void -ipsec_free_exchange_data (void *vie) +ipsec_free_exchange_data(void *vie) { - struct ipsec_exch *ie = vie; + struct ipsec_exch *ie = vie; #ifdef USE_ISAKMP_CFG - struct isakmp_cfg_attr *attr; + struct isakmp_cfg_attr *attr; #endif - if (ie->sa_i_b) - free (ie->sa_i_b); - if (ie->id_ci) - free (ie->id_ci); - if (ie->id_cr) - free (ie->id_cr); - if (ie->g_xi) - free (ie->g_xi); - if (ie->g_xr) - free (ie->g_xr); - if (ie->g_xy) - free (ie->g_xy); - if (ie->skeyid) - free (ie->skeyid); - if (ie->skeyid_d) - free (ie->skeyid_d); - if (ie->skeyid_a) - free (ie->skeyid_a); - if (ie->skeyid_e) - free (ie->skeyid_e); - if (ie->hash_i) - free (ie->hash_i); - if (ie->hash_r) - free (ie->hash_r); - if (ie->group) - group_free (ie->group); + if (ie->sa_i_b) + free(ie->sa_i_b); + if (ie->id_ci) + free(ie->id_ci); + if (ie->id_cr) + free(ie->id_cr); + if (ie->g_xi) + free(ie->g_xi); + if (ie->g_xr) + free(ie->g_xr); + if (ie->g_xy) + free(ie->g_xy); + if (ie->skeyid) + free(ie->skeyid); + if (ie->skeyid_d) + free(ie->skeyid_d); + if (ie->skeyid_a) + free(ie->skeyid_a); + if (ie->skeyid_e) + free(ie->skeyid_e); + if (ie->hash_i) + free(ie->hash_i); + if (ie->hash_r) + free(ie->hash_r); + if (ie->group) + group_free(ie->group); #ifdef USE_ISAKMP_CFG - for (attr = LIST_FIRST (&ie->attrs); attr; attr = LIST_FIRST (&ie->attrs)) - { - LIST_REMOVE (attr, link); - if (attr->length) - free (attr->value); - free (attr); - } + for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_FIRST(&ie->attrs)) { + LIST_REMOVE(attr, link); + if (attr->length) + free(attr->value); + free(attr); + } #endif } /* Free the DOI-specific SA data pointed to by VISA. */ static void -ipsec_free_sa_data (void *visa) +ipsec_free_sa_data(void *visa) { - struct ipsec_sa *isa = visa; - - if (isa->src_net) - free (isa->src_net); - if (isa->src_mask) - free (isa->src_mask); - if (isa->dst_net) - free (isa->dst_net); - if (isa->dst_mask) - free (isa->dst_mask); - if (isa->skeyid_a) - free (isa->skeyid_a); - if (isa->skeyid_d) - free (isa->skeyid_d); + struct ipsec_sa *isa = visa; + + if (isa->src_net) + free(isa->src_net); + if (isa->src_mask) + free(isa->src_mask); + if (isa->dst_net) + free(isa->dst_net); + if (isa->dst_mask) + free(isa->dst_mask); + if (isa->skeyid_a) + free(isa->skeyid_a); + if (isa->skeyid_d) + free(isa->skeyid_d); } /* Free the DOI-specific protocol data of an SA pointed to by VIPROTO. */ static void -ipsec_free_proto_data (void *viproto) +ipsec_free_proto_data(void *viproto) { - struct ipsec_proto *iproto = viproto; - int i; + struct ipsec_proto *iproto = viproto; + int i; - for (i = 0; i < 2; i++) - if (iproto->keymat[i]) - free (iproto->keymat[i]); + for (i = 0; i < 2; i++) + if (iproto->keymat[i]) + free(iproto->keymat[i]); } /* Return exchange script based on TYPE. */ static int16_t * -ipsec_exchange_script (u_int8_t type) +ipsec_exchange_script(u_int8_t type) { - switch (type) - { + switch (type) { #ifdef USE_ISAKMP_CFG - case ISAKMP_EXCH_TRANSACTION: - return script_transaction; + case ISAKMP_EXCH_TRANSACTION: + return script_transaction; #endif - case IKE_EXCH_QUICK_MODE: - return script_quick_mode; - case IKE_EXCH_NEW_GROUP_MODE: - return script_new_group_mode; - } - return 0; + case IKE_EXCH_QUICK_MODE: + return script_quick_mode; + case IKE_EXCH_NEW_GROUP_MODE: + return script_new_group_mode; + } + return 0; } /* Initialize this DOI, requires doi_init to already have been called. */ void -ipsec_init (void) +ipsec_init(void) { - doi_register (&ipsec_doi); + doi_register(&ipsec_doi); } /* Given a message MSG, return a suitable IV (or rather keystate). */ static struct keystate * -ipsec_get_keystate (struct message *msg) +ipsec_get_keystate(struct message * msg) { - struct keystate *ks; - struct hash *hash; - - /* If we have already have an IV, use it. */ - if (msg->exchange && msg->exchange->keystate) - { - ks = malloc (sizeof *ks); - if (!ks) - { - log_error ("ipsec_get_keystate: malloc (%lu) failed", - (unsigned long)sizeof *ks); - return 0; + struct keystate *ks; + struct hash *hash; + + /* If we have already have an IV, use it. */ + if (msg->exchange && msg->exchange->keystate) { + ks = malloc(sizeof *ks); + if (!ks) { + log_error("ipsec_get_keystate: malloc (%lu) failed", + (unsigned long) sizeof *ks); + return 0; + } + memcpy(ks, msg->exchange->keystate, sizeof *ks); + return ks; } - memcpy (ks, msg->exchange->keystate, sizeof *ks); - return ks; - } - - /* - * For phase 2 when no SA yet is setup we need to hash the IV used by - * the ISAKMP SA concatenated with the message ID, and use that as an - * IV for further cryptographic operations. - */ - if (!msg->isakmp_sa->keystate) - { - log_print ("ipsec_get_keystate: no keystate in ISAKMP SA %p", - msg->isakmp_sa); - return 0; - } - ks = crypto_clone_keystate (msg->isakmp_sa->keystate); - if (!ks) - return 0; - - hash = hash_get (((struct ipsec_sa *)msg->isakmp_sa->data)->hash); - hash->Init (hash->ctx); - LOG_DBG_BUF ((LOG_CRYPTO, 80, "ipsec_get_keystate: final phase 1 IV", - ks->riv, ks->xf->blocksize)); - hash->Update (hash->ctx, ks->riv, ks->xf->blocksize); - LOG_DBG_BUF ((LOG_CRYPTO, 80, "ipsec_get_keystate: message ID", - ((u_int8_t *)msg->iov[0].iov_base) - + ISAKMP_HDR_MESSAGE_ID_OFF, - ISAKMP_HDR_MESSAGE_ID_LEN)); - hash->Update (hash->ctx, - ((u_int8_t *)msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF, - ISAKMP_HDR_MESSAGE_ID_LEN); - hash->Final (hash->digest, hash->ctx); - crypto_init_iv (ks, hash->digest, ks->xf->blocksize); - LOG_DBG_BUF ((LOG_CRYPTO, 80, "ipsec_get_keystate: phase 2 IV", - hash->digest, ks->xf->blocksize)); - return ks; + /* + * For phase 2 when no SA yet is setup we need to hash the IV used by + * the ISAKMP SA concatenated with the message ID, and use that as an + * IV for further cryptographic operations. + */ + if (!msg->isakmp_sa->keystate) { + log_print("ipsec_get_keystate: no keystate in ISAKMP SA %p", + msg->isakmp_sa); + return 0; + } + ks = crypto_clone_keystate(msg->isakmp_sa->keystate); + if (!ks) + return 0; + + hash = hash_get(((struct ipsec_sa *) msg->isakmp_sa->data)->hash); + hash->Init(hash->ctx); + LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: final phase 1 IV", + ks->riv, ks->xf->blocksize)); + hash->Update(hash->ctx, ks->riv, ks->xf->blocksize); + LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: message ID", + ((u_int8_t *) msg->iov[0].iov_base) + + ISAKMP_HDR_MESSAGE_ID_OFF, + ISAKMP_HDR_MESSAGE_ID_LEN)); + hash->Update(hash->ctx, + ((u_int8_t *) msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF, + ISAKMP_HDR_MESSAGE_ID_LEN); + hash->Final(hash->digest, hash->ctx); + crypto_init_iv(ks, hash->digest, ks->xf->blocksize); + LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: phase 2 IV", + hash->digest, ks->xf->blocksize)); + return ks; } static void -ipsec_setup_situation (u_int8_t *buf) +ipsec_setup_situation(u_int8_t * buf) { - SET_IPSEC_SIT_SIT (buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY); + SET_IPSEC_SIT_SIT(buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY); } -static size_t -ipsec_situation_size (void) +static size_t +ipsec_situation_size(void) { - return IPSEC_SIT_SIT_LEN; + return IPSEC_SIT_SIT_LEN; } -static u_int8_t -ipsec_spi_size (u_int8_t proto) +static u_int8_t +ipsec_spi_size(u_int8_t proto) { - return IPSEC_SPI_SIZE; + return IPSEC_SPI_SIZE; } static int -ipsec_validate_attribute (u_int16_t type, u_int8_t *value, u_int16_t len, - void *vmsg) +ipsec_validate_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, + void *vmsg) { - struct message *msg = vmsg; - - if ((msg->exchange->phase == 1 - && (type < IKE_ATTR_ENCRYPTION_ALGORITHM - || type > IKE_ATTR_GROUP_ORDER)) - || (msg->exchange->phase == 2 - && (type < IPSEC_ATTR_SA_LIFE_TYPE - || type > IPSEC_ATTR_ECN_TUNNEL))) - return -1; - return 0; + struct message *msg = vmsg; + + if ((msg->exchange->phase == 1 + && (type < IKE_ATTR_ENCRYPTION_ALGORITHM + || type > IKE_ATTR_GROUP_ORDER)) + || (msg->exchange->phase == 2 + && (type < IPSEC_ATTR_SA_LIFE_TYPE + || type > IPSEC_ATTR_ECN_TUNNEL))) + return -1; + return 0; } static int -ipsec_validate_exchange (u_int8_t exch) +ipsec_validate_exchange(u_int8_t exch) { - return exch != IKE_EXCH_QUICK_MODE && exch != IKE_EXCH_NEW_GROUP_MODE; + return exch != IKE_EXCH_QUICK_MODE && exch != IKE_EXCH_NEW_GROUP_MODE; } static int -ipsec_validate_id_information (u_int8_t type, u_int8_t *extra, u_int8_t *buf, - size_t sz, struct exchange *exchange) +ipsec_validate_id_information(u_int8_t type, u_int8_t * extra, u_int8_t * buf, + size_t sz, struct exchange * exchange) { - u_int8_t proto = GET_IPSEC_ID_PROTO (extra); - u_int16_t port = GET_IPSEC_ID_PORT (extra); - - LOG_DBG ((LOG_MESSAGE, 40, - "ipsec_validate_id_information: proto %d port %d type %d", - proto, port, type)); - if (type < IPSEC_ID_IPV4_ADDR || type > IPSEC_ID_KEY_ID) - return -1; - - switch (type) - { - case IPSEC_ID_IPV4_ADDR: - LOG_DBG_BUF ((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv4", - buf, sizeof (struct in_addr))); - break; - - case IPSEC_ID_IPV6_ADDR: - LOG_DBG_BUF ((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv6", - buf, sizeof (struct in6_addr))); - break; - - case IPSEC_ID_IPV4_ADDR_SUBNET: - LOG_DBG_BUF ((LOG_MESSAGE, 40, - "ipsec_validate_id_information: IPv4 network/netmask", - buf, 2 * sizeof (struct in_addr))); - break; - - case IPSEC_ID_IPV6_ADDR_SUBNET: - LOG_DBG_BUF ((LOG_MESSAGE, 40, - "ipsec_validate_id_information: IPv6 network/netmask", - buf, 2 * sizeof (struct in6_addr))); - break; - - default: - break; - } - - if (exchange->phase == 1 - && (proto != IPPROTO_UDP || port != UDP_DEFAULT_PORT) - && (proto != 0 || port != 0)) - { -/* XXX SSH's ISAKMP tester fails this test (proto 17 - port 0). */ + u_int8_t proto = GET_IPSEC_ID_PROTO(extra); + u_int16_t port = GET_IPSEC_ID_PORT(extra); + + LOG_DBG((LOG_MESSAGE, 40, + "ipsec_validate_id_information: proto %d port %d type %d", + proto, port, type)); + if (type < IPSEC_ID_IPV4_ADDR || type > IPSEC_ID_KEY_ID) + return -1; + + switch (type) { + case IPSEC_ID_IPV4_ADDR: + LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv4", + buf, sizeof(struct in_addr))); + break; + + case IPSEC_ID_IPV6_ADDR: + LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv6", + buf, sizeof(struct in6_addr))); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv4 network/netmask", + buf, 2 * sizeof(struct in_addr))); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv6 network/netmask", + buf, 2 * sizeof(struct in6_addr))); + break; + + default: + break; + } + + if (exchange->phase == 1 + && (proto != IPPROTO_UDP || port != UDP_DEFAULT_PORT) + && (proto != 0 || port != 0)) { + /* + * XXX SSH's ISAKMP tester fails this test (proto 17 - port + * 0). + */ #ifdef notyet - return -1; + return -1; #else - log_print ("ipsec_validate_id_information: " - "dubious ID information accepted"); + log_print("ipsec_validate_id_information: " + "dubious ID information accepted"); #endif - } - - /* XXX More checks? */ + } + /* XXX More checks? */ - return 0; + return 0; } static int -ipsec_validate_key_information (u_int8_t *buf, size_t sz) +ipsec_validate_key_information(u_int8_t * buf, size_t sz) { - /* XXX Not implemented yet. */ - return 0; + /* XXX Not implemented yet. */ + return 0; } static int -ipsec_validate_notification (u_int16_t type) +ipsec_validate_notification(u_int16_t type) { - return type < IPSEC_NOTIFY_RESPONDER_LIFETIME - || type > IPSEC_NOTIFY_INITIAL_CONTACT ? -1 : 0; + return type < IPSEC_NOTIFY_RESPONDER_LIFETIME + || type > IPSEC_NOTIFY_INITIAL_CONTACT ? -1 : 0; } static int -ipsec_validate_proto (u_int8_t proto) +ipsec_validate_proto(u_int8_t proto) { - return proto < IPSEC_PROTO_IPSEC_AH || proto > IPSEC_PROTO_IPCOMP ? -1 : 0; + return proto < IPSEC_PROTO_IPSEC_AH || proto > IPSEC_PROTO_IPCOMP ? -1 : 0; } static int -ipsec_validate_situation (u_int8_t *buf, size_t *sz, size_t len) +ipsec_validate_situation(u_int8_t * buf, size_t * sz, size_t len) { - if (len < IPSEC_SIT_SIT_OFF + IPSEC_SIT_SIT_LEN) - { - log_print ("ipsec_validate_situation: payload too short: %u", - (unsigned int)len); - return -1; - } - - /* Currently only "identity only" situations are supported. */ - if (GET_IPSEC_SIT_SIT (buf) != IPSEC_SIT_IDENTITY_ONLY) - return 1; + if (len < IPSEC_SIT_SIT_OFF + IPSEC_SIT_SIT_LEN) { + log_print("ipsec_validate_situation: payload too short: %u", + (unsigned int) len); + return -1; + } + /* Currently only "identity only" situations are supported. */ + if (GET_IPSEC_SIT_SIT(buf) != IPSEC_SIT_IDENTITY_ONLY) + return 1; - *sz = IPSEC_SIT_SIT_LEN; + *sz = IPSEC_SIT_SIT_LEN; - return 0; + return 0; } static int -ipsec_validate_transform_id (u_int8_t proto, u_int8_t transform_id) +ipsec_validate_transform_id(u_int8_t proto, u_int8_t transform_id) { - switch (proto) - { - /* - * As no unexpected protocols can occur, we just tie the default case - * to the first case, in orer to silence a GCC warning. - */ - default: - case ISAKMP_PROTO_ISAKMP: - return transform_id != IPSEC_TRANSFORM_KEY_IKE; - case IPSEC_PROTO_IPSEC_AH: - return - transform_id < IPSEC_AH_MD5 || transform_id > IPSEC_AH_DES ? -1 : 0; - case IPSEC_PROTO_IPSEC_ESP: - return transform_id < IPSEC_ESP_DES_IV64 - || (transform_id > IPSEC_ESP_AES_128_CTR - && transform_id < IPSEC_ESP_AES_MARS) - || transform_id > IPSEC_ESP_AES_TWOFISH ? -1 : 0; - case IPSEC_PROTO_IPCOMP: - return transform_id < IPSEC_IPCOMP_OUI - || transform_id > IPSEC_IPCOMP_V42BIS ? -1 : 0; - } + switch (proto) { + /* + * As no unexpected protocols can occur, we just tie the default case + * to the first case, in orer to silence a GCC warning. + */ + default: + case ISAKMP_PROTO_ISAKMP: + return transform_id != IPSEC_TRANSFORM_KEY_IKE; + case IPSEC_PROTO_IPSEC_AH: + return + transform_id < IPSEC_AH_MD5 || transform_id > IPSEC_AH_DES ? -1 : 0; + case IPSEC_PROTO_IPSEC_ESP: + return transform_id < IPSEC_ESP_DES_IV64 + || (transform_id > IPSEC_ESP_AES_128_CTR + && transform_id < IPSEC_ESP_AES_MARS) + || transform_id > IPSEC_ESP_AES_TWOFISH ? -1 : 0; + case IPSEC_PROTO_IPCOMP: + return transform_id < IPSEC_IPCOMP_OUI + || transform_id > IPSEC_IPCOMP_V42BIS ? -1 : 0; + } } static int -ipsec_initiator (struct message *msg) +ipsec_initiator(struct message * msg) { - struct exchange *exchange = msg->exchange; - int (**script) (struct message *) = 0; - - /* Check that the SA is coherent with the IKE rules. */ - if (exchange->type != ISAKMP_EXCH_TRANSACTION - && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT - && exchange->type != ISAKMP_EXCH_AGGRESSIVE - && exchange->type != ISAKMP_EXCH_INFO) - || (exchange->phase == 2 && exchange->type != IKE_EXCH_QUICK_MODE - && exchange->type != ISAKMP_EXCH_INFO))) - { - log_print ("ipsec_initiator: unsupported exchange type %d in phase %d", - exchange->type, exchange->phase); - return -1; - } - - switch (exchange->type) - { - case ISAKMP_EXCH_ID_PROT: - script = ike_main_mode_initiator; - break; + struct exchange *exchange = msg->exchange; + int (**script) (struct message *) = 0; + + /* Check that the SA is coherent with the IKE rules. */ + if (exchange->type != ISAKMP_EXCH_TRANSACTION + && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT + && exchange->type != ISAKMP_EXCH_AGGRESSIVE + && exchange->type != ISAKMP_EXCH_INFO) + || (exchange->phase == 2 && exchange->type != IKE_EXCH_QUICK_MODE + && exchange->type != ISAKMP_EXCH_INFO))) { + log_print("ipsec_initiator: unsupported exchange type %d in phase %d", + exchange->type, exchange->phase); + return -1; + } + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + script = ike_main_mode_initiator; + break; #ifdef USE_AGGRESSIVE - case ISAKMP_EXCH_AGGRESSIVE: - script = ike_aggressive_initiator; - break; + case ISAKMP_EXCH_AGGRESSIVE: + script = ike_aggressive_initiator; + break; #endif #ifdef USE_ISAKMP_CFG - case ISAKMP_EXCH_TRANSACTION: - script = isakmp_cfg_initiator; - break; + case ISAKMP_EXCH_TRANSACTION: + script = isakmp_cfg_initiator; + break; #endif - case ISAKMP_EXCH_INFO: - return message_send_info (msg); - case IKE_EXCH_QUICK_MODE: - script = ike_quick_mode_initiator; - break; - default: - log_print ("ipsec_initiator: unsupported exchange type %d", - exchange->type); - return -1; - } - - /* Run the script code for this step. */ - if (script) - return script[exchange->step] (msg); - - return 0; + case ISAKMP_EXCH_INFO: + return message_send_info(msg); + case IKE_EXCH_QUICK_MODE: + script = ike_quick_mode_initiator; + break; + default: + log_print("ipsec_initiator: unsupported exchange type %d", + exchange->type); + return -1; + } + + /* Run the script code for this step. */ + if (script) + return script[exchange->step] (msg); + + return 0; } /* @@ -954,148 +945,138 @@ ipsec_initiator (struct message *msg) * or 4-octet otherwise. */ static void -ipsec_delete_spi_list (struct sockaddr *addr, u_int8_t proto, - u_int8_t *spis, int nspis, char *type) +ipsec_delete_spi_list(struct sockaddr * addr, u_int8_t proto, + u_int8_t * spis, int nspis, char *type) { - struct sa *sa; - int i; - - for (i = 0; i < nspis; i++) - { - if (proto == ISAKMP_PROTO_ISAKMP) - { - u_int8_t *spi = spis + i * ISAKMP_HDR_COOKIES_LEN; - - /* - * This really shouldn't happen in IPSEC DOI - * code, but Cisco VPN 3000 sends ISAKMP DELETE's - * this way. - */ - sa = sa_lookup_isakmp_sa (addr, spi); - } - else - { - u_int32_t spi = ((u_int32_t *)spis)[i]; - - sa = ipsec_sa_lookup (addr, spi, proto); - } - - if (sa == NULL) - { - LOG_DBG ((LOG_SA, 30, "ipsec_delete_spi_list: " - "could not locate SA (SPI %08x, proto %u)", - ((u_int32_t *)spis)[i], proto)); - continue; - } + struct sa *sa; + int i; + + for (i = 0; i < nspis; i++) { + if (proto == ISAKMP_PROTO_ISAKMP) { + u_int8_t *spi = spis + i * ISAKMP_HDR_COOKIES_LEN; + + /* + * This really shouldn't happen in IPSEC DOI + * code, but Cisco VPN 3000 sends ISAKMP DELETE's + * this way. + */ + sa = sa_lookup_isakmp_sa(addr, spi); + } else { + u_int32_t spi = ((u_int32_t *) spis)[i]; + + sa = ipsec_sa_lookup(addr, spi, proto); + } - /* Delete the SA and search for the next */ - LOG_DBG ((LOG_SA, 30, "ipsec_delete_spi_list: " - "%s made us delete SA %p (%d references) for proto %d", - type, sa, sa->refcnt, proto)); + if (sa == NULL) { + LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: " + "could not locate SA (SPI %08x, proto %u)", + ((u_int32_t *) spis)[i], proto)); + continue; + } + /* Delete the SA and search for the next */ + LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: " + "%s made us delete SA %p (%d references) for proto %d", + type, sa, sa->refcnt, proto)); - sa_free (sa); - } + sa_free(sa); + } } static int -ipsec_responder (struct message *msg) +ipsec_responder(struct message * msg) { - struct exchange *exchange = msg->exchange; - int (**script) (struct message *) = 0; - struct payload *p; - u_int16_t type; - - /* Check that a new exchange is coherent with the IKE rules. */ - if (exchange->step == 0 && exchange->type != ISAKMP_EXCH_TRANSACTION - && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT - && exchange->type != ISAKMP_EXCH_AGGRESSIVE - && exchange->type != ISAKMP_EXCH_INFO) - || (exchange->phase == 2 && exchange->type == ISAKMP_EXCH_ID_PROT))) - { - message_drop (msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); - return -1; - } - - LOG_DBG ((LOG_MISC, 30, - "ipsec_responder: phase %d exchange %d step %d", exchange->phase, - exchange->type, exchange->step)); - switch (exchange->type) - { - case ISAKMP_EXCH_ID_PROT: - script = ike_main_mode_responder; - break; + struct exchange *exchange = msg->exchange; + int (**script) (struct message *) = 0; + struct payload *p; + u_int16_t type; + + /* Check that a new exchange is coherent with the IKE rules. */ + if (exchange->step == 0 && exchange->type != ISAKMP_EXCH_TRANSACTION + && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT + && exchange->type != ISAKMP_EXCH_AGGRESSIVE + && exchange->type != ISAKMP_EXCH_INFO) + || (exchange->phase == 2 && exchange->type == ISAKMP_EXCH_ID_PROT))) { + message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); + return -1; + } + LOG_DBG((LOG_MISC, 30, + "ipsec_responder: phase %d exchange %d step %d", exchange->phase, + exchange->type, exchange->step)); + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + script = ike_main_mode_responder; + break; #ifdef USE_AGGRESSIVE - case ISAKMP_EXCH_AGGRESSIVE: - script = ike_aggressive_responder; - break; + case ISAKMP_EXCH_AGGRESSIVE: + script = ike_aggressive_responder; + break; #endif #ifdef USE_ISAKMP_CFG - case ISAKMP_EXCH_TRANSACTION: - script = isakmp_cfg_responder; - break; + case ISAKMP_EXCH_TRANSACTION: + script = isakmp_cfg_responder; + break; #endif - case ISAKMP_EXCH_INFO: - for (p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_NOTIFY]); p; - p = TAILQ_NEXT (p, link)) - { - type = GET_ISAKMP_NOTIFY_MSG_TYPE (p->p); - LOG_DBG ((LOG_EXCHANGE, 10, - "ipsec_responder: got NOTIFY of type %s", - constant_name (isakmp_notify_cst, type))); + case ISAKMP_EXCH_INFO: + for (p = TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_NOTIFY]); p; + p = TAILQ_NEXT(p, link)) { + type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); + LOG_DBG((LOG_EXCHANGE, 10, + "ipsec_responder: got NOTIFY of type %s", + constant_name(isakmp_notify_cst, type))); - p->flags |= PL_MARK; + p->flags |= PL_MARK; + } + + /* + * If any DELETEs are in here, let the logic of leftover payloads deal + * with them. + */ + + return 0; + + case IKE_EXCH_QUICK_MODE: + script = ike_quick_mode_responder; + break; + + default: + message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); + return -1; } - /* - * If any DELETEs are in here, let the logic of leftover payloads deal - * with them. - */ - - return 0; - - case IKE_EXCH_QUICK_MODE: - script = ike_quick_mode_responder; - break; - - default: - message_drop (msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); - return -1; - } - - /* Run the script code for this step. */ - if (script) - return script[exchange->step] (msg); - - /* - * XXX So far we don't accept any proposals for exchanges we don't support. - */ - if (TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])) - { - message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); - return -1; - } - return 0; + /* Run the script code for this step. */ + if (script) + return script[exchange->step] (msg); + + /* + * XXX So far we don't accept any proposals for exchanges we don't support. + */ + if (TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_SA])) { + message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + return -1; + } + return 0; } -static enum hashes from_ike_hash (u_int16_t hash) +static enum hashes +from_ike_hash(u_int16_t hash) { - switch (hash) - { - case IKE_HASH_MD5: - return HASH_MD5; - case IKE_HASH_SHA: - return HASH_SHA1; - } - return -1; + switch (hash) { + case IKE_HASH_MD5: + return HASH_MD5; + case IKE_HASH_SHA: + return HASH_SHA1; + } + return -1; } -static enum transform from_ike_crypto (u_int16_t crypto) +static enum transform +from_ike_crypto(u_int16_t crypto) { - /* Coincidentally this is the null operation :-) */ - return crypto; + /* Coincidentally this is the null operation :-) */ + return crypto; } /* @@ -1104,92 +1085,90 @@ static enum transform from_ike_crypto (u_int16_t crypto) * VMSG is a pointer to the current message. */ int -ipsec_is_attribute_incompatible (u_int16_t type, u_int8_t *value, - u_int16_t len, void *vmsg) +ipsec_is_attribute_incompatible(u_int16_t type, u_int8_t * value, + u_int16_t len, void *vmsg) { - struct message *msg = vmsg; - - if (msg->exchange->phase == 1) - { - switch (type) - { - case IKE_ATTR_ENCRYPTION_ALGORITHM: - return !crypto_get (from_ike_crypto (decode_16 (value))); - case IKE_ATTR_HASH_ALGORITHM: - return !hash_get (from_ike_hash (decode_16 (value))); - case IKE_ATTR_AUTHENTICATION_METHOD: - return !ike_auth_get (decode_16 (value)); - case IKE_ATTR_GROUP_DESCRIPTION: - return (decode_16 (value) < IKE_GROUP_DESC_MODP_768 - || decode_16 (value) > IKE_GROUP_DESC_MODP_1536) - && (decode_16 (value) < IKE_GROUP_DESC_MODP_2048 - || decode_16 (value) > IKE_GROUP_DESC_MODP_8192); - case IKE_ATTR_GROUP_TYPE: - return 1; - case IKE_ATTR_GROUP_PRIME: - return 1; - case IKE_ATTR_GROUP_GENERATOR_1: - return 1; - case IKE_ATTR_GROUP_GENERATOR_2: - return 1; - case IKE_ATTR_GROUP_CURVE_A: - return 1; - case IKE_ATTR_GROUP_CURVE_B: - return 1; - case IKE_ATTR_LIFE_TYPE: - return decode_16 (value) < IKE_DURATION_SECONDS - || decode_16 (value) > IKE_DURATION_KILOBYTES; - case IKE_ATTR_LIFE_DURATION: - return len != 2 && len != 4; - case IKE_ATTR_PRF: - return 1; - case IKE_ATTR_KEY_LENGTH: - /* - * Our crypto routines only allows key-lengths which are multiples - * of an octet. - */ - return decode_16 (value) % 8 != 0; - case IKE_ATTR_FIELD_SIZE: - return 1; - case IKE_ATTR_GROUP_ORDER: - return 1; - } - } - else - { - switch (type) - { - case IPSEC_ATTR_SA_LIFE_TYPE: - return decode_16 (value) < IPSEC_DURATION_SECONDS - || decode_16 (value) > IPSEC_DURATION_KILOBYTES; - case IPSEC_ATTR_SA_LIFE_DURATION: - return len != 2 && len != 4; - case IPSEC_ATTR_GROUP_DESCRIPTION: - return (decode_16 (value) < IKE_GROUP_DESC_MODP_768 - || decode_16 (value) > IKE_GROUP_DESC_MODP_1536) - && (decode_16 (value) < IKE_GROUP_DESC_MODP_2048 - || IKE_GROUP_DESC_MODP_8192 < decode_16 (value)); - case IPSEC_ATTR_ENCAPSULATION_MODE: - return decode_16 (value) < IPSEC_ENCAP_TUNNEL - || decode_16 (value) > IPSEC_ENCAP_TRANSPORT; - case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: - return decode_16 (value) < IPSEC_AUTH_HMAC_MD5 - || decode_16 (value) > IPSEC_AUTH_HMAC_RIPEMD; - case IPSEC_ATTR_KEY_LENGTH: - /* XXX Blowfish needs '0'. Others appear to disregard this attr? */ - return 0; - case IPSEC_ATTR_KEY_ROUNDS: - return 1; - case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: - return 1; - case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: - return 1; - case IPSEC_ATTR_ECN_TUNNEL: - return 1; + struct message *msg = vmsg; + + if (msg->exchange->phase == 1) { + switch (type) { + case IKE_ATTR_ENCRYPTION_ALGORITHM: + return !crypto_get(from_ike_crypto(decode_16(value))); + case IKE_ATTR_HASH_ALGORITHM: + return !hash_get(from_ike_hash(decode_16(value))); + case IKE_ATTR_AUTHENTICATION_METHOD: + return !ike_auth_get(decode_16(value)); + case IKE_ATTR_GROUP_DESCRIPTION: + return (decode_16(value) < IKE_GROUP_DESC_MODP_768 + || decode_16(value) > IKE_GROUP_DESC_MODP_1536) + && (decode_16(value) < IKE_GROUP_DESC_MODP_2048 + || decode_16(value) > IKE_GROUP_DESC_MODP_8192); + case IKE_ATTR_GROUP_TYPE: + return 1; + case IKE_ATTR_GROUP_PRIME: + return 1; + case IKE_ATTR_GROUP_GENERATOR_1: + return 1; + case IKE_ATTR_GROUP_GENERATOR_2: + return 1; + case IKE_ATTR_GROUP_CURVE_A: + return 1; + case IKE_ATTR_GROUP_CURVE_B: + return 1; + case IKE_ATTR_LIFE_TYPE: + return decode_16(value) < IKE_DURATION_SECONDS + || decode_16(value) > IKE_DURATION_KILOBYTES; + case IKE_ATTR_LIFE_DURATION: + return len != 2 && len != 4; + case IKE_ATTR_PRF: + return 1; + case IKE_ATTR_KEY_LENGTH: + /* + * Our crypto routines only allows key-lengths which are multiples + * of an octet. + */ + return decode_16(value) % 8 != 0; + case IKE_ATTR_FIELD_SIZE: + return 1; + case IKE_ATTR_GROUP_ORDER: + return 1; + } + } else { + switch (type) { + case IPSEC_ATTR_SA_LIFE_TYPE: + return decode_16(value) < IPSEC_DURATION_SECONDS + || decode_16(value) > IPSEC_DURATION_KILOBYTES; + case IPSEC_ATTR_SA_LIFE_DURATION: + return len != 2 && len != 4; + case IPSEC_ATTR_GROUP_DESCRIPTION: + return (decode_16(value) < IKE_GROUP_DESC_MODP_768 + || decode_16(value) > IKE_GROUP_DESC_MODP_1536) + && (decode_16(value) < IKE_GROUP_DESC_MODP_2048 + || IKE_GROUP_DESC_MODP_8192 < decode_16(value)); + case IPSEC_ATTR_ENCAPSULATION_MODE: + return decode_16(value) < IPSEC_ENCAP_TUNNEL + || decode_16(value) > IPSEC_ENCAP_TRANSPORT; + case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: + return decode_16(value) < IPSEC_AUTH_HMAC_MD5 + || decode_16(value) > IPSEC_AUTH_HMAC_RIPEMD; + case IPSEC_ATTR_KEY_LENGTH: + /* + * XXX Blowfish needs '0'. Others appear to disregard + * this attr? + */ + return 0; + case IPSEC_ATTR_KEY_ROUNDS: + return 1; + case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: + return 1; + case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: + return 1; + case IPSEC_ATTR_ECN_TUNNEL: + return 1; + } } - } - /* XXX Silence gcc. */ - return 1; + /* XXX Silence gcc. */ + return 1; } #ifdef USE_DEBUG @@ -1198,25 +1177,25 @@ ipsec_is_attribute_incompatible (u_int16_t type, u_int8_t *value, * in human-readable form. VMSG is a pointer to the current message. */ int -ipsec_debug_attribute (u_int16_t type, u_int8_t *value, u_int16_t len, - void *vmsg) +ipsec_debug_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, + void *vmsg) { - struct message *msg = vmsg; - char val[20]; - - /* XXX Transient solution. */ - if (len == 2) - snprintf (val, sizeof val, "%d", decode_16 (value)); - else if (len == 4) - snprintf (val, sizeof val, "%d", decode_32 (value)); - else - snprintf (val, sizeof val, "unrepresentable"); - - LOG_DBG ((LOG_MESSAGE, 50, "Attribute %s value %s", - constant_name (msg->exchange->phase == 1 - ? ike_attr_cst : ipsec_attr_cst, type), - val)); - return 0; + struct message *msg = vmsg; + char val[20]; + + /* XXX Transient solution. */ + if (len == 2) + snprintf(val, sizeof val, "%d", decode_16(value)); + else if (len == 4) + snprintf(val, sizeof val, "%d", decode_32(value)); + else + snprintf(val, sizeof val, "unrepresentable"); + + LOG_DBG((LOG_MESSAGE, 50, "Attribute %s value %s", + constant_name(msg->exchange->phase == 1 + ? ike_attr_cst : ipsec_attr_cst, type), + val)); + return 0; } #endif @@ -1226,163 +1205,155 @@ ipsec_debug_attribute (u_int16_t type, u_int8_t *value, u_int16_t len, * current message, SA and protocol. */ int -ipsec_decode_attribute (u_int16_t type, u_int8_t *value, u_int16_t len, - void *vida) +ipsec_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, + void *vida) { - struct ipsec_decode_arg *ida = vida; - struct message *msg = ida->msg; - struct sa *sa = ida->sa; - struct ipsec_sa *isa = sa->data; - struct proto *proto = ida->proto; - struct ipsec_proto *iproto = proto->data; - struct exchange *exchange = msg->exchange; - struct ipsec_exch *ie = exchange->data; - static int lifetype = 0; - - if (exchange->phase == 1) - { - switch (type) - { - case IKE_ATTR_ENCRYPTION_ALGORITHM: - /* XXX Errors possible? */ - exchange->crypto = crypto_get (from_ike_crypto (decode_16 (value))); - break; - case IKE_ATTR_HASH_ALGORITHM: - /* XXX Errors possible? */ - ie->hash = hash_get (from_ike_hash (decode_16 (value))); - break; - case IKE_ATTR_AUTHENTICATION_METHOD: - /* XXX Errors possible? */ - ie->ike_auth = ike_auth_get (decode_16 (value)); - break; - case IKE_ATTR_GROUP_DESCRIPTION: - isa->group_desc = decode_16 (value); - break; - case IKE_ATTR_GROUP_TYPE: - break; - case IKE_ATTR_GROUP_PRIME: - break; - case IKE_ATTR_GROUP_GENERATOR_1: - break; - case IKE_ATTR_GROUP_GENERATOR_2: - break; - case IKE_ATTR_GROUP_CURVE_A: - break; - case IKE_ATTR_GROUP_CURVE_B: - break; - case IKE_ATTR_LIFE_TYPE: - lifetype = decode_16 (value); - return 0; - case IKE_ATTR_LIFE_DURATION: - switch (lifetype) - { - case IKE_DURATION_SECONDS: - switch (len) - { - case 2: - sa->seconds = decode_16 (value); - break; - case 4: - sa->seconds = decode_32 (value); - break; - default: - log_print ("ipsec_decode_attribute: unreasonable lifetime"); + struct ipsec_decode_arg *ida = vida; + struct message *msg = ida->msg; + struct sa *sa = ida->sa; + struct ipsec_sa *isa = sa->data; + struct proto *proto = ida->proto; + struct ipsec_proto *iproto = proto->data; + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + static int lifetype = 0; + + if (exchange->phase == 1) { + switch (type) { + case IKE_ATTR_ENCRYPTION_ALGORITHM: + /* XXX Errors possible? */ + exchange->crypto = crypto_get(from_ike_crypto(decode_16(value))); + break; + case IKE_ATTR_HASH_ALGORITHM: + /* XXX Errors possible? */ + ie->hash = hash_get(from_ike_hash(decode_16(value))); + break; + case IKE_ATTR_AUTHENTICATION_METHOD: + /* XXX Errors possible? */ + ie->ike_auth = ike_auth_get(decode_16(value)); + break; + case IKE_ATTR_GROUP_DESCRIPTION: + isa->group_desc = decode_16(value); + break; + case IKE_ATTR_GROUP_TYPE: + break; + case IKE_ATTR_GROUP_PRIME: + break; + case IKE_ATTR_GROUP_GENERATOR_1: + break; + case IKE_ATTR_GROUP_GENERATOR_2: + break; + case IKE_ATTR_GROUP_CURVE_A: + break; + case IKE_ATTR_GROUP_CURVE_B: + break; + case IKE_ATTR_LIFE_TYPE: + lifetype = decode_16(value); + return 0; + case IKE_ATTR_LIFE_DURATION: + switch (lifetype) { + case IKE_DURATION_SECONDS: + switch (len) { + case 2: + sa->seconds = decode_16(value); + break; + case 4: + sa->seconds = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: unreasonable lifetime"); + } + break; + case IKE_DURATION_KILOBYTES: + switch (len) { + case 2: + sa->kilobytes = decode_16(value); + break; + case 4: + sa->kilobytes = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: unreasonable lifetime"); + } + break; + default: + log_print("ipsec_decode_attribute: unknown lifetime type"); + } + break; + case IKE_ATTR_PRF: + break; + case IKE_ATTR_KEY_LENGTH: + exchange->key_length = decode_16(value) / 8; + break; + case IKE_ATTR_FIELD_SIZE: + break; + case IKE_ATTR_GROUP_ORDER: + break; } - break; - case IKE_DURATION_KILOBYTES: - switch (len) - { - case 2: - sa->kilobytes = decode_16 (value); - break; - case 4: - sa->kilobytes = decode_32 (value); - break; - default: - log_print ("ipsec_decode_attribute: unreasonable lifetime"); + } else { + switch (type) { + case IPSEC_ATTR_SA_LIFE_TYPE: + lifetype = decode_16(value); + return 0; + case IPSEC_ATTR_SA_LIFE_DURATION: + switch (lifetype) { + case IPSEC_DURATION_SECONDS: + switch (len) { + case 2: + sa->seconds = decode_16(value); + break; + case 4: + sa->seconds = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: unreasonable lifetime"); + } + break; + case IPSEC_DURATION_KILOBYTES: + switch (len) { + case 2: + sa->kilobytes = decode_16(value); + break; + case 4: + sa->kilobytes = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: unreasonable lifetime"); + } + break; + default: + log_print("ipsec_decode_attribute: unknown lifetime type"); + } + break; + case IPSEC_ATTR_GROUP_DESCRIPTION: + isa->group_desc = decode_16(value); + break; + case IPSEC_ATTR_ENCAPSULATION_MODE: + /* + * XXX Multiple protocols must have same + * encapsulation mode, no? + */ + iproto->encap_mode = decode_16(value); + break; + case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: + iproto->auth = decode_16(value); + break; + case IPSEC_ATTR_KEY_LENGTH: + iproto->keylen = decode_16(value); + break; + case IPSEC_ATTR_KEY_ROUNDS: + iproto->keyrounds = decode_16(value); + break; + case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: + break; + case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: + break; + case IPSEC_ATTR_ECN_TUNNEL: + break; } - break; - default: - log_print ("ipsec_decode_attribute: unknown lifetime type"); - } - break; - case IKE_ATTR_PRF: - break; - case IKE_ATTR_KEY_LENGTH: - exchange->key_length = decode_16 (value) / 8; - break; - case IKE_ATTR_FIELD_SIZE: - break; - case IKE_ATTR_GROUP_ORDER: - break; } - } - else - { - switch (type) - { - case IPSEC_ATTR_SA_LIFE_TYPE: - lifetype = decode_16 (value); - return 0; - case IPSEC_ATTR_SA_LIFE_DURATION: - switch (lifetype) - { - case IPSEC_DURATION_SECONDS: - switch (len) - { - case 2: - sa->seconds = decode_16 (value); - break; - case 4: - sa->seconds = decode_32 (value); - break; - default: - log_print ("ipsec_decode_attribute: unreasonable lifetime"); - } - break; - case IPSEC_DURATION_KILOBYTES: - switch (len) - { - case 2: - sa->kilobytes = decode_16 (value); - break; - case 4: - sa->kilobytes = decode_32 (value); - break; - default: - log_print ("ipsec_decode_attribute: unreasonable lifetime"); - } - break; - default: - log_print ("ipsec_decode_attribute: unknown lifetime type"); - } - break; - case IPSEC_ATTR_GROUP_DESCRIPTION: - isa->group_desc = decode_16 (value); - break; - case IPSEC_ATTR_ENCAPSULATION_MODE: - /* XXX Multiple protocols must have same encapsulation mode, no? */ - iproto->encap_mode = decode_16 (value); - break; - case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: - iproto->auth = decode_16 (value); - break; - case IPSEC_ATTR_KEY_LENGTH: - iproto->keylen = decode_16 (value); - break; - case IPSEC_ATTR_KEY_ROUNDS: - iproto->keyrounds = decode_16 (value); - break; - case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: - break; - case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: - break; - case IPSEC_ATTR_ECN_TUNNEL: - break; - } - } - lifetype = 0; - return 0; + lifetype = 0; + return 0; } /* @@ -1391,34 +1362,34 @@ ipsec_decode_attribute (u_int16_t type, u_int8_t *value, u_int16_t len, * processed. */ void -ipsec_decode_transform (struct message *msg, struct sa *sa, - struct proto *proto, u_int8_t *buf) +ipsec_decode_transform(struct message * msg, struct sa * sa, + struct proto * proto, u_int8_t * buf) { - struct ipsec_exch *ie = msg->exchange->data; - struct ipsec_decode_arg ida; - - LOG_DBG ((LOG_MISC, 20, "ipsec_decode_transform: transform %d chosen", - GET_ISAKMP_TRANSFORM_NO (buf))); - - ida.msg = msg; - ida.sa = sa; - ida.proto = proto; - - /* The default IKE lifetime is 8 hours. */ - if (sa->phase == 1) - sa->seconds = 28800; - - /* Extract the attributes and stuff them into the SA. */ - attribute_map (buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, - GET_ISAKMP_GEN_LENGTH (buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, - ipsec_decode_attribute, &ida); - - /* - * If no pseudo-random function was negotiated, it's HMAC. - * XXX As PRF_HMAC currently is zero, this is a no-op. - */ - if (!ie->prf_type) - ie->prf_type = PRF_HMAC; + struct ipsec_exch *ie = msg->exchange->data; + struct ipsec_decode_arg ida; + + LOG_DBG((LOG_MISC, 20, "ipsec_decode_transform: transform %d chosen", + GET_ISAKMP_TRANSFORM_NO(buf))); + + ida.msg = msg; + ida.sa = sa; + ida.proto = proto; + + /* The default IKE lifetime is 8 hours. */ + if (sa->phase == 1) + sa->seconds = 28800; + + /* Extract the attributes and stuff them into the SA. */ + attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + ipsec_decode_attribute, &ida); + + /* + * If no pseudo-random function was negotiated, it's HMAC. + * XXX As PRF_HMAC currently is zero, this is a no-op. + */ + if (!ie->prf_type) + ie->prf_type = PRF_HMAC; } /* @@ -1426,12 +1397,12 @@ ipsec_decode_transform (struct message *msg, struct sa *sa, * of the IKE security association SA. */ static void -ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +ipsec_delete_spi(struct sa * sa, struct proto * proto, int incoming) { - if (sa->phase == 1) - return; - /* XXX Error handling? Is it interesting? */ - sysdep_ipsec_delete_spi (sa, proto, incoming); + if (sa->phase == 1) + return; + /* XXX Error handling? Is it interesting? */ + sysdep_ipsec_delete_spi(sa, proto, incoming); } /* @@ -1439,80 +1410,72 @@ ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) * PEER is non-zero when the value is our peer's, and zero when it is ours. */ static int -ipsec_g_x (struct message *msg, int peer, u_int8_t *buf) +ipsec_g_x(struct message * msg, int peer, u_int8_t * buf) { - struct exchange *exchange = msg->exchange; - struct ipsec_exch *ie = exchange->data; - u_int8_t **g_x; - int initiator = exchange->initiator ^ peer; - char header[32]; - - g_x = initiator ? &ie->g_xi : &ie->g_xr; - *g_x = malloc (ie->g_x_len); - if (!*g_x) - { - log_error ("ipsec_g_x: malloc (%lu) failed", (unsigned long)ie->g_x_len); - return -1; - } - memcpy (*g_x, buf, ie->g_x_len); - snprintf (header, sizeof header, "ipsec_g_x: g^x%c", initiator ? 'i' : 'r'); - LOG_DBG_BUF ((LOG_MISC, 80, header, *g_x, ie->g_x_len)); - return 0; + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + u_int8_t **g_x; + int initiator = exchange->initiator ^ peer; + char header[32]; + + g_x = initiator ? &ie->g_xi : &ie->g_xr; + *g_x = malloc(ie->g_x_len); + if (!*g_x) { + log_error("ipsec_g_x: malloc (%lu) failed", (unsigned long) ie->g_x_len); + return -1; + } + memcpy(*g_x, buf, ie->g_x_len); + snprintf(header, sizeof header, "ipsec_g_x: g^x%c", initiator ? 'i' : 'r'); + LOG_DBG_BUF((LOG_MISC, 80, header, *g_x, ie->g_x_len)); + return 0; } /* Generate our DH value. */ int -ipsec_gen_g_x (struct message *msg) +ipsec_gen_g_x(struct message * msg) { - struct exchange *exchange = msg->exchange; - struct ipsec_exch *ie = exchange->data; - u_int8_t *buf; - - buf = malloc (ISAKMP_KE_SZ + ie->g_x_len); - if (!buf) - { - log_error ("ipsec_gen_g_x: malloc (%lu) failed", - ISAKMP_KE_SZ + (unsigned long)ie->g_x_len); - return -1; - } - - if (message_add_payload (msg, ISAKMP_PAYLOAD_KEY_EXCH, buf, - ISAKMP_KE_SZ + ie->g_x_len, 1)) - { - free (buf); - return -1; - } - - if (dh_create_exchange (ie->group, buf + ISAKMP_KE_DATA_OFF)) - { - log_print ("ipsec_gen_g_x: dh_create_exchange failed"); - free (buf); - return -1; - } - return ipsec_g_x (msg, 0, buf + ISAKMP_KE_DATA_OFF); + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + u_int8_t *buf; + + buf = malloc(ISAKMP_KE_SZ + ie->g_x_len); + if (!buf) { + log_error("ipsec_gen_g_x: malloc (%lu) failed", + ISAKMP_KE_SZ + (unsigned long) ie->g_x_len); + return -1; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_KEY_EXCH, buf, + ISAKMP_KE_SZ + ie->g_x_len, 1)) { + free(buf); + return -1; + } + if (dh_create_exchange(ie->group, buf + ISAKMP_KE_DATA_OFF)) { + log_print("ipsec_gen_g_x: dh_create_exchange failed"); + free(buf); + return -1; + } + return ipsec_g_x(msg, 0, buf + ISAKMP_KE_DATA_OFF); } /* Save the peer's DH value. */ int -ipsec_save_g_x (struct message *msg) +ipsec_save_g_x(struct message * msg) { - struct exchange *exchange = msg->exchange; - struct ipsec_exch *ie = exchange->data; - struct payload *kep; - - kep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]); - kep->flags |= PL_MARK; - ie->g_x_len = GET_ISAKMP_GEN_LENGTH (kep->p) - ISAKMP_KE_DATA_OFF; - - /* Check that the given length matches the group's expectancy. */ - if (ie->g_x_len != (size_t)dh_getlen (ie->group)) - { - /* XXX Is this a good notify type? */ - message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); - return -1; - } - - return ipsec_g_x (msg, 1, kep->p + ISAKMP_KE_DATA_OFF); + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + struct payload *kep; + + kep = TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]); + kep->flags |= PL_MARK; + ie->g_x_len = GET_ISAKMP_GEN_LENGTH(kep->p) - ISAKMP_KE_DATA_OFF; + + /* Check that the given length matches the group's expectancy. */ + if (ie->g_x_len != (size_t) dh_getlen(ie->group)) { + /* XXX Is this a good notify type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + return -1; + } + return ipsec_g_x(msg, 1, kep->p + ISAKMP_KE_DATA_OFF); } /* @@ -1520,24 +1483,21 @@ ipsec_save_g_x (struct message *msg) * size where SZ points. NB! A zero return is OK if *SZ is zero. */ static u_int8_t * -ipsec_get_spi (size_t *sz, u_int8_t proto, struct message *msg) +ipsec_get_spi(size_t * sz, u_int8_t proto, struct message * msg) { - struct sockaddr *dst, *src; - struct transport *transport = msg->transport; - - if (msg->exchange->phase == 1) - { - *sz = 0; - return 0; - } - else - { - /* We are the destination in the SA we want a SPI for. */ - transport->vtbl->get_src (transport, &dst); - /* The peer is the source. */ - transport->vtbl->get_dst (transport, &src); - return sysdep_ipsec_get_spi (sz, proto, src, dst, msg->exchange->seq); - } + struct sockaddr *dst, *src; + struct transport *transport = msg->transport; + + if (msg->exchange->phase == 1) { + *sz = 0; + return 0; + } else { + /* We are the destination in the SA we want a SPI for. */ + transport->vtbl->get_src(transport, &dst); + /* The peer is the source. */ + transport->vtbl->get_dst(transport, &src); + return sysdep_ipsec_get_spi(sz, proto, src, dst, msg->exchange->seq); + } } /* @@ -1547,215 +1507,196 @@ ipsec_get_spi (size_t *sz, u_int8_t proto, struct message *msg) * 0. */ int -ipsec_handle_leftover_payload (struct message *msg, u_int8_t type, - struct payload *payload) +ipsec_handle_leftover_payload(struct message * msg, u_int8_t type, + struct payload * payload) { - u_int32_t spisz, nspis; - struct sockaddr *dst; - int reenter = 0; - u_int8_t *spis, proto; - struct sa *sa; - - switch (type) - { - case ISAKMP_PAYLOAD_DELETE: - proto = GET_ISAKMP_DELETE_PROTO (payload->p); - nspis = GET_ISAKMP_DELETE_NSPIS (payload->p); - spisz = GET_ISAKMP_DELETE_SPI_SZ (payload->p); - - if (nspis == 0) - { - LOG_DBG ((LOG_SA, 60, "ipsec_handle_leftover_payload: message " - "specified zero SPIs, ignoring")); - return -1; - } - - /* verify proper SPI size */ - if ((proto == ISAKMP_PROTO_ISAKMP && spisz != ISAKMP_HDR_COOKIES_LEN) - || (proto != ISAKMP_PROTO_ISAKMP && spisz != sizeof (u_int32_t))) - { - log_print ("ipsec_handle_leftover_payload: " - "invalid SPI size %d for proto %d in DELETE payload", - spisz, proto); - return -1; - } - - spis = (u_int8_t *)malloc (nspis * spisz); - if (!spis) - { - log_error ("ipsec_handle_leftover_payload: malloc (%d) failed", - nspis * spisz); - return -1; - } - - /* extract SPI and get dst address */ - memcpy (spis, payload->p + ISAKMP_DELETE_SPI_OFF, nspis * spisz); - msg->transport->vtbl->get_dst (msg->transport, &dst); - - ipsec_delete_spi_list (dst, proto, spis, nspis, "DELETE"); - - free (spis); - payload->flags |= PL_MARK; - return 0; - - case ISAKMP_PAYLOAD_NOTIFY: - switch (GET_ISAKMP_NOTIFY_MSG_TYPE (payload->p)) - { - case IPSEC_NOTIFY_INITIAL_CONTACT: - /* - * Permit INITIAL-CONTACT if - * - this is not an AGGRESSIVE mode exchange - * - it is protected by an ISAKMP SA - * - * XXX Instead of the first condition above, we could permit this - * XXX only for phase 2. In the last packet of main-mode, this - * XXX payload, while encrypted, is not part of the hash digest. - * XXX As we currently send our own INITIAL-CONTACTs at this point, - * XXX this too would need to be changed. - */ - if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE) - { - log_print ("ipsec_handle_leftover_payload: got INITIAL-CONTACT " - "in AGGRESSIVE mode"); - return -1; - } - - if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT) == 0) - { - log_print ("ipsec_handle_leftover_payload: got INITIAL-CONTACT " - "without ISAKMP SA"); - return -1; - } - - /* - * Find out who is sending this and then delete every SA that is - * ready. Exchanges will timeout themselves and then the - * non-ready SAs will disappear too. - */ - msg->transport->vtbl->get_dst (msg->transport, &dst); - while ((sa = sa_lookup_by_peer (dst, sysdep_sa_len (dst))) != 0) - { - /* - * Don't delete the current SA -- we received the notification - * over it, so it's obviously still active. We temporarily need - * to remove the SA from the list to avoid an endless loop, - * but keep a reference so it won't disappear meanwhile. - */ - if (sa == msg->isakmp_sa) - { - sa_reference (sa); - sa_remove (sa); - reenter = 1; - continue; + u_int32_t spisz, nspis; + struct sockaddr *dst; + int reenter = 0; + u_int8_t *spis, proto; + struct sa *sa; + + switch (type) { + case ISAKMP_PAYLOAD_DELETE: + proto = GET_ISAKMP_DELETE_PROTO(payload->p); + nspis = GET_ISAKMP_DELETE_NSPIS(payload->p); + spisz = GET_ISAKMP_DELETE_SPI_SZ(payload->p); + + if (nspis == 0) { + LOG_DBG((LOG_SA, 60, "ipsec_handle_leftover_payload: message " + "specified zero SPIs, ignoring")); + return -1; + } + /* verify proper SPI size */ + if ((proto == ISAKMP_PROTO_ISAKMP && spisz != ISAKMP_HDR_COOKIES_LEN) + || (proto != ISAKMP_PROTO_ISAKMP && spisz != sizeof(u_int32_t))) { + log_print("ipsec_handle_leftover_payload: " + "invalid SPI size %d for proto %d in DELETE payload", + spisz, proto); + return -1; + } + spis = (u_int8_t *) malloc(nspis * spisz); + if (!spis) { + log_error("ipsec_handle_leftover_payload: malloc (%d) failed", + nspis * spisz); + return -1; + } + /* extract SPI and get dst address */ + memcpy(spis, payload->p + ISAKMP_DELETE_SPI_OFF, nspis * spisz); + msg->transport->vtbl->get_dst(msg->transport, &dst); + + ipsec_delete_spi_list(dst, proto, spis, nspis, "DELETE"); + + free(spis); + payload->flags |= PL_MARK; + return 0; + + case ISAKMP_PAYLOAD_NOTIFY: + switch (GET_ISAKMP_NOTIFY_MSG_TYPE(payload->p)) { + case IPSEC_NOTIFY_INITIAL_CONTACT: + /* + * Permit INITIAL-CONTACT if + * - this is not an AGGRESSIVE mode exchange + * - it is protected by an ISAKMP SA + * + * XXX Instead of the first condition above, we could permit this + * XXX only for phase 2. In the last packet of main-mode, this + * XXX payload, while encrypted, is not part of the hash digest. + * XXX As we currently send our own INITIAL-CONTACTs at this point, + * XXX this too would need to be changed. + */ + if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE) { + log_print("ipsec_handle_leftover_payload: got INITIAL-CONTACT " + "in AGGRESSIVE mode"); + return -1; + } + if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT) == 0) { + log_print("ipsec_handle_leftover_payload: got INITIAL-CONTACT " + "without ISAKMP SA"); + return -1; + } + /* + * Find out who is sending this and then delete every SA that is + * ready. Exchanges will timeout themselves and then the + * non-ready SAs will disappear too. + */ + msg->transport->vtbl->get_dst(msg->transport, &dst); + while ((sa = sa_lookup_by_peer(dst, sysdep_sa_len(dst))) != 0) { + /* + * Don't delete the current SA -- we received the + * notification over it, so it's obviously still + * active. We temporarily need to remove the SA + * from the list to avoid an endless loop, but + * keep a reference so it won't disappear meanwhile. + */ + if (sa == msg->isakmp_sa) { + sa_reference(sa); + sa_remove(sa); + reenter = 1; + continue; + } + LOG_DBG((LOG_SA, 30, + "ipsec_handle_leftover_payload: " + "INITIAL-CONTACT made us delete SA %p", + sa)); + sa_delete(sa, 0); + } + + if (reenter) { + sa_enter(msg->isakmp_sa); + sa_release(msg->isakmp_sa); + } + payload->flags |= PL_MARK; + return 0; } - - LOG_DBG ((LOG_SA, 30, - "ipsec_handle_leftover_payload: " - "INITIAL-CONTACT made us delete SA %p", - sa)); - sa_delete (sa, 0); - } - - if (reenter) - { - sa_enter (msg->isakmp_sa); - sa_release (msg->isakmp_sa); - } - payload->flags |= PL_MARK; - return 0; } - } - return -1; + return -1; } /* Return the encryption keylength in octets of the ESP protocol PROTO. */ int -ipsec_esp_enckeylength (struct proto *proto) +ipsec_esp_enckeylength(struct proto * proto) { - struct ipsec_proto *iproto = proto->data; - - /* Compute the keylength to use. */ - switch (proto->id) - { - case IPSEC_ESP_DES: - case IPSEC_ESP_DES_IV32: - case IPSEC_ESP_DES_IV64: - return 8; - case IPSEC_ESP_3DES: - return 24; - case IPSEC_ESP_CAST: - if (!iproto->keylen) - return 16; - return iproto->keylen / 8; - case IPSEC_ESP_AES: - case IPSEC_ESP_AES_128_CTR: - if (!iproto->keylen) - return 16; - /* Fallthrough */ - default: - return iproto->keylen / 8; - } + struct ipsec_proto *iproto = proto->data; + + /* Compute the keylength to use. */ + switch (proto->id) { + case IPSEC_ESP_DES: + case IPSEC_ESP_DES_IV32: + case IPSEC_ESP_DES_IV64: + return 8; + case IPSEC_ESP_3DES: + return 24; + case IPSEC_ESP_CAST: + if (!iproto->keylen) + return 16; + return iproto->keylen / 8; + case IPSEC_ESP_AES: + case IPSEC_ESP_AES_128_CTR: + if (!iproto->keylen) + return 16; + /* Fallthrough */ + default: + return iproto->keylen / 8; + } } /* Return the authentication keylength in octets of the ESP protocol PROTO. */ int -ipsec_esp_authkeylength (struct proto *proto) +ipsec_esp_authkeylength(struct proto * proto) { - struct ipsec_proto *iproto = proto->data; - - switch (iproto->auth) - { - case IPSEC_AUTH_HMAC_MD5: - return 16; - case IPSEC_AUTH_HMAC_SHA: - case IPSEC_AUTH_HMAC_RIPEMD: - return 20; - case IPSEC_AUTH_HMAC_SHA2_256: - return 32; - case IPSEC_AUTH_HMAC_SHA2_384: - return 48; - case IPSEC_AUTH_HMAC_SHA2_512: - return 64; - default: - return 0; - } + struct ipsec_proto *iproto = proto->data; + + switch (iproto->auth) { + case IPSEC_AUTH_HMAC_MD5: + return 16; + case IPSEC_AUTH_HMAC_SHA: + case IPSEC_AUTH_HMAC_RIPEMD: + return 20; + case IPSEC_AUTH_HMAC_SHA2_256: + return 32; + case IPSEC_AUTH_HMAC_SHA2_384: + return 48; + case IPSEC_AUTH_HMAC_SHA2_512: + return 64; + default: + return 0; + } } /* Return the authentication keylength in octets of the AH protocol PROTO. */ int -ipsec_ah_keylength (struct proto *proto) +ipsec_ah_keylength(struct proto * proto) { - switch (proto->id) - { - case IPSEC_AH_MD5: - return 16; - case IPSEC_AH_SHA: - case IPSEC_AH_RIPEMD: - return 20; - case IPSEC_AH_SHA2_256: - return 32; - case IPSEC_AH_SHA2_384: - return 48; - case IPSEC_AH_SHA2_512: - return 64; - default: - return -1; - } + switch (proto->id) { + case IPSEC_AH_MD5: + return 16; + case IPSEC_AH_SHA: + case IPSEC_AH_RIPEMD: + return 20; + case IPSEC_AH_SHA2_256: + return 32; + case IPSEC_AH_SHA2_384: + return 48; + case IPSEC_AH_SHA2_512: + return 64; + default: + return -1; + } } /* Return the total keymaterial length of the protocol PROTO. */ int -ipsec_keymat_length (struct proto *proto) +ipsec_keymat_length(struct proto * proto) { - switch (proto->proto) - { - case IPSEC_PROTO_IPSEC_ESP: - return ipsec_esp_enckeylength (proto) + ipsec_esp_authkeylength (proto); - case IPSEC_PROTO_IPSEC_AH: - return ipsec_ah_keylength (proto); - default: - return -1; - } + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_ESP: + return ipsec_esp_enckeylength(proto) + ipsec_esp_authkeylength(proto); + case IPSEC_PROTO_IPSEC_AH: + return ipsec_ah_keylength(proto); + default: + return -1; + } } /* @@ -1765,112 +1706,97 @@ ipsec_keymat_length (struct proto *proto) * Return 0 on success and -1 on failure. */ int -ipsec_get_id (char *section, int *id, struct sockaddr **addr, - struct sockaddr **mask, u_int8_t *tproto, u_int16_t *port) +ipsec_get_id(char *section, int *id, struct sockaddr ** addr, + struct sockaddr ** mask, u_int8_t * tproto, u_int16_t * port) { - char *type, *address, *netmask; - - type = conf_get_str (section, "ID-type"); - if (!type) - { - log_print ("ipsec_get_id: section %s has no \"ID-type\" tag", section); - return -1; - } - - *id = constant_value (ipsec_id_cst, type); - switch (*id) - { - case IPSEC_ID_IPV4_ADDR: - case IPSEC_ID_IPV6_ADDR: - address = conf_get_str (section, "Address"); - if (!address) - { - log_print ("ipsec_get_id: section %s has no \"Address\" tag", - section); - return -1; - } + char *type, *address, *netmask; - if (text2sockaddr (address, NULL, addr)) - { - log_print ("ipsec_get_id: invalid address %s in section %s", address, - section); - return -1; + type = conf_get_str(section, "ID-type"); + if (!type) { + log_print("ipsec_get_id: section %s has no \"ID-type\" tag", section); + return -1; } - - *tproto = conf_get_num (section, "Protocol", 0); - if (*tproto) - *port = conf_get_num (section, "Port", 0); - break; + *id = constant_value(ipsec_id_cst, type); + switch (*id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + address = conf_get_str(section, "Address"); + if (!address) { + log_print("ipsec_get_id: section %s has no \"Address\" tag", + section); + return -1; + } + if (text2sockaddr(address, NULL, addr)) { + log_print("ipsec_get_id: invalid address %s in section %s", address, + section); + return -1; + } + *tproto = conf_get_num(section, "Protocol", 0); + if (*tproto) + *port = conf_get_num(section, "Port", 0); + break; #ifdef notyet - case IPSEC_ID_FQDN: - return -1; + case IPSEC_ID_FQDN: + return -1; - case IPSEC_ID_USER_FQDN: - return -1; + case IPSEC_ID_USER_FQDN: + return -1; #endif - case IPSEC_ID_IPV4_ADDR_SUBNET: - case IPSEC_ID_IPV6_ADDR_SUBNET: - address = conf_get_str (section, "Network"); - if (!address) - { - log_print ("ipsec_get_id: section %s has no \"Network\" tag", - section); - return -1; - } - - if (text2sockaddr (address, NULL, addr)) - { - log_print ("ipsec_get_id: invalid section %s network %s", section, - address); - return -1; - } - - netmask = conf_get_str (section, "Netmask"); - if (!netmask) - { - log_print ("ipsec_get_id: section %s has no \"Netmask\" tag", - section); - return -1; - } - - if (text2sockaddr (netmask, NULL, mask)) - { - log_print ("ipsec_id_build: invalid section %s network %s", section, - netmask); - return -1; - } - - *tproto = conf_get_num (section, "Protocol", 0); - if (*tproto) - *port = conf_get_num (section, "Port", 0); - break; + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + address = conf_get_str(section, "Network"); + if (!address) { + log_print("ipsec_get_id: section %s has no \"Network\" tag", + section); + return -1; + } + if (text2sockaddr(address, NULL, addr)) { + log_print("ipsec_get_id: invalid section %s network %s", section, + address); + return -1; + } + netmask = conf_get_str(section, "Netmask"); + if (!netmask) { + log_print("ipsec_get_id: section %s has no \"Netmask\" tag", + section); + return -1; + } + if (text2sockaddr(netmask, NULL, mask)) { + log_print("ipsec_id_build: invalid section %s network %s", section, + netmask); + return -1; + } + *tproto = conf_get_num(section, "Protocol", 0); + if (*tproto) + *port = conf_get_num(section, "Port", 0); + break; #ifdef notyet - case IPSEC_ID_IPV4_RANGE: - return -1; + case IPSEC_ID_IPV4_RANGE: + return -1; - case IPSEC_ID_IPV6_RANGE: - return -1; + case IPSEC_ID_IPV6_RANGE: + return -1; - case IPSEC_ID_DER_ASN1_DN: - return -1; + case IPSEC_ID_DER_ASN1_DN: + return -1; - case IPSEC_ID_DER_ASN1_GN: - return -1; + case IPSEC_ID_DER_ASN1_GN: + return -1; - case IPSEC_ID_KEY_ID: - return -1; + case IPSEC_ID_KEY_ID: + return -1; #endif - default: - log_print ("ipsec_get_id: unknown ID type \"%s\" in section %s", type, - section); - return -1; - } + default: + log_print("ipsec_get_id: unknown ID type \"%s\" in section %s", type, + section); + return -1; + } - return 0; + return 0; } /* @@ -1878,102 +1804,99 @@ ipsec_get_id (char *section, int *id, struct sockaddr **addr, * we cannot fit the information in the supplied buffer. */ static void -ipsec_decode_id (char *buf, size_t size, u_int8_t *id, size_t id_len, - int isakmpform) +ipsec_decode_id(char *buf, size_t size, u_int8_t * id, size_t id_len, + int isakmpform) { - int id_type; - char *addr = 0, *mask = 0; - u_int32_t *idp; - - if (id) - { - if (!isakmpform) - { - /* Exchanges and SAs dont carry the IDs in ISAKMP form. */ - id -= ISAKMP_GEN_SZ; - id_len += ISAKMP_GEN_SZ; - } - - id_type = GET_ISAKMP_ID_TYPE (id); - idp = (u_int32_t *)(id + ISAKMP_ID_DATA_OFF); - switch (id_type) - { - case IPSEC_ID_IPV4_ADDR: - util_ntoa (&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); - snprintf (buf, size, "%08x: %s", - decode_32 (id + ISAKMP_ID_DATA_OFF), addr); - break; - - case IPSEC_ID_IPV4_ADDR_SUBNET: - util_ntoa (&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); - util_ntoa (&mask, AF_INET, id + ISAKMP_ID_DATA_OFF + 4); - snprintf (buf, size, "%08x/%08x: %s/%s", - decode_32 (id + ISAKMP_ID_DATA_OFF), - decode_32 (id + ISAKMP_ID_DATA_OFF + 4), addr, mask); - break; - - case IPSEC_ID_IPV6_ADDR: - util_ntoa (&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); - snprintf (buf, size, "%08x%08x%08x%08x: %s", *idp, *(idp + 1), - *(idp + 2), *(idp + 3), addr); - break; - - case IPSEC_ID_IPV6_ADDR_SUBNET: - util_ntoa (&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); - util_ntoa (&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF + - sizeof (struct in6_addr)); - snprintf (buf, size, "%08x%08x%08x%08x/%08x%08x%08x%08x: %s/%s", - *idp, *(idp + 1), *(idp + 2), *(idp + 3), *(idp + 4), - *(idp + 5), *(idp + 6), *(idp + 7), addr, mask); - break; - - case IPSEC_ID_FQDN: - case IPSEC_ID_USER_FQDN: - /* String is not NUL terminated, be careful */ - id_len -= ISAKMP_ID_DATA_OFF; - id_len = MIN (id_len, size - 1); - memcpy (buf, id + ISAKMP_ID_DATA_OFF, id_len); - buf[id_len] = '\0'; - break; + int id_type; + char *addr = 0, *mask = 0; + u_int32_t *idp; + + if (id) { + if (!isakmpform) { + /* + * Exchanges and SAs dont carry the IDs in ISAKMP + * form. + */ + id -= ISAKMP_GEN_SZ; + id_len += ISAKMP_GEN_SZ; + } + id_type = GET_ISAKMP_ID_TYPE(id); + idp = (u_int32_t *) (id + ISAKMP_ID_DATA_OFF); + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: + util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); + snprintf(buf, size, "%08x: %s", + decode_32(id + ISAKMP_ID_DATA_OFF), addr); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); + util_ntoa(&mask, AF_INET, id + ISAKMP_ID_DATA_OFF + 4); + snprintf(buf, size, "%08x/%08x: %s/%s", + decode_32(id + ISAKMP_ID_DATA_OFF), + decode_32(id + ISAKMP_ID_DATA_OFF + 4), addr, mask); + break; + + case IPSEC_ID_IPV6_ADDR: + util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + snprintf(buf, size, "%08x%08x%08x%08x: %s", *idp, *(idp + 1), + *(idp + 2), *(idp + 3), addr); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF + + sizeof(struct in6_addr)); + snprintf(buf, size, "%08x%08x%08x%08x/%08x%08x%08x%08x: %s/%s", + *idp, *(idp + 1), *(idp + 2), *(idp + 3), *(idp + 4), + *(idp + 5), *(idp + 6), *(idp + 7), addr, mask); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + /* String is not NUL terminated, be careful */ + id_len -= ISAKMP_ID_DATA_OFF; + id_len = MIN(id_len, size - 1); + memcpy(buf, id + ISAKMP_ID_DATA_OFF, id_len); + buf[id_len] = '\0'; + break; #ifdef USE_X509 - case IPSEC_ID_DER_ASN1_DN: - addr = x509_DN_string (id + ISAKMP_ID_DATA_OFF, - id_len - ISAKMP_ID_DATA_OFF); - if (!addr) - { - snprintf (buf, size, "unparsable ASN1 DN ID"); - return; - } - strlcpy (buf, addr, size); - break; + case IPSEC_ID_DER_ASN1_DN: + addr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, + id_len - ISAKMP_ID_DATA_OFF); + if (!addr) { + snprintf(buf, size, "unparsable ASN1 DN ID"); + return; + } + strlcpy(buf, addr, size); + break; #endif - default: - snprintf (buf, size, "<id type unknown: %x>", id_type); - break; - } - } - else - snprintf (buf, size, "<no ipsec id>"); - if (addr) - free (addr); - if (mask) - free (mask); + default: + snprintf(buf, size, "<id type unknown: %x>", id_type); + break; + } + } else + snprintf(buf, size, "<no ipsec id>"); + if (addr) + free(addr); + if (mask) + free(mask); } -char * -ipsec_decode_ids (char *fmt, u_int8_t *id1, size_t id1_len, - u_int8_t *id2, size_t id2_len, int isakmpform) +char * +ipsec_decode_ids(char *fmt, u_int8_t * id1, size_t id1_len, + u_int8_t * id2, size_t id2_len, int isakmpform) { - static char result[1024]; - char s_id1[256], s_id2[256]; + static char result[1024]; + char s_id1[256], s_id2[256]; - ipsec_decode_id (s_id1, sizeof s_id1, id1, id1_len, isakmpform); - ipsec_decode_id (s_id2, sizeof s_id2, id2, id2_len, isakmpform); + ipsec_decode_id(s_id1, sizeof s_id1, id1, id1_len, isakmpform); + ipsec_decode_id(s_id2, sizeof s_id2, id2, id2_len, isakmpform); - snprintf (result, sizeof result, fmt, s_id1, s_id2); - return result; + snprintf(result, sizeof result, fmt, s_id1, s_id2); + return result; } /* @@ -1981,75 +1904,69 @@ ipsec_decode_ids (char *fmt, u_int8_t *id1, size_t id1_len, * ISAKMP ID payload. Ths payload size should be stashed in SZ. * The caller is responsible for freeing the payload. */ -u_int8_t * -ipsec_build_id (char *section, size_t *sz) +u_int8_t * +ipsec_build_id(char *section, size_t * sz) { - struct sockaddr *addr, *mask; - u_int8_t *p; - int id, subnet = 0; - u_int8_t tproto = 0; - u_int16_t port = 0; - - if (ipsec_get_id (section, &id, &addr, &mask, &tproto, &port)) - return 0; - - if (id == IPSEC_ID_IPV4_ADDR_SUBNET || id == IPSEC_ID_IPV6_ADDR_SUBNET) - subnet = 1; - - *sz = ISAKMP_ID_SZ + sockaddr_addrlen (addr); - if (subnet) - *sz += sockaddr_addrlen (mask); - - p = malloc (*sz); - if (!p) - { - log_print ("ipsec_build_id: malloc(%lu) failed", (unsigned long)*sz); - return 0; - } - - SET_ISAKMP_ID_TYPE (p, id); - SET_ISAKMP_ID_DOI_DATA (p, (unsigned char *)"\000\000\000"); - - memcpy (p + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (addr), - sockaddr_addrlen (addr)); - if (subnet) - memcpy (p + ISAKMP_ID_DATA_OFF + sockaddr_addrlen (addr), - sockaddr_addrdata (mask), sockaddr_addrlen (mask)); - - SET_IPSEC_ID_PROTO (p + ISAKMP_ID_DOI_DATA_OFF, tproto); - SET_IPSEC_ID_PORT (p + ISAKMP_ID_DOI_DATA_OFF, port); - - return p; + struct sockaddr *addr, *mask; + u_int8_t *p; + int id, subnet = 0; + u_int8_t tproto = 0; + u_int16_t port = 0; + + if (ipsec_get_id(section, &id, &addr, &mask, &tproto, &port)) + return 0; + + if (id == IPSEC_ID_IPV4_ADDR_SUBNET || id == IPSEC_ID_IPV6_ADDR_SUBNET) + subnet = 1; + + *sz = ISAKMP_ID_SZ + sockaddr_addrlen(addr); + if (subnet) + *sz += sockaddr_addrlen(mask); + + p = malloc(*sz); + if (!p) { + log_print("ipsec_build_id: malloc(%lu) failed", (unsigned long) *sz); + return 0; + } + SET_ISAKMP_ID_TYPE(p, id); + SET_ISAKMP_ID_DOI_DATA(p, (unsigned char *) "\000\000\000"); + + memcpy(p + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(addr), + sockaddr_addrlen(addr)); + if (subnet) + memcpy(p + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(addr), + sockaddr_addrdata(mask), sockaddr_addrlen(mask)); + + SET_IPSEC_ID_PROTO(p + ISAKMP_ID_DOI_DATA_OFF, tproto); + SET_IPSEC_ID_PORT(p + ISAKMP_ID_DOI_DATA_OFF, port); + + return p; } /* * copy an ISAKMPD id */ int -ipsec_clone_id (u_int8_t **did, size_t *did_len, u_int8_t *id, size_t id_len) +ipsec_clone_id(u_int8_t ** did, size_t * did_len, u_int8_t * id, size_t id_len) { - if (*did) - free (*did); - - if (!id_len || !id) - { - *did = 0; - *did_len = 0; - return 0; - } - - *did = malloc (id_len); - if (!*did) - { - *did_len = 0; - log_error ("ipsec_clone_id: malloc(%lu) failed", (unsigned long)id_len); - return -1; - } - - *did_len = id_len; - memcpy (*did, id, id_len); - - return 0; + if (*did) + free(*did); + + if (!id_len || !id) { + *did = 0; + *did_len = 0; + return 0; + } + *did = malloc(id_len); + if (!*did) { + *did_len = 0; + log_error("ipsec_clone_id: malloc(%lu) failed", (unsigned long) id_len); + return -1; + } + *did_len = id_len; + memcpy(*did, id, id_len); + + return 0; } /* @@ -2058,13 +1975,13 @@ ipsec_clone_id (u_int8_t **did, size_t *did_len, u_int8_t *id, size_t id_len) * XXX I want to fix this later. */ void -ipsec_proto_init (struct proto *proto, char *section) +ipsec_proto_init(struct proto * proto, char *section) { - struct ipsec_proto *iproto = proto->data; + struct ipsec_proto *iproto = proto->data; - if (proto->sa->phase == 2 && section) - iproto->replay_window - = conf_get_num (section, "ReplayWindow", DEFAULT_REPLAY_WINDOW); + if (proto->sa->phase == 2 && section) + iproto->replay_window + = conf_get_num(section, "ReplayWindow", DEFAULT_REPLAY_WINDOW); } /* @@ -2072,34 +1989,31 @@ ipsec_proto_init (struct proto *proto, char *section) * the first contact we have made to our peer. */ int -ipsec_initial_contact (struct message *msg) +ipsec_initial_contact(struct message * msg) { - u_int8_t *buf; - - if (ipsec_contacted (msg)) - return 0; - - buf = malloc (ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); - if (!buf) - { - log_error ("ike_phase_1_initial_contact: malloc (%d) failed", - ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); - return -1; - } - SET_ISAKMP_NOTIFY_DOI (buf, IPSEC_DOI_IPSEC); - SET_ISAKMP_NOTIFY_PROTO (buf, ISAKMP_PROTO_ISAKMP); - SET_ISAKMP_NOTIFY_SPI_SZ (buf, ISAKMP_HDR_COOKIES_LEN); - SET_ISAKMP_NOTIFY_MSG_TYPE (buf, IPSEC_NOTIFY_INITIAL_CONTACT); - memcpy (buf + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, - ISAKMP_HDR_COOKIES_LEN); - if (message_add_payload (msg, ISAKMP_PAYLOAD_NOTIFY, buf, - ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN, 1)) - { - free (buf); - return -1; - } - - return ipsec_add_contact (msg); + u_int8_t *buf; + + if (ipsec_contacted(msg)) + return 0; + + buf = malloc(ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); + if (!buf) { + log_error("ike_phase_1_initial_contact: malloc (%d) failed", + ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); + return -1; + } + SET_ISAKMP_NOTIFY_DOI(buf, IPSEC_DOI_IPSEC); + SET_ISAKMP_NOTIFY_PROTO(buf, ISAKMP_PROTO_ISAKMP); + SET_ISAKMP_NOTIFY_SPI_SZ(buf, ISAKMP_HDR_COOKIES_LEN); + SET_ISAKMP_NOTIFY_MSG_TYPE(buf, IPSEC_NOTIFY_INITIAL_CONTACT); + memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, + ISAKMP_HDR_COOKIES_LEN); + if (message_add_payload(msg, ISAKMP_PAYLOAD_NOTIFY, buf, + ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN, 1)) { + free(buf); + return -1; + } + return ipsec_add_contact(msg); } /* @@ -2107,13 +2021,13 @@ ipsec_initial_contact (struct message *msg) * *A < *B, 0 if they are equal, and positive if *A is the largest of them. */ static int -addr_cmp (const void *a, const void *b) +addr_cmp(const void *a, const void *b) { - const struct contact *x = a, *y = b; - int minlen = MIN (x->len, y->len); - int rv = memcmp (x->addr, y->addr, minlen); + const struct contact *x = a, *y = b; + int minlen = MIN(x->len, y->len); + int rv = memcmp(x->addr, y->addr, minlen); - return rv ? rv : (x->len - y->len); + return rv ? rv : (x->len - y->len); } /* @@ -2123,297 +2037,283 @@ addr_cmp (const void *a, const void *b) * is unimportant, if this is to scale. */ static int -ipsec_add_contact (struct message *msg) +ipsec_add_contact(struct message * msg) { - struct contact *new_contacts; - struct sockaddr *dst, *addr; - int cnt; - - if (contact_cnt == contact_limit) - { - cnt = contact_limit ? 2 * contact_limit : 64; - new_contacts = realloc (contacts, cnt * sizeof contacts[0]); - if (!new_contacts) - { - log_error ("ipsec_add_contact: realloc (%p, %lu) failed", contacts, - cnt * (unsigned long)sizeof contacts[0]); - return -1; + struct contact *new_contacts; + struct sockaddr *dst, *addr; + int cnt; + + if (contact_cnt == contact_limit) { + cnt = contact_limit ? 2 * contact_limit : 64; + new_contacts = realloc(contacts, cnt * sizeof contacts[0]); + if (!new_contacts) { + log_error("ipsec_add_contact: realloc (%p, %lu) failed", contacts, + cnt * (unsigned long) sizeof contacts[0]); + return -1; + } + contact_limit = cnt; + contacts = new_contacts; } - contact_limit = cnt; - contacts = new_contacts; - } - msg->transport->vtbl->get_dst (msg->transport, &dst); - addr = malloc (sysdep_sa_len (dst)); - if (!addr) - { - log_error ("ipsec_add_contact: malloc (%d) failed", sysdep_sa_len (dst)); - return -1; - } - memcpy (addr, dst, sysdep_sa_len (dst)); - contacts[contact_cnt].addr = addr; - contacts[contact_cnt++].len = sysdep_sa_len (dst); - - /* - * XXX There are better algorithms for already mostly-sorted data like - * this, but only qsort is standard. I will someday do this inline. - */ - qsort (contacts, contact_cnt, sizeof *contacts, addr_cmp); - return 0; + msg->transport->vtbl->get_dst(msg->transport, &dst); + addr = malloc(sysdep_sa_len(dst)); + if (!addr) { + log_error("ipsec_add_contact: malloc (%d) failed", sysdep_sa_len(dst)); + return -1; + } + memcpy(addr, dst, sysdep_sa_len(dst)); + contacts[contact_cnt].addr = addr; + contacts[contact_cnt++].len = sysdep_sa_len(dst); + + /* + * XXX There are better algorithms for already mostly-sorted data like + * this, but only qsort is standard. I will someday do this inline. + */ + qsort(contacts, contact_cnt, sizeof *contacts, addr_cmp); + return 0; } /* Return true if the recipient of MSG has already been contacted. */ static int -ipsec_contacted (struct message *msg) +ipsec_contacted(struct message * msg) { - struct contact contact; - - msg->transport->vtbl->get_dst (msg->transport, &contact.addr); - contact.len = sysdep_sa_len (contact.addr); - return contacts - ? (bsearch (&contact, contacts, contact_cnt, sizeof *contacts, addr_cmp) - != 0) - : 0; + struct contact contact; + + msg->transport->vtbl->get_dst(msg->transport, &contact.addr); + contact.len = sysdep_sa_len(contact.addr); + return contacts + ? (bsearch(&contact, contacts, contact_cnt, sizeof *contacts, addr_cmp) + != 0) + : 0; } /* Add a HASH for to MSG. */ -u_int8_t * -ipsec_add_hash_payload (struct message *msg, size_t hashsize) +u_int8_t * +ipsec_add_hash_payload(struct message * msg, size_t hashsize) { - u_int8_t *buf; - - buf = malloc (ISAKMP_HASH_SZ + hashsize); - if (!buf) - { - log_error ("ipsec_add_hash_payload: malloc (%lu) failed", - ISAKMP_HASH_SZ + (unsigned long)hashsize); - return 0; - } - - if (message_add_payload (msg, ISAKMP_PAYLOAD_HASH, buf, - ISAKMP_HASH_SZ + hashsize, 1)) - { - free (buf); - return 0; - } - - return buf; + u_int8_t *buf; + + buf = malloc(ISAKMP_HASH_SZ + hashsize); + if (!buf) { + log_error("ipsec_add_hash_payload: malloc (%lu) failed", + ISAKMP_HASH_SZ + (unsigned long) hashsize); + return 0; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, + ISAKMP_HASH_SZ + hashsize, 1)) { + free(buf); + return 0; + } + return buf; } /* Fill in the HASH payload of MSG. */ int -ipsec_fill_in_hash (struct message *msg) +ipsec_fill_in_hash(struct message * msg) { - struct exchange *exchange = msg->exchange; - struct sa *isakmp_sa = msg->isakmp_sa; - struct ipsec_sa *isa = isakmp_sa->data; - struct hash *hash = hash_get (isa->hash); - struct prf *prf; - struct payload *payload; - u_int8_t *buf; - u_int32_t i; - char header[80]; - - /* If no SKEYID_a, we need not do anything. */ - if (!isa->skeyid_a) - return 0; - - payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]); - if (!payload) - { - log_print ("ipsec_fill_in_hash: no HASH payload found"); - return -1; - } - buf = payload->p; - - /* Allocate the prf and start calculating our HASH(1). */ - LOG_DBG_BUF ((LOG_MISC, 90, "ipsec_fill_in_hash: SKEYID_a", isa->skeyid_a, - isa->skeyid_len)); - prf = prf_alloc (isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); - if (!prf) - return -1; - - prf->Init (prf->prfctx); - LOG_DBG_BUF ((LOG_MISC, 90, "ipsec_fill_in_hash: message_id", - exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); - prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); - - /* Loop over all payloads after HASH(1). */ - for (i = 2; i < msg->iovlen; i++) - { - /* XXX Misleading payload type printouts. */ - snprintf (header, sizeof header, - "ipsec_fill_in_hash: payload %d after HASH(1)", i - 1); - LOG_DBG_BUF ((LOG_MISC, 90, header, msg->iov[i].iov_base, - msg->iov[i].iov_len)); - prf->Update (prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len); - } - prf->Final (buf + ISAKMP_HASH_DATA_OFF, prf->prfctx); - prf_free (prf); - LOG_DBG_BUF ((LOG_MISC, 80, "ipsec_fill_in_hash: HASH(1)", - buf + ISAKMP_HASH_DATA_OFF, hash->hashsize)); - - return 0; + struct exchange *exchange = msg->exchange; + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa = isakmp_sa->data; + struct hash *hash = hash_get(isa->hash); + struct prf *prf; + struct payload *payload; + u_int8_t *buf; + u_int32_t i; + char header[80]; + + /* If no SKEYID_a, we need not do anything. */ + if (!isa->skeyid_a) + return 0; + + payload = TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_HASH]); + if (!payload) { + log_print("ipsec_fill_in_hash: no HASH payload found"); + return -1; + } + buf = payload->p; + + /* Allocate the prf and start calculating our HASH(1). */ + LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: SKEYID_a", isa->skeyid_a, + isa->skeyid_len)); + prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); + if (!prf) + return -1; + + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: message_id", + exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); + prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); + + /* Loop over all payloads after HASH(1). */ + for (i = 2; i < msg->iovlen; i++) { + /* XXX Misleading payload type printouts. */ + snprintf(header, sizeof header, + "ipsec_fill_in_hash: payload %d after HASH(1)", i - 1); + LOG_DBG_BUF((LOG_MISC, 90, header, msg->iov[i].iov_base, + msg->iov[i].iov_len)); + prf->Update(prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len); + } + prf->Final(buf + ISAKMP_HASH_DATA_OFF, prf->prfctx); + prf_free(prf); + LOG_DBG_BUF((LOG_MISC, 80, "ipsec_fill_in_hash: HASH(1)", + buf + ISAKMP_HASH_DATA_OFF, hash->hashsize)); + + return 0; } /* Add a HASH payload to MSG, if we have an ISAKMP SA we're protected by. */ static int -ipsec_informational_pre_hook (struct message *msg) +ipsec_informational_pre_hook(struct message * msg) { - struct sa *isakmp_sa = msg->isakmp_sa; - struct ipsec_sa *isa; - struct hash *hash; - - if (!isakmp_sa) - return 0; - isa = isakmp_sa->data; - hash = hash_get (isa->hash); - return ipsec_add_hash_payload (msg, hash->hashsize) == 0; + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa; + struct hash *hash; + + if (!isakmp_sa) + return 0; + isa = isakmp_sa->data; + hash = hash_get(isa->hash); + return ipsec_add_hash_payload(msg, hash->hashsize) == 0; } /* * Fill in the HASH payload in MSG, if we have an ISAKMP SA we're protected by. */ static int -ipsec_informational_post_hook (struct message *msg) +ipsec_informational_post_hook(struct message * msg) { - if (!msg->isakmp_sa) - return 0; - return ipsec_fill_in_hash (msg); + if (!msg->isakmp_sa) + return 0; + return ipsec_fill_in_hash(msg); } ssize_t -ipsec_id_size (char *section, u_int8_t *id) +ipsec_id_size(char *section, u_int8_t * id) { - char *type, *data; - - type = conf_get_str (section, "ID-type"); - if (!type) - { - log_print ("ipsec_id_size: section %s has no \"ID-type\" tag", section); - return -1; - } - - *id = constant_value (ipsec_id_cst, type); - switch (*id) - { - case IPSEC_ID_IPV4_ADDR: - return sizeof (struct in_addr); - case IPSEC_ID_IPV4_ADDR_SUBNET: - return 2 * sizeof (struct in_addr); - case IPSEC_ID_IPV6_ADDR: - return sizeof (struct in6_addr); - case IPSEC_ID_IPV6_ADDR_SUBNET: - return 2 * sizeof (struct in6_addr); - case IPSEC_ID_FQDN: - case IPSEC_ID_USER_FQDN: - case IPSEC_ID_KEY_ID: - case IPSEC_ID_DER_ASN1_DN: - case IPSEC_ID_DER_ASN1_GN: - data = conf_get_str (section, "Name"); - if (!data) - { - log_print ("ipsec_id_size: section %s has no \"Name\" tag", section); - return -1; + char *type, *data; + + type = conf_get_str(section, "ID-type"); + if (!type) { + log_print("ipsec_id_size: section %s has no \"ID-type\" tag", section); + return -1; } - return strlen (data); - } - log_print ("ipsec_id_size: unrecognized/unsupported ID-type %d (%s)", - *id, type); - return -1; + *id = constant_value(ipsec_id_cst, type); + switch (*id) { + case IPSEC_ID_IPV4_ADDR: + return sizeof(struct in_addr); + case IPSEC_ID_IPV4_ADDR_SUBNET: + return 2 * sizeof(struct in_addr); + case IPSEC_ID_IPV6_ADDR: + return sizeof(struct in6_addr); + case IPSEC_ID_IPV6_ADDR_SUBNET: + return 2 * sizeof(struct in6_addr); + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + case IPSEC_ID_KEY_ID: + case IPSEC_ID_DER_ASN1_DN: + case IPSEC_ID_DER_ASN1_GN: + data = conf_get_str(section, "Name"); + if (!data) { + log_print("ipsec_id_size: section %s has no \"Name\" tag", section); + return -1; + } + return strlen(data); + } + log_print("ipsec_id_size: unrecognized/unsupported ID-type %d (%s)", + *id, type); + return -1; } /* * Generate a string version of the ID. */ -char * -ipsec_id_string (u_int8_t *id, size_t id_len) +char * +ipsec_id_string(u_int8_t * id, size_t id_len) { - char *buf = 0; - char *addrstr = 0; - size_t len, size; - - /* - * XXX Real ugly way of making the offsets correct. Be aware that id now - * will point before the actual buffer and cannot be dereferenced without - * an offset larger than or equal to ISAKM_GEN_SZ. - */ - id -= ISAKMP_GEN_SZ; - - /* This is the actual length of the ID data field. */ - id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; - - /* - * Conservative allocation. - * XXX I think the ASN1 DN case can be thought through to give a better - * estimate. - */ - size = MAX (sizeof "ipv6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - sizeof "asn1_dn/" + id_len - ISAKMP_ID_DATA_OFF); - buf = malloc (size); - if (!buf) - /* XXX Log? */ - goto fail; - - switch (GET_ISAKMP_ID_TYPE (id)) - { - case IPSEC_ID_IPV4_ADDR: - if (id_len < sizeof (struct in_addr)) - goto fail; - util_ntoa (&addrstr, AF_INET, id + ISAKMP_ID_DATA_OFF); - if (!addrstr) - goto fail; - snprintf (buf, size, "ipv4/%s", addrstr); - break; - - case IPSEC_ID_IPV6_ADDR: - if (id_len < sizeof (struct in6_addr)) - goto fail; - util_ntoa (&addrstr, AF_INET6, id + ISAKMP_ID_DATA_OFF); - if (!addrstr) - goto fail; - snprintf (buf, size, "ipv6/%s", addrstr); - break; - - case IPSEC_ID_FQDN: - case IPSEC_ID_USER_FQDN: - strlcpy (buf, - GET_ISAKMP_ID_TYPE (id) == IPSEC_ID_FQDN ? "fqdn/" : "ufqdn/", - size); - len = strlen (buf); - - memcpy (buf + len, id + ISAKMP_ID_DATA_OFF, id_len); - *(buf + len + id_len) = '\0'; - break; + char *buf = 0; + char *addrstr = 0; + size_t len, size; + + /* + * XXX Real ugly way of making the offsets correct. Be aware that id now + * will point before the actual buffer and cannot be dereferenced without + * an offset larger than or equal to ISAKM_GEN_SZ. + */ + id -= ISAKMP_GEN_SZ; + + /* This is the actual length of the ID data field. */ + id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; + + /* + * Conservative allocation. + * XXX I think the ASN1 DN case can be thought through to give a better + * estimate. + */ + size = MAX(sizeof "ipv6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + sizeof "asn1_dn/" + id_len - ISAKMP_ID_DATA_OFF); + buf = malloc(size); + if (!buf) + /* XXX Log? */ + goto fail; + + switch (GET_ISAKMP_ID_TYPE(id)) { + case IPSEC_ID_IPV4_ADDR: + if (id_len < sizeof(struct in_addr)) + goto fail; + util_ntoa(&addrstr, AF_INET, id + ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + snprintf(buf, size, "ipv4/%s", addrstr); + break; + + case IPSEC_ID_IPV6_ADDR: + if (id_len < sizeof(struct in6_addr)) + goto fail; + util_ntoa(&addrstr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + snprintf(buf, size, "ipv6/%s", addrstr); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + strlcpy(buf, + GET_ISAKMP_ID_TYPE(id) == IPSEC_ID_FQDN ? "fqdn/" : "ufqdn/", + size); + len = strlen(buf); + + memcpy(buf + len, id + ISAKMP_ID_DATA_OFF, id_len); + *(buf + len + id_len) = '\0'; + break; #ifdef USE_X509 - case IPSEC_ID_DER_ASN1_DN: - strlcpy (buf, "asn1_dn/", size); - len = strlen (buf); - addrstr = x509_DN_string (id + ISAKMP_ID_DATA_OFF, - id_len - ISAKMP_ID_DATA_OFF); - if (!addrstr) - goto fail; - if (size < len + strlen (addrstr) + 1) - goto fail; - strlcpy (buf + len, addrstr, size - len); - break; + case IPSEC_ID_DER_ASN1_DN: + strlcpy(buf, "asn1_dn/", size); + len = strlen(buf); + addrstr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, + id_len - ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + if (size < len + strlen(addrstr) + 1) + goto fail; + strlcpy(buf + len, addrstr, size - len); + break; #endif - default: - /* Unknown type. */ - LOG_DBG ((LOG_MISC, 10, "ipsec_id_string: unknown identity type %d\n", - GET_ISAKMP_ID_TYPE (id))); - goto fail; - } - - if (addrstr) - free (addrstr); - return buf; - - fail: - if (buf) - free (buf); - if (addrstr) - free (addrstr); - return 0; + default: + /* Unknown type. */ + LOG_DBG((LOG_MISC, 10, "ipsec_id_string: unknown identity type %d\n", + GET_ISAKMP_ID_TYPE(id))); + goto fail; + } + + if (addrstr) + free(addrstr); + return buf; + +fail: + if (buf) + free(buf); + if (addrstr) + free(addrstr); + return 0; } |