apps/wireless/bluetooth/btsak: Implement command to enable Bluetooth security.

This commit is contained in:
Gregory Nutt 2018-04-02 17:40:41 -06:00
parent e34216fe35
commit bd77fae5ce
6 changed files with 327 additions and 23 deletions

View File

@ -46,7 +46,7 @@ STACKSIZE = 4096
# Bluetooth SAK (Swiss Army Knife)
ASRCS =
CSRCS = btsak_advertise.c btsak_scan.c
CSRCS = btsak_advertise.c btsak_scan.c btsak_security.c
MAINSRC = btsak_main.c
AOBJS = $(ASRCS:.S=$(OBJEXT))

View File

@ -118,7 +118,7 @@ static inline void btsak_update_ipv6addr(FAR struct btsak_s *btsak)
*
****************************************************************************/
uint8_t btsak_char2nibble(char ch);
int btsak_char2nibble(char ch);
/****************************************************************************
* Name: btsak_str2long
@ -177,11 +177,35 @@ int btsak_str2payload(FAR const char *str, FAR uint8_t *buf);
* Name: btsak_str2addr
*
* Description:
* Convert a string 8-byte EADDR array.
* Convert a string of the form "xx:xx:xx:xx:xx:xx" 6-byte Bluetooth
* address (where xx is a one or two character hexadecimal number sub-
* string)
*
****************************************************************************/
void btsak_str2addr(FAR const char *str, FAR uint8_t *addr);
int btsak_str2addr(FAR const char *str, FAR uint8_t *addr);
/****************************************************************************
* Name: btsak_str2addrtype
*
* Description:
* Convert a string to an address type. String options are "public" or
* "private".
*
****************************************************************************/
int btsak_str2addrtype(FAR const char *str, FAR uint8_t *addrtype);
/****************************************************************************
* Name: btsak_str2seclevel
*
* Description:
* Convert a string to a security level. String options are "low",
* "medium", "high", or "fips"
*
****************************************************************************/
int btsak_str2seclevel(FAR const char *str, FAR enum bt_security_e *level);
/****************************************************************************
* Name: btsak_socket

View File

@ -197,9 +197,10 @@ static void btsak_cmd_advertisestop(FAR struct btsak_s *btsak, FAR char *cmd,
****************************************************************************/
/****************************************************************************
* Name:
* Name: btsak_cmd_advertise
*
* Description:
* advertise [-h] <start [-d] |get|stop> command
*
****************************************************************************/
@ -226,7 +227,7 @@ void btsak_cmd_advertise(FAR struct btsak_s *btsak, int argc, FAR char *argv[])
{
btsak_cmd_advertisestart(btsak, argv[0], argc - argind, &argv[argind]);
}
else if (strcmp(argv[argind], "-h") == 0)
else if (strcmp(argv[argind], "stop") == 0)
{
btsak_cmd_advertisestop(btsak, argv[0], argc - argind, &argv[argind]);
}

View File

@ -47,6 +47,7 @@
#include <strings.h>
#include <errno.h>
#include <nuttx/wireless/bt_core.h>
#include <nuttx/net/bluetooth.h>
#include "btsak.h"
@ -300,7 +301,7 @@ int bt_main(int argc, char *argv[])
*
****************************************************************************/
uint8_t btsak_char2nibble(char ch)
int btsak_char2nibble(char ch)
{
if (ch >= '0' && ch <= '9')
{
@ -316,13 +317,13 @@ uint8_t btsak_char2nibble(char ch)
}
else if (ch == '\0')
{
fprintf(stderr, "ERROR: Unexpected end hex\n");
exit(EXIT_FAILURE);
fprintf(stderr, "ERROR: Unexpected NUL terminator in hex string\n");
return -EPIPE;
}
else
{
fprintf(stderr, "ERROR: Unexpected character in hex value: %02x\n", ch);
exit(EXIT_FAILURE);
fprintf(stderr, "ERROR: Unexpected end character in hex string\n");
return -EINVAL;
}
}
@ -480,38 +481,114 @@ int btsak_str2payload(FAR const char *str, FAR uint8_t *buf)
* Name: btsak_str2addr
*
* Description:
* Convert a string 8-byte EADDR array.
* Convert a string of the form "xx:xx:xx:xx:xx:xx" 6-byte Bluetooth
* address (where xx is a one or two character hexadecimal number sub-
* string)
*
****************************************************************************/
void btsak_str2addr(FAR const char *str, FAR uint8_t *addr)
int btsak_str2addr(FAR const char *str, FAR uint8_t *addr)
{
FAR const char *src = str;
uint8_t bvalue;
int nibble;
uint8_t hex;
char ch;
int i;
for (i = 0; i < 8; i++)
for (i = 0; i < 6; i++)
{
ch = (char)*src++;
bvalue = btsak_char2nibble(ch) << 4;
nibble = btsak_char2nibble(ch) << 4;
if (nibble < 0)
{
return nibble;
}
hex = (uint8_t)nibble << 4;
ch = (char)*src++;
bvalue |= btsak_char2nibble(ch);
nibble = btsak_char2nibble(ch);
if (nibble < 0)
{
return nibble;
}
*addr++ = bvalue;
hex |= (uint8_t)nibble;
*addr++ = hex;
if (i < 7)
if (i < 5)
{
ch = (char)*src++;
if (ch != ':')
{
fprintf(stderr, "ERROR: Missing colon separator: %s\n", str);
fprintf(stderr, " Expected xx:xx:xx:xx:xx:xx:xx:xx\n");
exit(EXIT_FAILURE);
return -EINVAL;
}
}
}
return OK;
}
/****************************************************************************
* Name: btsak_str2addrtype
*
* Description:
* Convert a string to an address type. String options are "public" or
* "private".
*
****************************************************************************/
int btsak_str2addrtype(FAR const char *str, FAR uint8_t *addrtype)
{
if (!strcasecmp(str, "public") == 0)
{
*addrtype = BT_ADDR_LE_PUBLIC;
}
else if (!strcasecmp(str, "random"))
{
*addrtype = BT_ADDR_LE_RANDOM;
}
else
{
return -EINVAL;
}
return OK;
}
/****************************************************************************
* Name: btsak_str2seclevel
*
* Description:
* Convert a string to a security level. String options are "low",
* "medium", "high", or "fips"
*
****************************************************************************/
int btsak_str2seclevel(FAR const char *str, FAR enum bt_security_e *level)
{
if (!strcasecmp(str, "low") == 0)
{
*level = BT_SECURITY_LOW;
}
else if (!strcasecmp(str, "medium"))
{
*level = BT_SECURITY_MEDIUM;
}
else if (!strcasecmp(str, "high"))
{
*level = BT_SECURITY_HIGH;
}
else if (!strcasecmp(str, "fips"))
{
*level = BT_SECURITY_FIPS;
}
else
{
return -EINVAL;
}
return OK;
}
/****************************************************************************

View File

@ -249,9 +249,10 @@ static void btsak_cmd_scanstop(FAR struct btsak_s *btsak, FAR char *cmd,
****************************************************************************/
/****************************************************************************
* Name:
* Name: btsak_cmd_scan
*
* Description:
* scan [-h] <start [-d] |get|stop> command
*
****************************************************************************/

View File

@ -0,0 +1,201 @@
/****************************************************************************
* apps/wireless/bluetooth/btsak/btsak_security.c
* Bluetooth Swiss Army Knife -- Security command
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Based loosely on the i8sak IEEE 802.15.4 program by Anthony Merlino and
* Sebastien Lorquet. Commands inspired for btshell example in the
* Intel/Zephyr Arduino 101 package (BSD license).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/ioctl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <nuttx/wireless/bt_core.h>
#include <nuttx/wireless/bt_hci.h>
#include <nuttx/wireless/bt_ioctl.h>
#include "btsak.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if !defined(CONFIG_BTSAK_NINSTANCES) || CONFIG_BTSAK_NINSTANCES <= 0
# undef CONFIG_BTSAK_NINSTANCES
# define CONFIG_BTSAK_NINSTANCES 3
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: btsak_security_showusage
*
* Description:
* Show usage of the security command
*
****************************************************************************/
static void btsak_security_showusage(FAR const char *progname,
FAR const char *cmd, int exitcode)
{
fprintf(stderr, "%s:\tEnable security (encryption) for a connection:\n",
cmd);
fprintf(stderr,
"\tIf device is paired, key encryption will be enabled. If the link\n");
fprintf(stderr,
"\tis already encrypted with sufficiently strong key this function\n");
fprintf(stderr,
"\tdoes nothing.\n\n");
fprintf(stderr,
"\tIf the device is not paired pairing will be initiated. If the device\n");
fprintf(stderr,
"\tis paired and keys are too weak but input output capabilities allow\n");
fprintf(stderr,
"\tfor strong enough keys pairing will be initiated.\n\n");
fprintf(stderr,
"\tThis function may return error if required level of security is not\n");
fprintf(stderr,
"\tpossible to achieve due to local or remote device limitation (eg input\n");
fprintf(stderr,
"\toutput capabilities).\n\n");
fprintf(stderr, "Usage:\n\n");
fprintf(stderr, "\t%s <ifname> %s [-h] <addr> <addr-type> <level>\n",
progname, cmd);
fprintf(stderr,
"\nWhere:\n\n");
fprintf(stderr,
"\t<addr>\t- The 6-byte address of the connected peer\n");
fprintf(stderr,
"\t<addr-type>\t- Either \"public\" or \"random\"\n");
fprintf(stderr,
"\t<level>\t- Security level, on of:\n\n");
fprintf(stderr,
"\t\tlow\t- No encryption and no authentication\n");
fprintf(stderr,
"\t\tmedium\t- Encryption and no authentication (no MITM)\n");
fprintf(stderr,
"\t\thigh\t- Encryption and authentication (MITM)\n");
fprintf(stderr,
"\t\tfips\t- Authenticated LE secure connections and encryption\n");
exit(exitcode);
}
/****************************************************************************
* Public functions
****************************************************************************/
/****************************************************************************
* Name: btsak_cmd_security
*
* Description:
* security [-h] <start [-d] |get|stop> command
*
****************************************************************************/
void btsak_cmd_security(FAR struct btsak_s *btsak, int argc, FAR char *argv[])
{
struct bt_security_s sec;
int sockfd;
int ret;
/* Check for help */
if (argc < 2)
{
fprintf(stderr, "ERROR: Missing required arguments/n");
btsak_security_showusage(btsak->progname, argv[0], EXIT_FAILURE);
}
if (strcmp(argv[1], "-h") == 0)
{
btsak_security_showusage(btsak->progname, argv[0], EXIT_SUCCESS);
}
/* Verify that all required arguments were provided */
if (argc < 4)
{
fprintf(stderr, "ERROR: Missing required arguments/n");
btsak_security_showusage(btsak->progname, argv[0], EXIT_FAILURE);
}
/* The first argument must be an address of the form xx:xx:xx:xx:xx:xx */
ret = btsak_str2addr(argv[1], sec.se_addr.val);
if (ret < 0)
{
fprintf(stderr, "ERROR: Invalid address string: %s/n", argv[1]);
btsak_security_showusage(btsak->progname, argv[0], EXIT_FAILURE);
}
/* The second address is the address type, either "public" or "random" */
ret = btsak_str2addrtype(argv[2], &sec.se_addr.type);
if (ret < 0)
{
fprintf(stderr, "ERROR: Invalid address type: %s/n", argv[2]);
btsak_security_showusage(btsak->progname, argv[0], EXIT_FAILURE);
}
/* The third argument is the security level */
ret = btsak_str2seclevel(argv[3], &sec.se_level);
/* Perform the IOCTL to stop advertising */
strncpy(sec.se_name, btsak->ifname, HCI_DEVNAME_SIZE);
sockfd = btsak_socket(btsak);
if (sockfd >= 0)
{
ret = ioctl(sockfd, SIOCBT_SECURITY, (unsigned long)((uintptr_t)&sec));
if (ret < 0)
{
fprintf(stderr, "ERROR: ioctl(SIOCBT_SECURITY) failed: %d\n",
errno);
}
}
close(sockfd);
}