Merge branch 'id-type-prefix'

Introduce generic identity prefixes to enforce a specific type.
This commit is contained in:
Martin Willi
2014-10-30 11:21:22 +01:00
6 changed files with 212 additions and 57 deletions
+9
View File
@@ -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
----------------
+27 -2
View File
@@ -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
@@ -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 }},
{"[email protected]", 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 }},
{"[email protected]", 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)
+87
View File
@@ -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.
+9
View File
@@ -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.
*
+18 -3
View File
@@ -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.