diff options
author | Mudumba Ananth <ananthm@broadcom.com> | 2015-01-30 02:33:02 -0800 |
---|---|---|
committer | Andre Eisenbach <eisenbach@google.com> | 2015-04-13 14:09:06 -0700 |
commit | 899b77140675a157dba034e98527ab546bc9ac35 (patch) | |
tree | 998eb1873ed2ac4c14795b095e9b8b7516d2d6ec /stack/btm/btm_sec.c | |
parent | 7fb0da6c0df9491f06c61ab0ba4183129502a065 (diff) | |
download | android_system_bt-899b77140675a157dba034e98527ab546bc9ac35.tar.gz android_system_bt-899b77140675a157dba034e98527ab546bc9ac35.tar.bz2 android_system_bt-899b77140675a157dba034e98527ab546bc9ac35.zip |
BR/EDR secure connections support
As a part of BT 4.1 stack upgrade, added host support for BR/EDR
secure connections to be able to interact with controllers that
support secure connections and upgrade the SSP mechanism to use
secure connection rules.
This change checks for controller support in the extended_features
(LMP page 2) and then declares the host support (extended_features
LMP page 1) using WRITE SECURE CONNECTIONS HOST SUPPORT.
If both the sides support secure connections, the simple pairing
process utilizes the link key generated using P-256 elliptic curve
(in the controller) and both the sides will be
in a secure connection.
Bug: 19289699
Change-Id: Idb3c41f439973bea137f5a4a69468c1f55aecbd7
Diffstat (limited to 'stack/btm/btm_sec.c')
-rw-r--r-- | stack/btm/btm_sec.c | 581 |
1 files changed, 473 insertions, 108 deletions
diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c index db8622e39..b62cef80e 100644 --- a/stack/btm/btm_sec.c +++ b/stack/btm/btm_sec.c @@ -24,6 +24,7 @@ #define LOG_TAG "bt_btm_sec" +#include <stdarg.h> #include <string.h> #include "bt_types.h" @@ -97,6 +98,8 @@ static BOOLEAN btm_dev_authenticated(tBTM_SEC_DEV_REC *p_dev_rec); static BOOLEAN btm_dev_encrypted(tBTM_SEC_DEV_REC *p_dev_rec); static BOOLEAN btm_dev_authorized(tBTM_SEC_DEV_REC *p_dev_rec); static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec); +static BOOLEAN btm_sec_is_serv_level0 (UINT16 psm); +static UINT16 btm_sec_set_serv_level4_flags (UINT16 cur_security, BOOLEAN is_originator); static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); @@ -391,7 +394,28 @@ void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired) btm_cb.connect_only_paired = connect_only_paired; } +/******************************************************************************* +** +** Function BTM_SetSecureConnectionsOnly +** +** Description Enable or disable default treatment for Mode 4 Level 0 services +** +** Parameter secure_connections_only_mode - (TRUE or FALSE) whether or not the device +** TRUE means that the device should treat Mode 4 Level 0 services as +** services of other levels. (Secure_connections_only_mode) +** FALSE means that the device should provide default treatment for +** Mode 4 Level 0 services. +** +** Returns void +** +*******************************************************************************/ +void BTM_SetSecureConnectionsOnly (BOOLEAN secure_connections_only_mode) +{ + BTM_TRACE_API("%s: Mode : %u", __FUNCTION__, + secure_connections_only_mode); + btm_cb.devcb.secure_connections_only = secure_connections_only_mode; +} #define BTM_NO_AVAIL_SEC_SERVICES ((UINT16) 0xffff) /******************************************************************************* @@ -562,7 +586,9 @@ static BOOLEAN btm_sec_set_security_level (CONNECTION_TYPE conn_type, char *p_na /* Parameter validation. Originator should not set requirements for incoming connections */ sec_level &= ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM); - if (btm_cb.security_mode == BTM_SEC_MODE_SP) + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) { if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM; @@ -607,7 +633,9 @@ static BOOLEAN btm_sec_set_security_level (CONNECTION_TYPE conn_type, char *p_na /* Parameter validation. Acceptor should not set requirements for outgoing connections */ sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM); - if (btm_cb.security_mode == BTM_SEC_MODE_SP) + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) { if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM; @@ -1034,9 +1062,12 @@ tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport, || (p_dev_rec->sm4 == BTM_SM4_KNOWN)) { if ( btm_sec_check_prefetch_pin (p_dev_rec) ) - return(BTM_CMD_STARTED); + return (BTM_CMD_STARTED); } - if (BTM_SEC_MODE_SP == btm_cb.security_mode && BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) + if ((btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) && + BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) { /* local is 2.1 and peer is unknown */ if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) @@ -1763,21 +1794,50 @@ UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c, /******************************************************************************* ** -** Function BTM_IsLeScSuppLocally +** Function BTM_BothEndsSupportSecureConnections ** -** Description This function is called to check if LE SC is supported. +** Description This function is called to check if both the local device and the peer device +** specified by bd_addr support BR/EDR Secure Connections. ** -** Parameters: None. +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by both local +** and the remote device. +** else FALSE. ** -** Returns Boolean - TRUE if LE SC is supported. *******************************************************************************/ -BOOLEAN BTM_IsLeScSuppLocally (void) +BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr) { -#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE - return TRUE; -#else - return FALSE; -#endif + return ((controller_get_interface()->supports_secure_connections()) && + (BTM_PeerSupportsSecureConnections(bd_addr))); +} + +/******************************************************************************* +** +** Function BTM_PeerSupportsSecureConnections +** +** Description This function is called to check if the peer supports +** BR/EDR Secure Connections. +** +** Parameters: bd_addr - address of the peer +** +** Returns TRUE if BR/EDR Secure Connections are supported by the peer, +** else FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL) + { + BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x", __FUNCTION__, + (bd_addr[0]<<24) + (bd_addr[1]<<16) + (bd_addr[2]<<8) + bd_addr[3], + (bd_addr[4]<< 8) + bd_addr[5]); + return FALSE; + } + + return (p_dev_rec->remote_supports_secure_connections); } /******************************************************************************* @@ -1923,10 +1983,15 @@ static BOOLEAN btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN /* Already have a link key to the connected peer. Is the link key secure enough? ** Is a link key upgrade even possible? */ - if ((p_dev_rec->security_required & mtm_check) /* needs MITM */ - && (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) /* has unauthenticated link key */ - && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */ - && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) /* authenticated link key is possible */ + if ((p_dev_rec->security_required & mtm_check) /* needs MITM */ + && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) || + (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) + /* has unauthenticated + link key */ + && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */ + && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) + /* authenticated + link key is possible */ { /* upgrade is possible: check if the application wants the upgrade. * If the application is configured to use a global MITM flag, @@ -2004,6 +2069,12 @@ static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_origi #define BTM_SEC_OUT_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE) #define BTM_SEC_IN_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE) +#define BTM_SEC_OUT_LEVEL4_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \ + BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4) + +#define BTM_SEC_IN_LEVEL4_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \ + BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4) + tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle, CONNECTION_TYPE conn_type, tBTM_SEC_CALLBACK *p_callback, @@ -2048,8 +2119,8 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle return(BTM_MODE_UNSUPPORTED); } - /* SDP connection we will always let through */ - if (BT_PSM_SDP == psm) + /* Services level0 by default have no security */ + if ((btm_sec_is_serv_level0(psm)) && (!btm_cb.devcb.secure_connections_only)) { (*p_callback) (bd_addr,transport, p_ref_data, BTM_SUCCESS_NO_SECURITY); return(BTM_SUCCESS); @@ -2057,7 +2128,15 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle #if (L2CAP_UCD_INCLUDED == TRUE) if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK ) { - security_required = p_serv_rec->ucd_security_flags; + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->ucd_security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->ucd_security_flags; + } rc = BTM_CMD_STARTED; if (is_originator) @@ -2081,6 +2160,12 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle } } + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + if (rc == BTM_SUCCESS) { if (p_callback) @@ -2092,7 +2177,36 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle else #endif { - security_required = p_serv_rec->security_flags; + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->security_flags; + } + } + + BTM_TRACE_DEBUG("%s: security_required 0x%04x, is_originator 0x%02x, psm 0x%04x", + __FUNCTION__, security_required, is_originator, psm); + + if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4)) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* acceptor receives L2CAP Channel Connect Request for Secure Connections Only service */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d", + "rmt_support_for_sc : %d -> fail pairing", __FUNCTION__, + local_supports_sc, + p_dev_rec->remote_supports_secure_connections); + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, + BTM_MODE4_LEVEL4_NOT_SUPPORTED); + + return (BTM_MODE4_LEVEL4_NOT_SUPPORTED); + } } /* there are some devices (moto KRZR) which connects to several services at the same time */ @@ -2103,10 +2217,12 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle psm, btm_pair_state_descr(btm_cb.pairing_state), btm_cb.security_mode, p_dev_rec->sm4); BTM_TRACE_EVENT ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags); rc = BTM_CMD_STARTED; - if ((BTM_SEC_MODE_SP != btm_cb.security_mode) - || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4)) - || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE)) - ) + if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && + (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) { /* legacy mode - local is legacy or local is lisbon/peer is legacy * or SM4 with no possibility of link key upgrade */ @@ -2134,6 +2250,12 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle } } + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + if (rc == BTM_SUCCESS) { if (p_callback) @@ -2149,49 +2271,34 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle /* Save pointer to service record */ p_dev_rec->p_cur_service = p_serv_rec; - /* mess /w security_required in btm_sec_l2cap_access_req for Lisbon */ - if (btm_cb.security_mode == BTM_SEC_MODE_SP) + /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */ + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) { - if (is_originator) + if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { - if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) + if (is_originator) { /* SM4 to SM4 -> always authenticate & encrypt */ security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT); } - else - { - if ( !(BTM_SM4_KNOWN & p_dev_rec->sm4)) - { - BTM_TRACE_DEBUG ("remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags); - /* the remote features are not known yet */ - p_dev_rec->sm4 |= BTM_SM4_REQ_PEND; - - return(BTM_CMD_STARTED); - } - } - } - else - { - /* responder */ - if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) + else /* acceptor */ { /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */ chk_acp_auth_done = TRUE; /* SM4 to SM4 -> always authenticate & encrypt */ security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT); - } - else - { - if ( !(BTM_SM4_KNOWN & p_dev_rec->sm4)) - { - BTM_TRACE_DEBUG ("(rsp) remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags); - /* the remote features are not known yet */ - p_dev_rec->sm4 |= BTM_SM4_REQ_PEND; + } + } + else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) + { + /* the remote features are not known yet */ + BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x", __FUNCTION__, + (is_originator) ? "initiator" : "acceptor", p_dev_rec->sec_flags); - return(BTM_CMD_STARTED); - } - } + p_dev_rec->sm4 |= BTM_SM4_REQ_PEND; + return (BTM_CMD_STARTED); } } @@ -2234,9 +2341,15 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle } } - /* if the originator is using dynamic PSM in legacy mode, do not start any security process now. - * The layer above L2CAP needs to carry out the security requirement after L2CAP connect response is received*/ - if (is_originator && (btm_cb.security_mode != BTM_SEC_MODE_SP || !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001)) + /* if the originator is using dynamic PSM in legacy mode, do not start any security process now + * The layer above L2CAP needs to carry out the security requirement after L2CAP connect + * response is received */ + if (is_originator && + ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001)) { BTM_TRACE_EVENT ("dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm); /* restore the old settings */ @@ -2286,8 +2399,23 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { - /* If we already have a link key to the connected peer, is the link key secure enough ? */ - btm_sec_check_upgrade(p_dev_rec, is_originator); + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) + { + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + } + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | + BTM_SEC_AUTHENTICATED); + BTM_TRACE_DEBUG ("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags); + } + else + { + /* If we already have a link key to the connected peer, is it secure enough? */ + btm_sec_check_upgrade(p_dev_rec, is_originator); + } } BTM_TRACE_EVENT ("%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d", @@ -2354,6 +2482,16 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o return BTM_NO_RESOURCES; } + if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (!btm_sec_is_serv_level0(psm))) + { + security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags, + is_originator); + } + else + { + security_required = p_serv_rec->security_flags; + } + /* there are some devices (moto phone) which connects to several services at the same time */ /* we will process one after another */ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) @@ -2362,11 +2500,13 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state)); rc = BTM_CMD_STARTED; - security_required = p_serv_rec->security_flags; - if ((BTM_SEC_MODE_SP != btm_cb.security_mode) - || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4)) - || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE)) - ) + + if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED || + btm_cb.security_mode == BTM_SEC_MODE_NONE || + btm_cb.security_mode == BTM_SEC_MODE_SERVICE || + btm_cb.security_mode == BTM_SEC_MODE_LINK) || + (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && + (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) { /* legacy mode - local is legacy or local is lisbon/peer is legacy * or SM4 with no possibility of link key upgrade */ @@ -2393,23 +2533,100 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o rc = BTM_SUCCESS; } } + if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + rc = BTM_CMD_STARTED; + } + } + + if (rc == BTM_SUCCESS) + { + BTM_TRACE_EVENT("%s: allow to bypass, checking authorization", __FUNCTION__); + /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the requirements in */ + /* btm_sec_execute_procedure */ + if ((is_originator && (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) || + (!is_originator && (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE))) + { + BTM_TRACE_EVENT("%s: still need authorization", __FUNCTION__); + rc = BTM_CMD_STARTED; + } + } + + /* Check whether there is a pending security procedure, if so we should always queue */ + /* the new security request */ + if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) + { + BTM_TRACE_EVENT("%s: There is a pending security procedure", __FUNCTION__); + rc = BTM_CMD_STARTED; } if (rc == BTM_CMD_STARTED) { - btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback, p_ref_data); - return rc; + BTM_TRACE_EVENT("%s: call btm_sec_queue_mx_request", __FUNCTION__); + btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, + mx_chan_id, p_callback, p_ref_data); + } + else /* rc == BTM_SUCCESS */ + { + /* access granted */ + if (p_callback) + { + (*p_callback) (bd_addr, transport, p_ref_data, (UINT8)rc); + } + } + + BTM_TRACE_EVENT("%s: return with rc = 0x%02x in delayed state %s", __FUNCTION__, rc, + btm_pair_state_descr(btm_cb.pairing_state)); + return rc; + } + + if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) || + (btm_cb.security_mode == BTM_SEC_MODE_SC))) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* acceptor receives service connection establishment Request for */ + /* Secure Connections Only service */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service,local_support_for_sc %d,", + "remote_support_for_sc %d: fail pairing",__FUNCTION__, + local_supports_sc, p_dev_rec->remote_supports_secure_connections); + + if (p_callback) + (*p_callback) (bd_addr, transport, (void *)p_ref_data, + BTM_MODE4_LEVEL4_NOT_SUPPORTED); + + return (BTM_MODE4_LEVEL4_NOT_SUPPORTED); } } p_dev_rec->p_cur_service = p_serv_rec; - p_dev_rec->security_required = p_serv_rec->security_flags; + p_dev_rec->security_required = security_required; - if (BTM_SEC_MODE_SP == btm_cb.security_mode) + if (btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) { if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { - /* If we already have a link key, check if that link key is good enough */ - btm_sec_check_upgrade(p_dev_rec, is_originator); + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */ + if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) + { + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + } + + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED | + BTM_SEC_AUTHENTICATED); + BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags); + } + else + { + /* If we already have a link key, check if that link key is good enough */ + btm_sec_check_upgrade(p_dev_rec, is_originator); + } } } @@ -3104,51 +3321,94 @@ void btm_io_capabilities_req (UINT8 *p) evt_data.oob_data = BTM_OOB_NONE; evt_data.auth_req = BTM_DEFAULT_AUTH_REQ; - BTM_TRACE_EVENT ("btm_io_capabilities_req() State: %s", btm_pair_state_descr(btm_cb.pairing_state)); + BTM_TRACE_EVENT("%s: State: %s", __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state)); p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr); + + BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d", __FUNCTION__, + btm_cb.security_mode, p_dev_rec->num_read_pages); + + if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (p_dev_rec->num_read_pages == 0)) + { + BTM_TRACE_EVENT("%s: Device security mode is SC only.", + "To continue need to know remote features.", __FUNCTION__); + + p_dev_rec->remote_features_needed = TRUE; + return; + } + p_dev_rec->sm4 |= BTM_SM4_TRUE; - BTM_TRACE_EVENT ("btm_io_capabilities_req() State: %s Flags: 0x%04x p_cur_service: 0x%08x", - btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, p_dev_rec->p_cur_service); + BTM_TRACE_EVENT("%s: State: %s Flags: 0x%04x p_cur_service: 0x%08x", + __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), + btm_cb.pairing_flags, p_dev_rec->p_cur_service); - if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) + if (p_dev_rec->p_cur_service) { - if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP) - { - /* received IO capability response already-> not the originator of SSP */ + BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x", + __FUNCTION__, p_dev_rec->p_cur_service->psm, + p_dev_rec->p_cur_service->security_flags); + } + + switch (btm_cb.pairing_state) + { + /* initiator connecting */ + case BTM_PAIR_STATE_IDLE: + //TODO: Handle Idle pairing state + //security_required = p_dev_rec->security_required; + break; + + /* received IO capability response already->acceptor */ + case BTM_PAIR_STATE_INCOMING_SSP: is_orig = FALSE; if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) + { + /* acceptor in dedicated bonding */ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ; - } - /* security is already in progress */ - else if (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) - { -/* coverity[uninit_use_in_call] -Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp" -False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p); -*/ - if (memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN)) + } + break; + + /* initiator, at this point it is expected to be dedicated bonding + initiated by local device */ + case BTM_PAIR_STATE_WAIT_PIN_REQ: + if (!memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN)) { - /* and it's not the device in bonding -> reject it */ - err_code = HCI_ERR_HOST_BUSY_PAIRING; + evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ; } else { - /* local device initiated dedicated bonding */ - evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ; + err_code = HCI_ERR_HOST_BUSY_PAIRING; } - } - else - { + break; + + /* any other state is unexpected */ + default: err_code = HCI_ERR_HOST_BUSY_PAIRING; - } + BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d", __FUNCTION__, + btm_cb.pairing_state); + break; } - /* paring is not allowed */ if (btm_cb.pairing_disabled) + { + /* pairing is not allowed */ + BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.", __FUNCTION__); err_code = HCI_ERR_PAIRING_NOT_ALLOWED; + } + else if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections(); + /* device in Secure Connections Only mode */ + if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) + { + BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d,", + " remote_support_for_sc 0x%02x -> fail pairing", __FUNCTION__, + local_supports_sc, p_dev_rec->remote_supports_secure_connections); + + err_code = HCI_ERR_PAIRING_NOT_ALLOWED; + } + } if (err_code != 0) { @@ -3169,7 +3429,16 @@ False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDA p_dev_rec->p_cur_service && (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE)) { - evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_MITM) ? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO; + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + /* SC only mode device requires MITM protection */ + evt_data.auth_req = BTM_AUTH_SP_YES; + } + else + { + evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags & + BTM_SEC_OUT_MITM)? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO; + } } } @@ -3212,14 +3481,23 @@ False-positive: False-positive: evt_data.bd_addr is set at the beginning with: evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT)); } - /* if the user does not indicate "reply later" by setting the oob_data to unknown - * send the response right now. Save the current IO capability in the control block */ + if (btm_cb.security_mode == BTM_SEC_MODE_SC) + { + /* At this moment we know that both sides are SC capable, device in */ + /* SC only mode requires MITM for any service so let's set MITM bit */ + evt_data.auth_req |= BTM_AUTH_YN_BIT; + BTM_TRACE_DEBUG("%s: for device in \"SC only\" mode set auth_req to 0x%02x", + __FUNCTION__, evt_data.auth_req); + } + + /* if the user does not indicate "reply later" by setting the oob_data to unknown */ + /* send the response right now. Save the current IO capability in the control block */ btm_cb.devcb.loc_auth_req = evt_data.auth_req; btm_cb.devcb.loc_io_caps = evt_data.io_cap; - BTM_TRACE_EVENT ("btm_io_capabilities_req: State: %s IO_CAP:%d oob_data:%d auth_req:%d", - btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap, - evt_data.oob_data, evt_data.auth_req); + BTM_TRACE_EVENT("%s: State: %s IO_CAP:%d oob_data:%d auth_req:%d", + __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap, + evt_data.oob_data, evt_data.auth_req); btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap, evt_data.oob_data, evt_data.auth_req); @@ -5042,6 +5320,14 @@ static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec) return(BTM_CMD_STARTED); } + if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) && + (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) + { + BTM_TRACE_EVENT("%s: Security Manager: SC only service, but link key type is 0x%02x -", + "security failure", __FUNCTION__, p_dev_rec->link_key_type); + return (BTM_FAILED_ON_SECURITY); + } + /* If connection is not authorized and authorization is required */ /* start authorization and return PENDING to the caller */ if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) @@ -5701,6 +5987,52 @@ static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT tra /******************************************************************************* ** +** Function btm_sec_set_peer_sec_caps +** +** Description This function is called to set sm4 and rmt_sec_caps fields +** based on the available peer device features. +** +** Returns void +** +*******************************************************************************/ +void btm_sec_set_peer_sec_caps(tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec) +{ + BD_ADDR rem_bd_addr; + UINT8 *p_rem_bd_addr; + + if ((btm_cb.security_mode == BTM_SEC_MODE_SP || + btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG || + btm_cb.security_mode == BTM_SEC_MODE_SC) && + HCI_SSP_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1])) + { + p_dev_rec->sm4 = BTM_SM4_TRUE; + p_dev_rec->remote_supports_secure_connections = + (HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1])); + } + else + { + p_dev_rec->sm4 = BTM_SM4_KNOWN; + p_dev_rec->remote_supports_secure_connections = FALSE; + } + + BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d", __FUNCTION__, + p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections); + + + if (p_dev_rec->remote_features_needed) + { + BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!", + __FUNCTION__); + p_rem_bd_addr = (UINT8*) rem_bd_addr; + BDADDR_TO_STREAM(p_rem_bd_addr, p_dev_rec->bd_addr); + p_rem_bd_addr = (UINT8*) rem_bd_addr; + btm_io_capabilities_req(p_rem_bd_addr); + p_dev_rec->remote_features_needed = FALSE; + } +} + +/******************************************************************************* +** ** Function btm_sec_clean_pending_req_queue ** ** Description This function cleans up the pending security request when the @@ -5729,7 +6061,26 @@ static void btm_sec_clean_pending_req_queue (BD_ADDR remote_bda, tBT_TRANSPORT t } p_e = (tBTM_SEC_QUEUE_ENTRY *) GKI_getnext ((void *)p_e); } - return; +} + +/******************************************************************************* +** +** Function btm_sec_is_serv_level0 +** +** Description This function is called to check if the service corresponding +** to PSM is security mode 4 level 0 service. +** +** Returns TRUE if the service is security mode 4 level 0 service +** +*******************************************************************************/ +static BOOLEAN btm_sec_is_serv_level0(UINT16 psm) +{ + if (psm == BT_PSM_SDP) + { + BTM_TRACE_DEBUG("%s: PSM: 0x%04x -> mode 4 level 0 service", __FUNCTION__, psm); + return TRUE; + } + return FALSE; } /******************************************************************************* @@ -5776,7 +6127,23 @@ static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRA } p_e = (tBTM_SEC_QUEUE_ENTRY *) GKI_getnext ((void *)p_e); } - return; +} + +/******************************************************************************* +** +** Function btm_sec_set_serv_level4_flags +** +** Description This function is called to set security mode 4 level 4 flags. +** +** Returns service security requirements updated to include secure +** connections only mode. +** +*******************************************************************************/ +static UINT16 btm_sec_set_serv_level4_flags(UINT16 cur_security, BOOLEAN is_originator) +{ + UINT16 sec_level4_flags = is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS; + + return cur_security | sec_level4_flags; } #if (BLE_INCLUDED == TRUE) @@ -5805,7 +6172,6 @@ void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec) #endif } - /******************************************************************************* ** ** Function btm_sec_is_a_bonded_dev @@ -5894,7 +6260,6 @@ BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_D return(found); } - /******************************************************************************* ** ** Function btm_sec_use_smp_br_chnl |