Refactoring random SetupPinCode generation into a method. (#36009)
* Creating a Function to generate random Setup Pin codes and making sure that the generated pin code is valid
* Using generateRandomSetupPin function to generate random setup pin codes
* Integrating comments
* Handling return value of generateRandomSetupPin invocation
Co-authored-by: Andrei Litvin <andy314@gmail.com>
* Integrating comments
---------
Co-authored-by: Andrei Litvin <andy314@gmail.com>
diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp
index 6178348..345b307 100644
--- a/src/protocols/secure_channel/PASESession.cpp
+++ b/src/protocols/secure_channel/PASESession.cpp
@@ -139,10 +139,7 @@
if (useRandomPIN)
{
- ReturnErrorOnFailure(DRBG_get_bytes(reinterpret_cast<uint8_t *>(&setupPINCode), sizeof(setupPINCode)));
-
- // Passcodes shall be restricted to the values 00000001 to 99999998 in decimal, see 5.1.1.6
- setupPINCode = (setupPINCode % kSetupPINCodeMaximumValue) + 1;
+ ReturnErrorOnFailure(SetupPayload::generateRandomSetupPin(setupPINCode));
}
return verifier.Generate(pbkdf2IterCount, salt, setupPINCode);
diff --git a/src/setup_payload/SetupPayload.cpp b/src/setup_payload/SetupPayload.cpp
index 9683da2..915f20c 100644
--- a/src/setup_payload/SetupPayload.cpp
+++ b/src/setup_payload/SetupPayload.cpp
@@ -23,6 +23,7 @@
#include "SetupPayload.h"
+#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPVendorIdentifiers.hpp>
#include <lib/core/TLV.h>
@@ -207,6 +208,34 @@
return CHIP_NO_ERROR;
}
+CHIP_ERROR SetupPayload::generateRandomSetupPin(uint32_t & setupPINCode)
+{
+ uint8_t retries = 0;
+ const uint8_t maxRetries = 10;
+
+ do
+ {
+ ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&setupPINCode), sizeof(setupPINCode)));
+
+ // Passcodes shall be restricted to the values 00000001 to 99999998 in decimal, see 5.1.1.6
+ // TODO: Consider revising this method to ensure uniform distribution of setup PIN codes
+ setupPINCode = (setupPINCode % kSetupPINCodeMaximumValue) + 1;
+
+ // Make sure that the Generated Setup Pin code is not one of the invalid passcodes/pin codes defined in the
+ // specification.
+ if (IsValidSetupPIN(setupPINCode))
+ {
+ return CHIP_NO_ERROR;
+ }
+
+ retries++;
+ // We got pretty unlucky with the random number generator, Just try again.
+ // This shouldn't take many retries assuming DRBG_get_bytes is not broken.
+ } while (retries < maxRetries);
+
+ return CHIP_ERROR_INTERNAL;
+}
+
CHIP_ERROR SetupPayload::addOptionalVendorData(const OptionalQRCodeInfo & info)
{
VerifyOrReturnError(IsVendorTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT);
diff --git a/src/setup_payload/SetupPayload.h b/src/setup_payload/SetupPayload.h
index 3d5d101..829af12 100644
--- a/src/setup_payload/SetupPayload.h
+++ b/src/setup_payload/SetupPayload.h
@@ -259,6 +259,17 @@
**/
static bool IsVendorTag(uint8_t tag) { return !IsCommonTag(tag); }
+ /** @brief Generate a Random Setup Pin Code (Passcode)
+ *
+ * This function generates a random passcode within the defined limits (00000001 to 99999998)
+ * It also checks that the generated passcode is not equal to any invalid passcode values as defined in 5.1.7.1.
+ *
+ * @param[out] setupPINCode The generated random setup PIN code.
+ * @return Returns a CHIP_ERROR_INTERNAL if unable to generate a valid passcode within a reasonable number of attempts,
+ * CHIP_NO_ERROR otherwise
+ **/
+ static CHIP_ERROR generateRandomSetupPin(uint32_t & setupPINCode);
+
private:
std::map<uint8_t, OptionalQRCodeInfo> optionalVendorData;
std::map<uint8_t, OptionalQRCodeInfoExtension> optionalExtensionData;