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
1719static 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
453540char *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