diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
commit | c1343b3278cdf99533b7902744d15969f9d6fdc1 (patch) | |
tree | d5ed3dc5677a59260ec41cd39bb284d3e94c91b3 /src/libcharon/plugins/stroke/stroke_config.c | |
parent | b34738ed08c2227300d554b139e2495ca5da97d6 (diff) | |
download | vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.tar.gz vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.zip |
Imported Upstream version 5.0.1
Diffstat (limited to 'src/libcharon/plugins/stroke/stroke_config.c')
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 473 |
1 files changed, 313 insertions, 160 deletions
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 483e3d253..e43672b18 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -52,6 +52,11 @@ struct private_stroke_config_t { * credentials */ stroke_cred_t *cred; + + /** + * Virtual IP pool / DNS backend + */ + stroke_attribute_t *attributes; }; METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, @@ -186,48 +191,48 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg { stroke_end_t tmp_end; ike_cfg_t *ike_cfg; - char *interface; host_t *host; + u_int16_t ikeport; host = host_create_from_dns(msg->add_conn.other.address, 0, 0); if (host) { - interface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, host); - host->destroy(host); - if (interface) + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + host, NULL)) { DBG2(DBG_CFG, "left is other host, swapping ends"); tmp_end = msg->add_conn.me; msg->add_conn.me = msg->add_conn.other; msg->add_conn.other = tmp_end; - free(interface); + host->destroy(host); } else { + host->destroy(host); host = host_create_from_dns(msg->add_conn.me.address, 0, 0); if (host) { - interface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, host); - host->destroy(host); - if (!interface) + if (!hydra->kernel_interface->get_interface( + hydra->kernel_interface, host, NULL)) { DBG1(DBG_CFG, "left nor right host is our side, " "assuming left=local"); } - else - { - free(interface); - } - + host->destroy(host); } } } + ikeport = msg->add_conn.me.ikeport; + ikeport = (ikeport == IKEV2_UDP_PORT) ? + charon->socket->get_port(charon->socket, FALSE) : ikeport; ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND, - msg->add_conn.force_encap, - msg->add_conn.me.address, msg->add_conn.me.ikeport, - msg->add_conn.other.address, msg->add_conn.other.ikeport); + msg->add_conn.force_encap, + msg->add_conn.me.address, + msg->add_conn.me.allow_any, + ikeport, + msg->add_conn.other.address, + msg->add_conn.other.allow_any, + msg->add_conn.other.ikeport); add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); return ike_cfg; } @@ -257,6 +262,103 @@ static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy) } /** + * Parse public key / signature strength constraints + */ +static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg) +{ + enumerator_t *enumerator; + bool rsa = FALSE, ecdsa = FALSE, rsa_len = FALSE, ecdsa_len = FALSE; + int strength; + char *token; + + enumerator = enumerator_create_token(auth, "-", ""); + while (enumerator->enumerate(enumerator, &token)) + { + bool found = FALSE; + int i; + struct { + char *name; + signature_scheme_t scheme; + key_type_t key; + } schemes[] = { + { "md5", SIGN_RSA_EMSA_PKCS1_MD5, KEY_RSA, }, + { "sha1", SIGN_RSA_EMSA_PKCS1_SHA1, KEY_RSA, }, + { "sha224", SIGN_RSA_EMSA_PKCS1_SHA224, KEY_RSA, }, + { "sha256", SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, }, + { "sha384", SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, }, + { "sha512", SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, }, + { "sha1", SIGN_ECDSA_WITH_SHA1_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_256, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_384, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_521, KEY_ECDSA, }, + }; + + if (rsa_len || ecdsa_len) + { /* expecting a key strength token */ + strength = atoi(token); + if (strength) + { + if (rsa_len) + { + cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength); + } + else if (ecdsa_len) + { + cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength); + } + } + rsa_len = ecdsa_len = FALSE; + if (strength) + { + continue; + } + } + if (streq(token, "rsa")) + { + rsa = rsa_len = TRUE; + continue; + } + if (streq(token, "ecdsa")) + { + ecdsa = ecdsa_len = TRUE; + continue; + } + if (streq(token, "pubkey")) + { + continue; + } + + for (i = 0; i < countof(schemes); i++) + { + if (streq(schemes[i].name, token)) + { + /* for each matching string, allow the scheme, if: + * - it is an RSA scheme, and we enforced RSA + * - it is an ECDSA scheme, and we enforced ECDSA + * - it is not a key type specific scheme + */ + if ((rsa && schemes[i].key == KEY_RSA) || + (ecdsa && schemes[i].key == KEY_ECDSA) || + (!rsa && !ecdsa)) + { + cfg->add(cfg, AUTH_RULE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + } + found = TRUE; + } + } + if (!found) + { + DBG1(DBG_CFG, "ignoring invalid auth token: '%s'", token); + } + } + enumerator->destroy(enumerator); +} + +/** * build authentication config */ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, @@ -264,10 +366,10 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { identification_t *identity; certificate_t *certificate; - char *auth, *id, *pubkey, *cert, *ca; + char *auth, *id, *pubkey, *cert, *ca, *groups; stroke_end_t *end, *other_end; auth_cfg_t *cfg; - char eap_buf[32]; + bool loose = FALSE; /* select strings */ if (local) @@ -310,52 +412,17 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, ca = other_end->ca2; } } + if (id && *id == '%' && !streq(id, "%any")) + { /* has only an effect on rightid/2 */ + loose = !local; + id++; + } if (!auth) { if (primary) { - if (local) - { /* "leftauth" not defined, fall back to deprecated "authby" */ - switch (msg->add_conn.auth_method) - { - default: - case AUTH_CLASS_PUBKEY: - auth = "pubkey"; - break; - case AUTH_CLASS_PSK: - auth = "psk"; - break; - case AUTH_CLASS_EAP: - auth = "eap"; - break; - case AUTH_CLASS_ANY: - auth = "any"; - break; - } - } - else - { /* "rightauth" not defined, fall back to deprecated "eap" */ - if (msg->add_conn.eap_type) - { - if (msg->add_conn.eap_vendor) - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d", - msg->add_conn.eap_type, - msg->add_conn.eap_vendor); - } - else - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d", - msg->add_conn.eap_type); - } - auth = eap_buf; - } - else - { /* not EAP => no constraints for this peer */ - auth = "any"; - } - } + auth = "pubkey"; } else { /* no second authentication round, fine. But load certificates @@ -398,7 +465,18 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } } } - cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + if (identity->get_type(identity) != ID_ANY) + { + cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + if (loose) + { + cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE); + } + } + else + { + identity->destroy(identity); + } /* add raw RSA public key */ pubkey = end->rsakey; @@ -431,12 +509,13 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /* groups */ - if (end->groups) + groups = primary ? end->groups : end->groups2; + if (groups) { enumerator_t *enumerator; char *group; - enumerator = enumerator_create_token(end->groups, ",", " "); + enumerator = enumerator_create_token(groups, ",", " "); while (enumerator->enumerate(enumerator, &group)) { cfg->add(cfg, AUTH_RULE_GROUP, @@ -460,75 +539,51 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /* authentication metod (class, actually) */ - if (streq(auth, "pubkey") || + if (strneq(auth, "pubkey", strlen("pubkey")) || strneq(auth, "rsa", strlen("rsa")) || strneq(auth, "ecdsa", strlen("ecdsa"))) { - u_int strength; - cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); build_crl_policy(cfg, local, msg->add_conn.crl_policy); - if (sscanf(auth, "rsa-%d", &strength) == 1) - { - cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength); - } - if (sscanf(auth, "ecdsa-%d", &strength) == 1) - { - cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength); - } + parse_pubkey_constraints(auth, cfg); } else if (streq(auth, "psk") || streq(auth, "secret")) { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); } + else if (strneq(auth, "xauth", 5)) + { + char *pos; + + pos = strchr(auth, '-'); + if (pos) + { + cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos)); + } + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); + if (msg->add_conn.xauth_identity) + { + cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY, + identification_create_from_string(msg->add_conn.xauth_identity)); + } + } else if (strneq(auth, "eap", 3)) { - enumerator_t *enumerator; - char *str; - int i = 0, type = 0, vendor; + eap_vendor_type_t *type; cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); - /* parse EAP string, format: eap[-type[-vendor]] */ - enumerator = enumerator_create_token(auth, "-", " "); - while (enumerator->enumerate(enumerator, &str)) + type = eap_vendor_type_from_string(auth); + if (type) { - switch (i) + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type); + if (type->vendor) { - case 1: - type = eap_type_from_string(str); - if (!type) - { - type = atoi(str); - if (!type) - { - DBG1(DBG_CFG, "unknown EAP method: %s", str); - break; - } - } - cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); - break; - case 2: - if (type) - { - vendor = atoi(str); - if (vendor) - { - cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); - } - else - { - DBG1(DBG_CFG, "unknown EAP vendor: %s", str); - } - } - break; - default: - break; + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor); } - i++; + free(type); } - enumerator->destroy(enumerator); if (msg->add_conn.eap_identity) { @@ -570,7 +625,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, { identification_t *peer_id = NULL; peer_cfg_t *mediated_by = NULL; - host_t *vip = NULL; unique_policy_t unique; u_int32_t rekey = 0, reauth = 0, over, jitter; peer_cfg_t *peer_cfg; @@ -629,38 +683,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, { rekey = msg->add_conn.rekey.ike_lifetime - over; } - if (msg->add_conn.me.sourceip_mask) - { - if (msg->add_conn.me.sourceip) - { - vip = host_create_from_string(msg->add_conn.me.sourceip, 0); - } - if (!vip) - { /* if it is set to something like %poolname, request an address */ - if (msg->add_conn.me.subnets) - { /* use the same address as in subnet, if any */ - if (strchr(msg->add_conn.me.subnets, '.')) - { - vip = host_create_any(AF_INET); - } - else - { - vip = host_create_any(AF_INET6); - } - } - else - { - if (strchr(ike_cfg->get_my_addr(ike_cfg), ':')) - { - vip = host_create_any(AF_INET6); - } - else - { - vip = host_create_any(AF_INET); - } - } - } - } switch (msg->add_conn.unique) { case 1: /* yes */ @@ -670,6 +692,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, case 3: /* keep */ unique = UNIQUE_KEEP; break; + case 4: /* never */ + unique = UNIQUE_NEVER; + break; default: /* no */ unique = UNIQUE_NO; break; @@ -683,14 +708,131 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ peer_cfg = peer_cfg_create(msg->add_conn.name, - msg->add_conn.ikev2 ? 2 : 1, ike_cfg, + msg->add_conn.version, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, msg->add_conn.dpd.delay, - vip, msg->add_conn.other.sourceip_mask ? - msg->add_conn.name : msg->add_conn.other.sourceip, + msg->add_conn.mobike, msg->add_conn.aggressive, + msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout, msg->add_conn.ikeme.mediation, mediated_by, peer_id); + if (msg->add_conn.other.sourceip) + { + enumerator_t *enumerator; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.other.sourceip, + ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (streq(token, "%modeconfig") || streq(token, "%modecfg") || + streq(token, "%config") || streq(token, "%cfg") || + streq(token, "%config4") || streq(token, "%config6")) + { + /* empty pool, uses connection name */ + this->attributes->add_pool(this->attributes, + mem_pool_create(msg->add_conn.name, NULL, 0)); + peer_cfg->add_pool(peer_cfg, msg->add_conn.name); + } + else if (*token == '%') + { + /* external named pool */ + peer_cfg->add_pool(peer_cfg, token + 1); + } + else + { + /* in-memory pool, named using CIDR notation */ + host_t *base; + int bits; + + base = host_create_from_subnet(token, &bits); + if (base) + { + this->attributes->add_pool(this->attributes, + mem_pool_create(token, base, bits)); + peer_cfg->add_pool(peer_cfg, token); + base->destroy(base); + } + else + { + DBG1(DBG_CFG, "IP pool %s invalid, ignored", token); + } + } + } + enumerator->destroy(enumerator); + } + + if (msg->add_conn.me.sourceip) + { + enumerator_t *enumerator; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + host_t *vip = NULL; + + if (streq(token, "%modeconfig") || streq(token, "%modecfg") || + streq(token, "%config") || streq(token, "%cfg")) + { /* try to deduce an address family */ + if (msg->add_conn.me.subnets) + { /* use the same family as in local subnet, if any */ + if (strchr(msg->add_conn.me.subnets, '.')) + { + vip = host_create_any(AF_INET); + } + else + { + vip = host_create_any(AF_INET6); + } + } + else if (msg->add_conn.other.subnets) + { /* use the same family as in remote subnet, if any */ + if (strchr(msg->add_conn.other.subnets, '.')) + { + vip = host_create_any(AF_INET); + } + else + { + vip = host_create_any(AF_INET6); + } + } + else + { + if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':')) + { + vip = host_create_any(AF_INET6); + } + else + { + vip = host_create_any(AF_INET); + } + } + } + else if (streq(token, "%config4")) + { + vip = host_create_any(AF_INET); + } + else if (streq(token, "%config6")) + { + vip = host_create_any(AF_INET6); + } + else + { + vip = host_create_from_string(token, 0); + if (vip) + { + DBG1(DBG_CFG, "ignored invalid subnet token: %s", token); + } + } + + if (vip) + { + peer_cfg->add_virtual_ip(peer_cfg, vip); + } + } + enumerator->destroy(enumerator); + } + /* build leftauth= */ auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE); if (auth_cfg) @@ -1029,8 +1171,8 @@ METHOD(stroke_config_t, set_user_credentials, void, return; } - /* replace/set the username in the first EAP auth_cfg, also look for a - * suitable remote ID. + /* replace/set the username in the first EAP/XAuth auth_cfg, also look for + * a suitable remote ID. * note that adding the identity here is not fully thread-safe as the * peer_cfg and in turn the auth_cfg could be in use. for the default use * case (setting user credentials before upping the connection) this will @@ -1049,16 +1191,25 @@ METHOD(stroke_config_t, set_user_credentials, void, } auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS); - if (auth_class == AUTH_CLASS_EAP) + if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH) { - auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); - /* if aaa_identity is specified use that as remote ID */ - identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY); - if (identity && identity->get_type(identity) != ID_ANY) + if (auth_class == AUTH_CLASS_EAP) { - gw = identity; + auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); + /* if aaa_identity is specified use that as remote ID */ + identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY); + if (identity && identity->get_type(identity) != ID_ANY) + { + gw = identity; + } + DBG1(DBG_CFG, " configured EAP-Identity %Y", id); + } + else + { + auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY, + id->clone(id)); + DBG1(DBG_CFG, " configured XAuth username %Y", id); } - DBG1(DBG_CFG, " configured EAP-Identity %Y", id); type = SHARED_EAP; break; } @@ -1149,7 +1300,8 @@ METHOD(stroke_config_t, destroy, void, /* * see header file */ -stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) +stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred, + stroke_attribute_t *attributes) { private_stroke_config_t *this; @@ -1169,6 +1321,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), .ca = ca, .cred = cred, + .attributes = attributes, ); return &this->public; |