/* (C) 2012 by Harald Welte * * 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 . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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