summaryrefslogtreecommitdiffstats
path: root/stack/obx/obx_md5.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/obx/obx_md5.c')
-rw-r--r--stack/obx/obx_md5.c1050
1 files changed, 1050 insertions, 0 deletions
diff --git a/stack/obx/obx_md5.c b/stack/obx/obx_md5.c
new file mode 100644
index 0000000..6e0d6ea
--- /dev/null
+++ b/stack/obx/obx_md5.c
@@ -0,0 +1,1050 @@
+/*****************************************************************************
+**
+** Name: obx_md5.c
+**
+** File: OBEX Authentication related functions
+**
+** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btu.h"
+#include "obx_int.h"
+#include "wcassert.h"
+
+
+
+/*
+* This code implements the MD5 message-digest algorithm.
+* The algorithm is due to Ron Rivest. This code was
+* written by Colin Plumb in 1993, no copyright is claimed.
+* This code is in the public domain; do with it what you wish.
+*
+* Equivalent code is available from RSA Data Security, Inc.
+* This code has been tested against that, and is equivalent,
+* except that you don't need to include two pages of legalese
+* with every copy.
+*
+* To compute the message digest of a chunk of bytes, declare an
+* MD5Context structure, pass it to MD5Init, call MD5Update as
+* needed on buffers full of bytes, and then call MD5Final, which
+* will fill a supplied 16-byte array with the digest.
+*/
+typedef UINT32 word32;
+typedef UINT8 byte;
+struct xMD5Context {
+ word32 buf[4];
+ word32 bytes[2];
+ word32 in[16];
+};
+
+static void obx_md5_transform(word32 buf[4], word32 const in[16]);
+
+/*
+* Shuffle the bytes into little-endian order within words, as per the
+* MD5 spec. Note: this code works regardless of the byte order.
+*/
+static void obx_byte_swap(word32 *buf, unsigned words)
+{
+ byte *p = (byte *)buf;
+ do {
+ *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16
+ | (word32)((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+
+/*
+* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+* initialization constants.
+*/
+static void obx_md5_init(struct xMD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+/*
+* Update context to reflect the concatenation of another buffer full
+* of bytes.
+*/
+static void obx_md5_update(struct xMD5Context *ctx, byte const *buf, int len)
+{
+ word32 t;
+ /* Update byte count */
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+ t = 64 - (t & 0x3f); /* Space avail in ctx->in (at least 1) */
+ if ((unsigned)t > (unsigned)len)
+ {
+ memcpy ((byte *)ctx->in + 64 - (unsigned)t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy (ctx->in + (64 - (unsigned)t), buf, (unsigned)t);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ buf += (unsigned)t;
+ len -= (unsigned)t;
+ /* Process data in 64-byte chunks */
+ while (len >= 64)
+ {
+ /* coverity[access_dbuff_const] */
+ memcpy (ctx->in, buf, 64);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+ /* Handle any remaining bytes of data. */
+ memcpy (ctx->in, buf, len);
+}
+
+/*
+* Final wrapup - pad to 64-byte boundary with the bit pattern
+* 1 0* (64-bit count of bits processed, MSB-first)
+*/
+static void obx_md5_final(byte digest[16], struct xMD5Context *ctx)
+{
+ int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
+ byte *p = (byte *)ctx->in + count; /* First unused byte */
+ /* Set the first char of padding to 0x80. There is always room.*/
+ *p++ = 0x80;
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+ if (count < 0) /* Padding forces an extra block */
+ {
+ memset (p, 0, count+8);
+ obx_byte_swap(ctx->in, 16);
+ obx_md5_transform(ctx->buf, ctx->in);
+ p = (byte *)ctx->in;
+ count = 56;
+ }
+ memset (p, 0, count+8);
+ obx_byte_swap(ctx->in, 14);
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ obx_md5_transform(ctx->buf, ctx->in);
+ obx_byte_swap(ctx->buf, 4);
+ memcpy (digest, ctx->buf, 16);
+ memset (ctx, 0, sizeof(ctx));
+}
+
+/* The four core functions - F1 is optimized somewhat */
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+* The core of the MD5 algorithm, this alters an existing MD5 hash to
+* reflect the addition of 16 longwords of new data. MD5Update blocks
+* the data and converts bytes into longwords for this routine.
+*/
+static const word32 obx_md5_f1 [] =
+{
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821
+};
+
+static const word32 obx_md5_f2 [] =
+{
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+
+ 0xd62f105d,
+ 0x02441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a
+};
+
+static const word32 obx_md5_f3 [] =
+{
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x04881d05,
+
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665
+};
+
+static const word32 obx_md5_f4 [] =
+{
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391
+};
+
+static const UINT8 obx_md5_a [] =
+{
+ 1,
+ 2,
+ 3,
+ 0,
+ 1,
+ 2,
+ 3
+};
+
+static const word32 obx_md5_var1 [] =
+{
+ 7,
+ 12,
+ 17,
+ 22
+};
+
+static const word32 obx_md5_var2 [] =
+{
+ 5,
+ 9,
+ 14,
+ 20
+};
+
+static const word32 obx_md5_var3 [] =
+{
+ 4,
+ 11,
+ 16,
+ 23
+};
+
+static const word32 obx_md5_var4 [] =
+{
+ 6,
+ 10,
+ 15,
+ 21
+};
+
+static void obx_md5_transform(word32 buf[4], word32 const in[16])
+{
+ int xx, yy, zz, i, j, k;
+ word32 a[4];
+
+ a[0] = buf[0];
+ a[1] = buf[1];
+ a[2] = buf[2];
+ a[3] = buf[3];
+
+ yy = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f1 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f1[yy], obx_md5_var1[i]);
+ */
+ MD5STEP(F1, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f1[yy], obx_md5_var1[i]);
+ yy++;
+ }
+ }
+
+ yy = 1;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f2 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f2[zz], obx_md5_var2[i]);
+ */
+ MD5STEP(F2, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f2[zz++], obx_md5_var2[i]);
+ yy += 5;
+ yy %= 16;
+ }
+ }
+
+ yy = 5;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f3 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f3[zz], obx_md5_var3[i]);
+ */
+ MD5STEP(F3, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f3[zz++], obx_md5_var3[i]);
+ yy += 3;
+ yy %= 16;
+ }
+ }
+
+
+ yy = 0;
+ zz = 0;
+ for(xx=0; xx<4; xx++)
+ {
+ j = 3;
+ for(i=0; i < 4; i++)
+ {
+ k = j--;
+ /*
+ OBX_TRACE_DEBUG4( "f4 a: %d, yy: %d, inc: 0x%x, var: %d",
+ obx_md5_a[k], yy, obx_md5_f4[zz], obx_md5_var4[i]);
+ */
+ MD5STEP(F4, a[obx_md5_a[k]], a[obx_md5_a[k+1]], a[obx_md5_a[k+2]], a[obx_md5_a[k+3]],
+ in[yy] + obx_md5_f4[zz++], obx_md5_var4[i]);
+ yy += 7;
+ yy %= 16;
+ }
+ }
+
+ buf[0] += a[0];
+ buf[1] += a[1];
+ buf[2] += a[2];
+ buf[3] += a[3];
+}
+
+/*******************************************************************************
+**
+** Function OBX_MD5
+**
+** Description This function is called to run the MD5 algorithm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void OBX_MD5(void *digest, UINT8 *nonce, UINT8 * password, int password_len)
+{
+ struct xMD5Context context;
+ UINT8 before[OBX_NONCE_SIZE + OBX_MAX_AUTH_KEY_SIZE + 4];
+
+ memcpy(before, nonce, OBX_NONCE_SIZE);
+ before[OBX_NONCE_SIZE] = ':';
+ memcpy(before + OBX_NONCE_SIZE + 1, password, password_len);
+ /*
+ scru_dump_hex (before, "before", OBX_NONCE_SIZE + 1 + password_len, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+
+ obx_md5_init(&context);
+/* coverity[overrun-buffer-val] */
+/*
+FALSE-POSITIVE: coverity says "Overrun of static array "before" of size 36 bytes by passing it as an argument to a function which indexes it at byte position 63"
+obx_md5_update() only goes into that condition when (len >= 64). In this case, len is (OBX_NONCE_SIZE + 1 + password_len) which is less than or equal to 33.
+password_len is less than or equal to OBX_MAX_AUTH_KEY_SIZE. The size of before[] is more than enough */
+ obx_md5_update(&context, (byte const *)before, OBX_NONCE_SIZE + 1 + password_len);
+ obx_md5_final((byte *)digest, &context);
+ /*
+ scru_dump_hex (digest, "after", 16, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+}
+
+/*******************************************************************************
+**
+** Function obx_session_id
+**
+** Description This function is called to run the MD5 algorithm to create a
+** session id.
+**
+** Returns void
+**
+*******************************************************************************/
+void obx_session_id(UINT8 *p_sess_id, UINT8 *p_cl_addr, UINT8 * p_cl_nonce, int cl_nonce_len,
+ UINT8 *p_sr_addr, UINT8 * p_sr_nonce, int sr_nonce_len)
+{
+ struct xMD5Context context;
+ UINT8 before[(OBX_NONCE_SIZE + BD_ADDR_LEN) * 2 + 4];
+ UINT8 *p = before;
+ UINT8 len;
+
+ memcpy(p, p_cl_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy(p, p_cl_nonce, cl_nonce_len);
+ p += cl_nonce_len;
+ memcpy(p, p_sr_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy(p, p_sr_nonce, sr_nonce_len);
+ p += sr_nonce_len;
+ /*
+ scru_dump_hex (before, "before", OBX_NONCE_SIZE + 1 + password_len, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+
+ len = BD_ADDR_LEN + cl_nonce_len + BD_ADDR_LEN + sr_nonce_len;
+ obx_md5_init(&context);
+/* coverity [overrun-buffer-val] */
+/* Overrun of static array "before" of size 48 bytes by passing it as an argument to a function which indexes it at byte position 63*/
+/* FALSE-POSITIVE: obx_md5_update() only goes into that condition when (len >= 64). In this case, len is (OBX_NONCE_SIZE + 1 + password_len) which is less than or equal to 33.
+password_len is less than or equal to OBX_MAX_AUTH_KEY_SIZE. The size of before[] is more than enough */
+ obx_md5_update(&context, (byte const *)before, len);
+ obx_md5_final((byte *)p_sess_id, &context);
+ /*
+ scru_dump_hex (p_sess_id, "after", 16, TRACE_LAYER_OBEX, TRACE_TYPE_GENERIC);
+ */
+}
+
+#if (OBX_SERVER_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function obx_copy_and_rm_auth_hdrs
+**
+** Description This function is used to copy the given OBEX packet to a new packet
+** with the authentication headers removed.
+**
+** Returns tOBX_STATUS
+**
+*******************************************************************************/
+tOBX_STATUS obx_copy_and_rm_auth_hdrs(BT_HDR *p_pkt, BT_HDR *p_new, UINT8 * p_hi)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ UINT8 *pn, *po, *p_nlen = NULL;
+ int hsize, nsize;
+ UINT16 nlen, olen;
+ UINT8 size;
+ int xx;
+
+ WC_ASSERT(p_new);
+
+
+ po = (UINT8 *)(p_pkt + 1) + p_pkt->offset + 1;
+ BE_STREAM_TO_UINT16(olen, po);
+ OBX_TRACE_DEBUG3( "obx_copy_and_rm_auth_hdrs event: %d, new len:%d, olen:%d",
+ p_pkt->event, p_new->len, olen);
+
+ po = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ if(p_new->len == 0)
+ {
+ p_new->offset = p_pkt->offset;
+ p_nlen = (UINT8 *)(p_new + 1) + p_new->offset + 1;
+ }
+ pn = (UINT8 *)(p_new + 1) + p_new->offset;
+
+ /* Get the number of bytes before headers start */
+ size = obx_hdr_start_offset[p_pkt->event - 1];
+ if(p_new->len)
+ {
+ /* for OBX_AuthResponse
+ * - do not need to copy the stuff before headers
+ * there's already some header, skip them */
+ pn += p_new->len;
+ nlen = p_new->len;
+ }
+ else
+ {
+ /* for obx_unauthorize_rsp
+ * - needs to copy the stuff before headers */
+ memcpy(pn, po, size);
+ pn += size;
+ nlen = size;
+ }
+ po += size;
+
+ olen -= size;
+ while(olen)
+ {
+ OBX_TRACE_DEBUG1( "olen:%d", olen);
+ hsize = (int)obx_read_header_len(po);
+ if(olen > hsize)
+ olen -= hsize;
+ else
+ olen = 0;
+
+ xx = 0;
+ nsize = hsize;
+ while(p_hi[xx] != OBX_HI_NULL)
+ {
+ /*
+ OBX_TRACE_DEBUG2( "po:0x%x, hix:0x%x", *po, p_hi[xx]);
+ */
+ if(*po == p_hi[xx++])
+ {
+ nsize = 0;
+ break;
+ }
+ }
+ OBX_TRACE_DEBUG2( "hsize:%d, nsize:%d", hsize, nsize);
+ if(nsize)
+ {
+ /* skip auth challenge and auth response */
+ if((nlen+hsize) < p_pkt->layer_specific)
+ {
+ /* copy other headers */
+ memcpy(pn, po, hsize);
+ pn += hsize;
+ nlen += hsize;
+ }
+ else
+ {
+ OBX_TRACE_WARNING1( "obx_copy_and_rm_auth_hdrs Not enough room: %d", olen);
+ /* no more room in the new packet */
+ status = OBX_NO_RESOURCES;
+ break;
+ }
+ }
+ po += hsize;
+ }
+
+ if(status == OBX_SUCCESS)
+ {
+ if(p_nlen)
+ {
+ UINT16_TO_BE_STREAM(p_nlen, nlen);
+ }
+ p_new->len = nlen;
+ p_new->layer_specific = GKI_get_buf_size(p_new) - BT_HDR_SIZE - p_new->offset;
+ p_new->event = p_pkt->event;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function obx_unauthorize_rsp
+**
+** Description This function is used to add authentication challenge triplet
+**
+** Returns void.
+** Note: this function assumes that all data can fit in the MTU
+*******************************************************************************/
+BT_HDR * obx_unauthorize_rsp(tOBX_SR_CB *p_cb, tOBX_SR_SESS_CB *p_scb, BT_HDR *p_pkt)
+{
+ UINT8 *p;
+ UINT8 nonce[OBX_NONCE_SIZE+2];
+ UINT8 option[2];
+ UINT8 *p_target = NULL;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = 0;
+ BT_HDR *p_old;
+ UINT8 hi[] = {OBX_HI_CHALLENGE, OBX_HI_AUTH_RSP, OBX_HI_NULL};
+
+ OBX_TRACE_DEBUG1( "obx_unauthorize_rsp: %d", p_cb->target.len);
+ if(OBX_CheckHdr(p_pkt, OBX_HI_CHALLENGE) || OBX_CheckHdr(p_pkt, OBX_HI_AUTH_RSP))
+ {
+ p_old = p_pkt;
+ p_pkt = OBX_HdrInit(p_scb->ll_cb.comm.handle, (UINT16)(p_old->len + BT_HDR_SIZE + p_old->offset));
+ obx_copy_and_rm_auth_hdrs(p_old, p_pkt, hi);
+ GKI_freebuf(p_old);
+ }
+
+ if(p_cb->target.len)
+ {
+ /* There must be the target header, change it to be WHO header */
+ if( (p_target = OBX_CheckHdr(p_pkt, OBX_HI_TARGET)) != NULL)
+ {
+ *p_target = OBX_HI_WHO;
+ }
+ }
+ OBX_TRACE_DEBUG1( "p_target: %x", p_target);
+
+ if(p_cb->p_auth)
+ {
+ /* server registers for authentication */
+ /* prepare the triplet byte sequence */
+ /* add nonce: tag, length, value */
+ p_cb->p_auth->nonce = GKI_get_tick_count();
+ sprintf ((char *)nonce, "%016lu", p_cb->p_auth->nonce);
+
+ num_trip = 0;
+ triplet[num_trip].tag = OBX_NONCE_CHLNG_TAG;
+ triplet[num_trip].len = OBX_NONCE_SIZE;
+ triplet[num_trip].p_array = nonce;
+ num_trip++;
+
+ if(p_cb->p_auth->auth_option)
+ {
+ /* add option */
+ triplet[num_trip].tag = OBX_OPTIONS_CHLNG_TAG;
+ triplet[num_trip].len = 1;
+ option[0] = p_cb->p_auth->auth_option;
+ triplet[num_trip].p_array = option;
+ num_trip++;
+ }
+ if(p_cb->p_auth->realm_len)
+ {
+ /* add realm */
+ triplet[num_trip].tag = OBX_REALM_CHLNG_TAG;
+ triplet[num_trip].len = p_cb->p_auth->realm_len+1;
+ triplet[num_trip].p_array = p_cb->p_auth->realm;
+ num_trip++;
+ }
+
+ /* add the sequence to header */
+ OBX_AddTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, num_trip);
+ }
+
+ p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
+ /* change the opcode to unauthorized response */
+ *p++ = OBX_RSP_UNAUTHORIZED | OBX_FINAL;
+ /* adjust the packet len */
+ UINT16_TO_BE_STREAM(p, p_pkt->len);
+
+ /* add session sequence number, if session is active */
+ if ((p_scb->sess_st == OBX_SESS_ACTIVE) && ((p_target = OBX_CheckHdr(p_pkt, OBX_HI_SESSION_SN)) != NULL))
+ {
+ p_target++;
+ (*p_target)++;
+ }
+
+ p_pkt->event = OBX_CONNECT_RSP_EVT;
+
+ return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function OBX_Password
+**
+** Description This function is called by the server to respond to an
+** OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_Password(tOBX_HANDLE shandle, UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len)
+{
+ tOBX_STATUS status = OBX_SUCCESS;
+ BT_HDR *p_pkt;
+ BT_HDR *p_rsp;
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ BOOLEAN pass = FALSE;
+ BOOLEAN digest_done = FALSE;
+ BOOLEAN option_userid = FALSE;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ UINT8 xx;
+ UINT8 *p_target;
+ UINT16 tlen;
+ tOBX_SR_SESS_CB *p_scb = obx_sr_get_scb(shandle);
+ tOBX_SR_CB *p_cb = obx_sr_get_cb(shandle);
+ UINT8 *p;
+ tOBX_EVT_PARAM param; /* The event parameter. */
+
+ WC_ASSERT(password_len < OBX_MAX_AUTH_KEY_SIZE);
+
+ if(p_scb == NULL || p_scb->p_saved_msg == NULL)
+ return OBX_NO_RESOURCES;
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE.
+ * leave this unnecessary memset here */
+ memset(triplet,0,sizeof(triplet));
+
+ p_pkt = p_scb->p_saved_msg;
+
+ if(p_cb->p_auth == NULL)
+ {
+ pass = TRUE;
+ }
+ else if(OBX_ReadTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, &num_trip) == TRUE)
+ {
+ if(p_password && password_len )
+ {
+ /* if given password, verify it */
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_DIGEST_RSP_TAG)
+ {
+ sprintf((char *)nonce, "%016lu", p_cb->p_auth->nonce);
+ OBX_MD5 (temp_digest, nonce, p_password, password_len);
+ if (memcmp (temp_digest, triplet[xx].p_array, OBX_DIGEST_SIZE) == 0)
+ pass = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* check if challenged by client */
+ num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ if(pass == TRUE && OBX_ReadTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, &num_trip) == TRUE)
+ {
+ /* Make sure password was passed in and not empty */
+ if (p_password && password_len )
+ {
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_NONCE_CHLNG_TAG)
+ {
+ /* nonce tag is mandatory */
+ OBX_MD5 (temp_digest, triplet[xx].p_array, p_password, password_len);
+ digest_done = TRUE;
+ }
+ else if(triplet[xx].tag == OBX_OPTIONS_CHLNG_TAG)
+ {
+ /* user ID bit is set */
+ if(OBX_AO_USR_ID & triplet[xx].p_array[0])
+ option_userid = TRUE;
+ }
+ }
+
+ if (option_userid && (userid_len == 0 || p_userid == NULL) )
+ {
+ status = OBX_BAD_PARAMS;
+ }
+ }
+ }
+
+ if(status == OBX_SUCCESS)
+ {
+ p_scb->p_saved_msg = NULL;
+ if(pass == TRUE)
+ {
+ p_rsp = OBX_HdrInit(shandle, OBX_MIN_MTU);
+
+ /* add the authentication response if been challenged */
+ if(digest_done)
+ {
+ num_trip = 1;
+ triplet[0].tag = OBX_DIGEST_RSP_TAG;
+ triplet[0].len = OBX_DIGEST_SIZE;
+ triplet[0].p_array = temp_digest;
+ if(option_userid)
+ {
+ num_trip++;
+ triplet[1].tag = OBX_USERID_RSP_TAG;
+ triplet[1].len = userid_len;
+ triplet[1].p_array = p_userid;
+ }
+ OBX_AddTriplet(p_rsp, OBX_HI_AUTH_RSP, triplet, num_trip);
+ }
+
+ if( p_cb->target.len == OBX_DEFAULT_TARGET_LEN &&
+ OBX_ReadTargetHdr(p_pkt, &p_target, &tlen, 0) == TRUE)
+ {
+ /* API user is supposed to handle WHO header
+ * for this special case, we add it for the API user */
+ OBX_AddWhoHdr(p_rsp, p_target, tlen);
+ }
+
+ /* use OBX_ConnectRsp to fill the common data */
+ status = OBX_ConnectRsp(shandle, OBX_RSP_OK, p_rsp);
+ if(status == OBX_SUCCESS)
+ {
+ /* If authentication is successful, need to update session info */
+ p = &p_scb->sess_info[OBX_SESSION_INFO_ID_IDX];
+ UINT32_TO_BE_STREAM(p, p_scb->conn_id);
+ param.sess.p_sess_info = p_scb->sess_info;
+ param.sess.sess_op = OBX_SESS_OP_CREATE;
+ param.sess.sess_st = p_scb->sess_st;
+ param.sess.nssn = p_scb->param.ssn;
+ param.sess.ssn = p_scb->param.ssn;
+ param.sess.obj_offset = 0;
+ p = &p_scb->sess_info[OBX_SESSION_INFO_MTU_IDX];
+ UINT16_TO_BE_STREAM(p, p_scb->param.conn.mtu);
+ memcpy(param.sess.peer_addr, p_scb->peer_addr, BD_ADDR_LEN);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_SESSION_REQ_EVT, param, p_pkt);
+ (*p_cb->p_cback)(p_scb->ll_cb.comm.handle, OBX_CONNECT_REQ_EVT, p_scb->param, p_pkt);
+ }
+ else
+ GKI_freebuf(p_pkt);
+ }
+ else
+ {
+ /* server can not find the password, send unauthorized response */
+ p_pkt = obx_unauthorize_rsp(p_cb, p_scb, p_pkt);
+ obx_ssm_event(p_scb, OBX_CONNECT_CFM_SEVT, p_pkt);
+ }
+ }
+ /*
+ else p_scb->p_saved_msg is still valid.
+ */
+
+ return status;
+}
+#endif
+
+
+#if (OBX_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function OBX_AuthResponse
+**
+** Description This function is called by the client to respond to an
+** OBX_PASSWORD_EVT event.
+**
+** Returns OBX_SUCCESS, if successful.
+** OBX_NO_RESOURCES, if OBX does not resources
+**
+*******************************************************************************/
+tOBX_STATUS OBX_AuthResponse(tOBX_HANDLE handle,
+ UINT8 *p_password, UINT8 password_len,
+ UINT8 *p_userid, UINT8 userid_len,
+ BOOLEAN authenticate)
+{
+ tOBX_CL_CB *p_cb = obx_cl_get_cb(handle);
+ tOBX_STATUS status = OBX_NO_RESOURCES;
+ BT_HDR *p_pkt;
+ BT_HDR *p_saved_req;
+ UINT8 num_trip, flags = 0;
+ UINT16 nlen, xx;
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ BOOLEAN digest_done = FALSE;
+ BOOLEAN option_userid = FALSE;
+ UINT8 rsp_code;
+ BOOLEAN final;
+ UINT8 *p_target;
+ tOBX_TRIPLET triplet[OBX_MAX_NUM_AUTH_TRIPLET];
+ UINT8 hi[] = {OBX_HI_CONN_ID, OBX_HI_TARGET, OBX_HI_CHALLENGE, OBX_HI_AUTH_RSP,
+ OBX_HI_SESSION_SN, /* prevent SSN from being copied */
+ OBX_HI_NULL};
+ WC_ASSERT(password_len < OBX_MAX_AUTH_KEY_SIZE);
+ WC_ASSERT(p_password);
+
+ if(p_cb == NULL || p_cb->p_auth == NULL || p_cb->p_saved_req == NULL)
+ return OBX_NO_RESOURCES;
+
+ p_saved_req = p_cb->p_saved_req;
+ p_pkt = OBX_HdrInit(handle, GKI_MAX_BUF_SIZE); /* make sure added length will fit */
+ WC_ASSERT(p_pkt);
+ OBX_TRACE_DEBUG2("OBX_AuthResponse p_saved_req:%d, p_saved_req->len %d ",
+ p_saved_req->event, p_saved_req->len);
+
+ /* if the save_req contains SSN, add it now */
+ if ((p_target = OBX_CheckHdr(p_saved_req, OBX_HI_SESSION_SN)) != NULL)
+ {
+ p_target++;
+ OBX_Add1ByteHdr(p_pkt, OBX_HI_SESSION_SN, (UINT8)((*p_target) + 1));
+ }
+
+ /* The coverity complaints on this function is not correct.
+ * The value in triplet[] is set/initialized by OBX_ReadTriplet if num_trip returns TRUE.
+ * leave this unnecessary memset here */
+ memset(triplet,0,sizeof(triplet));
+
+ /* if target header exists in the original request
+ * and the Connection ID has not been assigned yet,
+ * copy the target header over */
+ if(OBX_ReadTargetHdr(p_saved_req, &p_target, &nlen, 0) == TRUE)
+ {
+ OBX_AddTargetHdr(p_pkt, p_target, nlen);
+ }
+
+ /* read the challenge from received packet */
+ num_trip = OBX_MAX_NUM_AUTH_TRIPLET;
+ if(OBX_ReadTriplet(p_cb->p_auth, OBX_HI_CHALLENGE, triplet, &num_trip) == TRUE)
+ {
+ status = OBX_SUCCESS;
+ for(xx=0; xx<num_trip; xx++)
+ {
+ if(triplet[xx].tag == OBX_NONCE_CHLNG_TAG)
+ {
+ /* nonce tag is mandatory */
+ OBX_MD5 (temp_digest, triplet[xx].p_array, p_password, password_len);
+ digest_done = TRUE;
+ }
+ else if(triplet[xx].tag == OBX_OPTIONS_CHLNG_TAG)
+ {
+ /* user ID bit is set */
+ if(OBX_AO_USR_ID & triplet[xx].p_array[0])
+ option_userid = TRUE;
+ }
+ }
+
+ if(option_userid && (userid_len == 0 || p_userid == NULL) )
+ {
+ status = OBX_BAD_PARAMS;
+ }
+ OBX_TRACE_DEBUG2( "num_trip:%d, option_userid:%d", num_trip, option_userid);
+
+ if(digest_done && status == OBX_SUCCESS)
+ {
+ /* Compose and add the authentication Response header */
+ num_trip = 1;
+ triplet[0].tag = OBX_DIGEST_RSP_TAG;
+ triplet[0].len = OBX_DIGEST_SIZE;
+ triplet[0].p_array = temp_digest;
+ if(option_userid)
+ {
+ /* add user id */
+ num_trip++;
+ triplet[1].tag = OBX_USERID_RSP_TAG;
+ triplet[1].len = userid_len;
+ triplet[1].p_array = p_userid;
+ }
+ OBX_AddTriplet(p_pkt, OBX_HI_AUTH_RSP, triplet, num_trip);
+
+ /* if we want to authenticate the server, add the challenge header here */
+ /* Note: we only do it for the CONNECT request */
+ if(authenticate && p_saved_req->event == OBX_CONNECT_REQ_EVT)
+ {
+ /* Indicate in the control block to verify the response */
+ p_cb->wait_auth = TRUE;
+
+ /* add the challenge nonce */
+ num_trip = 1;
+ triplet[0].tag = OBX_NONCE_CHLNG_TAG;
+ triplet[0].len = OBX_NONCE_SIZE;
+ triplet[0].p_array = nonce;
+ sprintf ((char *)nonce, "%016lu", GKI_get_tick_count());
+ OBX_AddTriplet(p_pkt, OBX_HI_CHALLENGE, triplet, num_trip);
+ OBX_MD5 ((UINT8 *)(p_cb->p_auth), nonce, p_password, password_len);
+ }
+
+ /* copy non-(target, conn_id, authentication) headers from p_saved_req. */
+ status = obx_copy_and_rm_auth_hdrs(p_saved_req, p_pkt, hi);
+ OBX_TRACE_DEBUG4( "status:%d, save:%d, pkt:%d, off:%d",
+ status, p_saved_req->event, p_pkt->event, p_pkt->offset);
+
+ if(status == OBX_SUCCESS)
+ {
+ /* get the final from the saved request */
+ rsp_code = OBX_RSP_DEFAULT;
+ obx_access_rsp_code(p_saved_req, &rsp_code);
+ final = (rsp_code & OBX_FINAL) ? TRUE : FALSE;
+ OBX_TRACE_DEBUG1( "saved final:%d", final);
+
+ /* call the associated API function to send the request again */
+ switch(p_pkt->event)
+ {
+ case OBX_CONNECT_REQ_EVT:
+ status = OBX_ConnectReq((BD_ADDR_PTR)BT_BD_ANY, 0, 0, NULL, &p_cb->ll_cb.comm.handle, p_pkt);
+ break;
+ case OBX_PUT_REQ_EVT:
+ status = OBX_PutReq(handle, final, p_pkt);
+ break;
+ case OBX_GET_REQ_EVT:
+ status = OBX_GetReq(handle, final, p_pkt);
+ break;
+ case OBX_SETPATH_REQ_EVT:
+ /* get the flags from old request - if SetPath */
+ flags = *((UINT8 *)(p_saved_req + 1) + p_saved_req->offset + 3);
+ status = OBX_SetPathReq(handle, flags, p_pkt);
+ break;
+ default:
+ /* it does not make sense to authenticate on Abort and Disconnect */
+ OBX_TRACE_WARNING1( "Authenticate on bad request: %d", p_pkt->event);
+ status = OBX_NO_RESOURCES;
+ } /* switch (event) */
+ }
+ } /* digest done */
+ } /* challenge heaer exists */
+
+ if(status != OBX_SUCCESS)
+ {
+ GKI_freebuf(p_pkt);
+ }
+
+ if(p_cb->wait_auth == FALSE)
+ {
+ GKI_freebuf(p_cb->p_auth);
+ p_cb->p_auth = NULL;
+ }
+ return status;
+}
+
+#if (OBX_MD5_TEST_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function OBX_VerifyResponse
+**
+** Description This function is called by the client to verify the challenge
+** response.
+**
+** Returns TRUE, if successful.
+** FALSE, if authentication failed
+**
+*******************************************************************************/
+BOOLEAN OBX_VerifyResponse(UINT32 nonce_u32, UINT8 *p_password, UINT8 password_len, UINT8 *p_response)
+{
+ BOOLEAN status = FALSE;
+ UINT8 nonce[OBX_NONCE_SIZE + 1];
+ UINT8 temp_digest[OBX_DIGEST_SIZE];
+
+ OBX_TRACE_API0( "OBX_VerifyResponse");
+ if (p_password && password_len)
+ {
+ sprintf((char *)nonce, "%016lu", nonce_u32);
+ OBX_MD5 (temp_digest, nonce, p_password, password_len);
+ if (memcmp (temp_digest, p_response, OBX_DIGEST_SIZE) == 0)
+ status = TRUE;
+ }
+ return status;
+}
+#endif /* OBX_MD5_TEST_INCLUDED */
+
+
+#endif
+
+
+