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