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