strongswan/src/libcharon/plugins/osmo_epdg/osmo_epdg_provider.c

172 lines
4.1 KiB
C

/*
* Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Alexander Couzens <acouzens@sysmocom.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "osmo_epdg_provider.h"
#include "osmo_epdg_utils.h"
#include "gsup_client.h"
#include <daemon.h>
#include <credentials/keys/shared_key.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#define AKA_SQN_LEN 6
#define AKA_K_LEN 16
#define AKA_OPC_LEN 16
#define AKA_MAC_LEN 8
#define AKA_AK_LEN 6
#define AKA_AMF_LEN 2
#define AKA_RES_LEN 8
typedef struct private_osmo_epdg_provider_t private_osmo_epdg_provider_t;
/**
* Private data of an osmo_epdg_provider_t object.
*/
struct private_osmo_epdg_provider_t {
/**
* Public osmo_epdg_provider_t interface.
*/
osmo_epdg_provider_t public;
osmo_epdg_gsup_client_t *gsup;
};
/**
* Get a shared key K from the credential database
*/
bool osmo_epdg_get_k(identification_t *id, char k[AKA_K_LEN])
{
shared_key_t *shared;
chunk_t key;
shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, id, NULL);
if (shared == NULL)
{
return FALSE;
}
key = shared->get_key(shared);
memset(k, '\0', AKA_K_LEN);
memcpy(k, key.ptr, min(key.len, AKA_K_LEN));
shared->destroy(shared);
return TRUE;
}
METHOD(simaka_provider_t, get_quintuplet, bool,
private_osmo_epdg_provider_t *this, identification_t *id,
char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
{
char apn[APN_MAXLEN];
char imsi[17] = {0};
ike_sa_t *ike_sa;
if (get_imsi(id, imsi, sizeof(imsi) - 1))
{
DBG1(DBG_NET, "epdg: get_quintuplet: Can't find IMSI in EAP identity.");
return FALSE;
}
ike_sa = charon->bus->get_sa(charon->bus);
if (!ike_sa)
{
DBG1(DBG_NET, "epdg: get_quintuplet: Can't get ike_sa.");
return FALSE;
}
if (get_apn(ike_sa, apn, APN_MAXLEN))
{
DBG1(DBG_NET, "epdg: get_quintuplet: Can't get APN.");
return FALSE;
}
osmo_epdg_gsup_response_t *resp = this->gsup->send_auth_request(
this->gsup, imsi, OSMO_GSUP_CN_DOMAIN_PS, NULL, NULL, apn, PDP_TYPE_N_IETF_IPv4);
if (!resp)
{
DBG1(DBG_NET, "epdg_provider: Failed to send auth request.");
return FALSE;
}
if (resp->gsup.message_type != OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT)
{
DBG1(DBG_NET, "epdg_provider: SendAuthInfo Error! Cause: %02x", resp->gsup.cause);
return FALSE;
}
struct osmo_auth_vector *auth = &resp->gsup.auth_vectors[0];
if (resp->gsup.num_auth_vectors == 0)
{
/* TODO: invalid auth data received */
return FALSE;
}
memcpy(rand, auth->rand, AKA_RAND_LEN);
memcpy(ck, auth->ck, AKA_CK_LEN);
memcpy(ik, auth->ik, AKA_IK_LEN);
memcpy(autn, auth->autn, AKA_AUTN_LEN);
memcpy(xres, auth->res, auth->res_len);
*xres_len = auth->res_len;
free(resp);
return TRUE;
}
METHOD(simaka_provider_t, resync, bool,
private_osmo_epdg_provider_t *this, identification_t *id,
char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
{
/* TODO: invalid auth data received */
/* prepare and fill up the struct */
/* send pdu blocking */
return FALSE;
}
METHOD(osmo_epdg_provider_t, destroy, void,
private_osmo_epdg_provider_t *this)
{
free(this);
}
/**
* See header
*/
osmo_epdg_provider_t *osmo_epdg_provider_create(osmo_epdg_gsup_client_t *gsup)
{
private_osmo_epdg_provider_t *this;
INIT(this,
.public = {
.provider = {
.get_triplet = (void*)return_false,
.get_quintuplet = _get_quintuplet,
.resync = _resync,
.is_pseudonym = (void*)return_null,
.gen_pseudonym = (void*)return_null,
.is_reauth = (void*)return_null,
.gen_reauth = (void*)return_null,
},
.destroy = _destroy,
},
.gsup = gsup,
);
return &this->public;
}