pluto supports AES_CCM and AES_GCM ESP algorithms

This commit is contained in:
Andreas Steffen
2009-07-12 00:05:42 +02:00
parent c5ebd00517
commit 540d02f6c0
7 changed files with 349 additions and 221 deletions
+29 -5
View File
@@ -139,6 +139,24 @@ static void __alg_info_esp_add(struct alg_info_esp *alg_info, int ealg_id,
) )
} }
/**
* Returns true if the given alg is an authenticated encryption algorithm
*/
static bool is_authenticated_encryption(int ealg_id)
{
switch (ealg_id)
{
case ESP_AES_CCM_8:
case ESP_AES_CCM_12:
case ESP_AES_CCM_16:
case ESP_AES_GCM_8:
case ESP_AES_GCM_12:
case ESP_AES_GCM_16:
return TRUE;
}
return FALSE;
}
/* /*
* Add ESP alg info _with_ logic (policy): * Add ESP alg info _with_ logic (policy):
*/ */
@@ -152,7 +170,13 @@ static void alg_info_esp_add(struct alg_info *alg_info, int ealg_id,
} }
if (ealg_id > 0) if (ealg_id > 0)
{ {
if (aalg_id > 0) if (is_authenticated_encryption(ealg_id))
{
__alg_info_esp_add((struct alg_info_esp *)alg_info,
ealg_id, ek_bits,
AUTH_ALGORITHM_NONE, 0);
}
else if (aalg_id > 0)
{ {
__alg_info_esp_add((struct alg_info_esp *)alg_info, __alg_info_esp_add((struct alg_info_esp *)alg_info,
ealg_id, ek_bits, ealg_id, ek_bits,
@@ -160,13 +184,13 @@ static void alg_info_esp_add(struct alg_info *alg_info, int ealg_id,
} }
else else
{ {
/* Policy: default to MD5 and SHA1 */ /* Policy: default to SHA-1 and MD5 */
__alg_info_esp_add((struct alg_info_esp *)alg_info,
ealg_id, ek_bits,
AUTH_ALGORITHM_HMAC_MD5, ak_bits);
__alg_info_esp_add((struct alg_info_esp *)alg_info, __alg_info_esp_add((struct alg_info_esp *)alg_info,
ealg_id, ek_bits, ealg_id, ek_bits,
AUTH_ALGORITHM_HMAC_SHA1, ak_bits); AUTH_ALGORITHM_HMAC_SHA1, ak_bits);
__alg_info_esp_add((struct alg_info_esp *)alg_info,
ealg_id, ek_bits,
AUTH_ALGORITHM_HMAC_MD5, ak_bits);
} }
} }
} }
+2 -1
View File
@@ -663,6 +663,7 @@ enum_names enc_mode_names =
/* Auth Algorithm attribute */ /* Auth Algorithm attribute */
static const char *const auth_alg_name[] = { static const char *const auth_alg_name[] = {
"AUTH_NONE",
"HMAC_MD5", "HMAC_MD5",
"HMAC_SHA1", "HMAC_SHA1",
"DES_MAC", "DES_MAC",
@@ -683,7 +684,7 @@ enum_names extended_auth_alg_names =
{ AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL }; { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL };
enum_names auth_alg_names = enum_names auth_alg_names =
{ AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_SIG_RSA, auth_alg_name { AUTH_ALGORITHM_NONE, AUTH_ALGORITHM_SIG_RSA, auth_alg_name
, &extended_auth_alg_names }; , &extended_auth_alg_names };
/* From draft-beaulieu-ike-xauth */ /* From draft-beaulieu-ike-xauth */
+62 -61
View File
@@ -2639,77 +2639,78 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid,
*/ */
switch (protoid) switch (protoid)
{ {
case PROTO_IPSEC_ESP: case PROTO_IPSEC_ESP:
switch (pi->attrs.transid) {
needed_len = kernel_alg_esp_enc_keylen(pi->attrs.transid);
if (needed_len && pi->attrs.key_len)
{ {
case ESP_NULL: needed_len = pi->attrs.key_len / BITS_PER_BYTE;
needed_len = 0;
break;
case ESP_DES:
needed_len = DES_CBC_BLOCK_SIZE;
break;
case ESP_3DES:
needed_len = DES_CBC_BLOCK_SIZE * 3;
break;
default:
#ifndef NO_KERNEL_ALG
if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) {
/* XXX: check key_len "coupling with kernel.c's */
if (pi->attrs.key_len) {
needed_len=pi->attrs.key_len/8;
DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
"key_len=%d from peer",
(int)needed_len));
}
break;
}
#endif
bad_case(pi->attrs.transid);
} }
#ifndef NO_KERNEL_ALG switch (pi->attrs.transid)
DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" {
"needed_len (after ESP enc)=%d", case ESP_NULL:
(int)needed_len)); needed_len = 0;
if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) { break;
case ESP_AES_CCM_8:
case ESP_AES_CCM_12:
case ESP_AES_CCM_16:
needed_len += 3;
break;
case ESP_AES_GCM_8:
case ESP_AES_GCM_12:
case ESP_AES_GCM_16:
case ESP_AES_CTR:
needed_len += 4;
break;
default:
if (needed_len == 0)
{
bad_case(pi->attrs.transid);
}
}
if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL))
{
needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth);
} else
#endif
switch (pi->attrs.auth)
{
case AUTH_ALGORITHM_NONE:
break;
case AUTH_ALGORITHM_HMAC_MD5:
needed_len += HMAC_MD5_KEY_LEN;
break;
case AUTH_ALGORITHM_HMAC_SHA1:
needed_len += HMAC_SHA1_KEY_LEN;
break;
case AUTH_ALGORITHM_DES_MAC:
default:
bad_case(pi->attrs.auth);
} }
DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" else
"needed_len (after ESP auth)=%d", {
(int)needed_len)); switch (pi->attrs.auth)
{
case AUTH_ALGORITHM_NONE:
break;
case AUTH_ALGORITHM_HMAC_MD5:
needed_len += HMAC_MD5_KEY_LEN;
break;
case AUTH_ALGORITHM_HMAC_SHA1:
needed_len += HMAC_SHA1_KEY_LEN;
break;
case AUTH_ALGORITHM_DES_MAC:
default:
bad_case(pi->attrs.auth);
}
}
break; break;
}
case PROTO_IPSEC_AH: case PROTO_IPSEC_AH:
{
switch (pi->attrs.transid) switch (pi->attrs.transid)
{ {
case AH_MD5: case AH_MD5:
needed_len = HMAC_MD5_KEY_LEN; needed_len = HMAC_MD5_KEY_LEN;
break; break;
case AH_SHA: case AH_SHA:
needed_len = HMAC_SHA1_KEY_LEN; needed_len = HMAC_SHA1_KEY_LEN;
break; break;
default: default:
bad_case(pi->attrs.transid); bad_case(pi->attrs.transid);
} }
break; break;
}
default: default:
bad_case(protoid); bad_case(protoid);
} }
pi->keymat_len = needed_len; pi->keymat_len = needed_len;
+107 -79
View File
@@ -1850,7 +1850,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
if (st->nat_traversal & NAT_T_DETECTED) if (st->nat_traversal & NAT_T_DETECTED)
{ {
natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ? natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ?
ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE; ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE;
natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port; natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port;
natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
natt_oa = st->nat_oa; natt_oa = st->nat_oa;
@@ -1861,12 +1861,11 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
if (ei == &esp_info[countof(esp_info)]) if (ei == &esp_info[countof(esp_info)])
{ {
/* Check for additional kernel alg */ /* Check for additional kernel alg */
#ifndef NO_KERNEL_ALG
if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid,
st->st_esp.attrs.auth))!=NULL) { st->st_esp.attrs.auth))!=NULL)
break; {
break;
} }
#endif
/* note: enum_show may use a static buffer, so two /* note: enum_show may use a static buffer, so two
* calls in one printf would be a mistake. * calls in one printf would be a mistake.
@@ -1879,9 +1878,11 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
goto fail; goto fail;
} }
if (st->st_esp.attrs.transid == ei->transid if (st->st_esp.attrs.transid == ei->transid &&
&& st->st_esp.attrs.auth == ei->auth) st->st_esp.attrs.auth == ei->auth)
{
break; break;
}
} }
key_len = st->st_esp.attrs.key_len/8; key_len = st->st_esp.attrs.key_len/8;
@@ -1900,40 +1901,52 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
{ {
key_len = ei->enckeylen; key_len = ei->enckeylen;
} }
/* Grrrrr.... f*cking 7 bits jurassic algos */
/* 168 bits in kernel, need 192 bits for keymat_len */ switch (ei->transid)
if (ei->transid == ESP_3DES && key_len == 21) {
key_len = 24; case ESP_3DES:
/* 168 bits in kernel, need 192 bits for keymat_len */
/* 56 bits in kernel, need 64 bits for keymat_len */ if (key_len == 21)
if (ei->transid == ESP_DES && key_len == 7) {
key_len = 8; key_len = 24;
}
break;
case ESP_DES:
/* 56 bits in kernel, need 64 bits for keymat_len */
if (key_len == 7)
{
key_len = 8;
}
break;
case ESP_AES_CCM_8:
case ESP_AES_CCM_12:
case ESP_AES_CCM_16:
key_len += 3;
break;
case ESP_AES_GCM_8:
case ESP_AES_GCM_12:
case ESP_AES_GCM_16:
case ESP_AES_CTR:
key_len += 4;
break;
default:
break;
}
/* divide up keying material */ /* divide up keying material */
/* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */
DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING,
if(st->st_esp.keymat_len != key_len + ei->authkeylen)
DBG_log("keymat_len=%d key_len=%d authkeylen=%d",
st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen);
)
passert(st->st_esp.keymat_len == key_len + ei->authkeylen);
set_text_said(text_said, &dst.addr, esp_spi, SA_ESP); set_text_said(text_said, &dst.addr, esp_spi, SA_ESP);
said_next->src = &src.addr; said_next->src = &src.addr;
said_next->dst = &dst.addr; said_next->dst = &dst.addr;
said_next->src_client = &src_client; said_next->src_client = &src_client;
said_next->dst_client = &dst_client; said_next->dst_client = &dst_client;
said_next->spi = esp_spi; said_next->spi = esp_spi;
said_next->satype = SADB_SATYPE_ESP; said_next->satype = SADB_SATYPE_ESP;
said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ?
REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
said_next->authalg = ei->authalg; said_next->authalg = ei->authalg;
said_next->authkeylen = ei->authkeylen; said_next->authkeylen = ei->authkeylen;
/* said_next->authkey = esp_dst_keymat + ei->enckeylen; */
said_next->authkey = esp_dst_keymat + key_len; said_next->authkey = esp_dst_keymat + key_len;
said_next->encalg = ei->encryptalg; said_next->encalg = ei->encryptalg;
/* said_next->enckeylen = ei->enckeylen; */
said_next->enckeylen = key_len; said_next->enckeylen = key_len;
said_next->enckey = esp_dst_keymat; said_next->enckey = esp_dst_keymat;
said_next->encapsulation = encapsulation; said_next->encapsulation = encapsulation;
@@ -1946,10 +1959,10 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
said_next->text_said = text_said; said_next->text_said = text_said;
if (!kernel_ops->add_sa(said_next, replace)) if (!kernel_ops->add_sa(said_next, replace))
{
goto fail; goto fail;
}
said_next++; said_next++;
encapsulation = ENCAPSULATION_MODE_TRANSPORT; encapsulation = ENCAPSULATION_MODE_TRANSPORT;
} }
@@ -1964,29 +1977,27 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
switch (st->st_ah.attrs.auth) switch (st->st_ah.attrs.auth)
{ {
case AUTH_ALGORITHM_HMAC_MD5: case AUTH_ALGORITHM_HMAC_MD5:
authalg = SADB_AALG_MD5HMAC; authalg = SADB_AALG_MD5HMAC;
break; break;
case AUTH_ALGORITHM_HMAC_SHA1:
case AUTH_ALGORITHM_HMAC_SHA1: authalg = SADB_AALG_SHA1HMAC;
authalg = SADB_AALG_SHA1HMAC; break;
break; default:
loglog(RC_LOG_SERIOUS, "%s not implemented yet",
default: enum_show(&auth_alg_names, st->st_ah.attrs.auth));
loglog(RC_LOG_SERIOUS, "%s not implemented yet"
, enum_show(&auth_alg_names, st->st_ah.attrs.auth));
goto fail; goto fail;
} }
set_text_said(text_said, &dst.addr, ah_spi, SA_AH); set_text_said(text_said, &dst.addr, ah_spi, SA_AH);
said_next->src = &src.addr; said_next->src = &src.addr;
said_next->dst = &dst.addr; said_next->dst = &dst.addr;
said_next->src_client = &src_client; said_next->src_client = &src_client;
said_next->dst_client = &dst_client; said_next->dst_client = &dst_client;
said_next->spi = ah_spi; said_next->spi = ah_spi;
said_next->satype = SADB_SATYPE_AH; said_next->satype = SADB_SATYPE_AH;
said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ?
REPLAY_WINDOW : REPLAY_WINDOW_XFRM;
said_next->authalg = authalg; said_next->authalg = authalg;
said_next->authkeylen = st->st_ah.keymat_len; said_next->authkeylen = st->st_ah.keymat_len;
said_next->authkey = ah_dst_keymat; said_next->authkey = ah_dst_keymat;
@@ -1995,10 +2006,10 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
said_next->text_said = text_said; said_next->text_said = text_said;
if (!kernel_ops->add_sa(said_next, replace)) if (!kernel_ops->add_sa(said_next, replace))
{
goto fail; goto fail;
}
said_next++; said_next++;
encapsulation = ENCAPSULATION_MODE_TRANSPORT; encapsulation = ENCAPSULATION_MODE_TRANSPORT;
} }
@@ -2094,7 +2105,9 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound)
s[1].text_said = text_said1; s[1].text_said = text_said1;
if (!kernel_ops->grp_sa(s + 1, s)) if (!kernel_ops->grp_sa(s + 1, s))
{
goto fail; goto fail;
}
} }
/* could update said, but it will not be used */ /* could update said, but it will not be used */
} }
@@ -2105,8 +2118,10 @@ fail:
{ {
/* undo the done SPIs */ /* undo the done SPIs */
while (said_next-- != said) while (said_next-- != said)
(void) del_spi(said_next->spi, said_next->proto {
, &src.addr, said_next->dst); (void) del_spi(said_next->spi, said_next->proto, &src.addr,
said_next->dst);
}
return FALSE; return FALSE;
} }
} }
@@ -2217,8 +2232,9 @@ bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time)
*use_time = UNDEFINED_TIME; *use_time = UNDEFINED_TIME;
if (kernel_ops->get_sa == NULL || !st->st_esp.present) if (kernel_ops->get_sa == NULL || !st->st_esp.present)
{
return FALSE; return FALSE;
}
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.proto = SA_ESP; sa.proto = SA_ESP;
@@ -2242,7 +2258,9 @@ bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time)
DBG_log("get %s", text_said) DBG_log("get %s", text_said)
) )
if (!kernel_ops->get_sa(&sa, bytes)) if (!kernel_ops->get_sa(&sa, bytes))
{
return FALSE; return FALSE;
}
DBG(DBG_KLIPS, DBG(DBG_KLIPS,
DBG_log(" current: %d bytes", *bytes) DBG_log(" current: %d bytes", *bytes)
) )
@@ -2267,7 +2285,9 @@ bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time)
sa.dst_client = &c->spd.that.client; sa.dst_client = &c->spd.that.client;
} }
if (!kernel_ops->get_policy(&sa, inbound, use_time)) if (!kernel_ops->get_policy(&sa, inbound, use_time))
{
return FALSE; return FALSE;
}
DBG(DBG_KLIPS, DBG(DBG_KLIPS,
DBG_log(" use_time: %T", use_time, FALSE) DBG_log(" use_time: %T", use_time, FALSE)
) )
@@ -2350,15 +2370,21 @@ bool install_inbound_ipsec_sa(struct state *st)
struct connection *o = route_owner(c, &esr, NULL, NULL); struct connection *o = route_owner(c, &esr, NULL, NULL);
if (o == NULL) if (o == NULL)
{
break; /* nobody has a route */ break; /* nobody has a route */
}
/* note: we ignore the client addresses at this end */ /* note: we ignore the client addresses at this end */
if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) &&
&& o->interface == c->interface) o->interface == c->interface)
{
break; /* existing route is compatible */ break; /* existing route is compatible */
}
if (o->kind == CK_TEMPLATE && streq(o->name, c->name)) if (o->kind == CK_TEMPLATE && streq(o->name, c->name))
{
break; /* ??? is this good enough?? */ break; /* ??? is this good enough?? */
}
loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route" loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route"
, o->name, ip_str(&o->spd.that.host_addr)); , o->name, ip_str(&o->spd.that.host_addr));
@@ -2370,12 +2396,11 @@ bool install_inbound_ipsec_sa(struct state *st)
/* check that we will be able to route and eroute */ /* check that we will be able to route and eroute */
switch (could_route(c)) switch (could_route(c))
{ {
case route_easy: case route_easy:
case route_nearconflict: case route_nearconflict:
break; break;
default:
default: return FALSE;
return FALSE;
} }
#ifdef KLIPS #ifdef KLIPS
@@ -2472,10 +2497,14 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS,
/* if no state provided, then install a shunt for later */ /* if no state provided, then install a shunt for later */
if (st == NULL) if (st == NULL)
{
eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE
, ERO_ADD, "add"); , ERO_ADD, "add");
}
else else
{
eroute_installed = sag_eroute(st, sr, ERO_ADD, "add"); eroute_installed = sag_eroute(st, sr, ERO_ADD, "add");
}
} }
/* notify the firewall of a new tunnel */ /* notify the firewall of a new tunnel */
@@ -2508,8 +2537,7 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS,
(void) do_command(c, sr, "prepare"); /* just in case; ignore failure */ (void) do_command(c, sr, "prepare"); /* just in case; ignore failure */
route_installed = do_command(c, sr, "route"); route_installed = do_command(c, sr, "route");
} }
else if (routed(sr->routing) else if (routed(sr->routing) || routes_agree(ro, c))
|| routes_agree(ro, c))
{ {
route_installed = TRUE; /* nothing to be done */ route_installed = TRUE; /* nothing to be done */
} }
@@ -2659,11 +2687,13 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS,
{ {
/* there was no previous eroute: delete whatever we installed */ /* there was no previous eroute: delete whatever we installed */
if (st == NULL) if (st == NULL)
(void) shunt_eroute(c, sr {
, sr->routing, ERO_DELETE, "delete"); (void) shunt_eroute(c, sr, sr->routing, ERO_DELETE, "delete");
}
else else
(void) sag_eroute(st, sr {
, ERO_DELETE, "delete"); (void) sag_eroute(st, sr, ERO_DELETE, "delete");
}
} }
} }
@@ -2686,18 +2716,19 @@ bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS)
switch (could_route(st->st_connection)) switch (could_route(st->st_connection))
{ {
case route_easy: case route_easy:
case route_nearconflict: case route_nearconflict:
break; break;
default:
default: return FALSE;
return FALSE;
} }
/* (attempt to) actually set up the SA group */ /* (attempt to) actually set up the SA group */
if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) ||
|| !setup_half_ipsec_sa(st, FALSE)) !setup_half_ipsec_sa(st, FALSE))
{
return FALSE; return FALSE;
}
for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next)
{ {
@@ -2731,12 +2762,11 @@ bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS)
switch (could_route(st->st_connection)) switch (could_route(st->st_connection))
{ {
case route_easy: case route_easy:
case route_nearconflict: case route_nearconflict:
break; break;
default:
default: return FALSE;
return FALSE;
} }
@@ -2779,8 +2809,7 @@ void delete_ipsec_sa(struct state *st USED_BY_KLIPS,
? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE;
(void) do_command(c, sr, "down"); (void) do_command(c, sr, "down");
if ((c->policy & POLICY_DONT_REKEY) if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE)
&& c->kind == CK_INSTANCE)
{ {
/* in this special case, even if the connection /* in this special case, even if the connection
* is still alive (due to an ISAKMP SA), * is still alive (due to an ISAKMP SA),
@@ -2889,8 +2918,7 @@ bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time)
/* Can't open the file, perhaps were are on 26sec? */ /* Can't open the file, perhaps were are on 26sec? */
time_t use_time; time_t use_time;
if (get_sa_info(st, TRUE, &bytes, &use_time) if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME)
&& use_time != UNDEFINED_TIME)
{ {
*idle_time = time(NULL) - use_time; *idle_time = time(NULL) - use_time;
ret = *idle_time >= idle_max; ret = *idle_time >= idle_max;
+35 -13
View File
@@ -341,7 +341,7 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
sadb.msg++; sadb.msg++;
while(msglen) while (msglen)
{ {
int supp_exttype = sadb.supported->sadb_supported_exttype; int supp_exttype = sadb.supported->sadb_supported_exttype;
int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
@@ -361,14 +361,14 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
supp_len; supp_len;
supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++) supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++)
{ {
int ret = kernel_alg_add(satype, supp_exttype, sadb.alg); kernel_alg_add(satype, supp_exttype, sadb.alg);
DBG(DBG_KLIPS, DBG(DBG_KLIPS,
DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
"alg[%d], exttype=%d, satype=%d, alg_id=%d, " "alg[%d], exttype=%d, satype=%d, alg_id=%d, "
"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
"res=%d, ret=%d" "res=%d"
, satype==SADB_SATYPE_ESP? "ESP" : "AH" , satype == SADB_SATYPE_ESP? "ESP" : "AH"
, i , i
, supp_exttype , supp_exttype
, satype , satype
@@ -376,9 +376,25 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
, sadb.alg->sadb_alg_ivlen , sadb.alg->sadb_alg_ivlen
, sadb.alg->sadb_alg_minbits , sadb.alg->sadb_alg_minbits
, sadb.alg->sadb_alg_maxbits , sadb.alg->sadb_alg_maxbits
, sadb.alg->sadb_alg_reserved , sadb.alg->sadb_alg_reserved)
, ret)
) )
/* if AES_CBC is registered then also register AES_CCM and AES_GCM */
if (satype == SADB_SATYPE_ESP &&
sadb.alg->sadb_alg_id == SADB_X_EALG_AESCBC)
{
struct sadb_alg alg = *sadb.alg;
int alg_id;
for (alg_id = SADB_X_EALG_AES_CCM_ICV8;
alg_id <= SADB_X_EALG_AES_GCM_ICV16; alg_id++)
{
if (alg_id != ESP_UNASSIGNED_17)
{
alg.sadb_alg_id = alg_id;
kernel_alg_add(satype, supp_exttype, &alg);
}
}
}
} }
} }
} }
@@ -515,7 +531,7 @@ void kernel_alg_show_connection(struct connection *c, const char *instance)
} }
bool kernel_alg_esp_auth_ok(u_int auth, bool kernel_alg_esp_auth_ok(u_int auth,
struct alg_info_esp *alg_info __attribute__((unused))) struct alg_info_esp *alg_info __attribute__((unused)))
{ {
return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)); return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth));
} }
@@ -619,14 +635,15 @@ static bool kernel_alg_db_add(struct db_context *db_ctx,
return FALSE; return FALSE;
} }
if (!(policy & POLICY_AUTHENTICATE)) /* skip ESP auth attrs for AH */ if (!(policy & POLICY_AUTHENTICATE) && /* skip ESP auth attrs for AH */
esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE)
{ {
aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
if (!ESP_AALG_PRESENT(aalg_id)) if (!ESP_AALG_PRESENT(aalg_id))
{ {
DBG_log("kernel_alg_db_add() kernel auth " DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present",
"aalg_id=%d not present", aalg_id); aalg_id);
return FALSE; return FALSE;
} }
} }
@@ -637,13 +654,18 @@ static bool kernel_alg_db_add(struct db_context *db_ctx,
/* open new transformation */ /* open new transformation */
db_trans_add(db_ctx, ealg_id); db_trans_add(db_ctx, ealg_id);
/* add ESP auth attr */ /* add ESP auth attr if not AH or AEAD */
if (!(policy & POLICY_AUTHENTICATE)) if (!(policy & POLICY_AUTHENTICATE) &&
esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE)
{
db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id);
}
/* add keylegth if specified in esp= string */ /* add keylength if specified in esp= string */
if (esp_info->esp_ealg_keylen) if (esp_info->esp_ealg_keylen)
{
db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen); db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen);
}
return TRUE; return TRUE;
} }
+72 -18
View File
@@ -590,6 +590,7 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace)
char data[1024]; char data[1024];
} req; } req;
struct rtattr *attr; struct rtattr *attr;
u_int16_t icv_size = 64;
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
@@ -625,6 +626,11 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace)
, sa->authalg); , sa->authalg);
return FALSE; return FALSE;
} }
DBG(DBG_CRYPT,
DBG_log("configured authentication algorithm %s with key size %d",
enum_show(&auth_alg_names, sa->authalg),
sa->authkeylen * BITS_PER_BYTE)
)
strcpy(algo.alg_name, name); strcpy(algo.alg_name, name);
algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
@@ -640,30 +646,78 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace)
attr = (struct rtattr *)((char *)attr + attr->rta_len); attr = (struct rtattr *)((char *)attr + attr->rta_len);
} }
if (sa->encalg) switch (sa->encalg)
{ {
struct xfrm_algo algo; case SADB_EALG_NONE:
const char *name; /* no encryption */
break;
case SADB_X_EALG_AES_CCM_ICV16:
case SADB_X_EALG_AES_GCM_ICV16:
icv_size += 32;
/* FALL */
case SADB_X_EALG_AES_CCM_ICV12:
case SADB_X_EALG_AES_GCM_ICV12:
icv_size += 32;
/* FALL */
case SADB_X_EALG_AES_CCM_ICV8:
case SADB_X_EALG_AES_GCM_ICV8:
{
struct xfrm_algo_aead *algo;
const char *name;
name = sparse_name(ealg_list, sa->encalg); name = sparse_name(ealg_list, sa->encalg);
if (!name) { if (!name)
loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u" {
, sa->encalg); loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u",
return FALSE; sa->encalg);
return FALSE;
}
DBG(DBG_CRYPT,
DBG_log("configured esp encryption algorithm %s with key size %d",
enum_show(&esp_transformid_names, sa->encalg),
sa->enckeylen * BITS_PER_BYTE)
)
attr->rta_type = XFRMA_ALG_AEAD;
attr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + sa->enckeylen);
req.n.nlmsg_len += attr->rta_len;
algo = (struct xfrm_algo_aead*)RTA_DATA(attr);
algo->alg_key_len = sa->enckeylen * BITS_PER_BYTE;
algo->alg_icv_len = icv_size;
strcpy(algo->alg_name, name);
memcpy(algo->alg_key, sa->enckey, sa->enckeylen);
attr = (struct rtattr *)((char *)attr + attr->rta_len);
break;
} }
default:
{
struct xfrm_algo *algo;
const char *name;
strcpy(algo.alg_name, name); name = sparse_name(ealg_list, sa->encalg);
algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE; if (!name)
{
loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u",
sa->encalg);
return FALSE;
}
DBG(DBG_CRYPT,
DBG_log("configured esp encryption algorithm %s with key size %d",
enum_show(&esp_transformid_names, sa->encalg),
sa->enckeylen * BITS_PER_BYTE)
)
attr->rta_type = XFRMA_ALG_CRYPT;
attr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + sa->enckeylen);
req.n.nlmsg_len += attr->rta_len;
attr->rta_type = XFRMA_ALG_CRYPT; algo = (struct xfrm_algo*)RTA_DATA(attr);
attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen); algo->alg_key_len = sa->enckeylen * BITS_PER_BYTE;
strcpy(algo->alg_name, name);
memcpy(algo->alg_key, sa->enckey, sa->enckeylen);
memcpy(RTA_DATA(attr), &algo, sizeof(algo)); attr = (struct rtattr *)((char *)attr + attr->rta_len);
memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey }
, sa->enckeylen);
req.n.nlmsg_len += attr->rta_len;
attr = (struct rtattr *)((char *)attr + attr->rta_len);
} }
if (sa->compalg) if (sa->compalg)
+43 -45
View File
@@ -473,14 +473,13 @@ out_sa(pb_stream *outs
if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs)) if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs))
return_on(ret, FALSE); return_on(ret, FALSE);
/* Within tranform: Attributes. */ /* Within transform: Attributes. */
/* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is
* automatically generated because it must be the same * automatically generated because it must be the same
* in every transform. Except IPCOMP. * in every transform. Except IPCOMP.
*/ */
if (p->protoid != PROTO_IPCOMP if (p->protoid != PROTO_IPCOMP && st->st_pfs_group != NULL)
&& st->st_pfs_group != NULL)
{ {
passert(!oakley_mode); passert(!oakley_mode);
passert(st->st_pfs_group != &unset_group); passert(st->st_pfs_group != &unset_group);
@@ -582,8 +581,7 @@ return_out:
* The code is can only handle values that can fit in unsigned long. * The code is can only handle values that can fit in unsigned long.
* "Clamping" is probably an acceptable way to impose this limitation. * "Clamping" is probably an acceptable way to impose this limitation.
*/ */
static u_int32_t static u_int32_t decode_long_duration(pb_stream *pbs)
decode_long_duration(pb_stream *pbs)
{ {
u_int32_t val = 0; u_int32_t val = 0;
@@ -631,8 +629,9 @@ preparse_isakmp_sa_body(const struct isakmp_sa *sa
/* Situation */ /* Situation */
if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL))
{
return SITUATION_NOT_SUPPORTED; return SITUATION_NOT_SUPPORTED;
}
if (*ipsecdoisit != SIT_IDENTITY_ONLY) if (*ipsecdoisit != SIT_IDENTITY_ONLY)
{ {
loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)"
@@ -647,8 +646,9 @@ preparse_isakmp_sa_body(const struct isakmp_sa *sa
* There may well be multiple transforms. * There may well be multiple transforms.
*/ */
if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs)) if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs))
{
return PAYLOAD_MALFORMED; return PAYLOAD_MALFORMED;
}
if (proposal->isap_np != ISAKMP_NEXT_NONE) if (proposal->isap_np != ISAKMP_NEXT_NONE)
{ {
loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal" loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal"
@@ -711,35 +711,31 @@ static struct {
u_int8_t *roof; u_int8_t *roof;
} backup; } backup;
/* /**
* backup the pointer into a pb_stream * Backup the pointer into a pb_stream
*/ */
void void backup_pbs(pb_stream *pbs)
backup_pbs(pb_stream *pbs)
{ {
backup.start = pbs->start; backup.start = pbs->start;
backup.cur = pbs->cur; backup.cur = pbs->cur;
backup.roof = pbs->roof; backup.roof = pbs->roof;
} }
/* /**
* restore the pointer into a pb_stream * Restore the pointer into a pb_stream
*/ */
void void restore_pbs(pb_stream *pbs)
restore_pbs(pb_stream *pbs)
{ {
pbs->start = backup.start; pbs->start = backup.start;
pbs->cur = backup.cur; pbs->cur = backup.cur;
pbs->roof = backup.roof; pbs->roof = backup.roof;
} }
/* /**
* Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies
*/ */
notification_t notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans,
parse_isakmp_policy(pb_stream *proposal_pbs lset_t *policy)
, u_int notrans
, lset_t *policy)
{ {
int last_transnum = -1; int last_transnum = -1;
@@ -753,8 +749,9 @@ parse_isakmp_policy(pb_stream *proposal_pbs
struct isakmp_transform trans; struct isakmp_transform trans;
if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs)) if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs))
{
return BAD_PROPOSAL_SYNTAX; return BAD_PROPOSAL_SYNTAX;
}
if (trans.isat_transnum <= last_transnum) if (trans.isat_transnum <= last_transnum)
{ {
/* picky, picky, picky */ /* picky, picky, picky */
@@ -781,8 +778,9 @@ parse_isakmp_policy(pb_stream *proposal_pbs
pb_stream attr_pbs; pb_stream attr_pbs;
if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs))
{
return BAD_PROPOSAL_SYNTAX; return BAD_PROPOSAL_SYNTAX;
}
passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32);
switch (a.isaat_af_type) switch (a.isaat_af_type)
@@ -827,11 +825,10 @@ parse_isakmp_policy(pb_stream *proposal_pbs
return NOTHING_WRONG; return NOTHING_WRONG;
} }
/* /**
* check that we can find a preshared secret * Check that we can find a preshared secret
*/ */
static err_t static err_t find_preshared_key(struct state* st)
find_preshared_key(struct state* st)
{ {
err_t ugh = NULL; err_t ugh = NULL;
struct connection *c = st->st_connection; struct connection *c = st->st_connection;
@@ -842,9 +839,13 @@ find_preshared_key(struct state* st)
idtoa(&c->spd.this.id, my_id, sizeof(my_id)); idtoa(&c->spd.this.id, my_id, sizeof(my_id));
if (his_id_was_instantiated(c)) if (his_id_was_instantiated(c))
{
strcpy(his_id, "%any"); strcpy(his_id, "%any");
}
else else
{
idtoa(&c->spd.that.id, his_id, sizeof(his_id)); idtoa(&c->spd.that.id, his_id, sizeof(his_id));
}
ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'"
, my_id, his_id); , my_id, his_id);
} }
@@ -860,13 +861,12 @@ find_preshared_key(struct state* st)
* *
* This routine is used by main_inI1_outR1() and main_inR1_outI2(). * This routine is used by main_inI1_outR1() and main_inR1_outI2().
*/ */
notification_t notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit,
parse_isakmp_sa_body(u_int32_t ipsecdoisit pb_stream *proposal_pbs,
, pb_stream *proposal_pbs struct isakmp_proposal *proposal,
, struct isakmp_proposal *proposal pb_stream *r_sa_pbs,
, pb_stream *r_sa_pbs struct state *st,
, struct state *st bool initiator)
, bool initiator)
{ {
struct connection *c = st->st_connection; struct connection *c = st->st_connection;
unsigned no_trans_left; unsigned no_trans_left;
@@ -1326,17 +1326,14 @@ static const struct ipsec_trans_attrs null_ipsec_trans_attrs = {
0, /* key_rounds */ 0, /* key_rounds */
}; };
static bool static bool parse_ipsec_transform(struct isakmp_transform *trans,
parse_ipsec_transform(struct isakmp_transform *trans struct ipsec_trans_attrs *attrs,
, struct ipsec_trans_attrs *attrs pb_stream *prop_pbs,
, pb_stream *prop_pbs pb_stream *trans_pbs,
, pb_stream *trans_pbs struct_desc *trans_desc,
, struct_desc *trans_desc int previous_transnum, /* or -1 if none */
, int previous_transnum /* or -1 if none */ bool selection, bool is_last, bool is_ipcomp,
, bool selection struct state *st) /* current state object */
, bool is_last
, bool is_ipcomp
, struct state *st) /* current state object */
{ {
lset_t seen_attrs = 0; lset_t seen_attrs = 0;
lset_t seen_durations = 0; lset_t seen_durations = 0;
@@ -1344,8 +1341,9 @@ parse_ipsec_transform(struct isakmp_transform *trans
const struct dh_desc *pfs_group = NULL; const struct dh_desc *pfs_group = NULL;
if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs)) if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs))
{
return FALSE; return FALSE;
}
if (trans->isat_transnum <= previous_transnum) if (trans->isat_transnum <= previous_transnum)
{ {
loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing"); loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing");