From 46001e1131e8239772627aa47f1e5867d82184e4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 Oct 2014 11:12:38 +0100 Subject: [PATCH 1/6] unit-tests: Re-align identification_create_from_string() unit test table data --- .../tests/suites/test_identification.c | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c index 5de785710..9b14b289f 100644 --- a/src/libstrongswan/tests/suites/test_identification.c +++ b/src/libstrongswan/tests/suites/test_identification.c @@ -122,58 +122,58 @@ 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 }}, }; START_TEST(test_from_string) From c0da835a9f773800d2ff8c002e234fd441fdcf0a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 Oct 2014 11:18:35 +0100 Subject: [PATCH 2/6] identification: Support prefixes in string constructors for an explicit type --- .../tests/suites/test_identification.c | 4 ++ src/libstrongswan/utils/identification.c | 48 +++++++++++++++++++ src/libstrongswan/utils/identification.h | 6 +++ 3 files changed, 58 insertions(+) diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c index 9b14b289f..d20ad9b15 100644 --- a/src/libstrongswan/tests/suites/test_identification.c +++ b/src/libstrongswan/tests/suites/test_identification.c @@ -174,6 +174,10 @@ static struct { .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" }}, }; START_TEST(test_from_string) diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 46ac7e890..43aa0908c 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -927,6 +927,49 @@ 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; +} + /* * Described in header. */ @@ -939,6 +982,11 @@ identification_t *identification_create_from_string(char *string) { string = "%any"; } + this = create_from_string_with_prefix_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..3e89974f4 100644 --- a/src/libstrongswan/utils/identification.h +++ b/src/libstrongswan/utils/identification.h @@ -302,6 +302,12 @@ 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. + * * This constructor never returns NULL. If it does not find a suitable * conversion function, it will copy the string to an ID_KEY_ID. * From 6528338753395f9cc43403e92ab9510bc832e8ce Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 Oct 2014 11:53:03 +0100 Subject: [PATCH 3/6] identification: Support custom types in string constructor prefixes --- .../tests/suites/test_identification.c | 6 +++ src/libstrongswan/utils/identification.c | 39 +++++++++++++++++++ src/libstrongswan/utils/identification.h | 3 ++ 3 files changed, 48 insertions(+) diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c index d20ad9b15..de00e4afd 100644 --- a/src/libstrongswan/tests/suites/test_identification.c +++ b/src/libstrongswan/tests/suites/test_identification.c @@ -178,6 +178,12 @@ static struct { .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 43aa0908c..b69adf399 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -17,6 +17,7 @@ #include #include +#include #include "identification.h" @@ -970,6 +971,39 @@ static private_identification_t* create_from_string_with_prefix_type(char *str) 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. */ @@ -987,6 +1021,11 @@ identification_t *identification_create_from_string(char *string) { 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 3e89974f4..e6a9fe1c6 100644 --- a/src/libstrongswan/utils/identification.h +++ b/src/libstrongswan/utils/identification.h @@ -307,6 +307,9 @@ struct identification_t { * 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. From 9388bf1363d8e149d7d9bc0ce46500e868256285 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 Oct 2014 12:06:04 +0100 Subject: [PATCH 4/6] man: Document identification type prefixes in ipsec.conf(5) --- man/ipsec.conf.5.in | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index fe37dff83..32d0b9a27 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -750,11 +750,36 @@ defaults to .B left or the subject of the certificate configured with .BR leftcert . -Can be an IP address, a fully-qualified domain name, an email address, or -a keyid. If +If .B leftcert is configured the identity has to be confirmed by the certificate. +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, +\fIipv4:10.0.0.1\fP does not create a valid ID_IPV4_ADDR IKE identity, as it +does not get converted to binary 0x0a000001. Instead, one could use +\fIipv4:#0a000001\fP 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: +.BR ipv4 , +.BR ipv6 , +.BR rfc822 , +.BR email , +.BR userfqdn , +.BR fqdn , +.BR dns , +.BR asn1dn , +.B asn1gn +and +.BR keyid . +Custom type prefixes may be specified by surrounding the numerical type value by +curly brackets. + For IKEv2 and .B rightid the prefix From 9da2b191890bad7fd133da9599e620836e34f9ac Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 Oct 2014 12:15:39 +0100 Subject: [PATCH 5/6] swanctl: Document identity type prefixes --- src/swanctl/swanctl.opt | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) 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..local.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..local.eap_id = id Client EAP-Identity to use in EAP-Identity exchange and the EAP method. @@ -335,9 +351,8 @@ connections..remote {} connections..remote.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..remote.groups = Authorization group memberships to require. From 045501d59803fde468978b4b9344dccaf92333b2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 30 Oct 2014 11:21:01 +0100 Subject: [PATCH 6/6] NEWS: Mention identity prefixes --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index f1a4b2146..a967e3a2e 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,12 @@ +strongswan-5.2.2 +---------------- + +- The left/rightid options in ipsec.conf, or any other identity in strongSwan, + now accept prefixes to enforce an explicit type, such as email: or fqdn:. + Note that no conversion is done for the remaining string, refer to + ipsec.conf(5) for details. + + strongswan-5.2.1 ----------------