129 lines
3.2 KiB
C
129 lines
3.2 KiB
C
/* Authentication related functions */
|
|
|
|
/*
|
|
* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include <openbsc/db.h>
|
|
#include <openbsc/debug.h>
|
|
#include <openbsc/gsm_data.h>
|
|
|
|
#include <osmocore/comp128.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
static int
|
|
_use_xor(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
|
|
{
|
|
int i, l = ainfo->a3a8_ki_len;
|
|
|
|
if ((l > A38_XOR_MAX_KEY_LEN) || (l < A38_XOR_MIN_KEY_LEN)) {
|
|
DEBUGP(DMM, "Invalid XOR key (len=%d) %s",
|
|
ainfo->a3a8_ki_len,
|
|
hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i<4; i++)
|
|
atuple->sres[i] = atuple->rand[i] ^ ainfo->a3a8_ki[i];
|
|
for (i=8; i<12; i++)
|
|
atuple->kc[i-4] = atuple->rand[i] ^ ainfo->a3a8_ki[i];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
|
|
{
|
|
if (ainfo->a3a8_ki_len != A38_COMP128_KEY_LEN) {
|
|
DEBUGP(DMM, "Invalid COMP128v1 key (len=%d) %s",
|
|
ainfo->a3a8_ki_len,
|
|
hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
|
|
return -1;
|
|
}
|
|
|
|
comp128(ainfo->a3a8_ki, atuple->rand, atuple->sres, atuple->kc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Return values
|
|
* -1 -> Internal error
|
|
* 0 -> Not available
|
|
* 1 -> Tuple returned, need to do auth, then enable cipher
|
|
* 2 -> Tuple returned, need to enable cipher
|
|
*/
|
|
int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
|
|
struct gsm_subscriber *subscr, int key_seq)
|
|
{
|
|
struct gsm_auth_info ainfo;
|
|
int i, rc;
|
|
|
|
/* Get subscriber info (if any) */
|
|
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
|
|
if (rc < 0) {
|
|
DEBUGP(DMM, "No retrievable Ki for subscriber, skipping auth");
|
|
return rc == -ENOENT ? 0 : -1;
|
|
}
|
|
|
|
/* If possible, re-use the last tuple and skip auth */
|
|
rc = db_get_lastauthtuple_for_subscr(atuple, subscr);
|
|
if ((rc == 0) &&
|
|
(atuple->key_seq != GSM_KEY_SEQ_INVAL) &&
|
|
(atuple->use_count < 3))
|
|
{
|
|
atuple->use_count++;
|
|
db_sync_lastauthtuple_for_subscr(atuple, subscr);
|
|
return 2;
|
|
}
|
|
|
|
/* Generate a new one */
|
|
atuple->use_count = 1;
|
|
atuple->key_seq = (atuple->key_seq + 1) % 7;
|
|
for (i=0; i<sizeof(atuple->rand); i++)
|
|
atuple->rand[i] = random() & 0xff;
|
|
|
|
switch (ainfo.auth_algo) {
|
|
case AUTH_ALGO_NONE:
|
|
return 0;
|
|
|
|
case AUTH_ALGO_XOR:
|
|
if (_use_xor(&ainfo, atuple))
|
|
return 0;
|
|
break;
|
|
|
|
case AUTH_ALGO_COMP128v1:
|
|
if (_use_comp128_v1(&ainfo, atuple))
|
|
return 0;
|
|
break;
|
|
|
|
default:
|
|
DEBUGP(DMM, "Unsupported auth type algo_id=%d\n",
|
|
ainfo.auth_algo);
|
|
return 0;
|
|
}
|
|
|
|
db_sync_lastauthtuple_for_subscr(atuple, subscr);
|
|
|
|
return 1;
|
|
}
|
|
|