a1a62dd53e5d679e87361637d088547c562fc4cb
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / oxmrawpublickey.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 "securevirtualresourcetypes.h"
25 #include "doxmresource.h"
26 #include "credresource.h"
27 #include "cacommon.h"
28 #include "cainterface.h"
29 #include "ocrandom.h"
30 #include "oic_malloc.h"
31 #include "logger.h"
32 #include "pbkdf2.h"
33 #include "base64.h"
34 #include "oxmrawpublickey.h"
35 #include "ownershiptransfermanager.h"
36 #include "oxmverifycommon.h"
37 #include "mbedtls/ctr_drbg.h"
38 #include "mbedtls/entropy.h"
39 #include "mbedtls/ssl_internal.h"
40
41 #define TAG "OIC_OXM_RawPubKey"
42
43 typedef struct RPKOxmData {
44     char rpkData[OXM_RPK_MASTER_KEY_MAX_SIZE + 1];
45     size_t rpkSize;
46     OicUuid_t newDevice;
47 }RPKOxmData_t;
48
49 static RPKOxmData_t g_RPKOxmData = {
50         .rpkData={0},
51         .rpkSize = 0,
52     };
53
54 static GetRPKMasterKeyCallback gGetRPKMasterKeyCallback = NULL;
55
56 void SetInputRPKMasterKeyCB(GetRPKMasterKeyCallback rpkCB)
57 {
58     if(NULL == rpkCB)
59     {
60         OIC_LOG(ERROR, TAG, "Failed to set callback for rpk.");
61         return;
62     }
63
64     gGetRPKMasterKeyCallback = rpkCB;
65 }
66
67 void UnsetRPKMasterKeyCB()
68 {
69     gGetRPKMasterKeyCallback = NULL;
70 }
71
72 OCStackResult CreateRPKBasedSelectOxmPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size)
73 {
74     if(!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size)
75     {
76         return OC_STACK_INVALID_PARAM;
77     }
78
79     otmCtx->selectedDeviceInfo->doxm->oxmSel = OIC_RAW_PUB_KEY;
80
81     return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true);
82 }
83
84 OCStackResult CreateRPKBasedOwnerTransferPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size)
85 {
86     if(!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size)
87     {
88         return OC_STACK_INVALID_PARAM;
89     }
90
91     OicUuid_t uuidPT = {.id={0}};
92     *payload = NULL;
93     *size = 0;
94
95     if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT))
96     {
97         OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
98         return OC_STACK_ERROR;
99     }
100     memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id , UUID_LENGTH);
101
102     return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true);
103 }
104
105 OCStackResult GetMasterRPK(char* master, size_t* master_len)
106 {
107     if(!master || !master_len)
108     {
109         OIC_LOG(ERROR, TAG, "RPK buffer is NULL");
110         return OC_STACK_INVALID_PARAM;
111     }
112
113     if(gGetRPKMasterKeyCallback)
114     {
115         gGetRPKMasterKeyCallback(g_RPKOxmData.rpkData, &g_RPKOxmData.rpkSize);
116     }
117     else
118     {
119         OIC_LOG(ERROR, TAG, "Invoke RPK callback failed!");
120         OIC_LOG(ERROR, TAG, "Callback for input RPK should be registered to use Random RPK based OxM.");
121         return OC_STACK_ERROR;
122     }
123
124     return OC_STACK_OK;
125 }
126
127 void SetUuidForRPKBasedOxm(const OicUuid_t* uuid)
128 {
129     if(NULL != uuid)
130     {
131         memcpy(g_RPKOxmData.newDevice.id, uuid->id, UUID_LENGTH);
132     }
133 }
134
135 int DerivePSKUsingRPK(uint8_t* result)
136 {
137     int dtlsRes = DeriveCryptoKeyFromPassword(
138                                               (const unsigned char *)g_RPKOxmData.rpkData,
139                                               g_RPKOxmData.rpkSize,
140                                               g_RPKOxmData.newDevice.id,
141                                               UUID_LENGTH, PBKDF_ITERATIONS,
142                                               OWNER_PSK_LENGTH_128, result);
143
144     OIC_LOG_V(DEBUG, TAG, "DeriveCryptoKeyFromPassword Completed (%d)", dtlsRes);
145     OIC_LOG_V(DEBUG, TAG, "RPK : %s", g_RPKOxmData.rpkData);
146     OIC_LOG(DEBUG, TAG, "UUID : ");
147     OIC_LOG_BUFFER(DEBUG, TAG, g_RPKOxmData.newDevice.id, UUID_LENGTH);
148     return dtlsRes;
149 }
150
151 int32_t GetDtlsPskForRPKOxm( CADtlsPskCredType_t type,
152               const unsigned char *UNUSED1, size_t UNUSED2,
153               unsigned char *result, size_t result_length)
154 {
155     int32_t ret = -1;
156
157     (void)UNUSED1;
158     (void)UNUSED2;
159
160     if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
161     {
162         return ret;
163     }
164
165     switch (type)
166     {
167         case CA_DTLS_PSK_HINT:
168         case CA_DTLS_PSK_IDENTITY:
169             {
170                 /**
171                  * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
172                  *
173                  * At this point, The server generate random hint and
174                  * provide it to client through server key exchange message.
175                  */
176                 OCFillRandomMem(result, result_length);
177                 ret = result_length;
178                 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
179                 OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
180             }
181             break;
182
183         case CA_DTLS_PSK_KEY:
184             {
185                 if(0 == DerivePSKUsingRPK((uint8_t*)result))
186                 {
187                     ret = OWNER_PSK_LENGTH_128;
188                 }
189                 else
190                 {
191                     OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from RPK");
192                     ret = -1;
193                 }
194             }
195             break;
196
197         default:
198             {
199                 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
200                 ret = -1;
201             }
202             break;
203     }
204     return ret;
205 }
206
207 OCStackResult GetMasterRPKCallback(OTMContext_t *otmCtx)
208 {
209     if (!otmCtx || !otmCtx->selectedDeviceInfo)
210     {
211         return OC_STACK_INVALID_PARAM;
212     }
213
214     uint8_t rpkData[OXM_RPK_MASTER_KEY_MAX_SIZE + 1] = {0};
215     size_t rpkLen = 0;
216     OCStackResult res = OC_STACK_ERROR;
217
218     res = GetMasterRPK((char*)rpkData, &rpkLen);
219
220     if (OC_STACK_OK != res)
221     {
222         OIC_LOG(ERROR, TAG, "Failed to generate RPK master key");
223         SetResult(otmCtx, res);
224         return res;
225     }
226
227     /**
228      * Since PSK will be used directly while RPK based ownership transfer,
229      * Credential should not be saved into SVR.
230      * For this reason, We will use a temporary get_psk_info callback to random RPK OxM.
231      */
232     //in case of OTM
233     if(!(otmCtx->selectedDeviceInfo->doxm->owned))
234     {
235         if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRPKOxm))
236         {
237             OIC_LOG(ERROR, TAG, "Failed to register DTLS credentials handler for random raw public key OxM.");
238             res = OC_STACK_ERROR;
239         }
240     }
241
242     //Set the device id to derive temporal PSK
243     SetUuidForRPKBasedOxm(&(otmCtx->selectedDeviceInfo->doxm->deviceID));
244
245     return res;
246 }
247
248 OCStackResult CreateSecureSessionRPKCallback(OTMContext_t* otmCtx)
249 {
250     OIC_LOG(INFO, TAG, "IN CreateSecureSessionRPKCallback");
251
252     if (!otmCtx || !otmCtx->selectedDeviceInfo)
253     {
254         return OC_STACK_INVALID_PARAM;
255     }
256
257     CAResult_t caresult = CAEnableAnonECDHCipherSuite(false);
258     if (CA_STATUS_OK != caresult)
259     {
260         OIC_LOG_V(ERROR, TAG, "Unable to disable anon cipher suite");
261         return OC_STACK_ERROR;
262     }
263     OIC_LOG(INFO, TAG, "Anonymous cipher suite disabled.");
264
265     caresult  = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, otmCtx->selectedDeviceInfo->endpoint.adapter);
266     if (CA_STATUS_OK != caresult)
267     {
268         OIC_LOG_V(ERROR, TAG, "Failed to select TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256");
269         return OC_STACK_ERROR;
270     }
271     OIC_LOG(INFO, TAG, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 cipher suite selected.");
272
273     OCProvisionDev_t* selDevInfo = otmCtx->selectedDeviceInfo;
274     CAEndpoint_t endpoint;
275     memcpy(&endpoint, &selDevInfo->endpoint, sizeof(CAEndpoint_t));
276
277     if(CA_ADAPTER_IP == endpoint.adapter)
278     {
279         endpoint.port = selDevInfo->securePort;
280         caresult = CAInitiateHandshake(&endpoint);
281     }
282     else if (CA_ADAPTER_GATT_BTLE == endpoint.adapter)
283     {
284         caresult = CAInitiateHandshake(&endpoint);
285     }
286 #ifdef __WITH_TLS__
287     else
288     {
289         endpoint.port = selDevInfo->tcpPort;
290         caresult = CAinitiateSslHandshake(&endpoint);
291     }
292 #endif
293     if (CA_STATUS_OK != caresult)
294     {
295         OIC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
296         return OC_STACK_ERROR;
297     }
298
299     OIC_LOG(INFO, TAG, "OUT CreateSecureSessionRPKCallback");
300
301     return OC_STACK_OK;
302 }