Bluetooth Authentication Failure: BluetoothAuthenticateDeviceEx() returns ERROR_INVALID_PARAMETER

  • Thread starter Thread starter Adl1452
  • Start date Start date
A

Adl1452

Guest
In the following code I'm using BluetoothAuthenticateDeviceEx() to initiate authentication with a remote Bluetooth device. "int callbacklock = 0;" and "BLUETOOTH_DEVICE_INFO btdi = { 0 };" are globals defined elsewhere in the code. The remote device is set up to do Just Works mode (Bluetooth classic mode only and no pass keys) with COD 000000 for testing purposes.

Code is built using Visual Studio 2015 Professional and MS SDK 8.1 on a Win7 64bit machine. Target platform is defined as x86. This is a Windows console application.

When this code is run, BluetoothAuthenticateDeviceEx() returns ERROR_INVALID_PARAMETER. Code never passes "while (callbacklock);" since the callback BluetoothAuthCallback() is never called by the running code (verified by no output of fprintf() within the callback). The BluetoothRegisterForAuthenticationEx() function works fine with return code ERROR_SUCCESS. If I remove "while (callbacklock);", connect() call is made and a pop up "A bluetooth device is trying to connect" is displayed on the bottom right corner of the desktop. If I click on it, bluetooth device is installed and the connect() succeeds. If I don't click the pop up, connect() fails. In our application we don't want any user interaction to receive or click a pop up (or install a remote bluetooth device). That's why BluetoothAuthenticateDeviceEx() is used with a callback to handle any request programmatically. As the description to BluetoothAuthenticateDeviceEx() indicates on MS web, the ERROR_INVALID_PARAMETER means a problem with btdi. However, I don't see a problem with btdi. I even printed out btdi.Address.ullLong value before and after BluetoothAuthenticateDeviceEx() and it has correct address of the remote device. Please let me know why BluetoothAuthenticateDeviceEx() fails in code below.

// Authentication callback
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
DWORD dwRet;

fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);
BLUETOOTH_AUTHENTICATE_RESPONSE AuthRes;
AuthRes.authMethod = pAuthCallbackParams->authenticationMethod;
fprintf(stderr, "Authmethod %d\n", AuthRes.authMethod);
// Check to make sure we are using numeric comparison (Just Works)
if (AuthRes.authMethod == BLUETOOTH_AUTHENTICATION_METHOD_NUMERIC_COMPARISON)
{
fprintf(stderr, "Numeric Comparison supported\n");
}
AuthRes.bthAddressRemote = pAuthCallbackParams->deviceInfo.Address;
AuthRes.negativeResponse = FALSE;

// Commented out code is used for pairing using the BLUETOOTH_AUTHENTICATION_METHOD_PASSKEY method
//memcpy_s(AuthRes.pinInfo.pin, sizeof(AuthRes.pinInfo.pin), L"1234", 0);
//AuthRes.pinInfo.pinLength = 0;
// Respond with numerical value for Just Works pairing
AuthRes.numericCompInfo.NumericValue = 1;

// Send authentication response to authenticate device
dwRet = BluetoothSendAuthenticationResponseEx(NULL, &AuthRes);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothSendAuthenticationResponseEx ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Bluetooth device denied passkey response or communicatino problem.\n");
}
else if (dwRet == E_FAIL)
{
fprintf(stderr, "Device returned a failure code during authentication.\n");
}
else if (dwRet == 1244)
{
fprintf(stderr, "Not authenticated\n");
}
}
else
{
fprintf(stderr, "BluetoothAuthCallback finish\n");
}

callbacklock = 0;

return 1; // This value is ignored
}





bool Bluetooth_Connect()
{
ULONG ulRetCode;
WSADATA WSAData = {0};
SOCKADDR_BTH RemoteBthAddr = {0};

INT iResult = BT_SUCCESS;
BOOL bContinueLookup = FALSE, bRemoteDeviceFound = FALSE;
ULONG ulFlags = 0, ulPQSSize = sizeof(WSAQUERYSET);
HANDLE hLookup = NULL;
PWSAQUERYSET pWSAQuerySet = NULL;


// Initialize WinSock.
ulRetCode = WSAStartup(MAKEWORD(2, 2), &WSAData);

pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
ulPQSSize);

if ( NULL == pWSAQuerySet ) {
iResult = STATUS_NO_MEMORY;
wprintf(L"!ERROR! | Unable to allocate memory for WSAQUERYSET\n");
return false;
}

//
// Search for the device with the correct name
//
if ( iResult == BT_SUCCESS )
{

for ( INT iRetryCount = 0; !bRemoteDeviceFound && (iRetryCount < BT_MAX_INQUIRY_RETRY);iRetryCount++ )
{
//
// WSALookupService is used for both service search and device inquiry
// LUP_CONTAINERS is the flag which signals that we're doing a device inquiry.
//
ulFlags = LUP_CONTAINERS;

//
// Friendly device name (if available) will be returned in lpszServiceInstanceName
//
ulFlags |= LUP_RETURN_NAME;

//
// BTH_ADDR will be returned in lpcsaBuffer member of WSAQUERYSET
//
ulFlags |= LUP_RETURN_ADDR;

if ( 0 == iRetryCount )
{
// wprintf(L"*INFO* | Inquiring device from cache...\n");
wprintf(L"*INFO* | Searching for device with Bluetooth...\n");
}
else
{
//
// Flush the device cache for all inquiries, except for the first inquiry
//
// By setting LUP_FLUSHCACHE flag, we're asking the lookup service to do
// a fresh lookup instead of pulling the information from device cache.
//
ulFlags |= LUP_FLUSHCACHE;

//
// Pause for some time before all the inquiries after the first inquiry
//
// Remote Name requests will arrive after device inquiry has
// completed. Without a window to receive IN_RANGE notifications,
// we don't have a direct mechanism to determine when remote
// name requests have completed.
//
wprintf(L"*INFO* | Unable to find device. Waiting for %d seconds before re-inquiry...\n", BT_DELAY_NEXT_INQUIRY);
Sleep(BT_DELAY_NEXT_INQUIRY * 1000);

wprintf(L"*INFO* | Inquiring device ...\n");
}

//
// Start the lookup service
//
iResult = BT_SUCCESS;
hLookup = 0;
bContinueLookup = FALSE;
ZeroMemory(pWSAQuerySet, ulPQSSize);
pWSAQuerySet->dwNameSpace = NS_BTH;
pWSAQuerySet->dwSize = sizeof(WSAQUERYSET);
iResult = WSALookupServiceBegin(pWSAQuerySet, ulFlags, &hLookup);

//
// Even if we have an error, we want to continue until we
// reach the CXN_MAX_INQUIRY_RETRY
//
if ( (NO_ERROR == iResult) && (NULL != hLookup) )
{
bContinueLookup = TRUE;
}
else if ( 0 < iRetryCount )
{
wprintf(L"=CRITICAL= | WSALookupServiceBegin() failed with error code %d, WSAGetLastError = %d\n", iResult, WSAGetLastError());
break;
}

while ( bContinueLookup )
{
//
// Get information about next bluetooth device
//
// Note you may pass the same WSAQUERYSET from LookupBegin
// as long as you don't need to modify any of the pointer
// members of the structure, etc.
//
//ZeroMemory(pWSAQuerySet, ulPQSSize);
//pWSAQuerySet->dwNameSpace = NS_BTH;
//pWSAQuerySet->dwSize = sizeof(WSAQUERYSET);
if ( NO_ERROR == WSALookupServiceNext(hLookup,
ulFlags,
&ulPQSSize,
pWSAQuerySet) )
{

//
// Compare the name to see if this is the device we are looking for.
//
if ( ( pWSAQuerySet->lpszServiceInstanceName != NULL ) && ( ( BT_SUCCESS == _strnicmp(pWSAQuerySet->lpszServiceInstanceName, "Test1",5)) || (BT_SUCCESS == _strnicmp(pWSAQuerySet->lpszServiceInstanceName, "Test2",5)) ) )
{
// //
// // Found a remote bluetooth device with matching name.
// // Get the address of the device and exit the lookup.
// //
CopyMemory(&RemoteBthAddr,
(PSOCKADDR_BTH) pWSAQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr,
sizeof(RemoteBthAddr));
bRemoteDeviceFound = TRUE;
bContinueLookup = FALSE;


}
}
else
{
iResult = WSAGetLastError();
if ( WSA_E_NO_MORE == iResult ) { //No more data
//
// No more devices found. Exit the lookup.
//
bContinueLookup = FALSE;
} else if ( WSAEFAULT == iResult ) {
//
// The buffer for QUERYSET was insufficient.
// In such case 3rd parameter "ulPQSSize" of function "WSALookupServiceNext()" receives
// the required size. So we can use this parameter to reallocate memory for QUERYSET.
//
HeapFree(GetProcessHeap(), 0, pWSAQuerySet);
pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
ulPQSSize);
if ( NULL == pWSAQuerySet ) {
wprintf(L"!ERROR! | Unable to allocate memory for WSAQERYSET\n");
iResult = STATUS_NO_MEMORY;
bContinueLookup = FALSE;
}
} else {
wprintf(L"=CRITICAL= | WSALookupServiceNext() failed with error code %d\n", iResult);
bContinueLookup = FALSE;
}
}
}

//
// End the lookup service
//
WSALookupServiceEnd(hLookup);

if ( STATUS_NO_MEMORY == iResult ) {
break;
}
}
}

if ( NULL != pWSAQuerySet ) {
HeapFree(GetProcessHeap(), 0, pWSAQuerySet);
pWSAQuerySet = NULL;
}

if ( !bRemoteDeviceFound ) {
iResult = BT_ERROR;
WSACleanup();
return false;
}


RemoteBthAddr.addressFamily = AF_BTH;
RemoteBthAddr.serviceClassId = RFCOMM_PROTOCOL_UUID;
//RemoteBthAddr.serviceClassId = SerialPortServiceClass_UUID;
//RemoteBthAddr.port = BT_PORT_ANY;
RemoteBthAddr.port = 0;


HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;
DWORD dwRet;

// setup device info
btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
btdi.Address.ullLong = RemoteBthAddr.btAddr;
btdi.ulClassofDevice = 0;
btdi.fConnected = FALSE;
btdi.fRemembered = FALSE;
btdi.fAuthenticated = FALSE;

fprintf(stderr, "\nAddress print1: %llx\n", btdi.Address.ullLong);

// register authentication callback. this prevents UI from showing up.
dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
ExitProcess(2);
}
fprintf(stderr, "\nAddress print2: %llx\n", btdi.Address.ullLong);

// authenticate device (will call authentication callback)
AUTHENTICATION_REQUIREMENTS authreqs = MITMProtectionNotRequired;
fprintf(stderr, "BluetoothAuthReqs = %d\n", authreqs);

callbacklock = 1;

dwRet = BluetoothAuthenticateDeviceEx(NULL, NULL, &btdi, NULL, authreqs);

fprintf(stderr, "\nAddress print3: %llx\n", btdi.Address.ullLong);

if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Cancelled");
}
else if (dwRet == ERROR_INVALID_PARAMETER)
{
fprintf(stderr, "Invalid Parameter");
}
else if (dwRet == ERROR_NO_MORE_ITEMS)
{
fprintf(stderr, "Already paired!");
}
}

fprintf(stderr, "Pairing finished\n");

while (callbacklock);
//
// Open a bluetooth socket using RFCOMM protocol
//
BtSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if ( INVALID_SOCKET == BtSocket ) {
wprintf(L"=CRITICAL= | socket() call failed. WSAGetLastError = [%d]\n", WSAGetLastError());
ulRetCode = ERROR;
WSACleanup();
return false;
}

// Set timeout on socket
int iOptVal = 25;
int iOptLen = sizeof (int);
iOptVal = 8192;
setsockopt(BtSocket,SOL_SOCKET,SO_RCVBUF,(char *) &iOptVal,iOptLen);
// getsockopt(BtSocket,SOL_SOCKET,SO_RCVBUF,(char *) &iOptVal,&iOptLen);
iOptVal = 10;
setsockopt(BtSocket,SOL_SOCKET,SO_RCVTIMEO,(char *) &iOptVal,iOptLen);
// setsockopt(BtSocket,SOL_SOCKET,SO_SNDTIMEO,(char *) &iOptVal,iOptLen);

//ULONG bAuthenticate = FALSE;
//setsockopt(BtSocket,SOL_SOCKET,SO_BTH_AUTHENTICATE,(char *) &bAuthenticate,sizeof(ULONG));

//
// Connect the socket (pSocket) to a given remote socket represented by address (pServerAddr)
//
if ( SOCKET_ERROR == connect(BtSocket,
(struct sockaddr *) &RemoteBthAddr,
sizeof(SOCKADDR_BTH)) ) {
wprintf(L"=CRITICAL= | connect() call failed. WSAGetLastError=[%d]\n", WSAGetLastError());
ulRetCode = ERROR;
WSACleanup();
return false;
}

Sleep(100);
char rcv_buf[16];
int x,n;

// flush the buffer
x=0;
while (x != -1)
{
x = recv(BtSocket,
(char *)rcv_buf,
(int)sizeof(rcv_buf),
0);
}

return true;
}

Continue reading...
 
Back
Top