Svace memory leak fixes
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / cloud / csr.c
1 /* *****************************************************************
2  *
3  * Copyright 2016 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 #include "utils.h"
21
22 #include "logger.h"
23 #include <stddef.h>
24 #include <string.h>
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "cacommonutil.h"
28
29 #include "ocpayload.h"
30 #include "payload_logging.h"
31 #include "doxmresource.h"
32 #include "pmutility.h"
33 #include "secureresourceprovider.h"
34
35 // headers required for mbed TLS
36 #include "mbedtls/platform.h"
37 #include "mbedtls/ssl.h"
38 #include "mbedtls/entropy.h"
39 #include "mbedtls/ctr_drbg.h"
40 #include "mbedtls/pkcs12.h"
41 #include "mbedtls/ssl_internal.h"
42 #include "mbedtls/x509_csr.h"
43
44 #ifndef NDEBUG
45 #include "mbedtls/debug.h"
46 #include "mbedtls/version.h"
47 #endif
48
49 #include <unistd.h>
50 #include <fcntl.h>
51
52 #define TAG "OIC_CLOUD_CSR"
53
54 //TODO: is it required in CSR response?
55 static OCByteString g_privateKey = {0, 0};
56
57 #define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
58
59 #define MAX_STRING_LEN 254
60
61 /**
62  * @def SEED
63  * @brief Seed for initialization RNG
64  */
65
66 #define SEED "IOTIVITY_RND"
67
68 typedef struct
69 {
70     char *subject;
71     char *prKey;
72     size_t prKeyLen;
73     char *pubKey;
74     size_t pubKeyLen;
75 } SignCred_t;
76
77 /**
78  * Make CSR subject like:
79  * Subject: C=KR, O=Samsung, OU=OCF Device, CN=uuid:1234567890
80  * @param[in] subj              the subject
81  */
82 static void CSRMakeSubject(char *subject, const char *countryCode, const char *organisation,
83                     const char *organizationalUnitName, const char *deviceId)
84 {
85     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
86
87     if (!deviceId)
88     {
89         OIC_LOG_V(ERROR, TAG, "%s: The device id is NULL",__func__);
90         return;
91     }
92     snprintf(subject, MAX_STRING_LEN, "C=%s, O=%s, OU=%s, CN=uuid:%s", countryCode, organisation, organizationalUnitName, deviceId);
93
94     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
95 }
96 /**
97  * Generates elliptic keypair.
98  *
99  * @param[out]  pk    mbedtls public key container
100  *
101  * @return  0 on success or -1 on error
102  */
103 static int ecdsaGenKeypair(mbedtls_pk_context * pk)
104 {
105     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
106     mbedtls_entropy_context entropy;
107     mbedtls_ctr_drbg_context ctr_drbg;
108
109     VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
110
111     // Entropy seeding
112 #ifdef __unix__
113     unsigned char seed[sizeof(SEED)] = {0};
114     int urandomFd = -2;
115     urandomFd = open("/dev/urandom", O_RDONLY);
116     if(urandomFd == -1)
117     {
118         OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
119         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
120         return -1;
121     }
122     if(0 > read(urandomFd, seed, sizeof(seed)))
123     {
124         OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
125         close(urandomFd);
126         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
127         return -1;
128     }
129     close(urandomFd);
130
131 #else
132     unsigned char * seed = (unsigned char*) SEED;
133 #endif
134     // Initialize and seed DRBG context
135     mbedtls_ctr_drbg_init(&ctr_drbg);
136     mbedtls_entropy_init(&entropy);
137     if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
138                                    &entropy, seed, sizeof(SEED)))
139     {
140         OIC_LOG(ERROR, TAG, "Seed initialization failed!");
141         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
142         return -1;
143     }
144     mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
145     // Initialize l context
146     mbedtls_pk_init(pk);
147     if (0 > mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)))
148     {
149         OIC_LOG(ERROR, TAG, "mbedtls_pk_info_from_type error");
150         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
151         return -1;
152     }
153     if (0 > mbedtls_ecp_group_load(&mbedtls_pk_ec(*pk)->grp, MBEDTLS_ECP_DP_SECP256R1))
154     {
155         OIC_LOG(ERROR, TAG, "mbedtls_ecp_group_load error");
156         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
157         return -1;
158     }
159     if (0 > mbedtls_ecp_gen_keypair(&mbedtls_pk_ec(*pk)->grp,
160                                     &mbedtls_pk_ec(*pk)->d,
161                                     &mbedtls_pk_ec(*pk)->Q,
162                                     mbedtls_ctr_drbg_random, &ctr_drbg))
163     {
164         OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
165         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
166         return -1;
167     }
168
169     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
170     return 0;
171 }
172
173
174
175 /**
176  * Generates keypair and certificate signing request.
177  *
178  * @param[in]  subjectName    CSR Subject names should contain
179  * a comma-separated list of OID types and values:
180  * e.g. "C=UA,O=ABC,CN=uuid:32323232-3232-3232-3232-323232323232"
181  * @param[out] prKey          private key in DER
182  * @param[out] prKeyLen       private key buffer length
183  * @param[out] pubKey         public key in DER
184  * @param[out] pubKeyLen      public key buffer length
185  * @param[out] CSR            certificate signing request in DER
186  * @param[out] CSRLen         certificate signing request buffer length
187  *
188  * @return  0 on success or -1 on error
189  */
190 static int GenerateCSR(char *subject, OCByteString *csr)
191 {
192     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
193     VERIFY_NON_NULL_RET(subject, TAG, "Param subject is NULL", -1);
194     VERIFY_NON_NULL_RET(csr, TAG, "Param csr is NULL", -1);
195
196     int ret = 0;
197     int bufsize = 1024;
198     unsigned char * buf = NULL;
199     mbedtls_entropy_context entropy;
200     mbedtls_ctr_drbg_context ctr_drbg;
201     mbedtls_pk_context * key = NULL;
202     mbedtls_x509write_csr req;
203
204     // Initialize keypair context
205     key = (mbedtls_pk_context *)OICMalloc(sizeof(mbedtls_pk_context));
206     if (NULL == key)
207     {
208         OIC_LOG_V(ERROR, TAG, "OICMalloc returned NULL on key allocation");
209         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
210         return -1;
211     }
212     // Generate keypair
213     if (0 > ecdsaGenKeypair(key))
214     {
215         OIC_LOG(ERROR, TAG, "ecdsaGenKeypair error");
216         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
217         OICFree(key);
218         return -1;
219     }
220
221     // Initialize CSR context
222     mbedtls_x509write_csr_init(&req);
223     // Set up MD algorithm, key and subject to CSR
224     mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
225     mbedtls_x509write_csr_set_key(&req, key);
226     if (0 > mbedtls_x509write_csr_set_subject_name(&req, subject))
227     {
228         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_set_subject_name error");
229         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
230         return -1;
231     }
232
233     // Entropy seeding
234 #ifdef __unix__
235     unsigned char seed[sizeof(SEED)] = {0};
236     int urandomFd = -2;
237     urandomFd = open("/dev/urandom", O_RDONLY);
238     if(urandomFd == -1)
239     {
240         OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
241         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
242         return -1;
243     }
244     if(0 > read(urandomFd, seed, sizeof(seed)))
245     {
246         OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
247         close(urandomFd);
248         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
249         return -1;
250     }
251     close(urandomFd);
252
253 #else
254     unsigned char * seed = (unsigned char *) SEED;
255 #endif
256     // Initialize and seed DRBG context
257     mbedtls_ctr_drbg_init(&ctr_drbg);
258     mbedtls_entropy_init(&entropy);
259     if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
260                                    &entropy, seed, sizeof(SEED)))
261     {
262         OIC_LOG(ERROR, TAG, "Seed initialization failed!");
263         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
264         return -1;
265     }
266     mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
267
268     // Create CSR
269     buf = (unsigned char *)OICMalloc(bufsize * sizeof(unsigned char));
270     if (NULL == buf)
271     {
272         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on buf allocation");
273         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
274         return -1;
275     }
276     ret = mbedtls_x509write_csr_der(&req, buf, bufsize,
277                                     mbedtls_ctr_drbg_random, &ctr_drbg);
278     if (ret < 0)
279     {
280         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_der error");
281         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
282         OICFree(buf);
283         return -1;
284     }
285
286     // CSR to output
287     csr->bytes = (uint8_t *)OICMalloc(ret * sizeof(uint8_t));
288     if (NULL == csr->bytes)
289     {
290         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
291         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
292         OICFree(buf);
293         return -1;
294     }
295     memcpy(csr->bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
296     csr->len = ret;
297     // Private key to output
298     ret = mbedtls_pk_write_key_der(key, buf, bufsize);
299     if (ret < 0)
300     {
301         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_key_der error");
302         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
303         return -1;
304     }
305     g_privateKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
306     if (NULL == g_privateKey.bytes)
307     {
308         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on g_privateKey.bytes allocation");
309         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
310         return -1;
311     }
312     memcpy(g_privateKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
313     g_privateKey.len = ret;
314     // Public key to output
315     ret = mbedtls_pk_write_pubkey_der(key, buf, bufsize);
316     if (ret < 0)
317     {
318         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_pubkey_der error");
319         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
320         return -1;
321     }
322     //leave this, may be public key will be required in future
323     OCByteString publicKey;
324     publicKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
325     if (NULL == publicKey.bytes)
326     {
327         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on pubKey allocation");
328         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
329         return -1;
330     }
331     memcpy(publicKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
332     publicKey.len = ret;
333     OICFree(publicKey.bytes);
334
335     mbedtls_entropy_free(&entropy);
336     mbedtls_ctr_drbg_free(&ctr_drbg);
337     mbedtls_x509write_csr_free(&req);
338     OICFree(key);
339
340     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
341     return 0;
342 }
343
344 /**
345  * Cloud CSR Sign response handler
346
347  * @param[in] ctx       context
348  * @param[out] data     data required to external application
349  * @param[in] response  peer response
350  * @return  OCStackResult application result
351  */
352 static OCStackResult HandleCertificateIssueRequest(void *ctx, void **data, OCClientResponse *response)
353 {
354     OCStackResult result = OC_STACK_OK;
355     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
356
357     OC_UNUSED(ctx);
358     OC_UNUSED(data);
359
360     if (!response)
361     {
362         OIC_LOG_V(ERROR, TAG, "%s: Client response is null",__func__);
363         return OC_STACK_INVALID_PARAM;
364     }
365
366     if (response->result < 4 && response->payload)
367     {
368         OIC_LOG_V(ERROR, TAG, "CSR sign error: result: %d, payload null: %s",
369                   response->result, response->payload ? "no" : "yes");
370         OIC_LOG_PAYLOAD(DEBUG, response->payload);
371         return OC_STACK_ERROR;
372     }
373
374     char *deviceId = 0;
375
376     if (!OCRepPayloadGetPropString((OCRepPayload *)response->payload,
377                                    OC_RSRVD_DEVICE_ID, &deviceId))
378     {
379         OIC_LOG(ERROR, TAG, "Can't get: Device Id");
380         result = OC_STACK_ERROR;
381     }
382
383     OicSecKey_t cert;
384     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
385                                    OC_RSRVD_CERT, &cert))
386     {
387         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CERT);
388         result = OC_STACK_ERROR;
389     }
390     else
391     {
392         OicSecKey_t key =
393         {
394             g_privateKey.bytes,
395             g_privateKey.len,
396             OIC_ENCODING_DER
397         };
398
399         uint16_t credId;
400         result = SRPSaveOwnCertChain(&cert, &key, &credId);
401         if (result != OC_STACK_OK)
402         {
403             OIC_LOG(ERROR, TAG, "Can't add cert");
404         }
405     }
406
407     //get cacert
408     OicSecKey_t caCert;
409     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
410                                    OC_RSRVD_CACERT, &caCert))
411     {
412         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CACERT);
413         result = OC_STACK_ERROR;
414     }
415     else
416     {
417         uint16_t credId;
418         result = SRPSaveTrustCertChain(caCert.data, caCert.len, caCert.encoding, &credId);
419         if (result != OC_STACK_OK)
420         {
421             OIC_LOG(ERROR, TAG, "Can't insert CA cert");
422         }
423     }
424
425     OICFree(deviceId);
426
427     OICClearMemory(g_privateKey.bytes, g_privateKey.len);
428     OICFree(g_privateKey.bytes);
429     g_privateKey.bytes = NULL;
430     g_privateKey.len   = 0;
431
432     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
433
434     return result;
435 }
436
437 /**
438  * Certificate-Issue request function
439  *
440  * @param[in] endPoint          cloud host and port
441  * @return  OCStackResult application result
442  */
443 OCStackResult OCCloudCertificateIssueRequest(void* ctx,
444                                              const OCDevAddr *endPoint,
445                                              OCCloudResponseCB callback)
446 {
447     OCStackResult ret = OC_STACK_OK;
448
449     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
450
451     if (NULL == endPoint)
452     {
453         OIC_LOG(ERROR, TAG, "Input parameter endpoint is NULL");
454         return OC_STACK_INVALID_PARAM;
455     }
456
457     char *deviceId = getDeviceId();
458
459     char subject[MAX_STRING_LEN] = { 0 };
460     CSRMakeSubject(subject, "KR", "Samsung", "OCF Device", deviceId);
461
462     OIC_LOG_V(DEBUG, TAG, "Certificate Request subject: %s", subject);
463
464     OCByteString request = {0};
465     if (0 != GenerateCSR(subject, &request))
466     {
467         OIC_LOG(ERROR, TAG, "Cann't get the sertificate request");
468         ret = OC_STACK_ERROR;
469         goto exit;
470     }
471     OIC_LOG(DEBUG, TAG, "Certificate Request:");
472     OIC_LOG_BUFFER(DEBUG, TAG, request.bytes, request.len);
473
474     OIC_LOG(DEBUG, TAG, "Private Key:");
475     OIC_LOG_BUFFER(DEBUG, TAG, g_privateKey.bytes, g_privateKey.len);
476
477     OCRepPayload* payload = OCRepPayloadCreate();
478     if (!payload)
479     {
480         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
481         ret = OC_STACK_ERROR;
482         goto exit;
483     }
484
485     OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, deviceId);
486
487     OicSecKey_t csr = {.data = request.bytes, .len = request.len, .encoding = OIC_ENCODING_DER};
488
489     OCRepPayloadSetPropPubDataType(payload, OC_RSRVD_CSR, &csr);
490
491     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)payload);
492
493     char uri[MAX_URI_QUERY] = { 0 };
494     snprintf(uri, MAX_URI_QUERY, DEFAULT_QUERY,
495              endPoint->addr, endPoint->port,
496              OC_RSRVD_PROV_CERT_URI);
497     OIC_LOG_V(DEBUG, TAG, "Certificate Request Query: %s", uri);
498
499     OCCallbackData cbData;
500     fillCallbackData(&cbData, ctx, callback, HandleCertificateIssueRequest, NULL);
501
502     ret = OCDoResource(NULL, OC_REST_POST, uri, NULL,
503                        (OCPayload *)payload,
504                        CT_ADAPTER_TCP,
505                        OC_LOW_QOS, &cbData, NULL, 0);
506
507     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
508 exit:
509     OICFree(request.bytes);
510     return ret;
511 }