diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-06-30 23:07:59 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-07-02 22:55:39 +0200 |
commit | d07b4f99cef6906702c555cfcb923d0d76473916 (patch) | |
tree | 6fceb9bd114c0597685aa1a6ed63a9d72d936cef /openbsc/src/gprs | |
parent | 496aee463faf8bb0d1fe5062fcee5b52bd5eec52 (diff) |
[SGSN] Use libosmocore GPRS encryption plugins from LLC layer
This adds the bits that call into libosmocore (and its plugins)
to implement GPRS (LLC) encryption.
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r-- | openbsc/src/gprs/gprs_llc.c | 96 |
1 files changed, 88 insertions, 8 deletions
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index 7e16d1b96..4c870d3fd 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -313,6 +313,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command, uint8_t addr, ctrl[2]; uint32_t fcs_calc; uint16_t nu = 0; + uint32_t oc; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ @@ -334,9 +335,14 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command, lle->llme->bvci = msgb_bvci(msg); lle->llme->nsei = msgb_nsei(msg); - /* Increment V(U) */ + /* Obtain current values for N(u) and OC */ nu = lle->vu_send; + oc = lle->oc_ui_send; + /* Increment V(U) */ lle->vu_send = (lle->vu_send + 1) % 512; + /* Increment Overflow Counter, if needed */ + if ((lle->vu_send + 1) / 512) + lle->oc_ui_send += 512; /* Address Field */ addr = sapi & 0xf; @@ -362,6 +368,34 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command, fcs[1] = (fcs_calc >> 8) & 0xff; fcs[2] = (fcs_calc >> 16) & 0xff; + /* encrypt information field + FCS, if needed! */ + if (lle->llme->algo != GPRS_ALGO_GEA0) { + uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */ + uint16_t crypt_len = (fcs + 3) - (llch + 3); + uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK]; + uint32_t iv; + int rc, i; + uint64_t kc = *(uint64_t *)&lle->llme->kc; + + /* Compute the 'Input' Paraemeter */ + iv = gprs_cipher_gen_input_ui(iov_ui, sapi, nu, oc); + + /* Compute the keystream that we need to XOR with the data */ + rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo, + kc, iv, GPRS_CIPH_SGSN2MS); + if (rc < 0) { + LOGP(DLLC, LOGL_ERROR, "Error crypting UI frame: %d\n", rc); + return rc; + } + + /* XOR the cipher output with the information field + FCS */ + for (i = 0; i < crypt_len; i++) + *(llch + 3 + i) ^= cipher_out[i]; + + /* Mark frame as encrypted */ + ctrl[1] |= 0x02; + } + /* Identifiers passed down: (BVCI, NSEI) */ /* Send BSSGP-DL-UNITDATA.req */ @@ -431,6 +465,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, } /* Increment the sequence number that we expect in the next frame */ lle->vu_recv = (gph->seq_tx + 1) % 512; + /* Increment Overflow Counter */ + if ((gph->seq_tx + 1) / 512) + lle->oc_ui_recv += 512; break; } @@ -591,8 +628,10 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, } } - /* calculate what FCS we expect */ - ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length); + if (!ghp->is_encrypted) { + /* calculate what FCS we expect */ + ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length); + } /* FIXME: parse sack frame */ if (ghp->cmd == GPRS_LLC_SACK) { @@ -622,11 +661,6 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) return rc; } - if (llhp.fcs != llhp.fcs_calc) { - LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n"); - return -EIO; - } - switch (gprs_tlli_type(msgb_tlli(msg))) { case TLLI_LOCAL: case TLLI_FOREIGN: @@ -658,6 +692,48 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) } } + /* decrypt information field + FCS, if needed! */ + if (llhp.is_encrypted) { + uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */ + uint16_t crypt_len = llhp.data_len + 3; + uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK]; + uint32_t iv; + uint64_t kc = *(uint64_t *)&lle->llme->kc; + int rc, i; + + if (lle->llme->algo == GPRS_ALGO_GEA0) { + LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that " + "has no KC/Algo! Dropping.\n"); + return 0; + } + + iv = gprs_cipher_gen_input_ui(iov_ui, lle->sapi, llhp.seq_tx, + lle->oc_ui_recv); + rc = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo, + kc, iv, GPRS_CIPH_MS2SGSN); + if (rc < 0) { + LOGP(DLLC, LOGL_ERROR, "Error decrypting frame: %d\n", + rc); + return rc; + } + + /* XOR the cipher output with the information field + FCS */ + for (i = 0; i < crypt_len; i++) + *(llhp.data + i) ^= cipher_out[i]; + } else { + if (lle->llme->algo != GPRS_ALGO_GEA0) { + LOGP(DLLC, LOGL_NOTICE, "unencrypted frame for LLC " + "that is supposed to be encrypted. Dropping.\n"); + return 0; + } + } + + /* We have to do the FCS check _after_ decryption */ + if (llhp.fcs != llhp.fcs_calc) { + LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n"); + return -EIO; + } + /* Update LLE's (BVCI, NSEI) tuple */ lle->llme->bvci = msgb_bvci(msg); lle->llme->nsei = msgb_nsei(msg); @@ -704,6 +780,10 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme, { unsigned int i; + /* Update the crypto parameters */ + memcpy(llme->kc, kc, sizeof(llme->kc)); + llme->algo = alg; + if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) { /* TLLI Assignment 8.3.1 */ /* New TLLI shall be assigned and used when (re)transmitting LLC frames */ |