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