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