1 /******************************************************************************
2 *
3 * Copyright (C) 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains GATT authentication handling functions
22 *
23 ******************************************************************************/
24 #include "common/bt_target.h"
25 #include "osi/allocator.h"
26
27 #if BLE_INCLUDED == TRUE
28 #include <string.h>
29
30 #include "gatt_int.h"
31 #include "stack/gatt_api.h"
32 #include "btm_int.h"
33
34 /*******************************************************************************
35 **
36 ** Function gatt_sign_data
37 **
38 ** Description This function sign the data for write command.
39 **
40 ** Returns TRUE if encrypted, otherwise FALSE.
41 **
42 *******************************************************************************/
43 #if (SMP_INCLUDED == TRUE)
gatt_sign_data(tGATT_CLCB * p_clcb)44 static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb)
45 {
46 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
47 UINT8 *p_data = NULL, *p;
48 UINT16 payload_size = p_clcb->p_tcb->payload_size;
49 BOOLEAN status = FALSE;
50 UINT8 *p_signature;
51
52 /* do not need to mark channel securoty activity for data signing */
53 gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK);
54
55 p_data = (UINT8 *)osi_malloc((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */
56
57 if (p_data != NULL) {
58 p = p_data;
59 UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
60 UINT16_TO_STREAM(p, p_attr->handle);
61 ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
62
63 /* sign data length should be attribulte value length plus 2B handle + 1B op code */
64 if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len) {
65 p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
66 }
67
68 p_signature = p_attr->value + p_attr->len;
69 if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
70 p_data,
71 (UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
72 p_signature)) {
73 p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
74 gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
75 #if (GATTC_INCLUDED == TRUE)
76 gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA);
77 #endif ///GATTC_INCLUDED == TRUE
78 } else {
79 gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
80 }
81
82 osi_free(p_data);
83 }
84
85 return status;
86 }
87 #endif ///SMP_INCLUDED == TRUE
88
89 /*******************************************************************************
90 **
91 ** Function gatt_verify_signature
92 **
93 ** Description This function start to verify the sign data when receiving
94 ** the data from peer device.
95 **
96 ** Returns
97 **
98 *******************************************************************************/
99 #if (SMP_INCLUDED == TRUE)
gatt_verify_signature(tGATT_TCB * p_tcb,BT_HDR * p_buf)100 void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
101 {
102 UINT16 cmd_len;
103 #if (GATTS_INCLUDED == TRUE)
104 UINT8 op_code;
105 #endif ///GATTS_INCLUDED == TRUE
106 UINT8 *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
107 UINT32 counter;
108
109 if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
110 GATT_TRACE_ERROR("%s: Data length %u less than expected %u",
111 __func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4);
112 return;
113 }
114 cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
115 p = p_orig + cmd_len - 4;
116 STREAM_TO_UINT32(counter, p);
117
118 if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) {
119 #if (GATTS_INCLUDED == TRUE)
120 STREAM_TO_UINT8(op_code, p_orig);
121 gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig);
122 #endif ///GATTS_INCLUDED == TRUE
123 } else {
124 /* if this is a bad signature, assume from attacker, ignore it */
125 GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
126 }
127
128 return;
129 }
130 #endif ///SMP_INCLUDED == TRUE
131
132 /*******************************************************************************
133 **
134 ** Function gatt_sec_check_complete
135 **
136 ** Description security check complete and proceed to data sending action.
137 **
138 ** Returns void.
139 **
140 *******************************************************************************/
gatt_sec_check_complete(BOOLEAN sec_check_ok,tGATT_CLCB * p_clcb,UINT8 sec_act)141 void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
142 {
143 if (p_clcb && p_clcb->p_tcb) {
144 if (fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
145 gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
146 }
147 #if (GATTC_INCLUDED == TRUE)
148 if (!sec_check_ok) {
149 gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
150 } else if (p_clcb->operation == GATTC_OPTYPE_WRITE) {
151 gatt_act_write(p_clcb, sec_act);
152 } else if (p_clcb->operation == GATTC_OPTYPE_READ) {
153 gatt_act_read(p_clcb, p_clcb->counter);
154 }
155 #endif ///GATTC_INCLUDED == TRUE
156 }
157 }
158 /*******************************************************************************
159 **
160 ** Function gatt_enc_cmpl_cback
161 **
162 ** Description link encryption complete callback.
163 **
164 ** Returns
165 **
166 *******************************************************************************/
gatt_enc_cmpl_cback(BD_ADDR bd_addr,tBT_TRANSPORT transport,void * p_ref_data,tBTM_STATUS result)167 void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result)
168 {
169 tGATT_TCB *p_tcb;
170 UINT8 sec_flag;
171 BOOLEAN status = FALSE;
172 UNUSED(p_ref_data);
173
174 GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
175 if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) {
176 if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
177 return;
178 }
179 tGATT_PENDING_ENC_CLCB *p_buf =
180 (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
181 if (p_buf != NULL) {
182 if (result == BTM_SUCCESS) {
183 if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) {
184 BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
185
186 if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
187 status = TRUE;
188 }
189 } else {
190 status = TRUE;
191 }
192 }
193 gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act);
194 osi_free(p_buf);
195 /* start all other pending operation in queue */
196 for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
197 count > 0; count--) {
198 p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
199 if (p_buf != NULL) {
200 gatt_security_check_start(p_buf->p_clcb);
201 osi_free(p_buf);
202 } else {
203 break;
204 }
205 }
206 } else {
207 GATT_TRACE_ERROR("Unknown operation encryption completed");
208 }
209 } else {
210 GATT_TRACE_ERROR("enc callback for unknown bd_addr");
211 }
212 }
213
214 /*******************************************************************************
215 **
216 ** Function gatt_notify_enc_cmpl
217 **
218 ** Description link encryption complete notification for all encryption process
219 ** initiated outside GATT.
220 **
221 ** Returns
222 **
223 *******************************************************************************/
gatt_notify_enc_cmpl(BD_ADDR bd_addr)224 void gatt_notify_enc_cmpl(BD_ADDR bd_addr)
225 {
226 tGATT_TCB *p_tcb;
227 UINT8 i = 0;
228
229 if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
230 for (i = 0; i < GATT_MAX_APPS; i++) {
231 if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
232 (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr);
233 }
234 }
235
236 if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
237 gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
238
239 size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
240 for (; count > 0; count--) {
241 tGATT_PENDING_ENC_CLCB *p_buf =
242 (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
243 if (p_buf != NULL) {
244 gatt_security_check_start(p_buf->p_clcb);
245 osi_free(p_buf);
246 } else {
247 break;
248 }
249 }
250 }
251 } else {
252 GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
253 }
254 return;
255 }
256 /*******************************************************************************
257 **
258 ** Function gatt_set_sec_act
259 **
260 ** Description This function set the sec_act in clcb
261 **
262 ** Returns none
263 **
264 *******************************************************************************/
gatt_set_sec_act(tGATT_TCB * p_tcb,tGATT_SEC_ACTION sec_act)265 void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
266 {
267 if (p_tcb) {
268 p_tcb->sec_act = sec_act;
269 }
270 }
271 /*******************************************************************************
272 **
273 ** Function gatt_get_sec_act
274 **
275 ** Description This function get the sec_act in clcb
276 **
277 ** Returns none
278 **
279 *******************************************************************************/
gatt_get_sec_act(tGATT_TCB * p_tcb)280 tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
281 {
282 tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
283 if (p_tcb) {
284 sec_act = p_tcb->sec_act;
285 }
286 return sec_act;
287 }
288 /*******************************************************************************
289 **
290 ** Function gatt_determine_sec_act
291 **
292 ** Description This routine determine the security action based on auth_request and
293 ** current link status
294 **
295 ** Returns tGATT_SEC_ACTION security action
296 **
297 *******************************************************************************/
gatt_determine_sec_act(tGATT_CLCB * p_clcb)298 tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
299 {
300 tGATT_SEC_ACTION act = GATT_SEC_OK;
301 UINT8 sec_flag;
302 tGATT_TCB *p_tcb = p_clcb->p_tcb;
303 tGATT_AUTH_REQ auth_req = p_clcb->auth_req;
304 BOOLEAN is_link_encrypted = FALSE;
305 BOOLEAN is_link_key_known = FALSE;
306 BOOLEAN is_key_mitm = FALSE;
307 #if (SMP_INCLUDED == TRUE)
308 UINT8 key_type;
309 tBTM_BLE_SEC_REQ_ACT sec_act = BTM_LE_SEC_NONE;
310 #endif ///SMP_INCLUDED == TRUE
311 if (auth_req == GATT_AUTH_REQ_NONE ) {
312 return act;
313 }
314
315 BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_clcb->p_tcb->transport);
316 #if (SMP_INCLUDED == TRUE)
317 btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act);
318 #endif ///SMP_INCLUDED == TRUE
319 /* if a encryption is pending, need to wait */
320 if (
321 #if (SMP_INCLUDED == TRUE)
322 sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD &&
323 #endif ///SMP_INCLUDED == TRUE
324 auth_req != GATT_AUTH_REQ_NONE) {
325 return GATT_SEC_ENC_PENDING;
326 }
327
328 if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED | BTM_SEC_FLAG_LKEY_KNOWN)) {
329 if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
330 is_link_encrypted = TRUE;
331 }
332
333 is_link_key_known = TRUE;
334
335 if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
336 is_key_mitm = TRUE;
337 }
338 }
339
340 /* first check link key upgrade required or not */
341 switch (auth_req) {
342 case GATT_AUTH_REQ_MITM:
343 case GATT_AUTH_REQ_SIGNED_MITM:
344 if (!is_key_mitm) {
345 act = GATT_SEC_ENCRYPT_MITM;
346 }
347 break;
348
349 case GATT_AUTH_REQ_NO_MITM:
350 case GATT_AUTH_REQ_SIGNED_NO_MITM:
351 if (!is_link_key_known) {
352 act = GATT_SEC_ENCRYPT_NO_MITM;
353 }
354 break;
355 default:
356 break;
357 }
358
359 /* now check link needs to be encrypted or not if the link key upgrade is not required */
360 if (act == GATT_SEC_OK) {
361 if (p_tcb->transport == BT_TRANSPORT_LE &&
362 (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
363 (p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
364 /* this is a write command request
365 check data signing required or not */
366 if (!is_link_encrypted) {
367 #if (SMP_INCLUDED == TRUE)
368 btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
369 #endif ///SMP_INCLUDED == TRUE
370 if (
371 #if (SMP_INCLUDED == TRUE)
372 (key_type & BTM_LE_KEY_LCSRK) &&
373 #endif ///SMP_INCLUDED == TRUE
374 ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
375 (auth_req == GATT_AUTH_REQ_SIGNED_MITM))) {
376 act = GATT_SEC_SIGN_DATA;
377 } else {
378 act = GATT_SEC_ENCRYPT;
379 }
380 }
381 } else {
382 if (!is_link_encrypted) {
383 act = GATT_SEC_ENCRYPT;
384 }
385 }
386
387 }
388
389 return act ;
390
391 }
392
393
394
395 /*******************************************************************************
396 **
397 ** Function gatt_get_link_encrypt_status
398 **
399 ** Description This routine get the encryption status of the specified link
400 **
401 **
402 ** Returns tGATT_STATUS link encryption status
403 **
404 *******************************************************************************/
gatt_get_link_encrypt_status(tGATT_TCB * p_tcb)405 tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
406 {
407 tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED;
408 UINT8 sec_flag = 0;
409
410 BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
411
412 if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) {
413 encrypt_status = GATT_ENCRYPED_NO_MITM;
414 if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
415 encrypt_status = GATT_ENCRYPED_MITM;
416 }
417 }
418
419 GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x", encrypt_status);
420 return encrypt_status ;
421 }
422
423
424 /*******************************************************************************
425 **
426 ** Function gatt_convert_sec_action
427 **
428 ** Description Convert GATT security action enum into equivalent BTM BLE security action enum
429 **
430 ** Returns BOOLEAN TRUE - conversation is successful
431 **
432 *******************************************************************************/
gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act,tBTM_BLE_SEC_ACT * p_btm_sec_act)433 static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
434 {
435 BOOLEAN status = TRUE;
436 switch (gatt_sec_act) {
437 case GATT_SEC_ENCRYPT:
438 *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
439 break;
440 case GATT_SEC_ENCRYPT_NO_MITM:
441 *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
442 break;
443 case GATT_SEC_ENCRYPT_MITM:
444 *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
445 break;
446 default:
447 status = FALSE;
448 break;
449 }
450
451 return status;
452 }
453 /*******************************************************************************
454 **
455 ** Function gatt_check_enc_req
456 **
457 ** Description check link security.
458 **
459 ** Returns TRUE if encrypted, otherwise FALSE.
460 **
461 *******************************************************************************/
gatt_security_check_start(tGATT_CLCB * p_clcb)462 BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
463 {
464 tGATT_TCB *p_tcb = p_clcb->p_tcb;
465 tGATT_SEC_ACTION gatt_sec_act;
466 tBTM_BLE_SEC_ACT btm_ble_sec_act;
467 BOOLEAN status = TRUE;
468 #if (SMP_INCLUDED == TRUE)
469 tBTM_STATUS btm_status;
470 #endif ///SMP_INCLUDED == TRUE
471 tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
472
473 gatt_sec_act = gatt_determine_sec_act(p_clcb);
474
475 if (sec_act_old == GATT_SEC_NONE) {
476 gatt_set_sec_act(p_tcb, gatt_sec_act);
477 }
478
479 switch (gatt_sec_act ) {
480 case GATT_SEC_SIGN_DATA:
481 #if (SMP_INCLUDED == TRUE)
482 GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
483 gatt_sign_data(p_clcb);
484 #endif ///SMP_INCLUDED == TRUE
485 break;
486 case GATT_SEC_ENCRYPT:
487 case GATT_SEC_ENCRYPT_NO_MITM:
488 case GATT_SEC_ENCRYPT_MITM:
489 if (sec_act_old < GATT_SEC_ENCRYPT) {
490 GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
491 gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
492 #if (SMP_INCLUDED == TRUE)
493 btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
494 if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) {
495 GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
496 status = FALSE;
497 }
498 #endif ///SMP_INCLUDED == TRUE
499 }
500 if (status) {
501 gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
502 }
503 break;
504 case GATT_SEC_ENC_PENDING:
505 gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
506 /* wait for link encrypotion to finish */
507 break;
508 default:
509 gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
510 break;
511 }
512
513 if (status == FALSE) {
514 gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
515 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
516 }
517
518 return status;
519 }
520
521
522 #endif /* BLE_INCLUDED */
523