MACsec: Add PAE implementation
This adds initial implementation of IEEE Std 802.1X-2010 PAE for MACsec. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
7baec808ef
commit
887d9d01ab
11 changed files with 5711 additions and 1 deletions
|
@ -1,4 +1,4 @@
|
||||||
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
|
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps
|
||||||
|
|
||||||
all:
|
all:
|
||||||
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
|
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
|
||||||
|
|
8
src/pae/Makefile
Normal file
8
src/pae/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
all:
|
||||||
|
@echo Nothing to be made.
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *~ *.o *.d
|
||||||
|
|
||||||
|
install:
|
||||||
|
@echo Nothing to be made.
|
744
src/pae/ieee802_1x_cp.c
Normal file
744
src/pae/ieee802_1x_cp.c
Normal file
|
@ -0,0 +1,744 @@
|
||||||
|
/*
|
||||||
|
* IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine
|
||||||
|
* Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "utils/eloop.h"
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "common/ieee802_1x_defs.h"
|
||||||
|
#include "utils/state_machine.h"
|
||||||
|
#include "ieee802_1x_kay.h"
|
||||||
|
#include "ieee802_1x_secy_ops.h"
|
||||||
|
#include "pae/ieee802_1x_cp.h"
|
||||||
|
|
||||||
|
#define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
|
||||||
|
#define STATE_MACHINE_DEBUG_PREFIX "CP"
|
||||||
|
|
||||||
|
static u8 default_cs_id[] = CS_ID_GCM_AES_128;
|
||||||
|
|
||||||
|
/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
|
||||||
|
enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
|
||||||
|
|
||||||
|
struct ieee802_1x_cp_sm {
|
||||||
|
enum cp_states {
|
||||||
|
CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED,
|
||||||
|
CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
|
||||||
|
CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
|
||||||
|
} CP_state;
|
||||||
|
Boolean changed;
|
||||||
|
|
||||||
|
/* CP -> Client */
|
||||||
|
Boolean port_valid;
|
||||||
|
|
||||||
|
/* Logon -> CP */
|
||||||
|
enum connect_type connect;
|
||||||
|
u8 *authorization_data;
|
||||||
|
|
||||||
|
/* KaY -> CP */
|
||||||
|
Boolean chgd_server; /* clear by CP */
|
||||||
|
Boolean elected_self;
|
||||||
|
u8 *authorization_data1;
|
||||||
|
enum confidentiality_offset cipher_offset;
|
||||||
|
u8 *cipher_suite;
|
||||||
|
Boolean new_sak; /* clear by CP */
|
||||||
|
struct ieee802_1x_mka_ki distributed_ki;
|
||||||
|
u8 distributed_an;
|
||||||
|
Boolean using_receive_sas;
|
||||||
|
Boolean all_receiving;
|
||||||
|
Boolean server_transmitting;
|
||||||
|
Boolean using_transmit_sa;
|
||||||
|
|
||||||
|
/* CP -> KaY */
|
||||||
|
struct ieee802_1x_mka_ki *lki;
|
||||||
|
u8 lan;
|
||||||
|
Boolean ltx;
|
||||||
|
Boolean lrx;
|
||||||
|
struct ieee802_1x_mka_ki *oki;
|
||||||
|
u8 oan;
|
||||||
|
Boolean otx;
|
||||||
|
Boolean orx;
|
||||||
|
|
||||||
|
/* CP -> SecY */
|
||||||
|
Boolean protect_frames;
|
||||||
|
enum validate_frames validate_frames;
|
||||||
|
|
||||||
|
Boolean replay_protect;
|
||||||
|
u32 replay_window;
|
||||||
|
|
||||||
|
u8 *current_cipher_suite;
|
||||||
|
enum confidentiality_offset confidentiality_offset;
|
||||||
|
Boolean controlled_port_enabled;
|
||||||
|
|
||||||
|
/* SecY -> CP */
|
||||||
|
Boolean port_enabled; /* SecY->CP */
|
||||||
|
|
||||||
|
/* private */
|
||||||
|
u32 transmit_when;
|
||||||
|
u32 transmit_delay;
|
||||||
|
u32 retire_when;
|
||||||
|
u32 retire_delay;
|
||||||
|
|
||||||
|
/* not defined IEEE Std 802.1X-2010 */
|
||||||
|
struct ieee802_1x_kay *kay;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
|
||||||
|
void *timeout_ctx);
|
||||||
|
static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
|
||||||
|
void *timeout_ctx);
|
||||||
|
|
||||||
|
|
||||||
|
static int changed_cipher(struct ieee802_1x_cp_sm *sm)
|
||||||
|
{
|
||||||
|
return sm->confidentiality_offset != sm->cipher_offset ||
|
||||||
|
os_memcmp(sm->current_cipher_suite, sm->cipher_suite,
|
||||||
|
CS_ID_LEN) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int changed_connect(struct ieee802_1x_cp_sm *sm)
|
||||||
|
{
|
||||||
|
return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, INIT)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, INIT);
|
||||||
|
|
||||||
|
sm->controlled_port_enabled = FALSE;
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
|
||||||
|
sm->port_valid = FALSE;
|
||||||
|
|
||||||
|
os_free(sm->lki);
|
||||||
|
sm->lki = NULL;
|
||||||
|
sm->ltx = FALSE;
|
||||||
|
sm->lrx = FALSE;
|
||||||
|
|
||||||
|
os_free(sm->oki);
|
||||||
|
sm->oki = NULL;
|
||||||
|
sm->otx = FALSE;
|
||||||
|
sm->orx = FALSE;
|
||||||
|
|
||||||
|
sm->port_enabled = TRUE;
|
||||||
|
sm->chgd_server = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, CHANGE)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, CHANGE);
|
||||||
|
|
||||||
|
sm->port_valid = FALSE;
|
||||||
|
sm->controlled_port_enabled = FALSE;
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
|
||||||
|
if (sm->lki)
|
||||||
|
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
|
||||||
|
if (sm->oki)
|
||||||
|
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, ALLOWED)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, ALLOWED);
|
||||||
|
|
||||||
|
sm->protect_frames = FALSE;
|
||||||
|
sm->replay_protect = FALSE;
|
||||||
|
sm->validate_frames = Checked;
|
||||||
|
|
||||||
|
sm->port_valid = FALSE;
|
||||||
|
sm->controlled_port_enabled = TRUE;
|
||||||
|
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
|
||||||
|
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
|
||||||
|
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, AUTHENTICATED)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, AUTHENTICATED);
|
||||||
|
|
||||||
|
sm->protect_frames = FALSE;
|
||||||
|
sm->replay_protect = FALSE;
|
||||||
|
sm->validate_frames = Checked;
|
||||||
|
|
||||||
|
sm->port_valid = FALSE;
|
||||||
|
sm->controlled_port_enabled = TRUE;
|
||||||
|
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
|
||||||
|
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
|
||||||
|
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, SECURED)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_conf conf;
|
||||||
|
|
||||||
|
SM_ENTRY(CP, SECURED);
|
||||||
|
|
||||||
|
sm->chgd_server = FALSE;
|
||||||
|
|
||||||
|
ieee802_1x_kay_cp_conf(sm->kay, &conf);
|
||||||
|
sm->protect_frames = conf.protect;
|
||||||
|
sm->replay_protect = conf.replay_protect;
|
||||||
|
sm->validate_frames = conf.validate;
|
||||||
|
|
||||||
|
/* NOTE: now no other than default cipher suiter(AES-GCM-128) */
|
||||||
|
os_memcpy(sm->current_cipher_suite, sm->cipher_suite, CS_ID_LEN);
|
||||||
|
secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite,
|
||||||
|
CS_ID_LEN);
|
||||||
|
|
||||||
|
sm->confidentiality_offset = sm->cipher_offset;
|
||||||
|
|
||||||
|
sm->port_valid = TRUE;
|
||||||
|
|
||||||
|
secy_cp_control_confidentiality_offset(sm->kay,
|
||||||
|
sm->confidentiality_offset);
|
||||||
|
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
|
||||||
|
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
|
||||||
|
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, RECEIVE)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, RECEIVE);
|
||||||
|
/* RECEIVE state machine not keep with Figure 12-2 in
|
||||||
|
* IEEE Std 802.1X-2010 */
|
||||||
|
sm->oki = sm->lki;
|
||||||
|
sm->oan = sm->lan;
|
||||||
|
sm->otx = sm->ltx;
|
||||||
|
sm->orx = sm->lrx;
|
||||||
|
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
|
||||||
|
sm->otx, sm->orx);
|
||||||
|
|
||||||
|
sm->lki = os_malloc(sizeof(*sm->lki));
|
||||||
|
if (!sm->lki) {
|
||||||
|
wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
|
||||||
|
sm->lan = sm->distributed_an;
|
||||||
|
sm->ltx = FALSE;
|
||||||
|
sm->lrx = FALSE;
|
||||||
|
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
|
||||||
|
sm->ltx, sm->lrx);
|
||||||
|
ieee802_1x_kay_create_sas(sm->kay, sm->lki);
|
||||||
|
ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
|
||||||
|
sm->new_sak = FALSE;
|
||||||
|
sm->all_receiving = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, RECEIVING)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, RECEIVING);
|
||||||
|
|
||||||
|
sm->lrx = TRUE;
|
||||||
|
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
|
||||||
|
sm->ltx, sm->lrx);
|
||||||
|
sm->transmit_when = sm->transmit_delay;
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
|
||||||
|
eloop_register_timeout(sm->transmit_when / 1000, 0,
|
||||||
|
ieee802_1x_cp_transmit_when_timeout, sm, NULL);
|
||||||
|
/* the electedSelf have been set before CP entering to RECEIVING
|
||||||
|
* but the CP will transmit from RECEIVING to READY under
|
||||||
|
* the !electedSelf when KaY is not key server */
|
||||||
|
ieee802_1x_cp_sm_step(sm);
|
||||||
|
sm->using_receive_sas = FALSE;
|
||||||
|
sm->server_transmitting = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, READY)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, READY);
|
||||||
|
|
||||||
|
ieee802_1x_kay_enable_new_info(sm->kay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, TRANSMIT)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, TRANSMIT);
|
||||||
|
|
||||||
|
sm->controlled_port_enabled = TRUE;
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
sm->ltx = TRUE;
|
||||||
|
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
|
||||||
|
sm->ltx, sm->lrx);
|
||||||
|
ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki);
|
||||||
|
sm->all_receiving = FALSE;
|
||||||
|
sm->server_transmitting = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, TRANSMITTING)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, TRANSMITTING);
|
||||||
|
sm->retire_when = sm->orx ? sm->retire_delay : 0;
|
||||||
|
sm->otx = FALSE;
|
||||||
|
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
|
||||||
|
sm->otx, sm->orx);
|
||||||
|
ieee802_1x_kay_enable_new_info(sm->kay);
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
|
||||||
|
eloop_register_timeout(sm->retire_when / 1000, 0,
|
||||||
|
ieee802_1x_cp_retire_when_timeout, sm, NULL);
|
||||||
|
sm->using_transmit_sa = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, ABANDON)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, ABANDON);
|
||||||
|
sm->lrx = FALSE;
|
||||||
|
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
|
||||||
|
sm->ltx, sm->lrx);
|
||||||
|
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
|
||||||
|
|
||||||
|
os_free(sm->lki);
|
||||||
|
sm->lki = NULL;
|
||||||
|
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
|
||||||
|
sm->ltx, sm->lrx);
|
||||||
|
sm->new_sak = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SM_STATE(CP, RETIRE)
|
||||||
|
{
|
||||||
|
SM_ENTRY(CP, RETIRE);
|
||||||
|
/* RETIRE state machine not keep with Figure 12-2 in
|
||||||
|
* IEEE Std 802.1X-2010 */
|
||||||
|
os_free(sm->oki);
|
||||||
|
sm->oki = NULL;
|
||||||
|
sm->orx = FALSE;
|
||||||
|
sm->otx = FALSE;
|
||||||
|
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
|
||||||
|
sm->otx, sm->orx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CP state machine handler entry
|
||||||
|
*/
|
||||||
|
SM_STEP(CP)
|
||||||
|
{
|
||||||
|
if (!sm->port_enabled)
|
||||||
|
SM_ENTER(CP, INIT);
|
||||||
|
|
||||||
|
switch (sm->CP_state) {
|
||||||
|
case CP_BEGIN:
|
||||||
|
SM_ENTER(CP, INIT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_INIT:
|
||||||
|
SM_ENTER(CP, CHANGE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_CHANGE:
|
||||||
|
if (sm->connect == UNAUTHENTICATED)
|
||||||
|
SM_ENTER(CP, ALLOWED);
|
||||||
|
else if (sm->connect == AUTHENTICATED)
|
||||||
|
SM_ENTER(CP, AUTHENTICATED);
|
||||||
|
else if (sm->connect == SECURE)
|
||||||
|
SM_ENTER(CP, SECURED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_ALLOWED:
|
||||||
|
if (sm->connect != UNAUTHENTICATED)
|
||||||
|
SM_ENTER(CP, CHANGE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_AUTHENTICATED:
|
||||||
|
if (sm->connect != AUTHENTICATED)
|
||||||
|
SM_ENTER(CP, CHANGE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_SECURED:
|
||||||
|
if (changed_connect(sm))
|
||||||
|
SM_ENTER(CP, CHANGE);
|
||||||
|
else if (sm->new_sak)
|
||||||
|
SM_ENTER(CP, RECEIVE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_RECEIVE:
|
||||||
|
if (sm->using_receive_sas)
|
||||||
|
SM_ENTER(CP, RECEIVING);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_RECEIVING:
|
||||||
|
if (sm->new_sak || changed_connect(sm))
|
||||||
|
SM_ENTER(CP, ABANDON);
|
||||||
|
if (!sm->elected_self)
|
||||||
|
SM_ENTER(CP, READY);
|
||||||
|
if (sm->elected_self &&
|
||||||
|
(sm->all_receiving || !sm->transmit_when))
|
||||||
|
SM_ENTER(CP, TRANSMIT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_TRANSMIT:
|
||||||
|
if (sm->using_transmit_sa)
|
||||||
|
SM_ENTER(CP, TRANSMITTING);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_TRANSMITTING:
|
||||||
|
if (!sm->retire_when || changed_connect(sm))
|
||||||
|
SM_ENTER(CP, RETIRE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_RETIRE:
|
||||||
|
if (changed_connect(sm))
|
||||||
|
SM_ENTER(CP, CHANGE);
|
||||||
|
else if (sm->new_sak)
|
||||||
|
SM_ENTER(CP, RECEIVE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CP_READY:
|
||||||
|
if (sm->new_sak || changed_connect(sm))
|
||||||
|
SM_ENTER(CP, RECEIVE);
|
||||||
|
if (sm->server_transmitting)
|
||||||
|
SM_ENTER(CP, TRANSMIT);
|
||||||
|
break;
|
||||||
|
case CP_ABANDON:
|
||||||
|
if (changed_connect(sm))
|
||||||
|
SM_ENTER(CP, RETIRE);
|
||||||
|
else if (sm->new_sak)
|
||||||
|
SM_ENTER(CP, RECEIVE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wpa_printf(MSG_ERROR, "CP: the state machine is not defined");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_sm_init -
|
||||||
|
*/
|
||||||
|
struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
|
||||||
|
struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_cp_conf *pcp_conf)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm;
|
||||||
|
|
||||||
|
sm = os_zalloc(sizeof(*sm));
|
||||||
|
if (sm == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm->kay = kay;
|
||||||
|
|
||||||
|
sm->port_valid = FALSE;
|
||||||
|
|
||||||
|
sm->chgd_server = FALSE;
|
||||||
|
|
||||||
|
sm->protect_frames = pcp_conf->protect;
|
||||||
|
sm->validate_frames = pcp_conf->validate;
|
||||||
|
sm->replay_protect = pcp_conf->replay_protect;
|
||||||
|
sm->replay_window = pcp_conf->replay_window;
|
||||||
|
|
||||||
|
sm->controlled_port_enabled = FALSE;
|
||||||
|
|
||||||
|
sm->lki = NULL;
|
||||||
|
sm->lrx = FALSE;
|
||||||
|
sm->ltx = FALSE;
|
||||||
|
sm->oki = NULL;
|
||||||
|
sm->orx = FALSE;
|
||||||
|
sm->otx = FALSE;
|
||||||
|
|
||||||
|
sm->cipher_suite = os_zalloc(CS_ID_LEN);
|
||||||
|
sm->current_cipher_suite = os_zalloc(CS_ID_LEN);
|
||||||
|
if (!sm->cipher_suite || !sm->current_cipher_suite) {
|
||||||
|
wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
|
||||||
|
os_free(sm->cipher_suite);
|
||||||
|
os_free(sm->current_cipher_suite);
|
||||||
|
os_free(sm);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
os_memcpy(sm->current_cipher_suite, default_cs_id, CS_ID_LEN);
|
||||||
|
os_memcpy(sm->cipher_suite, default_cs_id, CS_ID_LEN);
|
||||||
|
sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
|
||||||
|
sm->confidentiality_offset = sm->cipher_offset;
|
||||||
|
sm->transmit_delay = MKA_LIFE_TIME;
|
||||||
|
sm->retire_delay = MKA_SAK_RETIRE_TIME;
|
||||||
|
sm->CP_state = CP_BEGIN;
|
||||||
|
sm->changed = FALSE;
|
||||||
|
sm->authorization_data = NULL;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "CP: state machine created");
|
||||||
|
|
||||||
|
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
|
||||||
|
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
|
||||||
|
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
|
||||||
|
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
|
||||||
|
secy_cp_control_confidentiality_offset(sm->kay,
|
||||||
|
sm->confidentiality_offset);
|
||||||
|
|
||||||
|
SM_ENTER(CP, INIT);
|
||||||
|
SM_STEP_RUN(CP);
|
||||||
|
|
||||||
|
return sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm)
|
||||||
|
{
|
||||||
|
enum cp_states prev_state;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
prev_state = sm->CP_state;
|
||||||
|
SM_STEP_RUN(CP);
|
||||||
|
if (prev_state == sm->CP_state)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = eloop_ctx;
|
||||||
|
ieee802_1x_cp_step_run(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_sm_deinit -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "CP: state machine removed");
|
||||||
|
if (!sm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
|
||||||
|
os_free(sm->lki);
|
||||||
|
os_free(sm->oki);
|
||||||
|
os_free(sm->cipher_suite);
|
||||||
|
os_free(sm->current_cipher_suite);
|
||||||
|
os_free(sm->authorization_data);
|
||||||
|
os_free(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_connect_pending
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_connect_pending(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
|
||||||
|
sm->connect = PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_connect_unauthenticated
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx;
|
||||||
|
|
||||||
|
sm->connect = UNAUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_connect_authenticated
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_connect_authenticated(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
|
||||||
|
sm->connect = AUTHENTICATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_connect_secure
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_connect_secure(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
|
||||||
|
sm->connect = SECURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_chgdserver -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
|
||||||
|
sm->chgd_server = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_electedself -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->elected_self = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_authorizationdata -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
os_free(sm->authorization_data);
|
||||||
|
sm->authorization_data = os_zalloc(len);
|
||||||
|
if (sm->authorization_data)
|
||||||
|
os_memcpy(sm->authorization_data, pdata, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_ciphersuite -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
os_memcpy(sm->cipher_suite, pid, CS_ID_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_offset -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->cipher_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_signal_newsak -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_signal_newsak(void *cp_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->new_sak = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_distributedki -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
|
||||||
|
const struct ieee802_1x_mka_ki *dki)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_distributedan -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->distributed_an = an;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_usingreceivesas -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->using_receive_sas = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_allreceiving -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->all_receiving = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_servertransmitting -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->server_transmitting = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_set_usingtransmitsas -
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
sm->using_transmit_sa = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cp_sm_step - Advance EAPOL state machines
|
||||||
|
* @sm: EAPOL state machine
|
||||||
|
*
|
||||||
|
* This function is called to advance CP state machines after any change
|
||||||
|
* that could affect their state.
|
||||||
|
*/
|
||||||
|
void ieee802_1x_cp_sm_step(void *cp_ctx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Run ieee802_1x_cp_step_run from a registered timeout
|
||||||
|
* to make sure that other possible timeouts/events are processed
|
||||||
|
* and to avoid long function call chains.
|
||||||
|
*/
|
||||||
|
struct ieee802_1x_cp_sm *sm = cp_ctx;
|
||||||
|
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
|
||||||
|
eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
|
||||||
|
void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = eloop_ctx;
|
||||||
|
sm->retire_when = 0;
|
||||||
|
ieee802_1x_cp_step_run(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_cp_sm *sm = eloop_ctx;
|
||||||
|
sm->transmit_when = 0;
|
||||||
|
ieee802_1x_cp_step_run(sm);
|
||||||
|
}
|
50
src/pae/ieee802_1x_cp.h
Normal file
50
src/pae/ieee802_1x_cp.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* IEEE Std 802.1X-2010 Controlled Port of PAE state machine - CP state machine
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_CP_H
|
||||||
|
#define IEEE802_1X_CP_H
|
||||||
|
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "common/ieee802_1x_defs.h"
|
||||||
|
|
||||||
|
struct ieee802_1x_cp_sm;
|
||||||
|
struct ieee802_1x_kay;
|
||||||
|
struct ieee802_1x_mka_ki;
|
||||||
|
|
||||||
|
struct ieee802_1x_cp_conf {
|
||||||
|
Boolean protect;
|
||||||
|
Boolean replay_protect;
|
||||||
|
enum validate_frames validate;
|
||||||
|
u32 replay_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee802_1x_cp_sm *
|
||||||
|
ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_cp_conf *pcp_conf);
|
||||||
|
void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm);
|
||||||
|
void ieee802_1x_cp_sm_step(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_connect_pending(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_connect_authenticated(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_connect_secure(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status);
|
||||||
|
void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len);
|
||||||
|
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid);
|
||||||
|
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset);
|
||||||
|
void ieee802_1x_cp_signal_newsak(void *cp_ctx);
|
||||||
|
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
|
||||||
|
const struct ieee802_1x_mka_ki *dki);
|
||||||
|
void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an);
|
||||||
|
void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status);
|
||||||
|
void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status);
|
||||||
|
void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status);
|
||||||
|
void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status);
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_CP_H */
|
3526
src/pae/ieee802_1x_kay.c
Normal file
3526
src/pae/ieee802_1x_kay.c
Normal file
File diff suppressed because it is too large
Load diff
194
src/pae/ieee802_1x_kay.h
Normal file
194
src/pae/ieee802_1x_kay.h
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_KAY_H
|
||||||
|
#define IEEE802_1X_KAY_H
|
||||||
|
|
||||||
|
#include "utils/list.h"
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "common/ieee802_1x_defs.h"
|
||||||
|
|
||||||
|
struct macsec_init_params;
|
||||||
|
struct ieee802_1x_cp_conf;
|
||||||
|
|
||||||
|
#define MI_LEN 12
|
||||||
|
#define MAX_KEY_LEN 32 /* 32 bytes, 256 bits */
|
||||||
|
#define MAX_CKN_LEN 32 /* 32 bytes, 256 bits */
|
||||||
|
|
||||||
|
/* MKA timer, unit: millisecond */
|
||||||
|
#define MKA_HELLO_TIME 2000
|
||||||
|
#define MKA_LIFE_TIME 6000
|
||||||
|
#define MKA_SAK_RETIRE_TIME 3000
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_ki {
|
||||||
|
u8 mi[MI_LEN];
|
||||||
|
u32 kn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_sci {
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
u16 port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mka_key {
|
||||||
|
u8 key[MAX_KEY_LEN];
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mka_key_name {
|
||||||
|
u8 name[MAX_CKN_LEN];
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mka_created_mode {
|
||||||
|
PSK,
|
||||||
|
EAP_EXCHANGE,
|
||||||
|
DISTRIBUTED,
|
||||||
|
CACHED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_kay_ctx {
|
||||||
|
/* pointer to arbitrary upper level context */
|
||||||
|
void *ctx;
|
||||||
|
|
||||||
|
/* abstract wpa driver interface */
|
||||||
|
int (*macsec_init)(void *ctx, struct macsec_init_params *params);
|
||||||
|
int (*macsec_deinit)(void *ctx);
|
||||||
|
int (*enable_protect_frames)(void *ctx, Boolean enabled);
|
||||||
|
int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
|
||||||
|
int (*set_current_cipher_suite)(void *ctx, const u8 *cs, size_t cs_len);
|
||||||
|
int (*enable_controlled_port)(void *ctx, Boolean enabled);
|
||||||
|
int (*get_receive_lowest_pn)(void *ctx, u32 channel, u8 an,
|
||||||
|
u32 *lowest_pn);
|
||||||
|
int (*get_transmit_next_pn)(void *ctx, u32 channel, u8 an,
|
||||||
|
u32 *next_pn);
|
||||||
|
int (*set_transmit_next_pn)(void *ctx, u32 channel, u8 an, u32 next_pn);
|
||||||
|
int (*get_available_receive_sc)(void *ctx, u32 *channel);
|
||||||
|
int (*create_receive_sc)(void *ctx, u32 channel,
|
||||||
|
struct ieee802_1x_mka_sci *sci,
|
||||||
|
enum validate_frames vf,
|
||||||
|
enum confidentiality_offset co);
|
||||||
|
int (*delete_receive_sc)(void *ctx, u32 channel);
|
||||||
|
int (*create_receive_sa)(void *ctx, u32 channel, u8 an, u32 lowest_pn,
|
||||||
|
const u8 *sak);
|
||||||
|
int (*enable_receive_sa)(void *ctx, u32 channel, u8 an);
|
||||||
|
int (*disable_receive_sa)(void *ctx, u32 channel, u8 an);
|
||||||
|
int (*get_available_transmit_sc)(void *ctx, u32 *channel);
|
||||||
|
int (*create_transmit_sc)(void *ctx, u32 channel,
|
||||||
|
const struct ieee802_1x_mka_sci *sci,
|
||||||
|
enum confidentiality_offset co);
|
||||||
|
int (*delete_transmit_sc)(void *ctx, u32 channel);
|
||||||
|
int (*create_transmit_sa)(void *ctx, u32 channel, u8 an, u32 next_pn,
|
||||||
|
Boolean confidentiality, const u8 *sak);
|
||||||
|
int (*enable_transmit_sa)(void *ctx, u32 channel, u8 an);
|
||||||
|
int (*disable_transmit_sa)(void *ctx, u32 channel, u8 an);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_kay {
|
||||||
|
Boolean enable;
|
||||||
|
Boolean active;
|
||||||
|
|
||||||
|
Boolean authenticated;
|
||||||
|
Boolean secured;
|
||||||
|
Boolean failed;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_sci actor_sci;
|
||||||
|
u8 actor_priority;
|
||||||
|
struct ieee802_1x_mka_sci key_server_sci;
|
||||||
|
u8 key_server_priority;
|
||||||
|
|
||||||
|
enum macsec_cap macsec_capable;
|
||||||
|
Boolean macsec_desired;
|
||||||
|
Boolean macsec_protect;
|
||||||
|
Boolean macsec_replay_protect;
|
||||||
|
u32 macsec_replay_window;
|
||||||
|
enum validate_frames macsec_validate;
|
||||||
|
enum confidentiality_offset macsec_confidentiality;
|
||||||
|
|
||||||
|
u32 ltx_kn;
|
||||||
|
u8 ltx_an;
|
||||||
|
u32 lrx_kn;
|
||||||
|
u8 lrx_an;
|
||||||
|
|
||||||
|
u32 otx_kn;
|
||||||
|
u8 otx_an;
|
||||||
|
u32 orx_kn;
|
||||||
|
u8 orx_an;
|
||||||
|
|
||||||
|
/* not defined in IEEE802.1X */
|
||||||
|
struct ieee802_1x_kay_ctx *ctx;
|
||||||
|
Boolean is_key_server;
|
||||||
|
Boolean is_obliged_key_server;
|
||||||
|
char if_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
int macsec_csindex; /* MACsec cipher suite table index */
|
||||||
|
int mka_algindex; /* MKA alg table index */
|
||||||
|
|
||||||
|
u32 dist_kn;
|
||||||
|
u8 dist_an;
|
||||||
|
time_t dist_time;
|
||||||
|
|
||||||
|
u8 mka_version;
|
||||||
|
u8 algo_agility[4];
|
||||||
|
u32 sc_ch;
|
||||||
|
|
||||||
|
u32 pn_exhaustion;
|
||||||
|
Boolean port_enable;
|
||||||
|
Boolean rx_enable;
|
||||||
|
Boolean tx_enable;
|
||||||
|
|
||||||
|
struct dl_list participant_list;
|
||||||
|
enum macsec_policy policy;
|
||||||
|
|
||||||
|
struct ieee802_1x_cp_sm *cp;
|
||||||
|
|
||||||
|
struct l2_packet_data *l2_mka;
|
||||||
|
|
||||||
|
enum validate_frames vf;
|
||||||
|
enum confidentiality_offset co;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee802_1x_kay *
|
||||||
|
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
|
||||||
|
const char *ifname, const u8 *addr);
|
||||||
|
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_participant *
|
||||||
|
ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
|
||||||
|
struct mka_key_name *ckn, struct mka_key *cak,
|
||||||
|
u32 life, enum mka_created_mode mode,
|
||||||
|
Boolean is_authenticator);
|
||||||
|
void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
|
||||||
|
struct mka_key_name *ckn);
|
||||||
|
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
|
||||||
|
struct mka_key_name *ckn,
|
||||||
|
Boolean status);
|
||||||
|
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
|
||||||
|
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
|
||||||
|
int cs_index);
|
||||||
|
|
||||||
|
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *lki, u8 lan,
|
||||||
|
Boolean ltx, Boolean lrx);
|
||||||
|
int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *oki,
|
||||||
|
u8 oan, Boolean otx, Boolean orx);
|
||||||
|
int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *lki);
|
||||||
|
int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *ki);
|
||||||
|
int ieee802_1x_kay_enable_tx_sas(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *lki);
|
||||||
|
int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_mka_ki *lki);
|
||||||
|
int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
|
||||||
|
int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
|
||||||
|
struct ieee802_1x_cp_conf *pconf);
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_KAY_H */
|
419
src/pae/ieee802_1x_kay_i.h
Normal file
419
src/pae/ieee802_1x_kay_i.h
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
* IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_KAY_I_H
|
||||||
|
#define IEEE802_1X_KAY_I_H
|
||||||
|
|
||||||
|
#include "utils/list.h"
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "common/ieee802_1x_defs.h"
|
||||||
|
|
||||||
|
#define MKA_VERSION_ID 1
|
||||||
|
|
||||||
|
/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 */
|
||||||
|
enum mka_packet_type {
|
||||||
|
MKA_BASIC_PARAMETER_SET = MKA_VERSION_ID,
|
||||||
|
MKA_LIVE_PEER_LIST = 1,
|
||||||
|
MKA_POTENTIAL_PEER_LIST = 2,
|
||||||
|
MKA_SAK_USE = 3,
|
||||||
|
MKA_DISTRIBUTED_SAK = 4,
|
||||||
|
MKA_DISTRIBUTED_CAK = 5,
|
||||||
|
MKA_KMD = 6,
|
||||||
|
MKA_ANNOUNCEMENT = 7,
|
||||||
|
MKA_ICV_INDICATOR = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ICV_LEN 16 /* 16 bytes */
|
||||||
|
#define SAK_WRAPPED_LEN 24
|
||||||
|
/* KN + Wrapper SAK */
|
||||||
|
#define DEFAULT_DIS_SAK_BODY_LENGTH (SAK_WRAPPED_LEN + 4)
|
||||||
|
#define MAX_RETRY_CNT 5
|
||||||
|
|
||||||
|
struct ieee802_1x_kay;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_peer_id {
|
||||||
|
u8 mi[MI_LEN];
|
||||||
|
u32 mn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_kay_peer {
|
||||||
|
struct ieee802_1x_mka_sci sci;
|
||||||
|
u8 mi[MI_LEN];
|
||||||
|
u32 mn;
|
||||||
|
time_t expire;
|
||||||
|
Boolean is_key_server;
|
||||||
|
u8 key_server_priority;
|
||||||
|
Boolean macsec_desired;
|
||||||
|
enum macsec_cap macsec_capbility;
|
||||||
|
Boolean sak_used;
|
||||||
|
struct dl_list list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct key_conf {
|
||||||
|
u8 *key;
|
||||||
|
struct ieee802_1x_mka_ki ki;
|
||||||
|
enum confidentiality_offset offset;
|
||||||
|
u8 an;
|
||||||
|
Boolean tx;
|
||||||
|
Boolean rx;
|
||||||
|
int key_len; /* unit: byte */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct data_key {
|
||||||
|
u8 *key;
|
||||||
|
int key_len;
|
||||||
|
struct ieee802_1x_mka_ki key_identifier;
|
||||||
|
enum confidentiality_offset confidentiality_offset;
|
||||||
|
u8 an;
|
||||||
|
Boolean transmits;
|
||||||
|
Boolean receives;
|
||||||
|
struct os_time created_time;
|
||||||
|
u32 next_pn;
|
||||||
|
|
||||||
|
/* not defined data */
|
||||||
|
Boolean rx_latest;
|
||||||
|
Boolean tx_latest;
|
||||||
|
|
||||||
|
int user; /* FIXME: to indicate if it can be delete safely */
|
||||||
|
|
||||||
|
struct dl_list list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
|
||||||
|
struct transmit_sc {
|
||||||
|
struct ieee802_1x_mka_sci sci; /* const SCI sci */
|
||||||
|
Boolean transmitting; /* bool transmitting (read only) */
|
||||||
|
|
||||||
|
struct os_time created_time; /* Time createdTime */
|
||||||
|
|
||||||
|
u8 encoding_sa; /* AN encodingSA (read only) */
|
||||||
|
u8 enciphering_sa; /* AN encipheringSA (read only) */
|
||||||
|
|
||||||
|
/* not defined data */
|
||||||
|
unsigned int channel;
|
||||||
|
|
||||||
|
struct dl_list list;
|
||||||
|
struct dl_list sa_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
|
||||||
|
struct transmit_sa {
|
||||||
|
Boolean in_use; /* bool inUse (read only) */
|
||||||
|
u32 next_pn; /* PN nextPN (read only) */
|
||||||
|
struct os_time created_time; /* Time createdTime */
|
||||||
|
|
||||||
|
Boolean enable_transmit; /* bool EnableTransmit */
|
||||||
|
|
||||||
|
u8 an;
|
||||||
|
Boolean confidentiality;
|
||||||
|
struct data_key *pkey;
|
||||||
|
|
||||||
|
struct transmit_sc *sc;
|
||||||
|
struct dl_list list; /* list entry in struct transmit_sc::sa_list */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
|
||||||
|
struct receive_sc {
|
||||||
|
struct ieee802_1x_mka_sci sci; /* const SCI sci */
|
||||||
|
Boolean receiving; /* bool receiving (read only) */
|
||||||
|
|
||||||
|
struct os_time created_time; /* Time createdTime */
|
||||||
|
|
||||||
|
unsigned int channel;
|
||||||
|
|
||||||
|
struct dl_list list;
|
||||||
|
struct dl_list sa_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
|
||||||
|
struct receive_sa {
|
||||||
|
Boolean enable_receive; /* bool enableReceive */
|
||||||
|
Boolean in_use; /* bool inUse (read only) */
|
||||||
|
|
||||||
|
u32 next_pn; /* PN nextPN (read only) */
|
||||||
|
u32 lowest_pn; /* PN lowestPN (read only) */
|
||||||
|
u8 an;
|
||||||
|
struct os_time created_time;
|
||||||
|
|
||||||
|
struct data_key *pkey;
|
||||||
|
struct receive_sc *sc; /* list entry in struct receive_sc::sa_list */
|
||||||
|
|
||||||
|
struct dl_list list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct macsec_ciphersuite {
|
||||||
|
u8 id[CS_ID_LEN];
|
||||||
|
char name[32];
|
||||||
|
enum macsec_cap capable;
|
||||||
|
int sak_len; /* unit: byte */
|
||||||
|
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mka_alg {
|
||||||
|
u8 parameter[4];
|
||||||
|
size_t cak_len;
|
||||||
|
size_t kek_len;
|
||||||
|
size_t ick_len;
|
||||||
|
size_t icv_len;
|
||||||
|
|
||||||
|
int (*cak_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2, u8 *cak);
|
||||||
|
int (*ckn_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2,
|
||||||
|
const u8 *sid, size_t sid_len, u8 *ckn);
|
||||||
|
int (*kek_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *kek);
|
||||||
|
int (*ick_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *ick);
|
||||||
|
int (*icv_hash)(const u8 *ick, const u8 *msg, size_t msg_len, u8 *icv);
|
||||||
|
|
||||||
|
int index; /* index for configuring */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MKA_ALG_INDEX 0
|
||||||
|
|
||||||
|
/* See IEEE Std 802.1X-2010, 9.16 MKA management */
|
||||||
|
struct ieee802_1x_mka_participant {
|
||||||
|
/* used for active and potential participant */
|
||||||
|
struct mka_key_name ckn;
|
||||||
|
struct mka_key cak;
|
||||||
|
Boolean cached;
|
||||||
|
|
||||||
|
/* used by management to monitor and control activation */
|
||||||
|
Boolean active;
|
||||||
|
Boolean participant;
|
||||||
|
Boolean retain;
|
||||||
|
|
||||||
|
enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
|
||||||
|
|
||||||
|
/* used for active participant */
|
||||||
|
Boolean principal;
|
||||||
|
struct dl_list live_peers;
|
||||||
|
struct dl_list potential_peers;
|
||||||
|
|
||||||
|
/* not defined in IEEE 802.1X */
|
||||||
|
struct dl_list list;
|
||||||
|
|
||||||
|
struct mka_key kek;
|
||||||
|
struct mka_key ick;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_ki lki;
|
||||||
|
u8 lan;
|
||||||
|
Boolean ltx;
|
||||||
|
Boolean lrx;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_ki oki;
|
||||||
|
u8 oan;
|
||||||
|
Boolean otx;
|
||||||
|
Boolean orx;
|
||||||
|
|
||||||
|
Boolean is_key_server;
|
||||||
|
Boolean is_obliged_key_server;
|
||||||
|
Boolean can_be_key_server;
|
||||||
|
Boolean is_elected;
|
||||||
|
|
||||||
|
struct dl_list sak_list;
|
||||||
|
struct dl_list rxsc_list;
|
||||||
|
|
||||||
|
struct transmit_sc *txsc;
|
||||||
|
|
||||||
|
u8 mi[MI_LEN];
|
||||||
|
u32 mn;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_peer_id current_peer_id;
|
||||||
|
struct ieee802_1x_mka_sci current_peer_sci;
|
||||||
|
time_t cak_life;
|
||||||
|
time_t mka_life;
|
||||||
|
Boolean to_dist_sak;
|
||||||
|
Boolean to_use_sak;
|
||||||
|
Boolean new_sak;
|
||||||
|
|
||||||
|
Boolean advised_desired;
|
||||||
|
enum macsec_cap advised_capability;
|
||||||
|
|
||||||
|
struct data_key *new_key;
|
||||||
|
u32 retry_count;
|
||||||
|
|
||||||
|
struct ieee802_1x_kay *kay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_hdr {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 type:8;
|
||||||
|
/* octet 2 */
|
||||||
|
u32 reserve:8;
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 reserve1:4;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 reserve1:4;
|
||||||
|
u32 length:4;
|
||||||
|
#else
|
||||||
|
#error "Please fix <bits/endian.h>"
|
||||||
|
#endif
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_basic_body {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 version:8;
|
||||||
|
/* octet 2 */
|
||||||
|
u32 priority:8;
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 macsec_capbility:2;
|
||||||
|
u32 macsec_desired:1;
|
||||||
|
u32 key_server:1;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 key_server:1;
|
||||||
|
u32 macsec_desired:1;
|
||||||
|
u32 macsec_capbility:2;
|
||||||
|
u32 length:4;
|
||||||
|
#endif
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_sci actor_sci;
|
||||||
|
u8 actor_mi[MI_LEN];
|
||||||
|
u32 actor_mn;
|
||||||
|
u8 algo_agility[4];
|
||||||
|
|
||||||
|
/* followed by CAK Name*/
|
||||||
|
u8 ckn[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_peer_body {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 type:8;
|
||||||
|
/* octet 2 */
|
||||||
|
u32 reserve:8;
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 reserve1:4;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 reserve1:4;
|
||||||
|
u32 length:4;
|
||||||
|
#endif
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
|
||||||
|
u8 peer[0];
|
||||||
|
/* followed by Peers */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_sak_use_body {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 type:8;
|
||||||
|
/* octet 2 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 orx:1;
|
||||||
|
u32 otx:1;
|
||||||
|
u32 oan:2;
|
||||||
|
u32 lrx:1;
|
||||||
|
u32 ltx:1;
|
||||||
|
u32 lan:2;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 lan:2;
|
||||||
|
u32 ltx:1;
|
||||||
|
u32 lrx:1;
|
||||||
|
u32 oan:2;
|
||||||
|
u32 otx:1;
|
||||||
|
u32 orx:1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 delay_protect:1;
|
||||||
|
u32 reserve:1;
|
||||||
|
u32 prx:1;
|
||||||
|
u32 ptx:1;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 ptx:1;
|
||||||
|
u32 prx:1;
|
||||||
|
u32 reserve:1;
|
||||||
|
u32 delay_protect:1;
|
||||||
|
u32 length:4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
|
||||||
|
/* octet 5 - 16 */
|
||||||
|
u8 lsrv_mi[MI_LEN];
|
||||||
|
/* octet 17 - 20 */
|
||||||
|
u32 lkn;
|
||||||
|
/* octet 21 - 24 */
|
||||||
|
u32 llpn;
|
||||||
|
|
||||||
|
/* octet 25 - 36 */
|
||||||
|
u8 osrv_mi[MI_LEN];
|
||||||
|
/* octet 37 - 40 */
|
||||||
|
u32 okn;
|
||||||
|
/* octet 41 - 44 */
|
||||||
|
u32 olpn;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_dist_sak_body {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 type:8;
|
||||||
|
/* octet 2 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 reserve:4;
|
||||||
|
u32 confid_offset:2;
|
||||||
|
u32 dan:2;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 dan:2;
|
||||||
|
u32 confid_offset:2;
|
||||||
|
u32 reserve:4;
|
||||||
|
#endif
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 reserve1:4;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 reserve1:4;
|
||||||
|
u32 length:4;
|
||||||
|
#endif
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
/* octet 5 - 8 */
|
||||||
|
u32 kn;
|
||||||
|
|
||||||
|
/* for GCM-AES-128: octet 9-32: SAK
|
||||||
|
* for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
|
||||||
|
*/
|
||||||
|
u8 sak[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee802_1x_mka_icv_body {
|
||||||
|
/* octet 1 */
|
||||||
|
u32 type:8;
|
||||||
|
/* octet 2 */
|
||||||
|
u32 reserve:8;
|
||||||
|
/* octet 3 */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
u32 length:4;
|
||||||
|
u32 reserve1:4;
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
u32 reserve1:4;
|
||||||
|
u32 length:4;
|
||||||
|
#endif
|
||||||
|
/* octet 4 */
|
||||||
|
u32 length1:8;
|
||||||
|
|
||||||
|
/* octet 5 - */
|
||||||
|
u8 icv[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_KAY_I_H */
|
189
src/pae/ieee802_1x_key.c
Normal file
189
src/pae/ieee802_1x_key.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* IEEE 802.1X-2010 Key Hierarchy
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*
|
||||||
|
* SAK derivation specified in IEEE Std 802.1X-2010, Clause 6.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "crypto/md5.h"
|
||||||
|
#include "crypto/sha1.h"
|
||||||
|
#include "crypto/aes_wrap.h"
|
||||||
|
#include "crypto/crypto.h"
|
||||||
|
#include "ieee802_1x_key.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void joint_two_mac(const u8 *mac1, const u8 *mac2, u8 *out)
|
||||||
|
{
|
||||||
|
if (os_memcmp(mac1, mac2, ETH_ALEN) < 0) {
|
||||||
|
os_memcpy(out, mac1, ETH_ALEN);
|
||||||
|
os_memcpy(out + ETH_ALEN, mac2, ETH_ALEN);
|
||||||
|
} else {
|
||||||
|
os_memcpy(out, mac2, ETH_ALEN);
|
||||||
|
os_memcpy(out + ETH_ALEN, mac1, ETH_ALEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* IEEE Std 802.1X-2010, 6.2.1 KDF */
|
||||||
|
static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
|
||||||
|
int ctx_bits, int ret_bits, u8 *ret)
|
||||||
|
{
|
||||||
|
const int h = 128;
|
||||||
|
const int r = 8;
|
||||||
|
int i, n;
|
||||||
|
int lab_len, ctx_len, ret_len, buf_len;
|
||||||
|
u8 *buf;
|
||||||
|
|
||||||
|
lab_len = os_strlen(label);
|
||||||
|
ctx_len = (ctx_bits + 7) / 8;
|
||||||
|
ret_len = ((ret_bits & 0xffff) + 7) / 8;
|
||||||
|
buf_len = lab_len + ctx_len + 4;
|
||||||
|
|
||||||
|
os_memset(ret, 0, ret_len);
|
||||||
|
|
||||||
|
n = (ret_bits + h - 1) / h;
|
||||||
|
if (n > ((0x1 << r) - 1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
buf = os_zalloc(buf_len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_memcpy(buf + 1, label, lab_len);
|
||||||
|
os_memcpy(buf + lab_len + 2, context, ctx_len);
|
||||||
|
WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
buf[0] = (u8) (i + 1);
|
||||||
|
if (omac1_aes_128(kdk, buf, buf_len, ret)) {
|
||||||
|
os_free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = ret + h / 8;
|
||||||
|
}
|
||||||
|
os_free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********** AES-CMAC-128 **********/
|
||||||
|
/**
|
||||||
|
* ieee802_1x_cak_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 6.2.2
|
||||||
|
* CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
|
||||||
|
const u8 *mac2, u8 *cak)
|
||||||
|
{
|
||||||
|
u8 context[2 * ETH_ALEN];
|
||||||
|
|
||||||
|
joint_two_mac(mac1, mac2, context);
|
||||||
|
return aes_kdf_128(msk, "IEEE8021 EAP CAK",
|
||||||
|
context, sizeof(context) * 8, 128, cak);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_ckn_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 6.2.2
|
||||||
|
* CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
|
||||||
|
const u8 *mac2, const u8 *sid,
|
||||||
|
size_t sid_bytes, u8 *ckn)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
u8 *context;
|
||||||
|
size_t ctx_len = sid_bytes + ETH_ALEN * 2;
|
||||||
|
|
||||||
|
context = os_zalloc(ctx_len);
|
||||||
|
if (!context) {
|
||||||
|
wpa_printf(MSG_ERROR, "MKA-%s: out of memory", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
os_memcpy(context, sid, sid_bytes);
|
||||||
|
joint_two_mac(mac1, mac2, context + sid_bytes);
|
||||||
|
|
||||||
|
res = aes_kdf_128(msk, "IEEE8021 EAP CKN", context, ctx_len * 8,
|
||||||
|
128, ckn);
|
||||||
|
os_free(context);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_kek_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 9.3.3
|
||||||
|
* KEK = KDF(Key, Label, Keyid, KEKLength)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
|
||||||
|
size_t ckn_bytes, u8 *kek)
|
||||||
|
{
|
||||||
|
u8 context[16];
|
||||||
|
|
||||||
|
/* First 16 octets of CKN, with null octets appended to pad if needed */
|
||||||
|
os_memset(context, 0, sizeof(context));
|
||||||
|
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
|
||||||
|
|
||||||
|
return aes_kdf_128(cak, "IEEE8021 KEK", context, sizeof(context) * 8,
|
||||||
|
128, kek);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_ick_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 9.3.3
|
||||||
|
* ICK = KDF(Key, Label, Keyid, ICKLength)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
|
||||||
|
size_t ckn_bytes, u8 *ick)
|
||||||
|
{
|
||||||
|
u8 context[16];
|
||||||
|
|
||||||
|
/* First 16 octets of CKN, with null octets appended to pad if needed */
|
||||||
|
os_memset(context, 0, sizeof(context));
|
||||||
|
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
|
||||||
|
|
||||||
|
return aes_kdf_128(cak, "IEEE8021 ICK", context, sizeof(context) * 8,
|
||||||
|
128, ick);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_icv_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 9.4.1
|
||||||
|
* ICV = AES-CMAC(ICK, M, 128)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
|
||||||
|
size_t msg_bytes, u8 *icv)
|
||||||
|
{
|
||||||
|
if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
|
||||||
|
wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802_1x_sak_128bits_aes_cmac
|
||||||
|
*
|
||||||
|
* IEEE Std 802.1X-2010, 9.8.1
|
||||||
|
* SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
|
||||||
|
*/
|
||||||
|
int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
|
||||||
|
size_t ctx_bytes, u8 *sak)
|
||||||
|
{
|
||||||
|
return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
|
||||||
|
}
|
26
src/pae/ieee802_1x_key.h
Normal file
26
src/pae/ieee802_1x_key.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* IEEE 802.1X-2010 Key Hierarchy
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_KEY_H
|
||||||
|
#define IEEE802_1X_KEY_H
|
||||||
|
|
||||||
|
int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
|
||||||
|
const u8 *mac2, u8 *cak);
|
||||||
|
int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
|
||||||
|
const u8 *mac2, const u8 *sid,
|
||||||
|
size_t sid_bytes, u8 *ckn);
|
||||||
|
int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
|
||||||
|
size_t ckn_bytes, u8 *kek);
|
||||||
|
int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
|
||||||
|
size_t ckn_bytes, u8 *ick);
|
||||||
|
int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
|
||||||
|
size_t msg_bytes, u8 *icv);
|
||||||
|
int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
|
||||||
|
size_t ctx_bytes, u8 *sak);
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_KEY_H */
|
492
src/pae/ieee802_1x_secy_ops.c
Normal file
492
src/pae/ieee802_1x_secy_ops.c
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
/*
|
||||||
|
* SecY Operations
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "utils/includes.h"
|
||||||
|
|
||||||
|
#include "utils/common.h"
|
||||||
|
#include "utils/eloop.h"
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "drivers/driver.h"
|
||||||
|
#include "pae/ieee802_1x_kay.h"
|
||||||
|
#include "pae/ieee802_1x_kay_i.h"
|
||||||
|
#include "pae/ieee802_1x_secy_ops.h"
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
|
||||||
|
enum validate_frames vf)
|
||||||
|
{
|
||||||
|
kay->vf = vf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean enabled)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->enable_protect_frames) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy enable_protect_frames operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->enable_protect_frames(ops->ctx, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->set_replay_protect) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy set_replay_protect operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->set_replay_protect(ops->ctx, enabled, win);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
|
||||||
|
const u8 *cs, size_t cs_len)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->set_current_cipher_suite) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy set_current_cipher_suite operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
|
||||||
|
enum confidentiality_offset co)
|
||||||
|
{
|
||||||
|
kay->co = co;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean enabled)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->enable_controlled_port) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy enable_controlled_port operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->enable_controlled_port(ops->ctx, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct receive_sa *rxsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->get_receive_lowest_pn) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy get_receive_lowest_pn operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->get_receive_lowest_pn(ops->ctx,
|
||||||
|
rxsa->sc->channel,
|
||||||
|
rxsa->an,
|
||||||
|
&rxsa->lowest_pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_get_transmit_next_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->get_transmit_next_pn) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy get_receive_lowest_pn operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->get_transmit_next_pn(ops->ctx,
|
||||||
|
txsa->sc->channel,
|
||||||
|
txsa->an,
|
||||||
|
&txsa->next_pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->set_transmit_next_pn) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy get_receive_lowest_pn operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->set_transmit_next_pn(ops->ctx,
|
||||||
|
txsa->sc->channel,
|
||||||
|
txsa->an,
|
||||||
|
txsa->next_pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->get_available_receive_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy get_available_receive_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->get_available_receive_sc(ops->ctx, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsc) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->create_receive_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy create_receive_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->create_receive_sc(ops->ctx, rxsc->channel, &rxsc->sci,
|
||||||
|
kay->vf, kay->co);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsc) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->delete_receive_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy delete_receive_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->delete_receive_sc(ops->ctx, rxsc->channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->create_receive_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy create_receive_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->create_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an,
|
||||||
|
rxsa->lowest_pn, rxsa->pkey->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->enable_receive_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy enable_receive_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rxsa->enable_receive = TRUE;
|
||||||
|
|
||||||
|
return ops->enable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_disable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !rxsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->disable_receive_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy disable_receive_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rxsa->enable_receive = FALSE;
|
||||||
|
|
||||||
|
return ops->disable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->get_available_transmit_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy get_available_transmit_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->get_available_transmit_sc(ops->ctx, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sc *txsc)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsc) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->create_transmit_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy create_transmit_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->create_transmit_sc(ops->ctx, txsc->channel, &txsc->sci,
|
||||||
|
kay->co);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sc *txsc)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsc) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->delete_transmit_sc) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy delete_transmit_sc operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->delete_transmit_sc(ops->ctx, txsc->channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_create_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->create_transmit_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy create_transmit_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->create_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an,
|
||||||
|
txsa->next_pn, txsa->confidentiality,
|
||||||
|
txsa->pkey->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->enable_transmit_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy enable_transmit_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
txsa->enable_transmit = TRUE;
|
||||||
|
|
||||||
|
return ops->enable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay || !txsa) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->disable_transmit_sa) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy disable_transmit_sa operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
txsa->enable_transmit = FALSE;
|
||||||
|
|
||||||
|
return ops->disable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_init_macsec(struct ieee802_1x_kay *kay)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
struct macsec_init_params params;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->macsec_init) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy macsec_init operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.use_es = FALSE;
|
||||||
|
params.use_scb = FALSE;
|
||||||
|
params.always_include_sci = TRUE;
|
||||||
|
|
||||||
|
ret = ops->macsec_init(ops->ctx, ¶ms);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int secy_deinit_macsec(struct ieee802_1x_kay *kay)
|
||||||
|
{
|
||||||
|
struct ieee802_1x_kay_ctx *ops;
|
||||||
|
|
||||||
|
if (!kay) {
|
||||||
|
wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = kay->ctx;
|
||||||
|
if (!ops || !ops->macsec_deinit) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"KaY: secy macsec_deinit operation not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops->macsec_deinit(ops->ctx);
|
||||||
|
}
|
62
src/pae/ieee802_1x_secy_ops.h
Normal file
62
src/pae/ieee802_1x_secy_ops.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* SecY Operations
|
||||||
|
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_SECY_OPS_H
|
||||||
|
#define IEEE802_1X_SECY_OPS_H
|
||||||
|
|
||||||
|
#include "common/defs.h"
|
||||||
|
#include "common/ieee802_1x_defs.h"
|
||||||
|
|
||||||
|
struct ieee802_1x_kay_conf;
|
||||||
|
struct receive_sa;
|
||||||
|
struct transmit_sa;
|
||||||
|
struct receive_sc;
|
||||||
|
struct transmit_sc;
|
||||||
|
|
||||||
|
int secy_init_macsec(struct ieee802_1x_kay *kay);
|
||||||
|
int secy_deinit_macsec(struct ieee802_1x_kay *kay);
|
||||||
|
|
||||||
|
/****** CP -> SecY ******/
|
||||||
|
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
|
||||||
|
enum validate_frames vf);
|
||||||
|
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
|
||||||
|
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
|
||||||
|
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
|
||||||
|
const u8 *cs, size_t cs_len);
|
||||||
|
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
|
||||||
|
enum confidentiality_offset co);
|
||||||
|
int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean flag);
|
||||||
|
|
||||||
|
/****** KaY -> SecY *******/
|
||||||
|
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct receive_sa *rxsa);
|
||||||
|
int secy_get_transmit_next_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa);
|
||||||
|
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa);
|
||||||
|
int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel);
|
||||||
|
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
|
||||||
|
int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
|
||||||
|
int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
|
||||||
|
int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
|
||||||
|
int secy_disable_receive_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct receive_sa *rxsa);
|
||||||
|
|
||||||
|
int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel);
|
||||||
|
int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sc *txsc);
|
||||||
|
int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sc *txsc);
|
||||||
|
int secy_create_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa);
|
||||||
|
int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa);
|
||||||
|
int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
|
||||||
|
struct transmit_sa *txsa);
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_SECY_OPS_H */
|
Loading…
Reference in a new issue