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