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