256 lines
6.6 KiB
C
256 lines
6.6 KiB
C
|
/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
|
||
|
*
|
||
|
* All Rights Reserved
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License as published by
|
||
|
* the Free Software Foundation; either version 3 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 Affero General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Affero General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#include <osmocom/core/talloc.h>
|
||
|
#include <osmocom/core/utils.h>
|
||
|
#include <osmocom/core/msgb.h>
|
||
|
#include <osmocom/crypt/auth.h>
|
||
|
|
||
|
#include <asn1c/OCTET_STRING.h>
|
||
|
#include <asn1c/der_encoder.h>
|
||
|
|
||
|
#include <osmocom/map/IMSI.h>
|
||
|
#include <osmocom/map/TBCD-STRING.h>
|
||
|
#include <osmocom/map/SendAuthenticationInfoArg.h>
|
||
|
#include <osmocom/map/SendAuthenticationInfoRes.h>
|
||
|
#include <osmocom/map/SendAuthenticationInfoResOld.h>
|
||
|
|
||
|
/* move this to generic osmocom asn1c helper */
|
||
|
asn_enc_rval_t
|
||
|
der_encode_to_msgb(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
|
||
|
struct msgb *msg)
|
||
|
{
|
||
|
asn_enc_rval_t ar;
|
||
|
|
||
|
ar = der_encode_to_buffer(type_descriptor, struct_ptr,
|
||
|
msg->data, msgb_tailroom(msg));
|
||
|
if (ar.encoded > 0)
|
||
|
msgb_put(msg, ar.encoded);
|
||
|
|
||
|
return ar;
|
||
|
}
|
||
|
|
||
|
/* move this to generic osmocom asn1c helper */
|
||
|
int tbcd2char(char *out, unsigned int out_len, const TBCD_STRING_t *oct)
|
||
|
{
|
||
|
char *cur = out;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < oct->size; i++) {
|
||
|
uint8_t inbyte = oct->buf[i];
|
||
|
uint8_t nibble;
|
||
|
|
||
|
nibble = inbyte >> 4;
|
||
|
/* padding should never occur on the first nibble of an octet */
|
||
|
if (nibble == 0xF)
|
||
|
return -EINVAL;
|
||
|
*cur++ = osmo_bcd2char(oct->buf[i] >> 4);
|
||
|
if (cur - out >= out_len)
|
||
|
goto ret;
|
||
|
|
||
|
nibble = inbyte & 0xF;
|
||
|
if (nibble == 0xF)
|
||
|
break;
|
||
|
*cur++ = osmo_bcd2char(oct->buf[i] >> 4);
|
||
|
if (cur - out >= out_len)
|
||
|
goto ret;
|
||
|
}
|
||
|
|
||
|
ret:
|
||
|
out[out_len-1] = '\0';
|
||
|
|
||
|
return cur - out;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* The nesting is as follows:
|
||
|
* SendAuthenticationInfoRes
|
||
|
* AuthenticationSetList
|
||
|
* QuintupletList_t
|
||
|
* AuthenticationQuintuplet
|
||
|
* TripletList_t
|
||
|
* AuthenticationTriplet
|
||
|
*/
|
||
|
|
||
|
|
||
|
static SendAuthenticationInfoRes_t *
|
||
|
make_authinfo_res(void *ctx, const struct osmo_auth_vector *vecs, int num_vecs, int umts)
|
||
|
{
|
||
|
SendAuthenticationInfoRes_t *ai_res;
|
||
|
int i;
|
||
|
|
||
|
ai_res = talloc_zero(ctx, SendAuthenticationInfoRes_t);
|
||
|
|
||
|
ai_res->authenticationSetList = talloc_zero(ai_res, AuthenticationSetList_t);
|
||
|
|
||
|
if (umts) {
|
||
|
ai_res->authenticationSetList->present = AuthenticationSetList_PR_quintupletList;
|
||
|
|
||
|
for (i = 0; i < num_vecs; i++) {
|
||
|
const struct osmo_auth_vector *vec = &vecs[i];
|
||
|
AuthenticationQuintuplet_t *qt;
|
||
|
|
||
|
qt = talloc_zero(ai_res, AuthenticationQuintuplet_t);
|
||
|
OCTET_STRING_fromBuf(&qt->rand, vec->rand, sizeof(vec->rand));
|
||
|
OCTET_STRING_fromBuf(&qt->xres, vec->res, vec->res_len);
|
||
|
OCTET_STRING_fromBuf(&qt->ck, vec->ck, sizeof(vec->ck));
|
||
|
OCTET_STRING_fromBuf(&qt->ik, vec->ik, sizeof(vec->ik));
|
||
|
OCTET_STRING_fromBuf(&qt->autn, vec->autn, sizeof(vec->autn));
|
||
|
|
||
|
asn_sequence_add(&ai_res->authenticationSetList->choice.quintupletList.list, qt);
|
||
|
}
|
||
|
} else {
|
||
|
ai_res->authenticationSetList->present = AuthenticationSetList_PR_tripletList;
|
||
|
|
||
|
for (i = 0; i < num_vecs; i++) {
|
||
|
const struct osmo_auth_vector *vec = &vecs[i];
|
||
|
AuthenticationTriplet_t *t;
|
||
|
|
||
|
t = talloc_zero(ai_res, AuthenticationTriplet_t);
|
||
|
OCTET_STRING_fromBuf(&t->rand, vec->rand, sizeof(vec->rand));
|
||
|
OCTET_STRING_fromBuf(&t->sres, vec->sres, sizeof(vec->sres));
|
||
|
OCTET_STRING_fromBuf(&t->kc, vec->rand, sizeof(vec->kc));
|
||
|
|
||
|
asn_sequence_add(&ai_res->authenticationSetList->choice.tripletList.list, t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ai_res;
|
||
|
}
|
||
|
|
||
|
static SendAuthenticationInfoResOld_t *
|
||
|
make_authinfo_res_old(void *ctx, const struct osmo_auth_vector *vecs, int num_vecs)
|
||
|
{
|
||
|
SendAuthenticationInfoResOld_t *ai_res;
|
||
|
int i;
|
||
|
|
||
|
ai_res = talloc_zero(ctx, SendAuthenticationInfoResOld_t);
|
||
|
|
||
|
for (i = 0; i < num_vecs; i++) {
|
||
|
const struct osmo_auth_vector *vec = &vecs[i];
|
||
|
struct Member *t;
|
||
|
|
||
|
t = talloc_zero(ai_res, struct Member);
|
||
|
OCTET_STRING_fromBuf(&t->rand, vec->rand, sizeof(vec->rand));
|
||
|
OCTET_STRING_fromBuf(&t->sres, vec->sres, sizeof(vec->sres));
|
||
|
OCTET_STRING_fromBuf(&t->kc, vec->rand, sizeof(vec->kc));
|
||
|
|
||
|
asn_sequence_add(&ai_res->list, t);
|
||
|
}
|
||
|
|
||
|
return ai_res;
|
||
|
}
|
||
|
|
||
|
struct msgb *
|
||
|
handle_authinfo_req(void *ctx, const SendAuthenticationInfoArg_t *ai_arg,
|
||
|
int is_v2)
|
||
|
{
|
||
|
struct msgb *msg;
|
||
|
struct osmo_auth_vector vecs[3];
|
||
|
char imsi[15+1];
|
||
|
unsigned int num_vec;
|
||
|
asn_enc_rval_t ar;
|
||
|
int rc;
|
||
|
|
||
|
|
||
|
/* FIXME: decode IMSI */
|
||
|
rc = tbcd2char(imsi, sizeof(imsi), &ai_arg->imsi);
|
||
|
if (rc < 0)
|
||
|
return NULL;
|
||
|
|
||
|
/* don't send more thnan three (our policy) */
|
||
|
num_vec = OSMO_MAX(ai_arg->numberOfRequestedVectors, ARRAY_SIZE(vecs));
|
||
|
|
||
|
/* generate the triplets/quintuplets */
|
||
|
if (ai_arg->re_synchronisationInfo) {
|
||
|
Re_synchronisationInfo_t *res = ai_arg->re_synchronisationInfo;
|
||
|
if (res->rand.size < 16 || res->auts.size < 16)
|
||
|
return NULL;
|
||
|
/* always only one */
|
||
|
num_vec = 1;
|
||
|
rc = auc_gen_vec_auts(vecs, imsi, res->rand.buf, res->auts.buf);
|
||
|
} else
|
||
|
rc = auc_gen_vecs(vecs, imsi, num_vec);
|
||
|
|
||
|
if (rc < 0)
|
||
|
return NULL;
|
||
|
|
||
|
msg = msgb_alloc(1024, "authinfo_res");
|
||
|
if (!msg)
|
||
|
return NULL;
|
||
|
|
||
|
/* actaully encode the response MAP component */
|
||
|
if (!ai_arg->re_synchronisationInfo && is_v2) {
|
||
|
SendAuthenticationInfoResOld_t *ai_res_old;
|
||
|
ai_res_old = make_authinfo_res_old(ctx, vecs, num_vec);
|
||
|
ar = der_encode_to_msgb(&asn_DEF_SendAuthenticationInfoResOld,
|
||
|
ai_res_old, msg);
|
||
|
talloc_free(ai_res_old);
|
||
|
} else {
|
||
|
SendAuthenticationInfoRes_t *ai_res;
|
||
|
int is_umts = 0;
|
||
|
if (vecs[0].auth_types & OSMO_AUTH_TYPE_UMTS)
|
||
|
is_umts = 1;
|
||
|
ai_res = make_authinfo_res(ctx, vecs, num_vec, is_umts);
|
||
|
ar = der_encode_to_msgb(&asn_DEF_SendAuthenticationInfoRes,
|
||
|
ai_res, msg);
|
||
|
talloc_free(ai_res);
|
||
|
}
|
||
|
|
||
|
if (ar.encoded < 0) {
|
||
|
msgb_free(msg);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
struct osmo_auth_vector vecs[3];
|
||
|
SendAuthenticationInfoRes_t *res;
|
||
|
asn_enc_rval_t ar;
|
||
|
uint8_t buf[1024];
|
||
|
uint32_t buf_len = sizeof(buf);
|
||
|
|
||
|
memset(vecs, 0, sizeof(vecs));
|
||
|
|
||
|
res = make_authinfo_res(NULL, vecs, ARRAY_SIZE(vecs), 1);
|
||
|
if (!res)
|
||
|
exit(1);
|
||
|
|
||
|
ar = der_encode_to_buffer(&asn_DEF_SendAuthenticationInfoRes, res, buf, buf_len);
|
||
|
if (ar.encoded < 0)
|
||
|
exit(2);
|
||
|
|
||
|
buf_len = ar.encoded;
|
||
|
|
||
|
printf("Output: %s\n", osmo_hexdump(buf, buf_len));
|
||
|
//write(1, buf, buf_len);
|
||
|
|
||
|
exit(0);
|
||
|
}
|
||
|
#endif
|