1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
26 #include "pinoxmcommon.h"
29 #include "securevirtualresourcetypes.h"
30 #include "srmresourcestrings.h"
31 #include "doxmresource.h"
32 #include "credresource.h"
33 #include "cainterface.h"
35 #define TAG "OIC_PIN_OXM_COMMON"
37 #define NUMBER_OF_PINNUM (10)
38 #define NUMBER_OF_ALPHABET (26)
40 static GeneratePinCallback gGenPinCallback = NULL;
41 static InputPinCallback gInputPinCallback = NULL;
43 typedef struct PinOxmData {
44 uint8_t pinData[OXM_RANDOM_PIN_MAX_SIZE + 1];
46 OicSecPinType_t pinType;
50 static PinOxmData_t g_PinOxmData = {
52 .pinSize = OXM_RANDOM_PIN_DEFAULT_SIZE,
53 .pinType = (OicSecPinType_t)(OXM_RANDOM_PIN_DEFAULT_PIN_TYPE),
57 * Internal function to check pinType
59 static bool IsValidPinType(OicSecPinType_t pinType)
61 return ((NUM_PIN & pinType) ||
62 (LOWERCASE_CHAR_PIN & pinType) ||
63 (UPPERCASE_CHAR_PIN & pinType));
66 OCStackResult SetRandomPinPolicy(size_t pinSize, OicSecPinType_t pinType)
68 if(OXM_RANDOM_PIN_MIN_SIZE > pinSize)
70 OIC_LOG(ERROR, TAG, "PIN size is too small");
71 return OC_STACK_INVALID_PARAM;
73 if(OXM_RANDOM_PIN_MAX_SIZE < pinSize)
75 OIC_LOG_V(ERROR, TAG, "PIN size can not exceed %d bytes", OXM_RANDOM_PIN_MAX_SIZE);
76 return OC_STACK_INVALID_PARAM;
78 if(false == IsValidPinType(pinType))
80 OIC_LOG(ERROR, TAG, "Invalid PIN type.");
81 return OC_STACK_INVALID_PARAM;
84 g_PinOxmData.pinSize = pinSize;
85 g_PinOxmData.pinType = pinType;
90 void SetInputPinCB(InputPinCallback pinCB)
94 OIC_LOG(ERROR, TAG, "Failed to set callback for input pin.");
98 gInputPinCallback = pinCB;
101 void SetGeneratePinCB(GeneratePinCallback pinCB)
105 OIC_LOG(ERROR, TAG, "Failed to set callback for generate pin.");
109 gGenPinCallback = pinCB;
112 void UnsetInputPinCB()
114 gInputPinCallback = NULL;
117 void UnsetGeneratePinCB()
119 gGenPinCallback = NULL;
123 * Internal function to generate PIN element according to pinType.
124 * This function assumes the pinType is valid.
125 * In case of invalid pinType, '0' will be returned as default vaule.
127 static char GenerateRandomPinElement(OicSecPinType_t pinType)
129 const char defaultRetValue = '0';
130 char allowedCharacters[NUMBER_OF_PINNUM + NUMBER_OF_ALPHABET * 2];
133 if(NUM_PIN & pinType)
135 for(char pinEle = '0'; pinEle <= '9'; pinEle++)
137 allowedCharacters[curIndex++] = pinEle;
140 if(UPPERCASE_CHAR_PIN & pinType)
142 for(char pinEle = 'A'; pinEle <= 'Z'; pinEle++)
144 allowedCharacters[curIndex++] = pinEle;
147 if(LOWERCASE_CHAR_PIN & pinType)
149 for(char pinEle = 'a'; pinEle <= 'z'; pinEle++)
151 allowedCharacters[curIndex++] = pinEle;
157 return defaultRetValue;
160 return allowedCharacters[OCGetRandomRange(0, curIndex)];
163 OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize)
167 OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
168 return OC_STACK_INVALID_PARAM;
170 if(g_PinOxmData.pinSize + 1 > bufferSize)
172 OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
173 return OC_STACK_INVALID_PARAM;
175 if(false == IsValidPinType(g_PinOxmData.pinType))
177 OIC_LOG(ERROR, TAG, "Invalid PIN type.");
178 OIC_LOG(ERROR, TAG, "Please set the PIN type using SetRandomPinPolicy API.");
179 return OC_STACK_ERROR;
182 for(size_t i = 0; i < g_PinOxmData.pinSize; i++)
184 pinBuffer[i] = GenerateRandomPinElement(g_PinOxmData.pinType);
185 g_PinOxmData.pinData[i] = pinBuffer[i];
188 pinBuffer[g_PinOxmData.pinSize] = '\0';
189 g_PinOxmData.pinData[g_PinOxmData.pinSize] = '\0';
193 gGenPinCallback(pinBuffer, g_PinOxmData.pinSize);
197 OIC_LOG(ERROR, TAG, "Invoke PIN callback failed!");
198 OIC_LOG(ERROR, TAG, "Callback for genrate PIN should be registered to use PIN based OxM.");
199 return OC_STACK_ERROR;
203 if(OC_STACK_OK == GetDoxmDeviceID(&deviceID))
205 //Set the device id to derive temporal PSK
206 SetUuidForPinBasedOxm(&deviceID);
209 * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
210 * Credential should not be saved into SVR.
211 * For this reason, use a temporary get_psk_info callback to random PIN OxM.
213 if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
215 OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
220 OIC_LOG(ERROR, TAG, "Failed to read device ID");
221 return OC_STACK_ERROR;
227 OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
231 OIC_LOG(ERROR, TAG, "PIN buffer is NULL");
232 return OC_STACK_INVALID_PARAM;
234 if(g_PinOxmData.pinSize + 1 > bufferSize)
236 OIC_LOG(ERROR, TAG, "PIN buffer size is too small");
237 return OC_STACK_INVALID_PARAM;
240 if(gInputPinCallback)
242 gInputPinCallback(pinBuffer, bufferSize);
243 OICStrcpy(g_PinOxmData.pinData, OXM_RANDOM_PIN_MAX_SIZE + 1, pinBuffer);
244 g_PinOxmData.pinSize = strlen(g_PinOxmData.pinData);
248 OIC_LOG(ERROR, TAG, "Invoke PIN callback failed!");
249 OIC_LOG(ERROR, TAG, "Callback for input PIN should be registered to use Random PIN based OxM.");
250 return OC_STACK_ERROR;
256 #ifdef _ENABLE_MULTIPLE_OWNER_
257 OCStackResult SetPreconfigPin(const char *pinBuffer, size_t pinLength)
259 if(NULL == pinBuffer || OXM_PRECONFIG_PIN_MAX_SIZE < pinLength)
261 return OC_STACK_INVALID_PARAM;
264 memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
265 g_PinOxmData.pinData[pinLength] = '\0';
269 #endif //_ENABLE_MULTIPLE_OWNER_
273 void SetUuidForPinBasedOxm(const OicUuid_t* uuid)
277 memcpy(g_PinOxmData.newDevice.id, uuid->id, UUID_LENGTH);
281 int DerivePSKUsingPIN(uint8_t* result)
283 int dtlsRes = DeriveCryptoKeyFromPassword(
284 (const unsigned char *)g_PinOxmData.pinData,
285 g_PinOxmData.pinSize,
286 g_PinOxmData.newDevice.id,
287 UUID_LENGTH, PBKDF_ITERATIONS,
288 OWNER_PSK_LENGTH_128, result);
290 OIC_LOG_V(DEBUG, TAG, "DeriveCryptoKeyFromPassword Completed (%d)", dtlsRes);
291 OIC_LOG_V(DEBUG, TAG, "PIN : %s", g_PinOxmData.pinData);
292 OIC_LOG(DEBUG, TAG, "UUID : ");
293 OIC_LOG_BUFFER(DEBUG, TAG, g_PinOxmData.newDevice.id, UUID_LENGTH);
298 int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
299 const unsigned char *UNUSED1, size_t UNUSED2,
300 unsigned char *result, size_t result_length)
307 if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
314 case CA_DTLS_PSK_HINT:
315 case CA_DTLS_PSK_IDENTITY:
318 * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
320 * At this point, The server generate random hint and
321 * provide it to client through server key exchange message.
323 OCFillRandomMem(result, result_length);
326 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
327 OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
331 case CA_DTLS_PSK_KEY:
333 if(0 == DerivePSKUsingPIN((uint8_t*)result))
335 ret = OWNER_PSK_LENGTH_128;
339 OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN");
347 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
356 #ifdef _ENABLE_MULTIPLE_OWNER_
357 int32_t GetDtlsPskForMotRandomPinOxm( CADtlsPskCredType_t type,
358 const unsigned char *UNUSED1, size_t UNUSED2,
359 unsigned char *result, size_t result_length)
366 if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
371 const OicSecDoxm_t* doxm = GetDoxmResourceData();
376 case CA_DTLS_PSK_HINT:
377 case CA_DTLS_PSK_IDENTITY:
379 memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
380 return (sizeof(doxm->deviceID.id));
384 case CA_DTLS_PSK_KEY:
386 if(0 == DerivePSKUsingPIN((uint8_t*)result))
388 ret = OWNER_PSK_LENGTH_128;
392 OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
400 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
411 int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
412 const unsigned char *UNUSED1, size_t UNUSED2,
413 unsigned char *result, size_t result_length)
420 if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
425 const OicSecDoxm_t* doxm = GetDoxmResourceData();
430 case CA_DTLS_PSK_HINT:
431 case CA_DTLS_PSK_IDENTITY:
434 * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
436 * At this point, The server generate random hint and
437 * provide it to client through server key exchange message.
439 OCFillRandomMem(result, result_length);
442 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
443 OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
447 case CA_DTLS_PSK_KEY:
450 memset(&uuid, 0x00, sizeof(uuid));
451 OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
453 //Load PreConfigured-PIN
454 const OicSecCred_t* cred = GetCredResourceData(&uuid);
457 char* pinBuffer = NULL;
458 uint32_t pinLength = 0;
459 if(OIC_ENCODING_RAW == cred->privateData.encoding)
461 pinBuffer = OICCalloc(1, cred->privateData.len + 1);
462 if(NULL == pinBuffer)
464 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
467 pinLength = cred->privateData.len;
468 memcpy(pinBuffer, cred->privateData.data, pinLength);
470 else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
472 size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
473 pinBuffer = OICCalloc(1, pinBufSize);
474 if(NULL == pinBuffer)
476 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
480 if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
482 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
488 OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
492 memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
496 if(0 == DerivePSKUsingPIN((uint8_t*)result))
498 ret = OWNER_PSK_LENGTH_128;
502 OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
510 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
521 int32_t GetDtlsPskForMotPreconfPinOxm( CADtlsPskCredType_t type,
522 const unsigned char *UNUSED1, size_t UNUSED2,
523 unsigned char *result, size_t result_length)
530 if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
535 const OicSecDoxm_t* doxm = GetDoxmResourceData();
540 case CA_DTLS_PSK_HINT:
541 case CA_DTLS_PSK_IDENTITY:
543 memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
544 return (sizeof(doxm->deviceID.id));
547 case CA_DTLS_PSK_KEY:
550 memset(&uuid, 0x00, sizeof(uuid));
551 OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
553 //Load PreConfigured-PIN
554 const OicSecCred_t* cred = GetCredResourceData(&uuid);
557 char* pinBuffer = NULL;
558 uint32_t pinLength = 0;
559 if(OIC_ENCODING_RAW == cred->privateData.encoding)
561 pinBuffer = OICCalloc(1, cred->privateData.len + 1);
562 if(NULL == pinBuffer)
564 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
567 pinLength = cred->privateData.len;
568 memcpy(pinBuffer, cred->privateData.data, pinLength);
570 else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
572 size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
573 pinBuffer = OICCalloc(1, pinBufSize);
574 if(NULL == pinBuffer)
576 OIC_LOG (ERROR, TAG, "Failed to allocate memory");
580 if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
582 OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
588 OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
592 memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
596 if(0 == DerivePSKUsingPIN((uint8_t*)result))
598 ret = OWNER_PSK_LENGTH_128;
602 OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
610 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
619 #endif //_ENABLE_MULTIPLE_OWNER_
621 #endif //__WITH_DTLS__