Update the random PIN generator module to provide high entropy.
[platform/upstream/iotivity.git] / resource / csdk / security / src / oxmpincommon.c
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <memory.h>
22
23 #include "ocstack.h"
24 #include "ocrandom.h"
25 #include "logger.h"
26 #include "pinoxmcommon.h"
27 #include "pbkdf2.h"
28 #include "base64.h"
29 #include "securevirtualresourcetypes.h"
30 #include "srmresourcestrings.h"
31 #include "doxmresource.h"
32 #include "credresource.h"
33 #include "cainterface.h"
34
35 #define TAG "PIN_OXM_COMMON"
36
37 #define NUMBER_OF_PINNUM (10)
38 #define NUMBER_OF_ALPHABET (26)
39
40 static GeneratePinCallback gGenPinCallback = NULL;
41 static InputPinCallback gInputPinCallback = NULL;
42
43 typedef struct PinOxmData {
44     uint8_t pinData[OXM_RANDOM_PIN_MAX_SIZE + 1];
45     size_t pinSize;
46     OicSecPinType_t pinType;
47     OicUuid_t newDevice;
48 }PinOxmData_t;
49
50 static PinOxmData_t g_PinOxmData = {
51         .pinData={0},
52         .pinSize = OXM_RANDOM_PIN_DEFAULT_SIZE,
53         .pinType = (OicSecPinType_t)(OXM_RANDOM_PIN_DEFAULT_PIN_TYPE),
54     };
55
56 /**
57  * Internal function to check pinType
58  */
59 static bool IsValidPinType(OicSecPinType_t pinType)
60 {
61     return ((NUM_PIN & pinType) ||
62             (LOWERCASE_CHAR_PIN & pinType) ||
63             (UPPERCASE_CHAR_PIN & pinType));
64 }
65
66 OCStackResult SetRandomPinPolicy(size_t pinSize, OicSecPinType_t pinType)
67 {
68     if(OXM_RANDOM_PIN_MIN_SIZE > pinSize)
69     {
70         OIC_LOG(ERROR, TAG, "PIN size is too small");
71         return OC_STACK_INVALID_PARAM;
72     }
73     if(OXM_RANDOM_PIN_MAX_SIZE < pinSize)
74     {
75         OIC_LOG_V(ERROR, TAG, "PIN size can not exceed %d bytes", OXM_RANDOM_PIN_MAX_SIZE);
76         return OC_STACK_INVALID_PARAM;
77     }
78     if(false == IsValidPinType(pinType))
79     {
80         OIC_LOG(ERROR, TAG, "Invalid PIN type.");
81         return OC_STACK_INVALID_PARAM;
82     }
83
84     g_PinOxmData.pinSize = pinSize;
85     g_PinOxmData.pinType = pinType;
86
87     return OC_STACK_OK;
88 }
89
90 void SetInputPinCB(InputPinCallback pinCB)
91 {
92     if(NULL == pinCB)
93     {
94         OIC_LOG(ERROR, TAG, "Failed to set callback for input pin.");
95         return;
96     }
97
98     gInputPinCallback = pinCB;
99 }
100
101 void SetGeneratePinCB(GeneratePinCallback pinCB)
102 {
103     if(NULL == pinCB)
104     {
105         OIC_LOG(ERROR, TAG, "Failed to set callback for generate pin.");
106         return;
107     }
108
109     gGenPinCallback = pinCB;
110 }
111
112 void UnsetInputPinCB()
113 {
114     gInputPinCallback = NULL;
115 }
116
117 void UnsetGeneratePinCB()
118 {
119     gGenPinCallback = NULL;
120 }
121
122 /**
123  * Internal function to generate PIN element according to pinType.
124  * This function assumes the pinType is valid.
125  * In case of invalid pinType, '0' will be returned as default vaule.
126  */
127 static char GenerateRandomPinElement(OicSecPinType_t pinType)
128 {
129     const char defaultRetValue = '0';
130     char allowedCharacters[NUMBER_OF_PINNUM + NUMBER_OF_ALPHABET * 2];
131     size_t curIndex = 0;
132
133     if(NUM_PIN & pinType)
134     {
135         for(char pinEle = '0'; pinEle <= '9'; pinEle++)
136         {
137             allowedCharacters[curIndex++] = pinEle;
138         }
139     }
140     if(UPPERCASE_CHAR_PIN & pinType)
141     {
142         for(char pinEle = 'A'; pinEle <= 'Z'; pinEle++)
143         {
144             allowedCharacters[curIndex++] = pinEle;
145         }
146     }
147     if(LOWERCASE_CHAR_PIN & pinType)
148     {
149         for(char pinEle = 'a'; pinEle <= 'z'; pinEle++)
150         {
151             allowedCharacters[curIndex++] = pinEle;
152         }
153     }
154
155     if(0 == curIndex)
156     {
157         return defaultRetValue;
158     }
159
160     return allowedCharacters[OCGetRandomRange(0, curIndex)];
161 }
162
163 OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize)
164 {
165     if(!pinBuffer)
166     {
167         OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
168         return OC_STACK_INVALID_PARAM;
169     }
170     if(g_PinOxmData.pinSize + 1 > bufferSize)
171     {
172         OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
173         return OC_STACK_INVALID_PARAM;
174     }
175     if(false == IsValidPinType(g_PinOxmData.pinType))
176     {
177         OIC_LOG(ERROR, TAG, "Invalid PIN type.");
178         OIC_LOG(ERROR, TAG, "Please set the PIN type using SetRandomPinPolicy API.");
179         return OC_STACK_ERROR;
180     }
181
182     for(size_t i = 0; i < g_PinOxmData.pinSize; i++)
183     {
184         pinBuffer[i] = GenerateRandomPinElement(g_PinOxmData.pinType);
185         g_PinOxmData.pinData[i] = pinBuffer[i];
186     }
187
188     pinBuffer[g_PinOxmData.pinSize] = '\0';
189     g_PinOxmData.pinData[g_PinOxmData.pinSize] = '\0';
190
191     if(gGenPinCallback)
192     {
193         gGenPinCallback(pinBuffer, g_PinOxmData.pinSize);
194     }
195     else
196     {
197         OIC_LOG(ERROR, TAG, "Invoke PIN callback failed!");
198         OIC_LOG(ERROR, TAG, "Callback for genrate PIN should be registered to use PIN based OxM.");
199         return OC_STACK_ERROR;
200     }
201
202     OicUuid_t deviceID;
203     if(OC_STACK_OK == GetDoxmDeviceID(&deviceID))
204     {
205         //Set the device id to derive temporal PSK
206         SetUuidForPinBasedOxm(&deviceID);
207
208         /**
209          * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
210          * Credential should not be saved into SVR.
211          * For this reason, use a temporary get_psk_info callback to random PIN OxM.
212          */
213         if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
214         {
215             OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
216         }
217     }
218     else
219     {
220         OIC_LOG(ERROR, TAG, "Failed to read device ID");
221         return OC_STACK_ERROR;
222     }
223
224     return OC_STACK_OK;
225 }
226
227 OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
228 {
229     if(!pinBuffer)
230     {
231         OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
232         return OC_STACK_INVALID_PARAM;
233     }
234     if(g_PinOxmData.pinSize + 1 > bufferSize)
235     {
236         OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
237         return OC_STACK_INVALID_PARAM;
238     }
239
240     if(gInputPinCallback)
241     {
242         gInputPinCallback(pinBuffer, bufferSize);
243         OICStrcpy(g_PinOxmData.pinData, OXM_RANDOM_PIN_MAX_SIZE + 1, pinBuffer);
244         g_PinOxmData.pinSize = strlen(g_PinOxmData.pinData);
245     }
246     else
247     {
248         OIC_LOG(ERROR, TAG, "Invoke PIN callback failed!");
249         OIC_LOG(ERROR, TAG, "Callback for input PIN should be registered to use Random PIN based OxM.");
250         return OC_STACK_ERROR;
251     }
252
253     return OC_STACK_OK;
254 }
255
256 #ifdef _ENABLE_MULTIPLE_OWNER_
257 OCStackResult SetPreconfigPin(const char* pinBuffer, size_t pinLength)
258 {
259     if(NULL == pinBuffer || OXM_PRECONFIG_PIN_MAX_SIZE < pinLength)
260     {
261         return OC_STACK_INVALID_PARAM;
262     }
263
264     memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
265     g_PinOxmData.pinData[pinLength] = '\0';
266
267     return OC_STACK_OK;
268 }
269 #endif //_ENABLE_MULTIPLE_OWNER_
270
271 #ifdef __WITH_DTLS__
272
273 void SetUuidForPinBasedOxm(const OicUuid_t* uuid)
274 {
275     if(NULL != uuid)
276     {
277         memcpy(g_PinOxmData.newDevice.id, uuid->id, UUID_LENGTH);
278     }
279 }
280
281 int DerivePSKUsingPIN(uint8_t* result)
282 {
283     int dtlsRes = DeriveCryptoKeyFromPassword(
284                                               (const unsigned char *)g_PinOxmData.pinData,
285                                               g_PinOxmData.pinSize,
286                                               g_PinOxmData.newDevice.id,
287                                               UUID_LENGTH, PBKDF_ITERATIONS,
288                                               OWNER_PSK_LENGTH_128, result);
289
290     OIC_LOG_V(DEBUG, TAG, "DeriveCryptoKeyFromPassword Completed (%d)", dtlsRes);
291     OIC_LOG_V(DEBUG, TAG, "PIN : %s", g_PinOxmData.pinData);
292     OIC_LOG(DEBUG, TAG, "UUID : ");
293     OIC_LOG_BUFFER(DEBUG, TAG, g_PinOxmData.newDevice.id, UUID_LENGTH);
294
295     return dtlsRes;
296 }
297
298 int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
299               const unsigned char *UNUSED1, size_t UNUSED2,
300               unsigned char *result, size_t result_length)
301 {
302     int32_t ret = -1;
303
304     (void)UNUSED1;
305     (void)UNUSED2;
306
307     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
308     {
309         return ret;
310     }
311
312     switch (type)
313     {
314         case CA_DTLS_PSK_HINT:
315         case CA_DTLS_PSK_IDENTITY:
316             {
317                 /**
318                  * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
319                  *
320                  * At this point, The server generate random hint and
321                  * provide it to client through server key exchange message.
322                  */
323                 OCFillRandomMem(result, result_length);
324                 ret = result_length;
325
326                 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
327                 OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
328             }
329             break;
330
331         case CA_DTLS_PSK_KEY:
332             {
333                 if(0 == DerivePSKUsingPIN((uint8_t*)result))
334                 {
335                     ret = OWNER_PSK_LENGTH_128;
336                 }
337                 else
338                 {
339                     OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN");
340                     ret = -1;
341                 }
342             }
343             break;
344
345         default:
346             {
347                 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
348                 ret = -1;
349             }
350             break;
351     }
352
353     return ret;
354 }
355
356 #ifdef _ENABLE_MULTIPLE_OWNER_
357 int32_t GetDtlsPskForMotRandomPinOxm( CADtlsPskCredType_t type,
358               const unsigned char *UNUSED1, size_t UNUSED2,
359               unsigned char *result, size_t result_length)
360 {
361     int32_t ret = -1;
362
363     (void)UNUSED1;
364     (void)UNUSED2;
365
366     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
367     {
368         return ret;
369     }
370
371     const OicSecDoxm_t* doxm = GetDoxmResourceData();
372     if(doxm)
373     {
374         switch (type)
375         {
376             case CA_DTLS_PSK_HINT:
377             case CA_DTLS_PSK_IDENTITY:
378                 {
379                     memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
380                     return (sizeof(doxm->deviceID.id));
381                 }
382                 break;
383
384             case CA_DTLS_PSK_KEY:
385                 {
386                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
387                     {
388                         ret = OWNER_PSK_LENGTH_128;
389                     }
390                     else
391                     {
392                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
393                         ret = -1;
394                     }
395                 }
396                 break;
397
398             default:
399                 {
400                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
401                     ret = -1;
402                 }
403                 break;
404         }
405     }
406
407     return ret;
408 }
409
410
411 int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
412               const unsigned char *UNUSED1, size_t UNUSED2,
413               unsigned char *result, size_t result_length)
414 {
415     int32_t ret = -1;
416
417     (void)UNUSED1;
418     (void)UNUSED2;
419
420     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
421     {
422         return ret;
423     }
424
425     const OicSecDoxm_t* doxm = GetDoxmResourceData();
426     if(doxm)
427     {
428         switch (type)
429         {
430             case CA_DTLS_PSK_HINT:
431             case CA_DTLS_PSK_IDENTITY:
432                 {
433                     /**
434                      * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
435                      *
436                      * At this point, The server generate random hint and
437                      * provide it to client through server key exchange message.
438                      */
439                     OCFillRandomMem(result, result_length);
440                     ret = result_length;
441
442                     OIC_LOG(DEBUG, TAG, "PSK HINT : ");
443                     OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
444                 }
445                 break;
446
447             case CA_DTLS_PSK_KEY:
448                 {
449                     OicUuid_t uuid;
450                     memset(&uuid, 0x00, sizeof(uuid));
451                     OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
452
453                     //Load PreConfigured-PIN
454                     const OicSecCred_t* cred = GetCredResourceData(&uuid);
455                     if(cred)
456                     {
457                         char* pinBuffer = NULL;
458                         uint32_t pinLength = 0;
459                         if(OIC_ENCODING_RAW == cred->privateData.encoding)
460                         {
461                             pinBuffer = OICCalloc(1, cred->privateData.len + 1);
462                             if(NULL == pinBuffer)
463                             {
464                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
465                                 return ret;
466                             }
467                             pinLength = cred->privateData.len;
468                             memcpy(pinBuffer, cred->privateData.data, pinLength);
469                         }
470                         else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
471                         {
472                             size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
473                             pinBuffer = OICCalloc(1, pinBufSize);
474                             if(NULL == pinBuffer)
475                             {
476                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
477                                 return ret;
478                             }
479
480                             if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
481                             {
482                                 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
483                                 return ret;
484                             }
485                         }
486                         else
487                         {
488                             OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
489                             return ret;
490                         }
491
492                         memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
493                         OICFree(pinBuffer);
494                     }
495
496                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
497                     {
498                         ret = OWNER_PSK_LENGTH_128;
499                     }
500                     else
501                     {
502                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
503                         ret = -1;
504                     }
505                 }
506                 break;
507
508             default:
509                 {
510                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
511                     ret = -1;
512                 }
513                 break;
514         }
515     }
516
517     return ret;
518 }
519
520
521 int32_t GetDtlsPskForMotPreconfPinOxm( CADtlsPskCredType_t type,
522               const unsigned char *UNUSED1, size_t UNUSED2,
523               unsigned char *result, size_t result_length)
524 {
525     int32_t ret = -1;
526
527     (void)UNUSED1;
528     (void)UNUSED2;
529
530     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
531     {
532         return ret;
533     }
534
535     const OicSecDoxm_t* doxm = GetDoxmResourceData();
536     if(doxm)
537     {
538         switch (type)
539         {
540             case CA_DTLS_PSK_HINT:
541             case CA_DTLS_PSK_IDENTITY:
542                 {
543                     memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
544                     return (sizeof(doxm->deviceID.id));
545                 }
546                 break;
547             case CA_DTLS_PSK_KEY:
548                 {
549                     OicUuid_t uuid;
550                     memset(&uuid, 0x00, sizeof(uuid));
551                     OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
552
553                     //Load PreConfigured-PIN
554                     const OicSecCred_t* cred = GetCredResourceData(&uuid);
555                     if(cred)
556                     {
557                         char* pinBuffer = NULL;
558                         uint32_t pinLength = 0;
559                         if(OIC_ENCODING_RAW == cred->privateData.encoding)
560                         {
561                             pinBuffer = OICCalloc(1, cred->privateData.len + 1);
562                             if(NULL == pinBuffer)
563                             {
564                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
565                                 return ret;
566                             }
567                             pinLength = cred->privateData.len;
568                             memcpy(pinBuffer, cred->privateData.data, pinLength);
569                         }
570                         else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
571                         {
572                             size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
573                             pinBuffer = OICCalloc(1, pinBufSize);
574                             if(NULL == pinBuffer)
575                             {
576                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
577                                 return ret;
578                             }
579
580                             if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
581                             {
582                                 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
583                                 return ret;
584                             }
585                         }
586                         else
587                         {
588                             OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
589                             return ret;
590                         }
591
592                         memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
593                         OICFree(pinBuffer);
594                     }
595
596                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
597                     {
598                         ret = OWNER_PSK_LENGTH_128;
599                     }
600                     else
601                     {
602                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
603                         ret = -1;
604                     }
605                 }
606                 break;
607
608             default:
609                 {
610                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
611                     ret = -1;
612                 }
613                 break;
614         }
615     }
616
617     return ret;
618 }
619 #endif //_ENABLE_MULTIPLE_OWNER_
620
621 #endif //__WITH_DTLS__