Update the random PIN generator module to provide high entropy.
authorChul Lee <chuls.lee@samsung.com>
Thu, 8 Sep 2016 13:26:01 +0000 (22:26 +0900)
committerRandeep Singh <randeep.s@samsung.com>
Sat, 29 Oct 2016 00:57:54 +0000 (00:57 +0000)
After this patch,
Server developer can choose the policy of random PIN generation
through SetRandomPinPolicy API.

Updated Random PIN module provides flexibility
in the PIN length and PIN type as following :
  PIN length : 4 bytes ~ 32 bytes
  PIN Type : Bitmask :
             NUM_PIN            = (0x1 << 0),    //Numeric PIN
             UPPERCASE_CHAR_PIN = (0x1 << 1),    //uppercase character PIN
             LOWERCASE_CHAR_PIN = (0x1 << 2)     //lowercase character PIN

Here is example for SetRandomPinPolicy API :

    //Now, Server will generate the 10 bytes PIN
    //which is nummeric and lowercase mixed PIN.
    if(OC_STACK_OK != SetRandomPinPolicy(10, NUM_PIN | LOWERCASE_CAHR_PIN))
    {
        OIC_LOG(ERROR, TAG, "Failed to setting PIN policy");
        return 0;
    }

Change-Id: I0f6b56a037a85a0d7c8e6d1db85f4a9808989964
Signed-off-by: Chul Lee <chuls.lee@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/11607
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Randeep Singh <randeep.s@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/13825

resource/csdk/octbstack_product_secured.def
resource/csdk/security/include/pinoxmcommon.h
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp
resource/csdk/security/provisioning/sample/subownerclient.c
resource/csdk/security/provisioning/src/multipleownershiptransfermanager.c
resource/csdk/security/provisioning/src/oxmrandompin.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/oxmpincommon.c

index d414235..47f25aa 100644 (file)
@@ -35,3 +35,4 @@ OCUnlinkDevices
 
 SetGeneratePinCB
 SetInputPinCB
+SetRandomPinPolicy
\ No newline at end of file
index 0432c38..3c4cabd 100644 (file)
  extern "C" {
 #endif // __cplusplus
 
-#define OXM_RANDOM_PIN_SIZE (8)
-#define OXM_PRECONFIG_PIN_SIZE (OXM_RANDOM_PIN_SIZE)
+#define OXM_RANDOM_PIN_DEFAULT_SIZE (8)
+#define OXM_RANDOM_PIN_DEFAULT_PIN_TYPE (NUM_PIN | LOWERCASE_CHAR_PIN | UPPERCASE_CHAR_PIN)
+#define OXM_RANDOM_PIN_MIN_SIZE (4)
+#define OXM_RANDOM_PIN_MAX_SIZE (32)
+#define OXM_PRECONFIG_PIN_MAX_SIZE (OXM_RANDOM_PIN_MAX_SIZE)
 
+/** Number of PIN type */
+#define OXM_PIN_TYPE_COUNT 3
+
+/**
+ * PIN type definition.
+ * This type supports multiple bit set.
+ * e.g.) NUM_PIN | UPPERCASE_CHAR_PIN
+ */
+typedef enum OicSecPinType{
+    NUM_PIN            = (0x1 << 0),    //Numeric PIN
+    UPPERCASE_CHAR_PIN = (0x1 << 1),    //uppercase character PIN
+    LOWERCASE_CHAR_PIN = (0x1 << 2)     //lowercase character PIN
+}OicSecPinType_t;
 
 /**
  * Function pointer to print pin code.
@@ -84,7 +100,7 @@ void UnsetGeneratePinCB();
  * @param pinBuffer is the reference to the buffer to store the generated PIN data.
  * @param bufferSize is the size of buffer.
  *
- * @return ::OC_STACK_SUCCESS in case of success or other value in case of error.
+ * @return ::OC_STACK_OK in case of success or other value in case of error.
  */
 OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize);
 
@@ -94,11 +110,10 @@ OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize);
  * @param[in,out] pinBuffer is the reference to the buffer to store the inputed PIN data.
  * @param[in] bufferSize is the size of buffer.
  *
- * @return ::OC_STACK_SUCCESS in case of success or other value in ccase of error.
+ * @return ::OC_STACK_OK in case of success or other value in ccase of error.
  */
 OCStackResult InputPin(char* pinBuffer, size_t bufferSize);
 
-
 #ifdef _ENABLE_MULTIPLE_OWNER_
 /**
  * Function to save the Pre-configured PIN.
@@ -121,6 +136,16 @@ OCStackResult SetPreconfigPin(const char* pinBuffer, size_t pinLength);
 OCStackResult GetPreconfigPin(char* pinBuffer, size_t bufferSize);
 #endif
 
+/**
+ * Function to setting the policy for random PIN generation
+ *
+ * @param[in] pinSize Byte length of random PIN
+ * @param[in] pinType Type of random PIN (ref OicSecPinType)
+ *
+ * @return ::OC_STACK_OK in case of success or other value in case of error.
+ */
+OCStackResult SetRandomPinPolicy(size_t pinSize, OicSecPinType_t pinType);
+
 #ifdef __WITH_DTLS__
 
 /**
index b7c44c4..761d898 100644 (file)
@@ -280,7 +280,7 @@ static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr,
 
 static void inputPinCB(char* pin, size_t len)
 {
-    if(!pin || OXM_RANDOM_PIN_SIZE>=len)
+    if(!pin || OXM_RANDOM_PIN_MIN_SIZE > len)
     {
         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
         return;
@@ -289,7 +289,7 @@ static void inputPinCB(char* pin, size_t len)
     printf("   > INPUT PIN: ");
     for(int ret=0; 1!=ret; )
     {
-        ret = scanf("%8s", pin);
+        ret = scanf("%32s", pin);
         for( ; 0x20<=getchar(); );  // for removing overflow garbages
                                     // '0x20<=code' is character region
     }
index a7a9d8f..8837e38 100644 (file)
@@ -480,6 +480,17 @@ int main()
      */
     SetGeneratePinCB(GeneratePinCB);
 
+    /**
+     * Random PIN generation policy can be changed through SetRandomPinPolicy() API.
+     * first param : byte length of random PIN ( 4 <= first param <= 32)
+     * second param : PIN type (This is bitmask)
+     */
+    if(OC_STACK_OK != SetRandomPinPolicy(8, NUM_PIN))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to setting PIN policy");
+        return 0;
+    }
+
     /*
      * Declare and create the example resource: LED
      */
@@ -499,8 +510,8 @@ int main()
         char in = getchar();
         if('G' == in || 'g' == in)
         {
-            char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0};
-            GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1);
+            char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
+            GeneratePin(ranPin, sizeof(ranPin));
         }
         if('E' == in || 'e' == in)
         {
index 0644bd7..bbc099f 100644 (file)
@@ -201,7 +201,7 @@ static void LedCB(void *ctx, OCDoHandle UNUSED,
 
 static void inputPinCB(char* pin, size_t len)
 {
-    if(!pin || OXM_RANDOM_PIN_SIZE>=len)
+    if(!pin || OXM_RANDOM_PIN_MAX_SIZE>=len)
     {
         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
         return;
@@ -210,7 +210,7 @@ static void inputPinCB(char* pin, size_t len)
     printf("   > INPUT PIN: ");
     for(int ret=0; 1!=ret; )
     {
-        ret = scanf("%8s", pin);
+        ret = scanf("%32s", pin);
         for( ; 0x20<=getchar(); );  // for removing overflow garbages
                                     // '0x20<=code' is character region
     }
@@ -328,7 +328,8 @@ static int multipleOwnershipTransfer(void)
         if(OIC_PRECONFIG_PIN == dev->doxm->oxmSel)
         {
             //Pre-Configured PIN initialization
-            if(OC_STACK_OK != OCAddPreconfigPIN(dev, "12341234", OXM_PRECONFIG_PIN_SIZE))
+            const char* testPreconfPin = "12341234";
+            if(OC_STACK_OK != OCAddPreconfigPIN(dev, testPreconfPin, strlen(testPreconfPin)))
             {
                 printf("\n\n\n*** %60s ***\n", "WARNNING : Failed to save the pre-configured PIN");
                 printf("*** %60s ***\n\n\n", "WARNNING : You can't use the pre-configured PIN OxM for MOT");
index 03e4eec..0537f9d 100644 (file)
@@ -397,7 +397,7 @@ OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *target
     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
-    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_MAX_SIZE >= preconfPINLen), ERROR);
 
     postCredRes = OC_STACK_NO_MEMORY;
     //Generate PIN based credential
@@ -585,7 +585,7 @@ OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
-    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_MAX_SIZE >= preconfPINLen), ERROR);
 
     OicSecCred_t* prevCred = GetCredResourceData(&targetDeviceInfo->doxm->deviceID);
     if(NULL != prevCred)
index 48afcf2..174b5a4 100644 (file)
@@ -78,9 +78,9 @@ OCStackResult InputPinCodeCallback(OTMContext_t *otmCtx)
         return OC_STACK_INVALID_PARAM;
     }
 
-    uint8_t pinData[OXM_RANDOM_PIN_SIZE + 1];
+    uint8_t pinData[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
 
-    OCStackResult res = InputPin((char*)pinData, OXM_RANDOM_PIN_SIZE + 1);
+    OCStackResult res = InputPin((char*)pinData, sizeof(pinData));
     if (OC_STACK_OK != res)
     {
         OIC_LOG(ERROR, TAG, "Failed to input PIN");
index 02a8030..ed475b6 100644 (file)
@@ -1146,11 +1146,11 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                                                     ehRequest->devAddr.adapter);
                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
 
-                        char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
+                        char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
                          //TODO ehRequest->messageID for copa over TCP always is null. Find reason why.
                         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP && previousMsgId != ehRequest->messageID)
                         {
-                            if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
+                            if(OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
                             {
                                 //Set the device id to derive temporal PSK
                                 SetUuidForPinBasedOxm(&gDoxm->deviceID);
@@ -1172,7 +1172,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         }
                         else if(previousMsgId != ehRequest->messageID)
                         {
-                            if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
+                            if(OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
                             {
                                 //Set the device id to derive temporal PSK
                                 SetUuidForPinBasedOxm(&gDoxm->deviceID);
index 450d4bf..dd8369f 100644 (file)
 
 #define TAG "PIN_OXM_COMMON"
 
+#define NUMBER_OF_PINNUM (10)
+#define NUMBER_OF_ALPHABET (26)
+
 static GeneratePinCallback gGenPinCallback = NULL;
 static InputPinCallback gInputPinCallback = NULL;
 
 typedef struct PinOxmData {
-    uint8_t pinData[OXM_RANDOM_PIN_SIZE + 1];
+    uint8_t pinData[OXM_RANDOM_PIN_MAX_SIZE + 1];
+    size_t pinSize;
+    OicSecPinType_t pinType;
     OicUuid_t newDevice;
 }PinOxmData_t;
 
-static PinOxmData_t g_PinOxmData;
+static PinOxmData_t g_PinOxmData = {
+        .pinData={0},
+        .pinSize = OXM_RANDOM_PIN_DEFAULT_SIZE,
+        .pinType = (OicSecPinType_t)(OXM_RANDOM_PIN_DEFAULT_PIN_TYPE),
+    };
+
+/**
+ * Internal function to check pinType
+ */
+static bool IsValidPinType(OicSecPinType_t pinType)
+{
+    return ((NUM_PIN & pinType) ||
+            (LOWERCASE_CHAR_PIN & pinType) ||
+            (UPPERCASE_CHAR_PIN & pinType));
+}
+
+OCStackResult SetRandomPinPolicy(size_t pinSize, OicSecPinType_t pinType)
+{
+    if(OXM_RANDOM_PIN_MIN_SIZE > pinSize)
+    {
+        OIC_LOG(ERROR, TAG, "PIN size is too small");
+        return OC_STACK_INVALID_PARAM;
+    }
+    if(OXM_RANDOM_PIN_MAX_SIZE < pinSize)
+    {
+        OIC_LOG_V(ERROR, TAG, "PIN size can not exceed %d bytes", OXM_RANDOM_PIN_MAX_SIZE);
+        return OC_STACK_INVALID_PARAM;
+    }
+    if(false == IsValidPinType(pinType))
+    {
+        OIC_LOG(ERROR, TAG, "Invalid PIN type.");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    g_PinOxmData.pinSize = pinSize;
+    g_PinOxmData.pinType = pinType;
 
+    return OC_STACK_OK;
+}
 
 void SetInputPinCB(InputPinCallback pinCB)
 {
@@ -77,6 +119,47 @@ void UnsetGeneratePinCB()
     gGenPinCallback = NULL;
 }
 
+/**
+ * Internal function to generate PIN element according to pinType.
+ * This function assumes the pinType is valid.
+ * In case of invalid pinType, '0' will be returned as default vaule.
+ */
+static char GenerateRandomPinElement(OicSecPinType_t pinType)
+{
+    const char defaultRetValue = '0';
+    char allowedCharacters[NUMBER_OF_PINNUM + NUMBER_OF_ALPHABET * 2];
+    size_t curIndex = 0;
+
+    if(NUM_PIN & pinType)
+    {
+        for(char pinEle = '0'; pinEle <= '9'; pinEle++)
+        {
+            allowedCharacters[curIndex++] = pinEle;
+        }
+    }
+    if(UPPERCASE_CHAR_PIN & pinType)
+    {
+        for(char pinEle = 'A'; pinEle <= 'Z'; pinEle++)
+        {
+            allowedCharacters[curIndex++] = pinEle;
+        }
+    }
+    if(LOWERCASE_CHAR_PIN & pinType)
+    {
+        for(char pinEle = 'a'; pinEle <= 'z'; pinEle++)
+        {
+            allowedCharacters[curIndex++] = pinEle;
+        }
+    }
+
+    if(0 == curIndex)
+    {
+        return defaultRetValue;
+    }
+
+    return allowedCharacters[OCGetRandomRange(0, curIndex)];
+}
+
 OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize)
 {
     if(!pinBuffer)
@@ -84,22 +167,30 @@ OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize)
         OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
         return OC_STACK_INVALID_PARAM;
     }
-    if(OXM_RANDOM_PIN_SIZE + 1 > bufferSize)
+    if(g_PinOxmData.pinSize + 1 > bufferSize)
     {
         OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
         return OC_STACK_INVALID_PARAM;
     }
-    for(size_t i = 0; i < OXM_RANDOM_PIN_SIZE; i++)
+    if(false == IsValidPinType(g_PinOxmData.pinType))
     {
-        pinBuffer[i] = OCGetRandomRange((uint32_t)'0', (uint32_t)'9');
+        OIC_LOG(ERROR, TAG, "Invalid PIN type.");
+        OIC_LOG(ERROR, TAG, "Please set the PIN type using SetRandomPinPolicy API.");
+        return OC_STACK_ERROR;
+    }
+
+    for(size_t i = 0; i < g_PinOxmData.pinSize; i++)
+    {
+        pinBuffer[i] = GenerateRandomPinElement(g_PinOxmData.pinType);
         g_PinOxmData.pinData[i] = pinBuffer[i];
     }
-    pinBuffer[OXM_RANDOM_PIN_SIZE] = '\0';
-    g_PinOxmData.pinData[OXM_RANDOM_PIN_SIZE] = '\0';
+
+    pinBuffer[g_PinOxmData.pinSize] = '\0';
+    g_PinOxmData.pinData[g_PinOxmData.pinSize] = '\0';
 
     if(gGenPinCallback)
     {
-        gGenPinCallback(pinBuffer, OXM_RANDOM_PIN_SIZE);
+        gGenPinCallback(pinBuffer, g_PinOxmData.pinSize);
     }
     else
     {
@@ -140,7 +231,7 @@ OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
         OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
         return OC_STACK_INVALID_PARAM;
     }
-    if(OXM_RANDOM_PIN_SIZE + 1 > bufferSize)
+    if(g_PinOxmData.pinSize + 1 > bufferSize)
     {
         OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
         return OC_STACK_INVALID_PARAM;
@@ -148,9 +239,9 @@ OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
 
     if(gInputPinCallback)
     {
-        gInputPinCallback(pinBuffer, OXM_RANDOM_PIN_SIZE + 1);
-        memcpy(g_PinOxmData.pinData, pinBuffer, OXM_RANDOM_PIN_SIZE);
-        g_PinOxmData.pinData[OXM_RANDOM_PIN_SIZE] = '\0';
+        gInputPinCallback(pinBuffer, bufferSize);
+        OICStrcpy(g_PinOxmData.pinData, OXM_RANDOM_PIN_MAX_SIZE + 1, pinBuffer);
+        g_PinOxmData.pinSize = strlen(g_PinOxmData.pinData);
     }
     else
     {
@@ -165,7 +256,7 @@ OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
 #ifdef _ENABLE_MULTIPLE_OWNER_
 OCStackResult SetPreconfigPin(const char* pinBuffer, size_t pinLength)
 {
-    if(NULL == pinBuffer || OXM_PRECONFIG_PIN_SIZE < pinLength)
+    if(NULL == pinBuffer || OXM_PRECONFIG_PIN_MAX_SIZE < pinLength)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -191,7 +282,7 @@ int DerivePSKUsingPIN(uint8_t* result)
 {
     int dtlsRes = DeriveCryptoKeyFromPassword(
                                               (const unsigned char *)g_PinOxmData.pinData,
-                                              OXM_RANDOM_PIN_SIZE,
+                                              g_PinOxmData.pinSize,
                                               g_PinOxmData.newDevice.id,
                                               UUID_LENGTH, PBKDF_ITERATIONS,
                                               OWNER_PSK_LENGTH_128, result);