Skip to content

Commit def8ca5

Browse files
committed
L-Band: Detect certificate corruption and remove as needed
Related to issue #459
1 parent 8d8f214 commit def8ca5

File tree

2 files changed

+160
-27
lines changed

2 files changed

+160
-27
lines changed

Firmware/RTK_Surveyor/States.ino

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ void updateSystemState()
278278
}
279279

280280
// Check for <1m horz accuracy before starting surveyIn
281-
systemPrintf("Waiting for Horz Accuracy < %0.2f meters: %0.2f, SIV: %d\r\n", settings.surveyInStartingAccuracy,
282-
horizontalAccuracy, numSV);
281+
systemPrintf("Waiting for Horz Accuracy < %0.2f meters: %0.2f, SIV: %d\r\n",
282+
settings.surveyInStartingAccuracy, horizontalAccuracy, numSV);
283283

284284
if (horizontalAccuracy > 0.0 && horizontalAccuracy < settings.surveyInStartingAccuracy)
285285
{
@@ -483,7 +483,7 @@ void updateSystemState()
483483
{
484484
marksFileExists = SD_MMC.exists(fileName);
485485
}
486-
#endif // COMPILE_SD_MMC
486+
#endif // COMPILE_SD_MMC
487487

488488
// Open the marks file
489489
FileSdFatMMC marksFile;
@@ -678,8 +678,8 @@ void updateSystemState()
678678
websocket->textAll(settingsCSV);
679679
}
680680
}
681-
#endif // COMPILE_AP
682-
#endif // COMPILE_WIFI
681+
#endif // COMPILE_AP
682+
#endif // COMPILE_WIFI
683683
}
684684
break;
685685

@@ -818,8 +818,23 @@ void updateSystemState()
818818
break;
819819

820820
case (STATE_KEYS_WIFI_CONNECTED): {
821-
if (pointperfectUpdateKeys() == true) // Connect to ThingStream MQTT and get PointPerfect key UBX packet
822-
displayKeysUpdated();
821+
822+
// Check that the certs are valid
823+
if (checkCertificates() == true)
824+
{
825+
// Update the keys
826+
if (pointperfectUpdateKeys() == true) // Connect to ThingStream MQTT and get PointPerfect key UBX packet
827+
displayKeysUpdated();
828+
}
829+
else
830+
{
831+
// Erase keys
832+
erasePointperfectCredentials();
833+
834+
// Provision device
835+
if(pointperfectProvisionDevice() == true) // Connect to ThingStream API and get keys
836+
displayKeysUpdated();
837+
}
823838

824839
// WiFi will be turned off once we exit this state, if no other service needs it
825840

@@ -941,9 +956,9 @@ void updateSystemState()
941956
espnowBeginPairing();
942957

943958
changeState(STATE_ESPNOW_PAIRING);
944-
#else // COMPILE_ESPNOW
959+
#else // COMPILE_ESPNOW
945960
changeState(STATE_ROVER_NOT_STARTED);
946-
#endif // COMPILE_ESPNOW
961+
#endif // COMPILE_ESPNOW
947962
}
948963
break;
949964

@@ -1029,7 +1044,7 @@ void updateSystemState()
10291044
// The code should only be able to enter this state if configureViaEthernet is true.
10301045
// If configureViaEthernet is not true, we need to restart again.
10311046
//(If we continue, startEthernerWebServerESP32W5500 will fail as it won't have exclusive access to SPI and
1032-
//ints).
1047+
// ints).
10331048
if (!configureViaEthernet)
10341049
{
10351050
displayConfigViaEthNotStarted(1500);
@@ -1098,8 +1113,8 @@ void updateSystemState()
10981113
websocket->textAll(settingsCSV);
10991114
}
11001115
}
1101-
#endif // COMPILE_AP
1102-
#endif // COMPILE_WIFI
1116+
#endif // COMPILE_AP
1117+
#endif // COMPILE_WIFI
11031118
}
11041119
break;
11051120

@@ -1115,7 +1130,7 @@ void updateSystemState()
11151130
ESP.restart();
11161131
}
11171132
break;
1118-
#endif // COMPILE_ETHERNET
1133+
#endif // COMPILE_ETHERNET
11191134

11201135
case (STATE_SHUTDOWN): {
11211136
forceDisplayUpdate = true;

Firmware/RTK_Surveyor/menuPP.ino

Lines changed: 132 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#ifdef COMPILE_L_BAND
22

3+
#include "mbedtls/ssl.h" //Needed for certificate validation
4+
35
//----------------------------------------
46
// Locals - compiled out
57
//----------------------------------------
@@ -12,7 +14,7 @@ static SFE_UBLOX_GNSS_SUPER i2cLBand; // NEO-D9S
1214
#ifndef POINTPERFECT_TOKEN
1315
#define POINTPERFECT_TOKEN \
1416
0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22, 0x33, 0x0A, 0x0B, 0x0C, 0x0D, 0x00, 0x01, 0x02, 0x03
15-
#endif // POINTPERFECT_TOKEN
17+
#endif // POINTPERFECT_TOKEN
1618

1719
static uint8_t pointPerfectTokenArray[16] = {POINTPERFECT_TOKEN}; // Token in HEX form
1820

@@ -196,7 +198,7 @@ bool pointperfectProvisionDevice()
196198
// Override ID with testing ID
197199
snprintf(hardwareID, sizeof(hardwareID), "%02X%02X%02X%02X%02X%02X", whitelistID[0], whitelistID[1],
198200
whitelistID[2], whitelistID[3], whitelistID[4], whitelistID[5]);
199-
#endif // WHITELISTED_ID
201+
#endif // WHITELISTED_ID
200202

201203
char givenName[100];
202204
snprintf(givenName, sizeof(givenName), "SparkFun RTK %s v%d.%d - %s", platformPrefix, FIRMWARE_VERSION_MAJOR,
@@ -317,9 +319,94 @@ bool pointperfectProvisionDevice()
317319
bluetoothStart();
318320

319321
return (retVal);
320-
#else // COMPILE_WIFI
322+
#else // COMPILE_WIFI
321323
return (false);
322-
#endif // COMPILE_WIFI
324+
#endif // COMPILE_WIFI
325+
}
326+
327+
// Check certificate and privatekey for valid formatting
328+
// Return false if improperly formatted
329+
bool checkCertificates()
330+
{
331+
bool validCertificates = true;
332+
char *certificateContents = nullptr; // Holds the contents of the keys prior to MQTT connection
333+
char *keyContents = nullptr;
334+
335+
// Allocate the buffers
336+
certificateContents = (char *)malloc(MQTT_CERT_SIZE);
337+
keyContents = (char *)malloc(MQTT_CERT_SIZE);
338+
if ((!certificateContents) || (!keyContents))
339+
{
340+
systemPrintln("Failed to allocate content buffers!");
341+
return (false);
342+
}
343+
344+
// Load the certificate
345+
memset(certificateContents, 0, MQTT_CERT_SIZE);
346+
loadFile("certificate", certificateContents);
347+
348+
if (checkCertificateValidity(certificateContents, strlen(certificateContents)) == false)
349+
{
350+
log_d("Certificate is corrupt.");
351+
validCertificates = false;
352+
}
353+
354+
// Load the private key
355+
memset(keyContents, 0, MQTT_CERT_SIZE);
356+
loadFile("privateKey", keyContents);
357+
358+
if (checkCertificateValidity(keyContents, strlen(keyContents)) == false)
359+
{
360+
log_d("PrivateKey is corrupt.");
361+
validCertificates = false;
362+
}
363+
364+
// Free the content buffers
365+
if (certificateContents)
366+
free(certificateContents);
367+
if (keyContents)
368+
free(keyContents);
369+
370+
return (validCertificates);
371+
}
372+
373+
// Check if a given certificate is in a valid format
374+
// This was created to detect corrupt or invalid certificates caused by bugs in v3.0 to and including v3.3.
375+
bool checkCertificateValidity(char *certificateContent, int certificateContentSize)
376+
{
377+
// Check for valid format of certificate
378+
// From ssl_client.cpp
379+
// https://stackoverflow.com/questions/70670070/mbedtls-cannot-parse-valid-x509-certificate
380+
mbedtls_x509_crt certificate;
381+
mbedtls_x509_crt_init(&certificate);
382+
383+
int result_code =
384+
mbedtls_x509_crt_parse(&certificate, (unsigned char *)certificateContent, certificateContentSize + 1);
385+
386+
mbedtls_x509_crt_free(&certificate);
387+
388+
if (result_code < 0)
389+
{
390+
log_d("Cert formatting invalid");
391+
return (false);
392+
}
393+
394+
return (true);
395+
}
396+
397+
// When called, removes the files used for SSL to PointPerfect obtained during provisioning
398+
// Also deletes keys so the user can immediately re-provision
399+
void erasePointperfectCredentials()
400+
{
401+
char fileName[80];
402+
403+
snprintf(fileName, sizeof(fileName), "/%s_%s_%d.txt", platformFilePrefix, "certificate", profileNumber);
404+
LittleFS.remove(fileName);
405+
406+
snprintf(fileName, sizeof(fileName), "/%s_%s_%d.txt", platformFilePrefix, "privateKey", profileNumber);
407+
LittleFS.remove(fileName);
408+
strcpy(settings.pointPerfectCurrentKey, ""); // Clear contents
409+
strcpy(settings.pointPerfectNextKey, ""); // Clear contents
323410
}
324411

325412
// Subscribe to MQTT channel, grab keys, then stop
@@ -445,9 +532,9 @@ bool pointperfectUpdateKeys()
445532

446533
// Return the key status
447534
return (gotKeys);
448-
#else // COMPILE_WIFI
535+
#else // COMPILE_WIFI
449536
return (false);
450-
#endif // COMPILE_WIFI
537+
#endif // COMPILE_WIFI
451538
}
452539

453540
char *ltrim(char *s)
@@ -565,6 +652,13 @@ int daysFromEpoch(long long endEpoch)
565652
{
566653
endEpoch /= 1000; // Convert PointPerfect ms Epoch to s
567654

655+
if (online.rtc == false)
656+
{
657+
// If we don't have RTC we can't calculate days to expire
658+
log_d("No RTC available");
659+
return (0);
660+
}
661+
568662
long localEpoch = rtc.getEpoch();
569663

570664
long delta = endEpoch - localEpoch; // number of s between dates
@@ -954,13 +1048,22 @@ void menuPointPerfect()
9541048
systemPrint("Days until keys expire: ");
9551049
if (strlen(settings.pointPerfectCurrentKey) > 0)
9561050
{
957-
int daysRemaining =
958-
daysFromEpoch(settings.pointPerfectNextKeyStart + settings.pointPerfectNextKeyDuration + 1);
959-
960-
if (daysRemaining < 0)
961-
systemPrintln("Expired");
1051+
if (online.rtc == false)
1052+
{
1053+
// If we don't have RTC we can't calculate days to expire
1054+
systemPrintln("No RTC");
1055+
}
9621056
else
963-
systemPrintln(daysRemaining);
1057+
{
1058+
1059+
int daysRemaining =
1060+
daysFromEpoch(settings.pointPerfectNextKeyStart + settings.pointPerfectNextKeyDuration + 1);
1061+
1062+
if (daysRemaining < 0)
1063+
systemPrintln("Expired");
1064+
else
1065+
systemPrintln(daysRemaining);
1066+
}
9641067
}
9651068
else
9661069
systemPrintln("No keys");
@@ -1021,8 +1124,23 @@ void menuPointPerfect()
10211124
{
10221125
pointperfectProvisionDevice(); // Connect to ThingStream API and get keys
10231126
}
1024-
else
1025-
pointperfectUpdateKeys();
1127+
else // We have certs and keys
1128+
{
1129+
// Check that the certs are valid
1130+
if (checkCertificates() == true)
1131+
{
1132+
// Update the keys
1133+
pointperfectUpdateKeys();
1134+
}
1135+
else
1136+
{
1137+
// Erase keys
1138+
erasePointperfectCredentials();
1139+
1140+
// Provision device
1141+
pointperfectProvisionDevice(); // Connect to ThingStream API and get keys
1142+
}
1143+
}
10261144
}
10271145
else
10281146
{

0 commit comments

Comments
 (0)