/******************************************************************************* ** ** Function SMP_SecureConnectionOobDataReply ** ** Description This function is called to provide the SC OOB data for ** SMP in response to SMP_SC_OOB_REQ_EVT ** ** Parameters: p_data - pointer to the data ** *******************************************************************************/ void SMP_SecureConnectionOobDataReply(UINT8 *p_data) { tSMP_CB *p_cb = &smp_cb; UINT8 failure = SMP_OOB_FAIL; tSMP_SC_OOB_DATA *p_oob = (tSMP_SC_OOB_DATA *) p_data; if (!p_oob) { SMP_TRACE_ERROR("%s received no data", __FUNCTION__); smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); return; } SMP_TRACE_EVENT ("%s req_oob_type: %d, loc_oob_data.present: %d, " "peer_oob_data.present: %d", __FUNCTION__, p_cb->req_oob_type, p_oob->loc_oob_data.present, p_oob->peer_oob_data.present); if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_SC_OOB_REQ_EVT) { return; } BOOLEAN data_missing = FALSE; switch (p_cb->req_oob_type) { case SMP_OOB_PEER: if (!p_oob->peer_oob_data.present) { data_missing = TRUE; } break; case SMP_OOB_LOCAL: if (!p_oob->loc_oob_data.present) { data_missing = TRUE; } break; case SMP_OOB_BOTH: if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present) { data_missing = TRUE; } break; default: SMP_TRACE_EVENT ("Unexpected OOB data type requested. Fail OOB"); data_missing = TRUE; break; } if (data_missing) { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); return; } p_cb->sc_oob_data = *p_oob; smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data); }
/******************************************************************************* ** ** Function smp_l2cap_if_init ** ** Description This function is called during the SMP task startup ** to register interface functions with L2CAP. ** *******************************************************************************/ void smp_l2cap_if_init (void) { tL2CAP_FIXED_CHNL_REG fixed_reg; SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; fixed_reg.fixed_chnl_opts.max_transmit = 0; fixed_reg.fixed_chnl_opts.rtrans_tout = 0; fixed_reg.fixed_chnl_opts.mon_tout = 0; fixed_reg.fixed_chnl_opts.mps = 0; fixed_reg.fixed_chnl_opts.tx_win_sz = 0; fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; fixed_reg.pL2CA_FixedData_Cb = smp_data_received; fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback; fixed_reg.pL2CA_FixedCong_Cb = NULL; /* do not handle congestion on this channel */ fixed_reg.default_idle_tout = 60; /* set 60 seconds timeout, 0xffff default idle timeout */ L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg); fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback; fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received; L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg); }
/******************************************************************************* ** ** Function SMP_ConfirmReply ** ** Description This function is called after Security Manager submitted ** numeric comparison request to the application. ** ** Parameters: bd_addr - Address of the device with which numeric ** comparison was requested ** res - comparison result SMP_SUCCESS if success ** *******************************************************************************/ void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res) { tSMP_CB *p_cb = & smp_cb; UINT8 failure = SMP_NUMERIC_COMPAR_FAIL; SMP_TRACE_EVENT ("%s: Result:%d", __FUNCTION__, res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->cb_evt != SMP_NC_REQ_EVT) { SMP_TRACE_WARNING ("%s() - Wrong State: %d", __FUNCTION__, p_cb->state); return; } if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__); return; } if (btm_find_dev (bd_addr) == NULL) { SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__); return; } if (res != SMP_SUCCESS) { SMP_TRACE_WARNING ("%s() - Numeric Comparison fails", __FUNCTION__); /* send pairing failure */ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); } else { smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL); } }
/******************************************************************************* ** ** Function SMP_CreateLocalSecureConnectionsOobData ** ** Description This function is called to start creation of local SC OOB ** data set (tSMP_LOC_OOB_DATA). ** ** Parameters: bd_addr - Address of the device to send OOB data block to ** ** Returns Boolean - TRUE: creation of local SC OOB data set started. *******************************************************************************/ BOOLEAN SMP_CreateLocalSecureConnectionsOobData (tBLE_BD_ADDR *addr_to_send_to) { tSMP_CB *p_cb = &smp_cb; #if (!CONFIG_BT_STACK_NO_LOG) UINT8 *bd_addr; #endif if (addr_to_send_to == NULL) { SMP_TRACE_ERROR ("%s addr_to_send_to is not provided", __FUNCTION__); return FALSE; } #if (!CONFIG_BT_STACK_NO_LOG) bd_addr = addr_to_send_to->bda; #endif SMP_TRACE_EVENT ("%s addr type: %u, BDA: %08x%04x, state: %u, br_state: %u", __FUNCTION__, addr_to_send_to->type, (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], (bd_addr[4] << 8) + bd_addr[5], p_cb->state, p_cb->br_state); if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br)) { SMP_TRACE_WARNING ("%s creation of local OOB data set "\ "starts only in IDLE state", __FUNCTION__); return FALSE; } p_cb->sc_oob_data.loc_oob_data.addr_sent_to = *addr_to_send_to; smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL); return TRUE; }
/******************************************************************************* ** ** Function cmac_subkey_cont ** ** Description This is the callback function when CIPHk(0[128]) is completed. ** ** Returns void ** *******************************************************************************/ static void cmac_subkey_cont(tSMP_ENC *p) { UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN]; UINT8 *pp = p->param_buf; SMP_TRACE_EVENT ("cmac_subkey_cont "); print128(pp, (const UINT8 *)"K1 before shift"); /* If MSB(L) = 0, then K1 = L << 1 */ if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 ) { /* Else K1 = ( L << 1 ) (+) Rb */ leftshift_onebit(pp, k1); smp_xor_128(k1, const_Rb); } else { leftshift_onebit(pp, k1); } if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 ) { /* K2 = (K1 << 1) (+) Rb */ leftshift_onebit(k1, k2); smp_xor_128(k2, const_Rb); } else { /* If MSB(K1) = 0, then K2 = K1 << 1 */ leftshift_onebit(k1, k2); } print128(k1, (const UINT8 *)"K1"); print128(k2, (const UINT8 *)"K2"); cmac_prepare_last_block (k1, k2); }
/******************************************************************************* ** ** Function SMP_BR_PairWith ** ** Description This function is called to start a SMP pairing over BR/EDR. ** Device support one SMP pairing at one time. ** ** Parameters bd_addr - peer device bd address. ** ** Returns SMP_STARTED if pairing started, otherwise reason for failure. ** *******************************************************************************/ tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) { tSMP_CB *p_cb = &smp_cb; UINT8 status = SMP_PAIR_INTERNAL_ERR; SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ", __func__, p_cb->state, p_cb->br_state, p_cb->flags); if (p_cb->state != SMP_STATE_IDLE || p_cb->smp_over_br || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { /* pending security on going, reject this one */ return SMP_BUSY; } p_cb->role = HCI_ROLE_MASTER; p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD; p_cb->smp_over_br = TRUE; memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN); if (!L2CA_ConnectFixedChnl (L2CAP_SMP_BR_CID, bd_addr, BLE_ADDR_UNKNOWN_TYPE)) { SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __FUNCTION__); smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); return status; } return SMP_STARTED; }
/******************************************************************************* ** ** Function SMP_SecurityGrant ** ** Description This function is called to grant security process. ** ** Parameters bd_addr - peer device bd address. ** res - result of the operation SMP_SUCCESS if success. ** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts. ** ** Returns None ** *******************************************************************************/ void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res) { SMP_TRACE_EVENT ("SMP_SecurityGrant "); if (smp_cb.smp_over_br) { if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP || smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) { return; } /* clear the SMP_SEC_REQUEST_EVT event after get grant */ /* avoid generating duplicate pair request */ smp_cb.cb_evt = 0; smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res); return; } if (smp_cb.state != SMP_STATE_WAIT_APP_RSP || smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) { return; } /* clear the SMP_SEC_REQUEST_EVT event after get grant */ /* avoid generate duplicate pair request */ smp_cb.cb_evt = 0; smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res); }
/******************************************************************************* ** ** Function SMP_KeypressNotification ** ** Description This function is called to notify Security Manager about Keypress Notification. ** ** Parameters: bd_addr Address of the device to send keypress notification to ** value Keypress notification parameter value ** *******************************************************************************/ void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value) { tSMP_CB *p_cb = &smp_cb; SMP_TRACE_EVENT ("%s: Value: %d", __FUNCTION__, value); if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__); return; } if (btm_find_dev (bd_addr) == NULL) { SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__); return; } /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */ /* during the passkey entry protocol */ if (p_cb->local_io_capability != SMP_IO_CAP_IN) { SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d", __FUNCTION__, p_cb->local_io_capability); return; } if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) { SMP_TRACE_ERROR ("%s() - wrong protocol %d", __FUNCTION__, p_cb->selected_association_model); return; } smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value); }
/******************************************************************************* ** ** Function SMP_OobDataReply ** ** Description This function is called to provide the OOB data for ** SMP in response to SMP_OOB_REQ_EVT ** ** Parameters: bd_addr - Address of the peer device ** res - result of the operation SMP_SUCCESS if success ** p_data - simple pairing Randomizer C. ** *******************************************************************************/ void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, UINT8 *p_data) { tSMP_CB *p_cb = & smp_cb; UINT8 failure = SMP_OOB_FAIL; tSMP_KEY key; SMP_TRACE_EVENT ("%s State: %d res:%d", __FUNCTION__, smp_cb.state, res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT) { return; } if (res != SMP_SUCCESS || len == 0 || !p_data) { smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); } else { if (len > BT_OCTET16_LEN) { len = BT_OCTET16_LEN; } memcpy(p_cb->tk, p_data, len); key.key_type = SMP_KEY_TYPE_TK; key.p_data = p_cb->tk; smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key); } }
/******************************************************************************* ** ** Function smp_br_connect_callback ** ** Description This callback function is called by L2CAP to indicate that ** SMP BR channel is ** connected (conn = TRUE)/disconnected (conn = FALSE). ** *******************************************************************************/ static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport) { tSMP_CB *p_cb = &smp_cb; tSMP_INT_DATA int_data; SMP_TRACE_EVENT ("%s", __func__); if (transport != BT_TRANSPORT_BR_EDR) { SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__, transport); return; } if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) return; SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x Event: %s", __func__, (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3], (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected"); if (connected) { if(!p_cb->connect_initialized) { p_cb->connect_initialized = TRUE; /* initialize local i/r key to be default keys */ p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY; p_cb->loc_auth_req = p_cb->peer_auth_req = 0; p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL); } } else { int_data.reason = reason; /* Disconnected while doing security */ smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); } }
/******************************************************************************* ** ** Function smp_connect_callback ** ** Description This callback function is called by L2CAP to indicate that ** SMP channel is ** connected (conn = TRUE)/disconnected (conn = FALSE). ** *******************************************************************************/ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport) { tSMP_CB *p_cb = &smp_cb; tSMP_INT_DATA int_data; BD_ADDR dummy_bda = {0}; SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__); if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) return; if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) { SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s", __FUNCTION__, (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3], (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected"); if (connected) { if(!p_cb->connect_initialized) { p_cb->connect_initialized = TRUE; /* initiating connection established */ p_cb->role = L2CA_GetBleConnRole(bd_addr); /* initialize local i/r key to be default keys */ p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY; p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ; p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL); } } else { int_data.reason = reason; /* Disconnected while doing security */ smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data); } } }
/******************************************************************************* ** ** Function leftshift_onebit ** ** Description utility function to left shift one bit for a 128 bits value. ** ** Returns void ** *******************************************************************************/ static void leftshift_onebit(UINT8 *input, UINT8 *output) { UINT8 i, overflow = 0 , next_overflow = 0; SMP_TRACE_EVENT ("leftshift_onebit "); /* input[0] is LSB */ for ( i = 0; i < BT_OCTET16_LEN ; i ++ ) { next_overflow = (input[i] & 0x80) ? 1 : 0; output[i] = (input[i] << 1) | overflow; overflow = next_overflow; } return; }
/******************************************************************************* ** ** Function SMP_Register ** ** Description This function register for the SMP services callback. ** ** Returns void ** *******************************************************************************/ BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback) { SMP_TRACE_EVENT ("SMP_Register state=%d", smp_cb.state); if (smp_cb.p_callback != NULL) { SMP_TRACE_ERROR ("SMP_Register: duplicate registration, overwrite it"); } smp_cb.p_callback = p_cback; return (TRUE); }
/******************************************************************************* ** ** Function cmac_generate_subkey ** ** Description This is the function to generate the two subkeys. ** ** Parameters key - CMAC key, expect SRK when used by SMP. ** ** Returns void ** *******************************************************************************/ static BOOLEAN cmac_generate_subkey(BT_OCTET16 key) { BT_OCTET16 z = {0}; BOOLEAN ret = TRUE; tSMP_ENC output; SMP_TRACE_EVENT (" cmac_generate_subkey"); if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) { cmac_subkey_cont(&output);; } else { ret = FALSE; } return ret; }
/******************************************************************************* ** ** Function smp_br_data_received ** ** Description This function is called when data is received from L2CAP on ** SMP BR channel. ** ** Returns void ** *******************************************************************************/ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); GKI_freebuf(p_buf); return; } /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd) { if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { p_cb->role = HCI_ROLE_SLAVE; p_cb->smp_over_br = TRUE; memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { GKI_freebuf (p_buf); smp_reject_unexpected_pairing_command(bd_addr); return; } /* else, out of state pairing request received, passed into State Machine */ } if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { btu_stop_timer (&p_cb->rsp_timer_ent); btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, SMP_WAIT_FOR_RSP_TOUT); p_cb->rcvd_cmd_code = cmd; p_cb->rcvd_cmd_len = (UINT8) p_buf->len; smp_br_state_machine_event(p_cb, cmd, p); } GKI_freebuf (p_buf); }
/******************************************************************************* ** ** Function AES_CMAC ** ** Description This is the AES-CMAC Generation Function with tlen implemented. ** ** Parameters key - CMAC key in little endian order, expect SRK when used by SMP. ** input - text to be signed in little endian byte order. ** length - length of the input in byte. ** tlen - lenth of mac desired ** p_signature - data pointer to where signed data to be stored, tlen long. ** ** Returns void ** *******************************************************************************/ BOOLEAN AES_CMAC ( BT_OCTET16 key, UINT8 *input, UINT16 length, UINT16 tlen, UINT8 *p_signature) { UINT16 len, diff; UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */ BOOLEAN ret = FALSE; SMP_TRACE_EVENT ("AES_CMAC "); if (n == 0) n = 1; len = n * BT_OCTET16_LEN; SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len); /* allocate a memory space of multiple of 16 bytes to hold text */ if ((cmac_cb.text = (UINT8 *)GKI_getbuf(len)) != NULL) { cmac_cb.round = n; memset(cmac_cb.text, 0, len); diff = len - length; if (input != NULL && length > 0) { memcpy(&cmac_cb.text[diff] , input, (int)length); cmac_cb.len = length; } else cmac_cb.len = 0; /* prepare calculation for subkey s and last block of data */ if (cmac_generate_subkey(key)) { /* start calculation */ ret = cmac_aes_k_calculate(key, p_signature, tlen); } /* clean up */ cmac_aes_cleanup(); } else { ret = FALSE; SMP_TRACE_ERROR("No resources"); } return ret; }
/******************************************************************************* ** ** Function SMP_Init ** ** Description This function initializes the SMP unit. ** ** Returns void ** *******************************************************************************/ void SMP_Init(void) { #if SMP_DYNAMIC_MEMORY smp_cb_ptr = (tSMP_CB *)osi_malloc(sizeof(tSMP_CB)); #endif memset(&smp_cb, 0, sizeof(tSMP_CB)); #if defined(SMP_INITIAL_TRACE_LEVEL) smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL; #else smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ #endif SMP_TRACE_EVENT ("%s", __FUNCTION__); smp_l2cap_if_init(); /* initialization of P-256 parameters */ p_256_init_curve(KEY_LENGTH_DWORDS_P256); }
/******************************************************************************* ** ** Function cmac_prepare_last_block ** ** Description This function proceeed to prepare the last block of message ** Mn depending on the size of the message. ** ** Returns void ** *******************************************************************************/ static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2) { // UINT8 x[16] = {0}; BOOLEAN flag; SMP_TRACE_EVENT ("cmac_prepare_last_block "); /* last block is a complete block set flag to 1 */ flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? TRUE : FALSE; SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round); if ( flag ) { /* last block is complete block */ smp_xor_128(&cmac_cb.text[0], k1); } else { /* padding then xor with k2 */ padding(&cmac_cb.text[0], (UINT8)(cmac_cb.len % 16)); smp_xor_128(&cmac_cb.text[0], k2); } }
/******************************************************************************* ** ** Function cmac_aes_k_calculate ** ** Description This function is the calculation of block cipher using AES-128. ** ** Returns void ** *******************************************************************************/ static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 tlen) { tSMP_ENC output; UINT8 i = 1, err = 0; UINT8 x[16] = {0}; UINT8 *p_mac; SMP_TRACE_EVENT ("cmac_aes_k_calculate "); while (i <= cmac_cb.round) { smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X */ if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output)) { err = 1; break; } memcpy(x, output.param_buf, BT_OCTET16_LEN); i ++; } if (!err) { p_mac = output.param_buf + (BT_OCTET16_LEN - tlen); memcpy(p_signature, p_mac, tlen); SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac); SMP_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x", *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); SMP_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x", *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); return TRUE; } else return FALSE; }
void test_cmac(void) { SMP_TRACE_EVENT ("test_cmac "); UINT8 M[64] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }; UINT8 key[16] = { 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab, 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b }; UINT8 i =0, tmp; UINT16 len; len = 64; for (i = 0; i < len/2; i ++) { tmp = M[i]; M[i] = M[len -1 - i]; M[len -1 - i] = tmp; } memset(&cmac_cb, 0, sizeof(tCMAC_CB)); SMP_TRACE_WARNING("\n Example 1: len = %d\n", len); AES_CMAC(key, M, len, 128, test_cmac_cback, 0); }
/******************************************************************************* ** ** Function SMP_PasskeyReply ** ** Description This function is called after Security Manager submitted ** passkey request to the application. ** ** Parameters: bd_addr - Address of the device for which passkey was requested ** res - result of the operation SMP_SUCCESS if success ** passkey - numeric value in the range of ** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). ** *******************************************************************************/ void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey) { tSMP_CB *p_cb = & smp_cb; UINT8 failure = SMP_PASSKEY_ENTRY_FAIL; SMP_TRACE_EVENT ("SMP_PasskeyReply: Key: %d Result:%d", passkey, res); /* If timeout already expired or has been canceled, ignore the reply */ if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) { SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state); return; } if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { SMP_TRACE_ERROR ("SMP_PasskeyReply() - Wrong BD Addr"); return; } if (btm_find_dev (bd_addr) == NULL) { SMP_TRACE_ERROR ("SMP_PasskeyReply() - no dev CB"); return; } if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) { SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey); /* send pairing failure */ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); } else if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_ENT) { smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey); } else { smp_convert_string_to_tk(p_cb->tk, passkey); } return; }
/******************************************************************************* ** ** Function smp_sm_event ** ** Description Handle events to the state machine. It looks up the entry ** in the smp_entry_table array. ** If it is a valid entry, it gets the state table.Set the next state, ** if not NULL state.Execute the action function according to the ** state table. If the state returned by action function is not NULL ** state, adjust the new state to the returned state.If (api_evt != MAX), ** call callback function. ** ** Returns void. ** *******************************************************************************/ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) { UINT8 curr_state = p_cb->state; tSMP_SM_TBL state_table; UINT8 action, entry, i; tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role]; SMP_TRACE_EVENT("main smp_sm_event"); if (curr_state >= SMP_STATE_MAX) { SMP_TRACE_DEBUG( "Invalid state: %d", curr_state) ; return; } SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",\ (p_cb->role == 0x01) ?"Slave" : "Master", smp_get_state_name( p_cb->state), p_cb->state, smp_get_event_name(event), event) ; /* look up the state table for the current state */ /* lookup entry /w event & curr_state */ /* If entry is ignore, return. * Otherwise, get state table (according to curr_state or all_state) */ if ((event <= SMP_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE )) { if (entry & SMP_ALL_TBL_MASK) { entry &= ~SMP_ALL_TBL_MASK; state_table = smp_all_table; } else state_table = smp_state_table[curr_state][p_cb->role]; } else { SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]", smp_get_event_name(event), event, smp_get_state_name(curr_state), curr_state); return; } /* Get possible next state from state table. */ smp_set_state(state_table[entry-1][SMP_SME_NEXT_STATE]); /* If action is not ignore, clear param, exec action and get next state. * The action function may set the Param for cback. * Depending on param, call cback or free buffer. */ /* execute action */ /* execute action functions */ for (i = 0; i < SMP_NUM_ACTIONS; i++) { if ((action = state_table[entry-1][i]) != SMP_SM_NO_ACTION) { (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); } else { break; } } SMP_TRACE_DEBUG( "result state = %s", smp_get_state_name( p_cb->state ) ) ; }
/******************************************************************************* ** ** Function smp_data_received ** ** Description This function is called when data is received from L2CAP on ** SMP channel. ** ** ** Returns void ** *******************************************************************************/ static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s", __FUNCTION__); STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); GKI_freebuf (p_buf); return; } /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) { if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) && !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { p_cb->role = L2CA_GetBleConnRole(bd_addr); memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { GKI_freebuf (p_buf); smp_reject_unexpected_pairing_command(bd_addr); return; } /* else, out of state pairing request/security request received, passed into SM */ } if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { btu_stop_timer (&p_cb->rsp_timer_ent); btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, SMP_WAIT_FOR_RSP_TOUT); if (cmd == SMP_OPCODE_CONFIRM) { SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x," "loc_auth_req = 0x%02x", __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { cmd = SMP_OPCODE_PAIR_COMMITM; } } p_cb->rcvd_cmd_code = cmd; p_cb->rcvd_cmd_len = (UINT8) p_buf->len; smp_sm_event(p_cb, cmd, p); } GKI_freebuf (p_buf); }
/* clean up */ cmac_aes_cleanup(); } else { ret = FALSE; SMP_TRACE_ERROR("No resources"); } return ret; } #if 0 /* testing code, sample data from spec */ void test_cmac_cback(UINT8 *p_mac, UINT16 tlen) { SMP_TRACE_EVENT ("test_cmac_cback "); SMP_TRACE_ERROR("test_cmac_cback"); }