@@ -25,9 +25,10 @@ License: Public domain
25
25
26
26
#include < string.h>
27
27
#include " hardwaretypes.h"
28
- #include " ../main/RFXNames.h"
29
28
#include " ../main/RFXtrx.h"
30
29
30
+ #include < openssl/sha.h>
31
+
31
32
#define OPENWEBNET_HEARTBEAT_DELAY 1
32
33
#define OPENWEBNET_STATUS_NB_HEARTBEAT 600
33
34
#define OPENWEBNET_RETRY_DELAY 30
@@ -176,6 +177,30 @@ bool COpenWebNetTCP::isStatusSocketConnected()
176
177
};
177
178
178
179
180
+ /* *
181
+ write ...
182
+ **/
183
+ bool COpenWebNetTCP::ownWrite (csocket *connectionSocket, const char * pdata, size_t size)
184
+ {
185
+ int bytesWritten = connectionSocket->write (pdata, size);
186
+ if (bytesWritten != size)
187
+ {
188
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: partial write: %u/%u" , bytesWritten, size);
189
+ return (false );
190
+ }
191
+ return (true );
192
+ }
193
+
194
+ /* *
195
+ read ...
196
+ **/
197
+ int COpenWebNetTCP::ownRead (csocket *connectionSocket, char * pdata, size_t size)
198
+ {
199
+ memset (pdata, 0 , size);
200
+ int read = connectionSocket->read (pdata, size, false );
201
+ return (read);
202
+ }
203
+
179
204
/* *
180
205
Calculate 'nonce-hash' authentication
181
206
**/
@@ -289,52 +314,231 @@ uint32_t COpenWebNetTCP::ownCalcPass(const std::string &password, const std::str
289
314
return (num1 & m_1);
290
315
}
291
316
317
+ /* *
318
+ Perform conversion 80/128 DEC-chars to 40/64 HEX-chars
319
+ **/
320
+ const std::string COpenWebNetTCP::decToHexStrConvert (std::string paramString)
321
+ {
322
+ char retStr[256 ];
323
+ size_t idxb, idxh;
324
+ for (idxb = 0 , idxh = 0 ; idxb < paramString.length (); idxb += 2 , idxh++)
325
+ {
326
+ std::string str = paramString.substr (idxb, 2 );
327
+ sprintf (&retStr[idxh], " %x" , atoi (str.c_str ()));
328
+ }
329
+ return std::string (retStr);
330
+ }
331
+
332
+ /* *
333
+ Perform conversion HEX-40/64 chars to 80/128 DEC-chars
334
+ **/
335
+ const std::string COpenWebNetTCP::hexToDecStrConvert (std::string paramString)
336
+ {
337
+ uint32_t bval;
338
+ size_t idxb, idxh;
339
+ char retStr[256 ];
340
+ for (idxb = 0 , idxh = 0 ; idxb < paramString.length (); idxb++, idxh += 2 )
341
+ {
342
+ std::stringstream s_strid;
343
+ s_strid << std::hex << paramString.substr (idxb, 1 );
344
+ s_strid >> bval;
345
+ sprintf (&retStr[idxh], " %02u" , bval & 0xf );
346
+ }
347
+
348
+ return std::string (retStr);
349
+ }
350
+
351
+ /* *
352
+ Perform conversion byte to HEX-chars
353
+ **/
354
+ const std::string COpenWebNetTCP::byteToHexStrConvert (uint8_t *digest, size_t digestLen, char *pArray)
355
+ {
356
+ size_t idxb, idxh;
357
+ char arrayOfChar1[] = " 0123456789abcdef" ;
358
+ for (idxb = 0 , idxh = 0 ; idxb < digestLen; idxb++, idxh += 2 )
359
+ {
360
+ uint8_t bval = digest[idxb] & 0xFF ;
361
+ pArray[idxh] = arrayOfChar1[(bval >> 4 ) & 0xf ];
362
+ pArray[idxh + 1 ] = arrayOfChar1[bval & 0xF ];
363
+ }
364
+ pArray[idxh] = 0 ;
365
+ return (std::string (pArray));
366
+ }
367
+
368
+ /* *
369
+ Perform SHA1/SHA256 and convert into HEX-chars
370
+ **/
371
+ const std::string COpenWebNetTCP::shaCalc (std::string paramString, int auth_type)
372
+ {
373
+ uint8_t *digest;
374
+ uint8_t strArray[OPENWEBNET_BUFFER_SIZE];
375
+ memset (strArray, 0 , sizeof (strArray));
376
+ memcpy (strArray, paramString.c_str (), paramString.length ());
377
+
378
+ if (auth_type == 0 )
379
+ {
380
+ // Perform SHA1
381
+ digest = SHA1 (strArray, paramString.length (), 0 );
382
+ char arrayOfChar2[(SHA_DIGEST_LENGTH * 2 ) + 1 ];
383
+ return (byteToHexStrConvert (digest, SHA_DIGEST_LENGTH, arrayOfChar2));
384
+ }
385
+ else
386
+ {
387
+ // Perform SHA256
388
+ digest = SHA256 (strArray, paramString.length (), 0 );
389
+ char arrayOfChar2[(SHA256_DIGEST_LENGTH * 2 ) + 1 ];
390
+ return (byteToHexStrConvert (digest, SHA256_DIGEST_LENGTH, arrayOfChar2));
391
+ }
392
+
393
+ return (std::string (" " ));
394
+ }
395
+
396
+ /* *
397
+ Perform HMAC authentication
398
+ **/
399
+ bool COpenWebNetTCP::hmacAuthentication (csocket *connectionSocket, int auth_type)
400
+ {
401
+ // Write ACK
402
+ ownWrite (connectionSocket, OPENWEBNET_MSG_OPEN_OK, strlen (OPENWEBNET_MSG_OPEN_OK));
403
+
404
+ // Read server Response
405
+ char databuffer[OPENWEBNET_BUFFER_SIZE];
406
+ int read = ownRead (connectionSocket, databuffer, sizeof (databuffer));
407
+ bt_openwebnet responseSrv (std::string (databuffer, read));
408
+ if (responseSrv.IsPwdFrame ())
409
+ {
410
+ struct timeval tv;
411
+ gettimeofday (&tv, NULL );
412
+
413
+ // receive Ra
414
+ const std::string strRcvSrv = responseSrv.Extract_who (); // Ra from server in DEC-chars
415
+ const std::string strRa = decToHexStrConvert (strRcvSrv); // convert Ra in HEX-chars
416
+ std::stringstream strRb_rand;
417
+ strRb_rand << " Time" << tv.tv_sec << tv.tv_usec ; // get random Rb from time..
418
+ const std::string strRb = shaCalc (strRb_rand.str (), auth_type); // sha of Rb and convert into HEX-chars
419
+ const std::string strA = " 736F70653E" ; // is the client identity (HEX-chars)
420
+ const std::string strB = " 636F70653E" ; // is the server identity (HEX-chars)
421
+ const std::string strKab = shaCalc (m_ownPassword, auth_type); // perform SHA of password
422
+ const std::string strHMAC = shaCalc (strRa + strRb + strA + strB + strKab, auth_type); // HMAC
423
+
424
+ #if 0
425
+ // print some logs for debug..
426
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: HMAC Ra digits received: '%s'", strRcvSrv.c_str());
427
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: Ra = '%s'", strRa.c_str());
428
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: Rb = '%s'", strRb.c_str());
429
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: A = '%s', B = '%s'", strA.c_str(), strB.c_str());
430
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: pwd = '%s', Kab = '%s'", m_ownPassword.c_str(), strKab.c_str());
431
+ _log.Log(LOG_STATUS, "COpenWebNetTCP: HMAC(Ra,Rb,A,B,Kab) = '%s'", strHMAC.c_str());
432
+ #endif
433
+ // Write HMAC
434
+ const std::string strSend = " *#" + hexToDecStrConvert (strRb) + " *" + hexToDecStrConvert (strHMAC) + " ##" ;
435
+ ownWrite (connectionSocket, strSend.c_str (), strSend.length ());
436
+
437
+ // Server response....
438
+ read = ownRead (connectionSocket, databuffer, sizeof (databuffer));
439
+ bt_openwebnet responseSrv2 (std::string (databuffer, read));
440
+ if (responseSrv2.IsPwdFrame ())
441
+ {
442
+ const std::string strRcvSrv2 = decToHexStrConvert (responseSrv2.Extract_who ());
443
+ const std::string strHMAC2 = shaCalc (strRa + strRb + strKab, auth_type);
444
+
445
+ if (strHMAC2.compare (strRcvSrv2) == 0 )
446
+ {
447
+ ownWrite (connectionSocket, OPENWEBNET_MSG_OPEN_OK, strlen (OPENWEBNET_MSG_OPEN_OK)); // Write ACK
448
+ return (true ); // HMAC authentication OK
449
+ }
450
+ else
451
+ {
452
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: HMAC(Ra,Rb,Kab) received: '%s'" , strRcvSrv2.c_str ());
453
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: not match with: '%s'" , strHMAC2.c_str ());
454
+ }
455
+ }
456
+ }
457
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: HMAC authentication ERROR!" );
458
+ return false ; // error!
459
+ }
460
+
461
+ /* *
462
+ Perform nonce-hash authentication
463
+ **/
464
+ bool COpenWebNetTCP::nonceHashAuthentication (csocket *connectionSocket, std::string nonce)
465
+ {
466
+ std::stringstream frame;
467
+ /* * calculate nonce-hash **/
468
+ uint32_t ownHash = ownCalcPass (m_ownPassword, nonce);
469
+ /* * write frame with nonce-hash **/
470
+ frame << " *#" ;
471
+ frame << ownHash;
472
+ frame << " ##" ;
473
+ ownWrite (connectionSocket, frame.str ().c_str (), frame.str ().length ());
474
+
475
+ char databuffer[OPENWEBNET_BUFFER_SIZE];
476
+ int read = ownRead (connectionSocket, databuffer, sizeof (databuffer));
477
+ bt_openwebnet responseNonce2 (std::string (databuffer, read));
478
+
479
+ if (responseNonce2.IsOKFrame ()) return true ; // hash authentication OK
480
+
481
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: hash authentication ERROR!" );
482
+ return false ;
483
+ }
484
+
292
485
/* *
293
486
Perform nonce-hash authentication
294
487
**/
295
488
296
- bool COpenWebNetTCP::nonceHashAuthentication (csocket *connectionSocket)
489
+ bool COpenWebNetTCP::ownAuthentication (csocket *connectionSocket)
297
490
{
298
491
char databuffer[OPENWEBNET_BUFFER_SIZE];
299
- memset (databuffer, 0 , OPENWEBNET_BUFFER_SIZE);
300
- int read = connectionSocket->read (databuffer, OPENWEBNET_BUFFER_SIZE, false );
492
+ int read = ownRead (connectionSocket, databuffer, sizeof (databuffer));
301
493
bt_openwebnet responseNonce (std::string (databuffer, read));
494
+
495
+ // _log.Log(LOG_STATUS, "COpenWebNetTCP: authentication rcv: '%s'", responseNonce.Extract_frame().c_str());
496
+
302
497
if (responseNonce.IsPwdFrame ())
303
498
{
304
- std::stringstream frame;
305
- uint32_t ownHash;
499
+ if (!m_ownPassword.length ())
500
+ {
501
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: no password set for a unofficial bticino gateway" );
502
+ return false ;
503
+ }
306
504
505
+ // Hash authentication for unofficial gateway
506
+ return (nonceHashAuthentication (connectionSocket, responseNonce.Extract_who ()));
507
+ }
508
+ else if (responseNonce.IsNormalFrame ())
509
+ {
307
510
if (!m_ownPassword.length ())
308
511
{
309
- _log.Log (LOG_STATUS , " COpenWebNetTCP: no password set for a unofficial bticino gateway " );
512
+ _log.Log (LOG_ERROR , " COpenWebNetTCP: bticino gateway requires the password " );
310
513
return false ;
311
514
}
312
515
313
- /* * calculate nonce-hash **/
314
- ownHash = ownCalcPass (m_ownPassword, responseNonce.Extract_who ());
315
- /* * write frame with nonce-hash **/
316
- frame << " *#" ;
317
- frame << ownHash;
318
- frame << " ##" ;
516
+ // TODO: only alphanumeric password....
319
517
320
- int bytesWritten = connectionSocket->write (frame.str ().c_str (), frame.str ().length ());
321
- if (bytesWritten != frame.str ().length ()) {
322
- _log.Log (LOG_ERROR, " COpenWebNetTCP: partial write" );
518
+ const std::string strFrame = responseNonce.Extract_frame ();
519
+ if (strFrame.compare (OPENWEBNET_AUTH_REQ_SHA1) == 0 ) // *98*1##
520
+ {
521
+ // HMAC authentication with SHA-1
522
+ return (hmacAuthentication (connectionSocket, 0 ));
523
+ }
524
+ else if (strFrame.compare (OPENWEBNET_AUTH_REQ_SHA2) == 0 ) // *98*2##
525
+ {
526
+ // HMAC authentication with SHA-256
527
+ return (hmacAuthentication (connectionSocket, 1 ));
528
+ }
529
+ else
530
+ {
531
+ _log.Log (LOG_ERROR, " COpenWebNetTCP: frame request error:'%s'" , strFrame);
532
+ return false ;
323
533
}
324
-
325
- /* * Open password for test **/
326
- memset (databuffer, 0 , OPENWEBNET_BUFFER_SIZE);
327
- read = connectionSocket->read (databuffer, OPENWEBNET_BUFFER_SIZE, false );
328
- bt_openwebnet responseNonce2 (std::string (databuffer, read));
329
- if (responseNonce2.IsOKFrame ()) return true ;
330
- _log.Log (LOG_ERROR, " COpenWebNetTCP: authentication ERROR!" );
331
- return false ;
332
534
}
333
535
else if (responseNonce.IsOKFrame ())
334
536
{
537
+ // no authentication required..ok!
538
+ // _log.Log(LOG_STATUS, "COpenWebNetTCP: authentication OK, no password!");
335
539
return true ;
336
540
}
337
- _log.Log (LOG_STATUS , " COpenWebNetTCP: ERROR_FRAME? %d" , responseNonce.frame_type );
541
+ _log.Log (LOG_ERROR , " COpenWebNetTCP: ERROR_FRAME? %d" , responseNonce.frame_type );
338
542
return false ;
339
543
}
340
544
@@ -361,22 +565,18 @@ csocket* COpenWebNetTCP::connectGwOwn(const char *connectionMode)
361
565
}
362
566
363
567
char databuffer[OPENWEBNET_BUFFER_SIZE];
364
- memset (databuffer, 0 , OPENWEBNET_BUFFER_SIZE);
365
- int read = connectionSocket->read (databuffer, OPENWEBNET_BUFFER_SIZE, false );
568
+ int read = ownRead (connectionSocket, databuffer, OPENWEBNET_BUFFER_SIZE);
366
569
bt_openwebnet responseSession (std::string (databuffer, read));
367
570
if (!responseSession.IsOKFrame ())
368
571
{
369
- _log.Log (LOG_STATUS , " COpenWebNetTCP: failed to begin session, NACK received (%s:%d)-> %s " , m_szIPAddress.c_str (), m_usIPPort, databuffer);
572
+ _log.Log (LOG_ERROR , " COpenWebNetTCP: failed to begin session, (%s:%d)-> '%s' " , m_szIPAddress.c_str (), m_usIPPort, databuffer);
370
573
disconnect (); // disconnet socket if present
371
574
return NULL ;
372
575
}
373
576
374
- int bytesWritten = connectionSocket->write (connectionMode, strlen (connectionMode));
375
- if (bytesWritten != strlen (connectionMode)) {
376
- _log.Log (LOG_ERROR, " COpenWebNetTCP: partial write" );
377
- }
577
+ ownWrite (connectionSocket, connectionMode, strlen (connectionMode));
378
578
379
- if (!nonceHashAuthentication (connectionSocket)) return NULL ;
579
+ if (!ownAuthentication (connectionSocket)) return NULL ;
380
580
381
581
return connectionSocket;
382
582
}
@@ -415,8 +615,7 @@ void COpenWebNetTCP::MonitorFrames()
415
615
if (bIsDataReadable)
416
616
{
417
617
char data[OPENWEBNET_BUFFER_SIZE];
418
- memset (data, 0 , OPENWEBNET_BUFFER_SIZE);
419
- int bread = m_pStatusSocket->read (data, OPENWEBNET_BUFFER_SIZE, false );
618
+ int bread = ownRead (m_pStatusSocket, data, OPENWEBNET_BUFFER_SIZE);
420
619
421
620
if (IsStopRequested (0 ))
422
621
break ;
@@ -1375,20 +1574,13 @@ bool COpenWebNetTCP::sendCommand(bt_openwebnet& command, std::vector<bt_openwebn
1375
1574
_log.Log (LOG_STATUS, " COpenWebNetTCP: Command session connected to: %s:%d" , m_szIPAddress.c_str (), m_usIPPort);
1376
1575
1377
1576
// Command session correctly open -> write command
1378
- int bytesWritten = commandSocket->write (command.frame_open .c_str (), command.frame_open .length ());
1379
- if (bytesWritten != command.frame_open .length ()) {
1380
- if (!silent) {
1381
- _log.Log (LOG_ERROR, " COpenWebNetTCP sendCommand: partial write" );
1382
- }
1383
- }
1577
+ ownWrite (commandSocket, command.frame_open .c_str (), command.frame_open .length ());
1384
1578
1385
1579
if (waitForResponse > 0 ) {
1386
1580
sleep_seconds (waitForResponse);
1387
1581
1388
1582
char responseBuffer[OPENWEBNET_BUFFER_SIZE];
1389
- memset (responseBuffer, 0 , OPENWEBNET_BUFFER_SIZE);
1390
- int read = commandSocket->read (responseBuffer, OPENWEBNET_BUFFER_SIZE, false );
1391
-
1583
+ int read = ownRead (commandSocket, responseBuffer, OPENWEBNET_BUFFER_SIZE);
1392
1584
if (!silent) {
1393
1585
_log.Log (LOG_STATUS, " COpenWebNetTCP: sent=%s received=%s" , command.frame_open .c_str (), responseBuffer);
1394
1586
}
0 commit comments