RPK OTM (#295)
[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     return dtlsRes;
328 }
329
330 int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
331               const unsigned char *UNUSED1, size_t UNUSED2,
332               unsigned char *result, size_t result_length)
333 {
334     int32_t ret = -1;
335
336     (void)UNUSED1;
337     (void)UNUSED2;
338
339     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
340     {
341         return ret;
342     }
343
344     switch (type)
345     {
346         case CA_DTLS_PSK_HINT:
347         case CA_DTLS_PSK_IDENTITY:
348             {
349                 /**
350                  * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
351                  *
352                  * At this point, The server generate random hint and
353                  * provide it to client through server key exchange message.
354                  */
355                 OCFillRandomMem(result, result_length);
356                 ret = result_length;
357                 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
358                 OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
359             }
360             break;
361
362         case CA_DTLS_PSK_KEY:
363             {
364                 if(0 == DerivePSKUsingPIN((uint8_t*)result))
365                 {
366                     ret = OWNER_PSK_LENGTH_128;
367                 }
368                 else
369                 {
370                     OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN");
371                     ret = -1;
372                 }
373             }
374             break;
375
376         default:
377             {
378                 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
379                 ret = -1;
380             }
381             break;
382     }
383     return ret;
384 }
385
386 #ifdef MULTIPLE_OWNER
387 int32_t GetDtlsPskForMotRandomPinOxm( CADtlsPskCredType_t type,
388               const unsigned char *UNUSED1, size_t UNUSED2,
389               unsigned char *result, size_t result_length)
390 {
391     int32_t ret = -1;
392
393     (void)UNUSED1;
394     (void)UNUSED2;
395
396     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
397     {
398         return ret;
399     }
400
401     const OicSecDoxm_t* doxm = GetDoxmResourceData();
402     if(doxm)
403     {
404         switch (type)
405         {
406             case CA_DTLS_PSK_HINT:
407             case CA_DTLS_PSK_IDENTITY:
408                 {
409                     memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
410                     return (sizeof(doxm->deviceID.id));
411                 }
412                 break;
413
414             case CA_DTLS_PSK_KEY:
415                 {
416                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
417                     {
418                         ret = OWNER_PSK_LENGTH_128;
419                     }
420                     else
421                     {
422                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
423                         ret = -1;
424                     }
425                 }
426                 break;
427
428             default:
429                 {
430                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
431                     ret = -1;
432                 }
433                 break;
434         }
435     }
436
437     return ret;
438 }
439
440
441 int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
442               const unsigned char *UNUSED1, size_t UNUSED2,
443               unsigned char *result, size_t result_length)
444 {
445     int32_t ret = -1;
446
447     (void)UNUSED1;
448     (void)UNUSED2;
449
450     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
451     {
452         return ret;
453     }
454
455     const OicSecDoxm_t* doxm = GetDoxmResourceData();
456     if(doxm)
457     {
458         switch (type)
459         {
460             case CA_DTLS_PSK_HINT:
461             case CA_DTLS_PSK_IDENTITY:
462                 {
463                     /**
464                      * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
465                      *
466                      * At this point, The server generate random hint and
467                      * provide it to client through server key exchange message.
468                      */
469                     OCFillRandomMem(result, result_length);
470                     ret = result_length;
471
472                     OIC_LOG(DEBUG, TAG, "PSK HINT : ");
473                     OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
474                 }
475                 break;
476
477             case CA_DTLS_PSK_KEY:
478                 {
479                     OicUuid_t uuid;
480                     memset(&uuid, 0x00, sizeof(uuid));
481                     OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
482
483                     //Load PreConfigured-PIN
484                     const OicSecCred_t* cred = GetCredResourceData(&uuid);
485                     if(cred)
486                     {
487                         char* pinBuffer = NULL;
488                         uint32_t pinLength = 0;
489                         if(OIC_ENCODING_RAW == cred->privateData.encoding)
490                         {
491                             pinBuffer = OICCalloc(1, cred->privateData.len + 1);
492                             if(NULL == pinBuffer)
493                             {
494                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
495                                 return ret;
496                             }
497                             pinLength = cred->privateData.len;
498                             memcpy(pinBuffer, cred->privateData.data, pinLength);
499                         }
500                         else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
501                         {
502                             size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
503                             pinBuffer = OICCalloc(1, pinBufSize);
504                             if(NULL == pinBuffer)
505                             {
506                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
507                                 return ret;
508                             }
509
510                             if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
511                             {
512                                 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
513                                 return ret;
514                             }
515                         }
516                         else
517                         {
518                             OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
519                             return ret;
520                         }
521
522                         memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
523                         OICFree(pinBuffer);
524                     }
525
526                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
527                     {
528                         ret = OWNER_PSK_LENGTH_128;
529                     }
530                     else
531                     {
532                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
533                         ret = -1;
534                     }
535                 }
536                 break;
537
538             default:
539                 {
540                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
541                     ret = -1;
542                 }
543                 break;
544         }
545     }
546
547     return ret;
548 }
549
550
551 int32_t GetDtlsPskForMotPreconfPinOxm( CADtlsPskCredType_t type,
552               const unsigned char *UNUSED1, size_t UNUSED2,
553               unsigned char *result, size_t result_length)
554 {
555     int32_t ret = -1;
556
557     (void)UNUSED1;
558     (void)UNUSED2;
559
560     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
561     {
562         return ret;
563     }
564
565     const OicSecDoxm_t* doxm = GetDoxmResourceData();
566     if(doxm)
567     {
568         switch (type)
569         {
570             case CA_DTLS_PSK_HINT:
571             case CA_DTLS_PSK_IDENTITY:
572                 {
573                     memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
574                     return (sizeof(doxm->deviceID.id));
575                 }
576                 break;
577             case CA_DTLS_PSK_KEY:
578                 {
579                     OicUuid_t uuid;
580                     memset(&uuid, 0x00, sizeof(uuid));
581                     OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
582
583                     //Load PreConfigured-PIN
584                     const OicSecCred_t* cred = GetCredResourceData(&uuid);
585                     if(cred)
586                     {
587                         char* pinBuffer = NULL;
588                         uint32_t pinLength = 0;
589                         if(OIC_ENCODING_RAW == cred->privateData.encoding)
590                         {
591                             pinBuffer = OICCalloc(1, cred->privateData.len + 1);
592                             if(NULL == pinBuffer)
593                             {
594                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
595                                 return ret;
596                             }
597                             pinLength = cred->privateData.len;
598                             memcpy(pinBuffer, cred->privateData.data, pinLength);
599                         }
600                         else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
601                         {
602                             size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
603                             pinBuffer = OICCalloc(1, pinBufSize);
604                             if(NULL == pinBuffer)
605                             {
606                                 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
607                                 return ret;
608                             }
609
610                             if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
611                             {
612                                 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
613                                 return ret;
614                             }
615                         }
616                         else
617                         {
618                             OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
619                             return ret;
620                         }
621
622                         memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
623                         OICFree(pinBuffer);
624                     }
625
626                     if(0 == DerivePSKUsingPIN((uint8_t*)result))
627                     {
628                         ret = OWNER_PSK_LENGTH_128;
629                     }
630                     else
631                     {
632                         OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
633                         ret = -1;
634                     }
635                 }
636                 break;
637
638             default:
639                 {
640                     OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
641                     ret = -1;
642                 }
643                 break;
644         }
645     }
646
647     return ret;
648 }
649 #endif //MULTIPLE_OWNER
650
651 #endif //__WITH_DTLS__