diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2016-07-16 15:19:53 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2016-07-16 15:19:53 +0200 |
commit | bf372706c469764d59e9f29c39e3ecbebd72b8d2 (patch) | |
tree | 0f0e296e2d50e4a7faf99ae6fa428d2681e81ea1 /src/libcharon/config | |
parent | 518dd33c94e041db0444c7d1f33da363bb8e3faf (diff) | |
download | vyos-strongswan-bf372706c469764d59e9f29c39e3ecbebd72b8d2.tar.gz vyos-strongswan-bf372706c469764d59e9f29c39e3ecbebd72b8d2.zip |
Imported Upstream version 5.5.0
Diffstat (limited to 'src/libcharon/config')
-rw-r--r-- | src/libcharon/config/child_cfg.c | 172 | ||||
-rw-r--r-- | src/libcharon/config/child_cfg.h | 116 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.c | 87 | ||||
-rw-r--r-- | src/libcharon/config/ike_cfg.h | 19 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.c | 89 | ||||
-rw-r--r-- | src/libcharon/config/peer_cfg.h | 97 | ||||
-rw-r--r-- | src/libcharon/config/proposal.c | 66 | ||||
-rw-r--r-- | src/libcharon/config/proposal.h | 10 |
8 files changed, 372 insertions, 284 deletions
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 3d3c7419b..76d7f2c58 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -1,8 +1,9 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2016 Andreas Steffen + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -110,12 +111,12 @@ struct private_child_cfg_t { /** * Inactivity timeout */ - u_int32_t inactivity; + uint32_t inactivity; /** * Reqid to install CHILD_SA with */ - u_int32_t reqid; + uint32_t reqid; /** * Optional mark to install inbound CHILD_SA with @@ -130,7 +131,17 @@ struct private_child_cfg_t { /** * Traffic Flow Confidentiality padding, if enabled */ - u_int32_t tfc; + uint32_t tfc; + + /** + * Optional manually-set IPsec policy priorities + */ + uint32_t manual_prio; + + /** + * Optional restriction of IPsec policy to a given network interface + */ + char *interface; /** * set up IPsec transport SA in MIPv6 proxy mode @@ -145,7 +156,7 @@ struct private_child_cfg_t { /** * anti-replay window size */ - u_int32_t replay_window; + uint32_t replay_window; }; METHOD(child_cfg_t, get_name, char*, @@ -200,25 +211,40 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*, METHOD(child_cfg_t, select_proposal, proposal_t*, private_child_cfg_t*this, linked_list_t *proposals, bool strip_dh, - bool private) + bool private, bool prefer_self) { - enumerator_t *stored_enum, *supplied_enum; - proposal_t *stored, *supplied, *selected = NULL; + enumerator_t *prefer_enum, *match_enum; + proposal_t *proposal, *match, *selected = NULL; - stored_enum = this->proposals->create_enumerator(this->proposals); - supplied_enum = proposals->create_enumerator(proposals); + if (prefer_self) + { + prefer_enum = this->proposals->create_enumerator(this->proposals); + match_enum = proposals->create_enumerator(proposals); + } + else + { + prefer_enum = proposals->create_enumerator(proposals); + match_enum = this->proposals->create_enumerator(this->proposals); + } - /* compare all stored proposals with all supplied. Stored ones are preferred. */ - while (stored_enum->enumerate(stored_enum, &stored)) + while (prefer_enum->enumerate(prefer_enum, &proposal)) { - stored = stored->clone(stored); - while (supplied_enum->enumerate(supplied_enum, &supplied)) + proposal = proposal->clone(proposal); + if (prefer_self) + { + proposals->reset_enumerator(proposals, match_enum); + } + else + { + this->proposals->reset_enumerator(this->proposals, match_enum); + } + while (match_enum->enumerate(match_enum, &match)) { if (strip_dh) { - stored->strip_dh(stored, MODP_NONE); + proposal->strip_dh(proposal, MODP_NONE); } - selected = stored->select(stored, supplied, private); + selected = proposal->select(proposal, match, private); if (selected) { DBG2(DBG_CFG, "received proposals: %#P", proposals); @@ -227,17 +253,15 @@ METHOD(child_cfg_t, select_proposal, proposal_t*, break; } } - stored->destroy(stored); + proposal->destroy(proposal); if (selected) { break; } - supplied_enum->destroy(supplied_enum); - supplied_enum = proposals->create_enumerator(proposals); } - stored_enum->destroy(stored_enum); - supplied_enum->destroy(supplied_enum); - if (selected == NULL) + prefer_enum->destroy(prefer_enum); + match_enum->destroy(match_enum); + if (!selected) { DBG1(DBG_CFG, "received proposals: %#P", proposals); DBG1(DBG_CFG, "configured proposals: %#P", this->proposals); @@ -405,7 +429,7 @@ METHOD(child_cfg_t, get_hostaccess, bool, * Note: The distribution of random values is not perfect, but it * should get the job done. */ -static u_int64_t apply_jitter(u_int64_t rekey, u_int64_t jitter) +static uint64_t apply_jitter(uint64_t rekey, uint64_t jitter) { if (jitter == 0) { @@ -417,10 +441,14 @@ static u_int64_t apply_jitter(u_int64_t rekey, u_int64_t jitter) #define APPLY_JITTER(l) l.rekey = apply_jitter(l.rekey, l.jitter) METHOD(child_cfg_t, get_lifetime, lifetime_cfg_t*, - private_child_cfg_t *this) + private_child_cfg_t *this, bool jitter) { lifetime_cfg_t *lft = malloc_thing(lifetime_cfg_t); memcpy(lft, &this->lifetime, sizeof(lifetime_cfg_t)); + if (!jitter) + { + lft->time.jitter = lft->bytes.jitter = lft->packets.jitter = 0; + } APPLY_JITTER(lft->time); APPLY_JITTER(lft->bytes); APPLY_JITTER(lft->packets); @@ -456,7 +484,7 @@ METHOD(child_cfg_t, get_dh_group, diffie_hellman_group_t, { enumerator_t *enumerator; proposal_t *proposal; - u_int16_t dh_group = MODP_NONE; + uint16_t dh_group = MODP_NONE; enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, &proposal)) @@ -476,13 +504,13 @@ METHOD(child_cfg_t, use_ipcomp, bool, return this->use_ipcomp; } -METHOD(child_cfg_t, get_inactivity, u_int32_t, +METHOD(child_cfg_t, get_inactivity, uint32_t, private_child_cfg_t *this) { return this->inactivity; } -METHOD(child_cfg_t, get_reqid, u_int32_t, +METHOD(child_cfg_t, get_reqid, uint32_t, private_child_cfg_t *this) { return this->reqid; @@ -494,29 +522,34 @@ METHOD(child_cfg_t, get_mark, mark_t, return inbound ? this->mark_in : this->mark_out; } -METHOD(child_cfg_t, get_tfc, u_int32_t, +METHOD(child_cfg_t, get_tfc, uint32_t, private_child_cfg_t *this) { return this->tfc; } -METHOD(child_cfg_t, get_replay_window, u_int32_t, +METHOD(child_cfg_t, get_manual_prio, uint32_t, private_child_cfg_t *this) { - return this->replay_window; + return this->manual_prio; } -METHOD(child_cfg_t, set_replay_window, void, - private_child_cfg_t *this, u_int32_t replay_window) +METHOD(child_cfg_t, get_interface, char*, + private_child_cfg_t *this) { - this->replay_window = replay_window; + return this->interface; +} + +METHOD(child_cfg_t, get_replay_window, uint32_t, + private_child_cfg_t *this) +{ + return this->replay_window; } -METHOD(child_cfg_t, set_mipv6_options, void, - private_child_cfg_t *this, bool proxy_mode, bool install_policy) +METHOD(child_cfg_t, set_replay_window, void, + private_child_cfg_t *this, uint32_t replay_window) { - this->proxy_mode = proxy_mode; - this->install_policy = install_policy; + this->replay_window = replay_window; } METHOD(child_cfg_t, use_proxy_mode, bool, @@ -532,7 +565,7 @@ METHOD(child_cfg_t, install_policy, bool, } #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; }) -#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) +#define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); }) METHOD(child_cfg_t, equals, bool, private_child_cfg_t *this, child_cfg_t *other_pub) @@ -576,10 +609,12 @@ METHOD(child_cfg_t, equals, bool, this->mark_out.value == other->mark_out.value && this->mark_out.mask == other->mark_out.mask && this->tfc == other->tfc && + this->manual_prio == other->manual_prio && this->replay_window == other->replay_window && this->proxy_mode == other->proxy_mode && this->install_policy == other->install_policy && - streq(this->updown, other->updown); + streq(this->updown, other->updown) && + streq(this->interface, other->interface); } METHOD(child_cfg_t, get_ref, child_cfg_t*, @@ -597,10 +632,8 @@ METHOD(child_cfg_t, destroy, void, this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy)); this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy)); - if (this->updown) - { - free(this->updown); - } + free(this->updown); + free(this->interface); free(this->name); free(this); } @@ -609,12 +642,7 @@ METHOD(child_cfg_t, destroy, void, /* * Described in header-file */ -child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, - char *updown, bool hostaccess, - ipsec_mode_t mode, action_t start_action, - action_t dpd_action, action_t close_action, - bool ipcomp, u_int32_t inactivity, u_int32_t reqid, - mark_t *mark_in, mark_t *mark_out, u_int32_t tfc) +child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) { private_child_cfg_t *this; @@ -634,12 +662,13 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, .get_close_action = _get_close_action, .get_lifetime = _get_lifetime, .get_dh_group = _get_dh_group, - .set_mipv6_options = _set_mipv6_options, .use_ipcomp = _use_ipcomp, .get_inactivity = _get_inactivity, .get_reqid = _get_reqid, .get_mark = _get_mark, .get_tfc = _get_tfc, + .get_manual_prio = _get_manual_prio, + .get_interface = _get_interface, .get_replay_window = _get_replay_window, .set_replay_window = _set_replay_window, .use_proxy_mode = _use_proxy_mode, @@ -649,35 +678,30 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, .destroy = _destroy, }, .name = strdup(name), - .updown = strdupnull(updown), - .hostaccess = hostaccess, - .mode = mode, - .start_action = start_action, - .dpd_action = dpd_action, - .close_action = close_action, - .use_ipcomp = ipcomp, - .inactivity = inactivity, - .reqid = reqid, - .proxy_mode = FALSE, - .install_policy = TRUE, + .updown = strdupnull(data->updown), + .hostaccess = data->hostaccess, + .reqid = data->reqid, + .mode = data->mode, + .proxy_mode = data->proxy_mode, + .start_action = data->start_action, + .dpd_action = data->dpd_action, + .close_action = data->close_action, + .mark_in = data->mark_in, + .mark_out = data->mark_out, + .lifetime = data->lifetime, + .inactivity = data->inactivity, + .use_ipcomp = data->ipcomp, + .tfc = data->tfc, + .manual_prio = data->priority, + .interface = strdupnull(data->interface), + .install_policy = !data->suppress_policies, .refcount = 1, .proposals = linked_list_create(), .my_ts = linked_list_create(), .other_ts = linked_list_create(), - .tfc = tfc, .replay_window = lib->settings->get_int(lib->settings, - "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns), + "%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns), ); - if (mark_in) - { - this->mark_in = *mark_in; - } - if (mark_out) - { - this->mark_out = *mark_out; - } - memcpy(&this->lifetime, lifetime, sizeof(lifetime_cfg_t)); - return &this->public; } diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 22641f77e..e736b2737 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -1,8 +1,9 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2016 Andreas Steffen + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,6 +26,7 @@ typedef enum action_t action_t; typedef struct child_cfg_t child_cfg_t; +typedef struct child_cfg_create_t child_cfg_create_t; #include <library.h> #include <selectors/traffic_selector.h> @@ -98,10 +100,12 @@ struct child_cfg_t { * @param proposals list from which proposals are selected * @param strip_dh TRUE strip out diffie hellman groups * @param private accept algorithms from a private range + * @param prefer_self whether to prefer configured or supplied proposals * @return selected proposal, or NULL if nothing matches */ proposal_t* (*select_proposal)(child_cfg_t*this, linked_list_t *proposals, - bool strip_dh, bool private); + bool strip_dh, bool private, + bool prefer_self); /** * Add a traffic selector to the config. @@ -155,9 +159,10 @@ struct child_cfg_t { * The rekey limits automatically contain a jitter to avoid simultaneous * rekeying. These values will change with each call to this function. * + * @param jitter subtract jitter value to randomize lifetimes * @return lifetime_cfg_t (has to be freed) */ - lifetime_cfg_t* (*get_lifetime) (child_cfg_t *this); + lifetime_cfg_t* (*get_lifetime) (child_cfg_t *this, bool jitter); /** * Get the mode to use for the CHILD_SA. @@ -210,14 +215,14 @@ struct child_cfg_t { * * @return inactivity timeout in s */ - u_int32_t (*get_inactivity)(child_cfg_t *this); + uint32_t (*get_inactivity)(child_cfg_t *this); /** * Specific reqid to use for CHILD_SA. * * @return reqid */ - u_int32_t (*get_reqid)(child_cfg_t *this); + uint32_t (*get_reqid)(child_cfg_t *this); /** * Optional mark for CHILD_SA. @@ -232,30 +237,35 @@ struct child_cfg_t { * * @return TFC padding, 0 to disable, -1 for MTU */ - u_int32_t (*get_tfc)(child_cfg_t *this); + uint32_t (*get_tfc)(child_cfg_t *this); /** - * Get anti-replay window size + * Get optional manually-set IPsec policy priority * - * @return anti-replay window size + * @return manually-set IPsec policy priority (automatic if 0) */ - u_int32_t (*get_replay_window)(child_cfg_t *this); + uint32_t (*get_manual_prio)(child_cfg_t *this); /** - * Set anti-replay window size + * Get optional network interface restricting IPsec policy * - * @param window anti-replay window size + * @return network interface) */ - void (*set_replay_window)(child_cfg_t *this, u_int32_t window); + char* (*get_interface)(child_cfg_t *this); /** - * Sets two options needed for Mobile IPv6 interoperability. + * Get anti-replay window size * - * @param proxy_mode use IPsec transport proxy mode (default FALSE) - * @param install_policy install IPsec kernel policies (default TRUE) + * @return anti-replay window size */ - void (*set_mipv6_options)(child_cfg_t *this, bool proxy_mode, - bool install_policy); + uint32_t (*get_replay_window)(child_cfg_t *this); + + /** + * Set anti-replay window size + * + * @param window anti-replay window size + */ + void (*set_replay_window)(child_cfg_t *this, uint32_t window); /** * Check whether IPsec transport SA should be set up in proxy mode. @@ -297,38 +307,56 @@ struct child_cfg_t { void (*destroy) (child_cfg_t *this); }; + +/** + * Data passed to the constructor of a child_cfg_t object. + */ +struct child_cfg_create_t { + /** Specific reqid to use for CHILD_SA, 0 for auto assignment */ + uint32_t reqid; + /** Optional inbound mark */ + mark_t mark_in; + /** Optional outbound mark */ + mark_t mark_out; + /** Mode to propose for CHILD_SA */ + ipsec_mode_t mode; + /** Use IPsec transport proxy mode */ + bool proxy_mode; + /** Use IPComp, if peer supports it */ + bool ipcomp; + /** TFC padding size, 0 to disable, -1 to pad to PMTU */ + uint32_t tfc; + /** Optional manually-set IPsec policy priority */ + uint32_t priority; + /** Optional network interface restricting IPsec policy (cloned) */ + char *interface; + /** lifetime_cfg_t for this child_cfg */ + lifetime_cfg_t lifetime; + /** Inactivity timeout in s before closing a CHILD_SA */ + uint32_t inactivity; + /** Start action */ + action_t start_action; + /** DPD action */ + action_t dpd_action; + /** Close action */ + action_t close_action; + /** updown script to execute on up/down event (cloned) */ + char *updown; + /** TRUE to allow access to the local host */ + bool hostaccess; + /** Don't install IPsec policies */ + bool suppress_policies; +}; + /** * Create a configuration template for CHILD_SA setup. * - * The "name" string gets cloned. - * - * The lifetime_cfg_t object gets cloned. - * To prevent two peers to start rekeying at the same time, a jitter may be - * specified. Rekeying of an SA starts at (x.rekey - random(0, x.jitter)). - * * After a call to create, a reference is obtained (refcount = 1). * - * @param name name of the child_cfg - * @param lifetime lifetime_cfg_t for this child_cfg - * @param updown updown script to execute on up/down event - * @param hostaccess TRUE to allow access to the local host - * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET - * @param start_action start action - * @param dpd_action DPD action - * @param close_action close action - * @param ipcomp use IPComp, if peer supports it - * @param inactivity inactivity timeout in s before closing a CHILD_SA - * @param reqid specific reqid to use for CHILD_SA, 0 for auto assign - * @param mark_in optional inbound mark (can be NULL) - * @param mark_out optional outbound mark (can be NULL) - * @param tfc TFC padding size, 0 to disable, -1 to pad to PMTU + * @param name name of the child_cfg (cloned) + * @param data data for this child_cfg * @return child_cfg_t object */ -child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime, - char *updown, bool hostaccess, - ipsec_mode_t mode, action_t start_action, - action_t dpd_action, action_t close_action, - bool ipcomp, u_int32_t inactivity, u_int32_t reqid, - mark_t *mark_in, mark_t *mark_out, u_int32_t tfc); +child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data); #endif /** CHILD_CFG_H_ @}*/ diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index a720e1493..7d52ac88f 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Tobias Brunner + * Copyright (C) 2012-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -83,12 +83,12 @@ struct private_ike_cfg_t { /** * our source port */ - u_int16_t my_port; + uint16_t my_port; /** * destination port */ - u_int16_t other_port; + uint16_t other_port; /** * should we send a certificate request? @@ -108,7 +108,7 @@ struct private_ike_cfg_t { /** * DSCP value to use on sent IKE packets */ - u_int8_t dscp; + uint8_t dscp; /** * List of proposals to use @@ -143,7 +143,7 @@ METHOD(ike_cfg_t, fragmentation, fragmentation_t, /** * Common function for resolve_me/other */ -static host_t* resolve(linked_list_t *hosts, int family, u_int16_t port) +static host_t* resolve(linked_list_t *hosts, int family, uint16_t port) { enumerator_t *enumerator; host_t *host = NULL; @@ -192,7 +192,7 @@ static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand) traffic_selector_t *ts; char *str; host_t *host; - u_int8_t mask; + uint8_t mask; u_int quality = 0; /* try single hosts first */ @@ -261,19 +261,19 @@ METHOD(ike_cfg_t, get_other_addr, char*, return this->other; } -METHOD(ike_cfg_t, get_my_port, u_int16_t, +METHOD(ike_cfg_t, get_my_port, uint16_t, private_ike_cfg_t *this) { return this->my_port; } -METHOD(ike_cfg_t, get_other_port, u_int16_t, +METHOD(ike_cfg_t, get_other_port, uint16_t, private_ike_cfg_t *this) { return this->other_port; } -METHOD(ike_cfg_t, get_dscp, u_int8_t, +METHOD(ike_cfg_t, get_dscp, uint8_t, private_ike_cfg_t *this) { return this->dscp; @@ -310,42 +310,57 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*, } METHOD(ike_cfg_t, select_proposal, proposal_t*, - private_ike_cfg_t *this, linked_list_t *proposals, bool private) + private_ike_cfg_t *this, linked_list_t *proposals, bool private, + bool prefer_self) { - enumerator_t *stored_enum, *supplied_enum; - proposal_t *stored, *supplied, *selected; + enumerator_t *prefer_enum, *match_enum; + proposal_t *proposal, *match, *selected = NULL; - stored_enum = this->proposals->create_enumerator(this->proposals); - supplied_enum = proposals->create_enumerator(proposals); - - - /* compare all stored proposals with all supplied. Stored ones are preferred.*/ - while (stored_enum->enumerate(stored_enum, (void**)&stored)) + if (prefer_self) + { + prefer_enum = this->proposals->create_enumerator(this->proposals); + match_enum = proposals->create_enumerator(proposals); + } + else { - proposals->reset_enumerator(proposals, supplied_enum); + prefer_enum = proposals->create_enumerator(proposals); + match_enum = this->proposals->create_enumerator(this->proposals); + } - while (supplied_enum->enumerate(supplied_enum, (void**)&supplied)) + while (prefer_enum->enumerate(prefer_enum, (void**)&proposal)) + { + if (prefer_self) + { + proposals->reset_enumerator(proposals, match_enum); + } + else { - selected = stored->select(stored, supplied, private); + this->proposals->reset_enumerator(this->proposals, match_enum); + } + while (match_enum->enumerate(match_enum, (void**)&match)) + { + selected = proposal->select(proposal, match, private); if (selected) { - /* they match, return */ - stored_enum->destroy(stored_enum); - supplied_enum->destroy(supplied_enum); DBG2(DBG_CFG, "received proposals: %#P", proposals); DBG2(DBG_CFG, "configured proposals: %#P", this->proposals); DBG2(DBG_CFG, "selected proposal: %P", selected); - return selected; + break; } } + if (selected) + { + break; + } } - /* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */ - stored_enum->destroy(stored_enum); - supplied_enum->destroy(supplied_enum); - DBG1(DBG_CFG, "received proposals: %#P", proposals); - DBG1(DBG_CFG, "configured proposals: %#P", this->proposals); - - return NULL; + prefer_enum->destroy(prefer_enum); + match_enum->destroy(match_enum); + if (!selected) + { + DBG1(DBG_CFG, "received proposals: %#P", proposals); + DBG1(DBG_CFG, "configured proposals: %#P", this->proposals); + } + return selected; } METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t, @@ -353,7 +368,7 @@ METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t, { enumerator_t *enumerator; proposal_t *proposal; - u_int16_t dh_group = MODP_NONE; + uint16_t dh_group = MODP_NONE; enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, &proposal)) @@ -545,9 +560,9 @@ int ike_cfg_get_family(ike_cfg_t *cfg, bool local) * Described in header. */ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, - char *me, u_int16_t my_port, - char *other, u_int16_t other_port, - fragmentation_t fragmentation, u_int8_t dscp) + char *me, uint16_t my_port, + char *other, uint16_t other_port, + fragmentation_t fragmentation, uint8_t dscp) { private_ike_cfg_t *this; diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index a72960f4f..5655a3497 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Tobias Brunner + * Copyright (C) 2012-2016 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -128,21 +128,21 @@ struct ike_cfg_t { * * @return source address port, host order */ - u_int16_t (*get_my_port)(ike_cfg_t *this); + uint16_t (*get_my_port)(ike_cfg_t *this); /** * Get the port to use as destination port. * * @return destination address, host order */ - u_int16_t (*get_other_port)(ike_cfg_t *this); + uint16_t (*get_other_port)(ike_cfg_t *this); /** * Get the DSCP value to use for IKE packets send from connections. * * @return DSCP value */ - u_int8_t (*get_dscp)(ike_cfg_t *this); + uint8_t (*get_dscp)(ike_cfg_t *this); /** * Adds a proposal to the list. @@ -165,16 +165,17 @@ struct ike_cfg_t { linked_list_t* (*get_proposals) (ike_cfg_t *this); /** - * Select a proposed from suggested proposals. + * Select a proposal from a list of supplied proposals. * * Returned proposal must be destroyed after use. * * @param proposals list of proposals to select from * @param private accept algorithms from a private range + * @param prefer_self whether to prefer configured or supplied proposals * @return selected proposal, or NULL if none matches. */ proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals, - bool private); + bool private, bool prefer_self); /** * Should we send a certificate request in IKE_SA_INIT? @@ -250,9 +251,9 @@ struct ike_cfg_t { * @return ike_cfg_t object. */ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap, - char *me, u_int16_t my_port, - char *other, u_int16_t other_port, - fragmentation_t fragmentation, u_int8_t dscp); + char *me, uint16_t my_port, + char *other, uint16_t other_port, + fragmentation_t fragmentation, uint8_t dscp); /** * Determine the address family of the local or remtoe address(es). If multiple diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index d28a79507..6463c7a36 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2007-2015 Tobias Brunner + * Copyright (C) 2007-2016 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -88,7 +88,7 @@ struct private_peer_cfg_t { /** * number of tries after giving up if peer does not respond */ - u_int32_t keyingtries; + uint32_t keyingtries; /** * enable support for MOBIKE @@ -108,32 +108,32 @@ struct private_peer_cfg_t { /** * Time before starting rekeying */ - u_int32_t rekey_time; + uint32_t rekey_time; /** * Time before starting reauthentication */ - u_int32_t reauth_time; + uint32_t reauth_time; /** * Time, which specifies the range of a random value subtracted from above. */ - u_int32_t jitter_time; + uint32_t jitter_time; /** * Delay before deleting a rekeying/reauthenticating SA */ - u_int32_t over_time; + uint32_t over_time; /** * DPD check intervall */ - u_int32_t dpd; + uint32_t dpd; /** * DPD timeout intervall (used for IKEv1 only) */ - u_int32_t dpd_timeout; + uint32_t dpd_timeout; /** * List of virtual IPs (host_t*) to request @@ -455,13 +455,13 @@ METHOD(peer_cfg_t, get_unique_policy, unique_policy_t, return this->unique; } -METHOD(peer_cfg_t, get_keyingtries, u_int32_t, +METHOD(peer_cfg_t, get_keyingtries, uint32_t, private_peer_cfg_t *this) { return this->keyingtries; } -METHOD(peer_cfg_t, get_rekey_time, u_int32_t, +METHOD(peer_cfg_t, get_rekey_time, uint32_t, private_peer_cfg_t *this, bool jitter) { if (this->rekey_time == 0) @@ -475,7 +475,7 @@ METHOD(peer_cfg_t, get_rekey_time, u_int32_t, return this->rekey_time - (random() % this->jitter_time); } -METHOD(peer_cfg_t, get_reauth_time, u_int32_t, +METHOD(peer_cfg_t, get_reauth_time, uint32_t, private_peer_cfg_t *this, bool jitter) { if (this->reauth_time == 0) @@ -489,7 +489,7 @@ METHOD(peer_cfg_t, get_reauth_time, u_int32_t, return this->reauth_time - (random() % this->jitter_time); } -METHOD(peer_cfg_t, get_over_time, u_int32_t, +METHOD(peer_cfg_t, get_over_time, uint32_t, private_peer_cfg_t *this) { return this->over_time; @@ -513,13 +513,13 @@ METHOD(peer_cfg_t, use_pull_mode, bool, return this->pull_mode; } -METHOD(peer_cfg_t, get_dpd, u_int32_t, +METHOD(peer_cfg_t, get_dpd, uint32_t, private_peer_cfg_t *this) { return this->dpd; } -METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t, +METHOD(peer_cfg_t, get_dpd_timeout, uint32_t, private_peer_cfg_t *this) { return this->dpd_timeout; @@ -724,29 +724,22 @@ METHOD(peer_cfg_t, destroy, void, /* * Described in header-file */ -peer_cfg_t *peer_cfg_create(char *name, - ike_cfg_t *ike_cfg, cert_policy_t cert_policy, - unique_policy_t unique, u_int32_t keyingtries, - u_int32_t rekey_time, u_int32_t reauth_time, - u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, bool pull_mode, - u_int32_t dpd, u_int32_t dpd_timeout, - bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id) +peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg, + peer_cfg_create_t *data) { private_peer_cfg_t *this; - if (rekey_time && jitter_time > rekey_time) + if (data->rekey_time && data->jitter_time > data->rekey_time) { - jitter_time = rekey_time; + data->jitter_time = data->rekey_time; } - if (reauth_time && jitter_time > reauth_time) + if (data->reauth_time && data->jitter_time > data->reauth_time) { - jitter_time = reauth_time; + data->jitter_time = data->reauth_time; } - if (dpd && dpd_timeout && dpd > dpd_timeout) + if (data->dpd && data->dpd_timeout && data->dpd > data->dpd_timeout) { - dpd_timeout = dpd; + data->dpd_timeout = data->dpd; } INIT(this, @@ -789,33 +782,29 @@ peer_cfg_t *peer_cfg_create(char *name, .ike_cfg = ike_cfg, .child_cfgs = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .cert_policy = cert_policy, - .unique = unique, - .keyingtries = keyingtries, - .rekey_time = rekey_time, - .reauth_time = reauth_time, - .jitter_time = jitter_time, - .over_time = over_time, - .use_mobike = mobike, - .aggressive = aggressive, - .pull_mode = pull_mode, - .dpd = dpd, - .dpd_timeout = dpd_timeout, + .cert_policy = data->cert_policy, + .unique = data->unique, + .keyingtries = data->keyingtries, + .rekey_time = data->rekey_time, + .reauth_time = data->reauth_time, + .jitter_time = data->jitter_time, + .over_time = data->over_time, + .use_mobike = !data->no_mobike, + .aggressive = data->aggressive, + .pull_mode = !data->push_mode, + .dpd = data->dpd, + .dpd_timeout = data->dpd_timeout, .vips = linked_list_create(), .pools = linked_list_create(), .local_auth = linked_list_create(), .remote_auth = linked_list_create(), .refcount = 1, - ); - #ifdef ME - this->mediation = mediation; - this->mediated_by = mediated_by; - this->peer_id = peer_id; -#else /* ME */ - DESTROY_IF(mediated_by); - DESTROY_IF(peer_id); + .mediation = data->mediation, + .mediated_by = data->mediated_by, + .peer_id = data->peer_id, #endif /* ME */ + ); return &this->public; } diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index b612a2ef1..8e4d5331c 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2007-2015 Tobias Brunner + * Copyright (C) 2007-2016 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,6 +26,7 @@ typedef enum cert_policy_t cert_policy_t; typedef enum unique_policy_t unique_policy_t; typedef struct peer_cfg_t peer_cfg_t; +typedef struct peer_cfg_create_t peer_cfg_create_t; #include <library.h> #include <utils/identification.h> @@ -222,30 +223,30 @@ struct peer_cfg_t { * * @return max number retries */ - u_int32_t (*get_keyingtries) (peer_cfg_t *this); + uint32_t (*get_keyingtries) (peer_cfg_t *this); /** * Get a time to start rekeying. * - * @param jitter remove a jitter value to randomize time + * @param jitter subtract a jitter value to randomize time * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter); + uint32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter); /** * Get a time to start reauthentication. * - * @param jitter remove a jitter value to randomize time + * @param jitter subtract a jitter value to randomize time * @return time in s when to start reauthentication, 0 disables it */ - u_int32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter); + uint32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter); /** * Get the timeout of a rekeying/reauthenticating SA. * * @return timeout in s */ - u_int32_t (*get_over_time)(peer_cfg_t *this); + uint32_t (*get_over_time)(peer_cfg_t *this); /** * Use MOBIKE (RFC4555) if peer supports it? @@ -273,14 +274,14 @@ struct peer_cfg_t { * * @return dpd_delay in seconds */ - u_int32_t (*get_dpd) (peer_cfg_t *this); + uint32_t (*get_dpd) (peer_cfg_t *this); /** * Get the DPD timeout interval (IKEv1 only) * * @return dpd_timeout in seconds */ - u_int32_t (*get_dpd_timeout) (peer_cfg_t *this); + uint32_t (*get_dpd_timeout) (peer_cfg_t *this); /** * Add a virtual IP to request as initiator. @@ -367,42 +368,52 @@ struct peer_cfg_t { }; /** + * Data passed to the constructor of a peer_cfg_t object. + */ +struct peer_cfg_create_t { + /** Whether to send a certificate payload */ + cert_policy_t cert_policy; + /** Uniqueness of an IKE_SA */ + unique_policy_t unique; + /** How many keying tries should be done before giving up */ + uint32_t keyingtries; + /** Timeout in seconds before starting rekeying */ + uint32_t rekey_time; + /** Timeout in seconds before starting reauthentication */ + uint32_t reauth_time; + /** Time range in seconds to randomly subtract from rekey/reauth time */ + uint32_t jitter_time; + /** Maximum overtime in seconds before closing a rekeying/reauth SA */ + uint32_t over_time; + /** Disable MOBIKE (RFC4555) */ + bool no_mobike; + /** Use/accept aggressive mode with IKEv1 */ + bool aggressive; + /** TRUE to use modeconfig push, FALSE for pull */ + bool push_mode; + /** DPD check interval, 0 to disable */ + uint32_t dpd; + /** DPD timeout interval (IKEv1 only), if 0 default applies */ + uint32_t dpd_timeout; +#ifdef ME + /** TRUE if this is a mediation connection */ + bool mediation; + /** peer_cfg_t of the mediation connection to mediate through (adopted) */ + peer_cfg_t *mediated_by; + /** ID that identifies our peer at the mediation server (adopted) */ + identification_t *peer_id; +#endif /* ME */ +}; + +/** * Create a configuration object for IKE_AUTH and later. * - * name-string gets cloned, ID's not. - * Virtual IPs are used if they are != NULL. A %any host means the virtual - * IP should be obtained from the other peer. - * Lifetimes are in seconds. To prevent to peers to start rekeying at the - * same time, a jitter may be specified. Rekeying of an SA starts at - * (rekeylifetime - random(0, jitter)). - * - * @param name name of the peer_cfg - * @param ike_cfg IKE config to use when acting as initiator - * @param cert_policy should we send a certificate payload? - * @param unique uniqueness of an IKE_SA - * @param keyingtries how many keying tries should be done before giving up - * @param rekey_time timeout before starting rekeying - * @param reauth_time timeout before starting reauthentication - * @param jitter_time timerange to randomly subtract from rekey/reauth time - * @param over_time maximum overtime before closing a rekeying/reauth SA - * @param mobike use MOBIKE (RFC4555) if peer supports it - * @param aggressive use/accept aggressive mode with IKEv1 - * @param pull_mode TRUE to use modeconfig pull, FALSE for push - * @param dpd DPD check interval, 0 to disable - * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies - * @param mediation TRUE if this is a mediation connection - * @param mediated_by peer_cfg_t of the mediation connection to mediate through - * @param peer_id ID that identifies our peer at the mediation server + * @param name name of the peer_cfg (cloned) + * @param ike_cfg IKE config to use when acting as initiator (adopted) + * @param data data for this peer_cfg * @return peer_cfg_t object */ -peer_cfg_t *peer_cfg_create(char *name, - ike_cfg_t *ike_cfg, cert_policy_t cert_policy, - unique_policy_t unique, u_int32_t keyingtries, - u_int32_t rekey_time, u_int32_t reauth_time, - u_int32_t jitter_time, u_int32_t over_time, - bool mobike, bool aggressive, bool pull_mode, - u_int32_t dpd, u_int32_t dpd_timeout, - bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id); +peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg, + peer_cfg_create_t *data); #endif /** PEER_CFG_H_ @}*/ diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index 95b6a00ea..a83acec23 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2006-2010 Martin Willi * Copyright (C) 2013-2015 Andreas Steffen * Hochschule fuer Technik Rapperswil @@ -61,7 +61,7 @@ struct private_proposal_t { /** * senders SPI */ - u_int64_t spi; + uint64_t spi; /** * Proposal number @@ -76,14 +76,14 @@ typedef struct { /** Type of the transform */ transform_type_t type; /** algorithm identifier */ - u_int16_t alg; + uint16_t alg; /** key size in bits, or zero if not needed */ - u_int16_t key_size; + uint16_t key_size; } entry_t; METHOD(proposal_t, add_algorithm, void, private_proposal_t *this, transform_type_t type, - u_int16_t alg, u_int16_t key_size) + uint16_t alg, uint16_t key_size) { entry_t entry = { .type = type, @@ -97,8 +97,8 @@ METHOD(proposal_t, add_algorithm, void, /** * filter function for peer configs */ -static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg, - void **unused, u_int16_t *key_size) +static bool alg_filter(uintptr_t type, entry_t **in, uint16_t *alg, + void **unused, uint16_t *key_size) { entry_t *entry = *in; @@ -127,7 +127,7 @@ METHOD(proposal_t, create_enumerator, enumerator_t*, METHOD(proposal_t, get_algorithm, bool, private_proposal_t *this, transform_type_t type, - u_int16_t *alg, u_int16_t *key_size) + uint16_t *alg, uint16_t *key_size) { enumerator_t *enumerator; bool found = FALSE; @@ -147,7 +147,7 @@ METHOD(proposal_t, has_dh_group, bool, { bool found = FALSE, any = FALSE; enumerator_t *enumerator; - u_int16_t current; + uint16_t current; enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP); while (enumerator->enumerate(enumerator, ¤t, NULL)) @@ -193,7 +193,7 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, proposal_t *selected, transform_type_t type, bool priv) { enumerator_t *e1, *e2; - u_int16_t alg1, alg2, ks1, ks2; + uint16_t alg1, alg2, ks1, ks2; bool found = FALSE, optional = FALSE; if (type == INTEGRITY_ALGORITHM && @@ -210,7 +210,7 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, e1 = create_enumerator(this, type); e2 = other->create_enumerator(other, type); - if (!e1->enumerate(e1, NULL, NULL)) + if (!e1->enumerate(e1, &alg1, NULL)) { if (!e2->enumerate(e2, &alg2, NULL)) { @@ -219,12 +219,23 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, else if (optional) { do - { /* if the other peer proposes NONE, we accept the proposal */ + { /* if NONE is proposed, we accept the proposal */ found = !alg2; } while (!found && e2->enumerate(e2, &alg2, NULL)); } } + else if (!e2->enumerate(e2, NULL, NULL)) + { + if (optional) + { + do + { /* if NONE is proposed, we accept the proposal */ + found = !alg1; + } + while (!found && e1->enumerate(e1, &alg1, NULL)); + } + } e1->destroy(e1); e1 = create_enumerator(this, type); @@ -244,7 +255,6 @@ static bool select_algo(private_proposal_t *this, proposal_t *other, "but peer implementation is unknown, skipped"); continue; } - /* ok, we have an algorithm */ selected->add_algorithm(selected, type, alg1, ks1); found = TRUE; break; @@ -288,9 +298,7 @@ METHOD(proposal_t, select_proposal, proposal_t*, } DBG2(DBG_CFG, " proposal matches"); - selected->set_spi(selected, other->get_spi(other)); - return selected; } @@ -301,12 +309,12 @@ METHOD(proposal_t, get_protocol, protocol_id_t, } METHOD(proposal_t, set_spi, void, - private_proposal_t *this, u_int64_t spi) + private_proposal_t *this, uint64_t spi) { this->spi = spi; } -METHOD(proposal_t, get_spi, u_int64_t, +METHOD(proposal_t, get_spi, uint64_t, private_proposal_t *this) { return this->spi; @@ -319,7 +327,7 @@ static bool algo_list_equals(private_proposal_t *this, proposal_t *other, transform_type_t type) { enumerator_t *e1, *e2; - u_int16_t alg1, alg2, ks1, ks2; + uint16_t alg1, alg2, ks1, ks2; bool equals = TRUE; e1 = create_enumerator(this, type); @@ -418,7 +426,7 @@ static void check_proposal(private_proposal_t *this) { enumerator_t *e; entry_t *entry; - u_int16_t alg, ks; + uint16_t alg, ks; bool all_aead = TRUE; int i; @@ -445,6 +453,16 @@ static void check_proposal(private_proposal_t *this) } } e->destroy(e); + /* remove MODP_NONE from IKE proposal */ + e = array_create_enumerator(this->transforms); + while (e->enumerate(e, &entry)) + { + if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg) + { + array_remove_at(this->transforms, e); + } + } + e->destroy(e); } if (this->protocol == PROTO_ESP) @@ -516,7 +534,7 @@ static int print_alg(private_proposal_t *this, printf_hook_data_t *data, { enumerator_t *enumerator; size_t written = 0; - u_int16_t alg, size; + uint16_t alg, size; enumerator = create_enumerator(this, kind); while (enumerator->enumerate(enumerator, &alg, &size)) @@ -861,16 +879,18 @@ static bool proposal_add_supported_ike(private_proposal_t *this, bool aead) case MODP_768_BIT: /* weak */ break; - case MODP_2048_BIT: - case MODP_2048_256: case MODP_2048_224: case MODP_1536_BIT: - case MODP_1024_BIT: case MODP_1024_160: case ECP_224_BIT: case ECP_224_BP: case ECP_192_BIT: case NTRU_112_BIT: + /* rarely used */ + break; + case MODP_2048_BIT: + case MODP_2048_256: + case MODP_1024_BIT: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0); break; default: diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h index 78b868868..f9f277820 100644 --- a/src/libcharon/config/proposal.h +++ b/src/libcharon/config/proposal.h @@ -78,13 +78,13 @@ struct proposal_t { * @param key_size key size to use */ void (*add_algorithm) (proposal_t *this, transform_type_t type, - u_int16_t alg, u_int16_t key_size); + uint16_t alg, uint16_t key_size); /** * Get an enumerator over algorithms for a specifc algo type. * * @param type kind of algorithm - * @return enumerator over u_int16_t alg, u_int16_t key_size + * @return enumerator over uint16_t alg, uint16_t key_size */ enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type); @@ -99,7 +99,7 @@ struct proposal_t { * @return TRUE if algorithm of this kind available */ bool (*get_algorithm) (proposal_t *this, transform_type_t type, - u_int16_t *alg, u_int16_t *key_size); + uint16_t *alg, uint16_t *key_size); /** * Check if the proposal has a specific DH group. @@ -141,14 +141,14 @@ struct proposal_t { * * @return spi for proto */ - u_int64_t (*get_spi) (proposal_t *this); + uint64_t (*get_spi) (proposal_t *this); /** * Set the SPI of the proposal. * * @param spi spi to set for proto */ - void (*set_spi) (proposal_t *this, u_int64_t spi); + void (*set_spi) (proposal_t *this, uint64_t spi); /** * Get the proposal number, as encoded in SA payload |