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