aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstrongswan/tests/suites/test_identification.c114
-rw-r--r--src/libstrongswan/utils/identification.c87
-rw-r--r--src/libstrongswan/utils/identification.h9
-rw-r--r--src/swanctl/swanctl.opt21
4 files changed, 176 insertions, 55 deletions
diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c
index 5de785710..de00e4afd 100644
--- a/src/libstrongswan/tests/suites/test_identification.c
+++ b/src/libstrongswan/tests/suites/test_identification.c
@@ -122,58 +122,68 @@ static struct {
} data;
} result;
} string_data[] = {
- {NULL, ID_ANY, { .type = ENC_CHUNK }},
- {"", ID_ANY, { .type = ENC_CHUNK }},
- {"%any", ID_ANY, { .type = ENC_CHUNK }},
- {"%any6", ID_ANY, { .type = ENC_CHUNK }},
- {"0.0.0.0", ID_ANY, { .type = ENC_CHUNK }},
- {"0::0", ID_ANY, { .type = ENC_CHUNK }},
- {"::", ID_ANY, { .type = ENC_CHUNK }},
- {"*", ID_ANY, { .type = ENC_CHUNK }},
- {"any", ID_FQDN, { .type = ENC_SIMPLE }},
- {"any6", ID_FQDN, { .type = ENC_SIMPLE }},
- {"0", ID_FQDN, { .type = ENC_SIMPLE }},
- {"**", ID_FQDN, { .type = ENC_SIMPLE }},
- {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0xc0, 0xa8, 0x01, 0x01) }},
- {"192.168.",ID_FQDN, { .type = ENC_SIMPLE }},
- {".", ID_FQDN, { .type = ENC_SIMPLE }},
- {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01) }},
- {"fec0::", ID_IPV6_ADDR, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) }},
- {"fec0:", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {":", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice@", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice", ID_FQDN, { .type = ENC_SIMPLE }},
- {"@", ID_FQDN, { .type = ENC_CHUNK }},
- {" @", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"@strongswan.org", ID_FQDN, { .type = ENC_STRING,
- .data.s = "strongswan.org" }},
- {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0xde, 0xad, 0xbe, 0xef) }},
- {"@#deadbee", ID_KEY_ID, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0x0d, 0xea, 0xdb, 0xee) }},
- {"foo=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"foo=", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"C=", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0x30, 0x0b, 0x31, 0x09, 0x30, 0x07, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x00)}},
- {"C=CH", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
- {"C=CH,", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
- {"C=CH, ", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
- .data.c = chunk_from_chars(0x30, 0x0d, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48)}},
- {"C=CH, O", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {NULL, ID_ANY, { .type = ENC_CHUNK }},
+ {"", ID_ANY, { .type = ENC_CHUNK }},
+ {"%any", ID_ANY, { .type = ENC_CHUNK }},
+ {"%any6", ID_ANY, { .type = ENC_CHUNK }},
+ {"0.0.0.0", ID_ANY, { .type = ENC_CHUNK }},
+ {"0::0", ID_ANY, { .type = ENC_CHUNK }},
+ {"::", ID_ANY, { .type = ENC_CHUNK }},
+ {"*", ID_ANY, { .type = ENC_CHUNK }},
+ {"any", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"any6", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"0", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"**", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
+ {"192.168.", ID_FQDN, { .type = ENC_SIMPLE }},
+ {".", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01) }},
+ {"fec0::", ID_IPV6_ADDR, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) }},
+ {"fec0:", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {":", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice@", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"@", ID_FQDN, { .type = ENC_CHUNK }},
+ {" @", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"@strongswan.org", ID_FQDN, { .type = ENC_STRING,
+ .data.s = "strongswan.org" }},
+ {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xde,0xad,0xbe,0xef) }},
+ {"@#deadbee", ID_KEY_ID, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x0d,0xea,0xdb,0xee) }},
+ {"foo=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"foo=", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"C=", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x30,0x0b,0x31,0x09,0x30,0x07,0x06,
+ 0x03,0x55,0x04,0x06,0x13,0x00) }},
+ {"C=CH", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
+ 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
+ {"C=CH,", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
+ 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
+ {"C=CH, ", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
+ 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
+ {"C=CH, O", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"IPv4:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
+ { "email:tester", ID_RFC822_ADDR, { .type = ENC_STRING,
+ .data.s = "tester" }},
+ { "{1}:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
+ { "{0x02}:tester", ID_FQDN, { .type = ENC_STRING,
+ .data.s = "tester" }},
+ { "{99}:somedata", 99, { .type = ENC_STRING,
+ .data.s = "somedata" }},
};
START_TEST(test_from_string)
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 46ac7e890..b69adf399 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -17,6 +17,7 @@
#include <string.h>
#include <stdio.h>
+#include <errno.h>
#include "identification.h"
@@ -927,6 +928,82 @@ static private_identification_t *identification_create(id_type_t type)
return this;
}
+/**
+ * Create an identity for a specific type, determined by prefix
+ */
+static private_identification_t* create_from_string_with_prefix_type(char *str)
+{
+ struct {
+ const char *str;
+ id_type_t type;
+ } prefixes[] = {
+ { "ipv4:", ID_IPV4_ADDR },
+ { "ipv6:", ID_IPV6_ADDR },
+ { "rfc822:", ID_RFC822_ADDR },
+ { "email:", ID_RFC822_ADDR },
+ { "userfqdn:", ID_USER_FQDN },
+ { "fqdn:", ID_FQDN },
+ { "dns:", ID_FQDN },
+ { "asn1dn:", ID_DER_ASN1_DN },
+ { "asn1gn:", ID_DER_ASN1_GN },
+ { "keyid:", ID_KEY_ID },
+ };
+ private_identification_t *this;
+ int i;
+
+ for (i = 0; i < countof(prefixes); i++)
+ {
+ if (strcasepfx(str, prefixes[i].str))
+ {
+ this = identification_create(prefixes[i].type);
+ str += strlen(prefixes[i].str);
+ if (*str == '#')
+ {
+ this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
+ }
+ else
+ {
+ this->encoded = chunk_clone(chunk_from_str(str));
+ }
+ return this;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Create an identity for a specific type, determined by a numerical prefix
+ *
+ * The prefix is of the form "{x}:", where x denotes the numerical identity
+ * type.
+ */
+static private_identification_t* create_from_string_with_num_type(char *str)
+{
+ private_identification_t *this;
+ u_long type;
+
+ if (*str++ != '{')
+ {
+ return NULL;
+ }
+ errno = 0;
+ type = strtoul(str, &str, 0);
+ if (errno || *str++ != '}' || *str++ != ':')
+ {
+ return NULL;
+ }
+ this = identification_create(type);
+ if (*str == '#')
+ {
+ this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
+ }
+ else
+ {
+ this->encoded = chunk_clone(chunk_from_str(str));
+ }
+ return this;
+}
+
/*
* Described in header.
*/
@@ -939,6 +1016,16 @@ identification_t *identification_create_from_string(char *string)
{
string = "%any";
}
+ this = create_from_string_with_prefix_type(string);
+ if (this)
+ {
+ return &this->public;
+ }
+ this = create_from_string_with_num_type(string);
+ if (this)
+ {
+ return &this->public;
+ }
if (strchr(string, '=') != NULL)
{
/* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index e62446879..e6a9fe1c6 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -302,6 +302,15 @@ struct identification_t {
* N, G, I, dnQualifier, ID, EN, EmployeeNumber, E, Email, emailAddress, UN,
* unstructuredName, TCGID.
*
+ * To skip automatic type detection the following prefixes may be used to
+ * enforce a specific type: ipv4:, ipv6:, rfc822:, email:, userfqdn:, fqdn:,
+ * dns:, asn1dn:, asn1gn: and keyid:. If a # follows the :, the remaining data
+ * is interpreted as hex encoded binary data for that ID, otherwise the raw
+ * string following the prefix is used as identity data, without conversion.
+ * To specify a non-standard ID type, the numerical type may be prefixed
+ * between curly backets, building a prefix. For instance the "{1}:" prefix
+ * defines an ID_IPV4_ADDR type.
+ *
* This constructor never returns NULL. If it does not find a suitable
* conversion function, it will copy the string to an ID_KEY_ID.
*
diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt
index f1e47a9e4..57835555c 100644
--- a/src/swanctl/swanctl.opt
+++ b/src/swanctl/swanctl.opt
@@ -303,6 +303,22 @@ connections.<conn>.local<suffix>.id =
authentication, the IKE identity must be contained in the certificate,
either as subject or as subjectAltName.
+ The identity can be an IP address, a fully-qualified domain name, an email
+ address or a Distinguished Name for which the ID type is determined
+ automatically and the string is converted to the appropriate encoding. To
+ enforce a specific identity type, a prefix may be used, followed by a colon
+ (:). If the number sign (#) follows the colon, the remaining data is
+ interpreted as hex encoding, otherwise the string is used as-is as the
+ identification data. Note that this implies that no conversion is performed
+ for non-string identities. For example, _ipv4:10.0.0.1_ does not create a
+ valid ID_IPV4_ADDR IKE identity, as it does not get converted to binary
+ 0x0a000001. Instead, one could use _ipv4:#0a000001_ to get a valid identity,
+ but just using the implicit type with automatic conversion is usually
+ simpler. The same applies to the ASN1 encoded types. The following prefixes
+ are known: _ipv4_, _ipv6_, _rfc822_, _email_, _userfqdn_, _fqdn_, _dns_,
+ _asn1dn_, _asn1gn_ and _keyid_. Custom type prefixes may be specified by
+ surrounding the numerical type value by curly brackets.
+
connections.<conn>.local<suffix>.eap_id = id
Client EAP-Identity to use in EAP-Identity exchange and the EAP method.
@@ -335,9 +351,8 @@ connections.<conn>.remote<suffix> {}
connections.<conn>.remote<suffix>.id = %any
IKE identity to expect for authentication round.
- IKE identity to expect for authentication round. When using certificate
- authentication, the IKE identity must be contained in the certificate,
- either as subject or as subjectAltName.
+ IKE identity to expect for authentication round. Refer to the _local_ _id_
+ section for details.
connections.<conn>.remote<suffix>.groups =
Authorization group memberships to require.